This is the mail archive of the
libstdc++@sourceware.cygnus.com
mailing list for the libstdc++ project.
stream inserter implementation for double/long double
- To: "libstdc++ at sourceware dot cygnus dot com" <libstdc++ at sourceware dot cygnus dot com>
- Subject: stream inserter implementation for double/long double
- From: Kevin Ediger <kediger at licor dot com>
- Date: Fri, 12 Nov 1999 15:49:08 -0600
- Organization: LI-COR, Inc.
- Reply-To: kediger at licor dot com
Here's my implementation of num_put::do_put() for double and long
double. I'll post my test cases shortly.
Index: locale_facets.tcc
===================================================================
RCS file: /cvs/libstdc++/libstdc++/bits/locale_facets.tcc,v
retrieving revision 1.16
diff -u -r1.16 locale_facets.tcc
--- locale_facets.tcc 1999/11/12 08:06:48 1.16
+++ locale_facets.tcc 1999/11/12 21:39:41
@@ -1023,22 +1023,119 @@
return _S_format_long(__s, __io, __fill, false, __v);
}
+ // The following code uses sprintf() to convert floating point values
for
+ // insertion into a stream. The current implementation replicates the
+ // code in _S_pad_numeric() (in _S_output_float()) in order to
prevent having to
+ // create a "wide" buffer in addition to the "narrow" buffer passed
to
+ // sprintf(). An optimization would be to replace sprintf() with
+ // code that works directly on a wide buffer and then use
+ // _S_pad_numeric() to do the padding. It would be good to replace
+ // sprintf() anyway to avoid accidental buffer overruns and to gain
+ // back the efficiency that C++ provides by knowing up front the type
+ // of the values to insert. This implementation follows the
+ // C++ standard fairly directly as outlined in 22.2.2.2
[lib.locale.num.put]
+ bool
+ _S_build_float_format(ios_base& __io,char* __fptr,char
__modifier,streamsize __prec)
+ {
+ bool __incl_prec = false;
+ ios_base::fmtflags __flags = __io.flags();
+ *__fptr++ = '%';
+ if ( __flags & ios_base::showpos ) /* [22.2.2.2.2] Table 60 */
+ *__fptr++ = '+';
+ if ( __flags & ios_base::showpoint )
+ *__fptr++ = '#';
+ if ( __flags & ios_base::fixed || __prec > 0 ) /* as per
[22.2.2.2.2.11] */
+ {
+ *__fptr++ = '.';
+ *__fptr++ = '*';
+ __incl_prec = true;
+ }
+ if ( __modifier )
+ *__fptr++ = __modifier;
+ ios_base::fmtflags __fltfield = __flags & ios_base::floatfield;
+ if ( __fltfield == ios_base::fixed ) /* [22.2.2.2.2] Table 58 */
+ *__fptr++ = 'f';
+ else if ( __fltfield == ios_base::scientific )
+ *__fptr++ = (__flags & ios_base::uppercase) ? 'E' : 'e';
+ else
+ *__fptr++ = (__flags & ios_base::uppercase) ? 'G' : 'g';
+ *__fptr = '\0';
+ return __incl_prec;
+ }
+
+ template<typename _CharT,typename _OutIter>
+ _OutIter
+ _S_output_float(_OutIter __s,ios_base& __io,_CharT __fill,const
char* __sptr,size_t __slen)
+ {
+ size_t __padding = __io.width() > streamsize(__slen) ?
+ __io.width()-__slen : 0;
+ locale __loc = __io.getloc();
+ ctype<_CharT> const& __ct = use_facet<ctype<_CharT> >(__loc);
+ ios_base::fmtflags __adjfield = __io.flags() &
ios_base::adjustfield;
+ const char* const __eptr = __sptr+__slen;
+ if ( __adjfield == ios_base::internal ) /* [22.2.2.2.2.19] Table
61 */
+ {
+ if ( __sptr<__eptr && (*__sptr == '+' || *__sptr == '-') )
+ __s = __ct.widen(*__sptr),++__s,++__sptr; /* [22.2.2.2.2.14];
widen() */
+ __s = _S_fill(__s,__fill,__padding),__padding=0;
+ }
+ else if ( __adjfield != ios_base::left )
+ __s = _S_fill(__s,__fill,__padding),__padding=0;
+ char __decimal_point = *(localeconv()->decimal_point); // the
"C" locale decimal character
+ for ( ; __sptr != __eptr ; ++__s,++__sptr )
+ {
+ if ( *__sptr == __decimal_point ) /* [22.2.2.2.2.17]; decimal point
conversion */
+ {
+ const _Format_cache<_CharT>* __fmt =
_Format_cache<_CharT>::_S_get(__io);
+ __s = __fmt->_M_decimal_point;
+ }
+ else
+ __s = __ct.widen(*__sptr); /* [22.2.2.2.2.14]; widen() */
+ }
+ if ( __padding )
+ _S_fill(__s,__fill,__padding); /* [22.2.2.2.2.19] Table 61 */
+ __io.width(0);
+ return __s;
+ }
+
template <typename _CharT, typename _OutIter>
_OutIter
num_put<_CharT, _OutIter>::
- do_put(iter_type __s, ios_base& /*__io*/, char_type /*__fill*/,
- double /*__v*/) const
+ do_put(iter_type __s, ios_base& __io, char_type __fill,
+ double __v) const
{
- return __s; // XXX not done
+ const streamsize __max_prec = numeric_limits<double>::digits10;
+ streamsize __prec = __io.precision();
+ if ( __prec > __max_prec ) /* protect against sprintf() buffer
overflows */
+ __prec = __max_prec;
+ char __sbuf[__max_prec*2]; /* the *2 provides for signs, exp,
'E', and pad */
+ size_t __slen;
+ char __fbuf[16]; /* long enough for the max format spec */
+ if ( _S_build_float_format(__io,__fbuf,0,__prec) )
+ __slen = sprintf(__sbuf,__fbuf,__prec,__v);
+ else
+ __slen = sprintf(__sbuf,__fbuf,__v);
+ return _S_output_float(__s,__io,__fill,__sbuf,__slen);/*
[22.2.2.2.2] Stages 2-4 */
}
template <typename _CharT, typename _OutIter>
_OutIter
num_put<_CharT, _OutIter>::
- do_put(iter_type __s, ios_base& /*__io*/, char_type /*__fill*/,
- long double /*__v*/) const
+ do_put(iter_type __s, ios_base& __io, char_type __fill,
+ long double __v) const
{
- return __s; // XXX not done
+ const streamsize __max_prec = numeric_limits<long
double>::digits10;
+ streamsize __prec = __io.precision();
+ if ( __prec > __max_prec ) /* protect against sprintf() buffer
overflows */
+ __prec = __max_prec;
+ char __sbuf[__max_prec*2]; /* the *2 provides for signs, exp,
'E', and pad */
+ size_t __slen;
+ char __fbuf[16]; /* long enough for the max format spec */
+ if ( _S_build_float_format(__io,__fbuf,'L',__prec) ) /* 'L' as
per [22.2.2.2.2] Table 59 */
+ __slen = sprintf(__sbuf,__fbuf,__prec,__v);
+ else
+ __slen = sprintf(__sbuf,__fbuf,__v);
+ return _S_output_float(__s,__io,__fill,__sbuf,__slen);/*
[22.2.2.2.2] Stages 2-4 */
}
template <typename _CharT, typename _OutIter>
===================================================================
Best Regards,
Kevin Ediger
--
LI-COR, Inc.
Voice: 402.467.3576 ext 3695, Fax: 402.467.0872
mailto:kediger@licor.com
http://www.licor.com