This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] PR 8761 and 7076, take 2


Here's the revised I/O patch including the changes I used from Benjamin's
reorg.  In addition, I've dispensed with using _S_format_int() and
ctype.widen().  Also, I'm no longer using __convert_from_v().  There's a new
function __convert_from_int() with a better interface.  And finally, I've made
_M_insert use the underlying sputn() routine for the streambuf.

All told, this patch brings execution time of PR8761's testcase from 25
seconds to 7.9 seconds.  At this point, I think the low-hanging fruit is
mostly gone.

There is an annoying wart where I had to make a friend declaration inside
ostreambuf_iterator to get access to the underlying streambuf.  Suggestions
for a cleaner implementation are quite welcome.

Another ugliness is that I had to force the cache to be called and built from
basic_ios::imbue.  The problem was that in the previous patch, the cache
wasn't created until an ostream insertion was done.  If you imbued the stream
with a modified locale, the imbue event would not get to the cache because it
didn't exist yet.  Then, the cache for char and wchar_t would be created
during the inserter.  These variants are always considered valid, so the
caches wouldn't be updated with the new locale info.

No new regressions except for the test link errors that Benjamin is looking into.


2003-01-15 Jerry Quinn  <jlquinn@optonline.net>

	* config/locale/generic/c_locale.h (__convert_from_v): Add
	specialization declarations.
	* config/locale/gnu/c_locale.h: Same.
        * src/locale.cc (__convert_from_v<long>,
	__convert_from_v<unsigned long>, __convert_from_v<long long>,
	__convert_from_v<unsigned long long>):  Add specialization definitions.
	* include/bits/basic_ios.tcc (_Format_cache): Declare here.
	(basic_ios::imbue): Force format cache to be built.
	* include/bits/ios_base.h (ios_base): Document storage location of
	format cache.
	* include/bits/locale_facets.h (convert_to_v): Declare here.
	(struct __pad): Same.
	(__verify_grouping): Same.
	(__add_grouping): Same.		
        (_Format_cache<_CharT>):  New class.
	(_Format_cache<char>, _Format_cache<wchar_t>): New specializations.
	* include/bits/locale_facets.tcc (__num_put_abs, __num_put_cvt): New
	inline functions.
	(__convert_from_int): New.
	(num_put::_M_convert_int): Remove unused parameter names. Choose large
	enough buffer for text.  Use format cache literal string.  Use
	__convert_from_int.  Use __num_put_abs.  Use __num_put_cvt. Formatted
	text is now at the end of the buffer.
	(num_put::_M_widen): Remove __loc.  Remove __ctype.  Remove __np.  Use
	_Format_cache.  Move __basefield to within grouping block.  Get
	grouping and thousands_sep info from cache.
	(__num_put_output<_CharT, _OutIter>): New function.
	(__num_put_output<_CharT>): New specialization.
	(num_put::_M_insert): Remove explicit loop over iterator.  Use
	__num_put_output.
	(_Format_cache<_CharT>::_Format_cache): New.
	(_Format_cache<_CharT>::_M_populate): New.
	(_Format_cache<_CharT>::_S_callback): New.
	(_Format_cache<_CharT>::_S_get): New.
	(_Format_cache<char>::_Format_cache): New specialization.
	(_Format_cache<wchar_t>::_Format_cache): New specialization.
	* include/bits/streambuf_iterator.h (ostreambuf_iterator): Add
	__num_put_output as friend function.
	* src/locale-inst.cc (_Format_cache<char>, _Format_cache<_char_t>):
	New.
	(__convert_from_v<long long>, __convert_from_v<unsigned long long>):
	Add ifdef.
	(__convert_from_int<char,unsigned long>): New.
	(__convert_from_int<char,unsigned long long>): New.
	(__convert_from_int<wchar_t, unsigned long>): New.
	(__convert_from_int<wchar_t, unsigned long long>): New.
	* src/localenames.cc (_Format_cache<char>::_Format_cache,
	_Format_cache<wchar_t>::_Format_cache): New.



diff -r -u libstdc++.orig/config/locale/generic/c_locale.h libstdc++-v3/config/locale/generic/c_locale.h
--- libstdc++.orig/config/locale/generic/c_locale.h	Mon Jan  6 22:54:06 2003
+++ libstdc++-v3/config/locale/generic/c_locale.h	Wed Jan 15 00:22:21 2003
@@ -1,6 +1,6 @@
 // Wrapper for underlying C-language localization -*- C++ -*-
 
-// Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
@@ -41,6 +41,16 @@
 {
   typedef int*			__c_locale;
 
+  // Convert numeric value of type _Tv to string and return length of string.
+  // If snprintf is available use it, otherwise fall back to the unsafe sprintf
+  // which, in general, can be dangerous and should be avoided.
+  template<typename _Tv>
+    int
+    __convert_from_v(char* __out, const int __size, const char* __fmt,
+		     _Tv __v, const __c_locale&, int __prec = -1);
+
+
+  // Generic definition.
   template<typename _Tv>
     int
     __convert_from_v(char* __out, const int __size, const char* __fmt,
diff -r -u libstdc++.orig/config/locale/gnu/c_locale.h libstdc++-v3/config/locale/gnu/c_locale.h
--- libstdc++.orig/config/locale/gnu/c_locale.h	Mon Jan  6 22:54:06 2003
+++ libstdc++-v3/config/locale/gnu/c_locale.h	Wed Jan 15 00:21:41 2003
@@ -1,6 +1,6 @@
 // Wrapper for underlying C-language localization -*- C++ -*-
 
-// Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
@@ -53,6 +53,17 @@
 {
   typedef __locale_t		__c_locale;
 
+  // Convert numeric value of type _Tv to string and return length of string.
+  // If snprintf is available use it, otherwise fall back to the unsafe sprintf
+  // which, in general, can be dangerous and should be avoided.
+  template<typename _Tv>
+    int
+    __convert_from_v(char* __out, const int __size, const char* __fmt,
+		     _Tv __v, const __c_locale&, int __prec = -1);
+
+
+
+  // Generic definition.
   template<typename _Tv>
     int
     __convert_from_v(char* __out, const int __size, const char* __fmt,
diff -r -u libstdc++.orig/include/bits/basic_ios.tcc libstdc++-v3/include/bits/basic_ios.tcc
--- libstdc++.orig/include/bits/basic_ios.tcc	Mon Jan  6 22:54:07 2003
+++ libstdc++-v3/include/bits/basic_ios.tcc	Wed Jan 15 23:56:07 2003
@@ -122,6 +122,9 @@
       return __ret;
     }
 
+  // Forward decl makes the _S_get call below happy.  Better way to do this?
+  template<typename _CharT> class _Format_cache;
+
   // Locales:
   template<typename _CharT, typename _Traits>
     locale
@@ -130,6 +133,10 @@
       locale __old(this->getloc());
       ios_base::imbue(__loc);
       _M_cache_facets(__loc);
+      // Force the cache to be rebuilt.  Else, for char and wchar_t, if imbue
+      // is called before first use of cache, modified locale is ignored because
+      // we think the cache is valid, i.e. cache callback is never called.
+      _Format_cache<_CharT>::_S_get(*this, false);
       if (this->rdbuf() != 0)
 	this->rdbuf()->pubimbue(__loc);
       return __old;
diff -r -u libstdc++.orig/include/bits/ios_base.h libstdc++-v3/include/bits/ios_base.h
--- libstdc++.orig/include/bits/ios_base.h	Mon Jan  6 22:54:07 2003
+++ libstdc++-v3/include/bits/ios_base.h	Wed Jan 15 23:56:52 2003
@@ -1,6 +1,6 @@
 // Iostreams base classes -*- C++ -*-
 
-// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
+// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
 // Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
@@ -414,6 +414,9 @@
     _Words  		_M_word_zero;    
 
     // Guaranteed storage.
+    // The first 5 iword and pword slots are reserved.  Currently
+    // pword(0) is used for the formatting cache.
+
     static const int 	_S_local_word_size = 8;
     _Words  		_M_local_word[_S_local_word_size];  
 
diff -r -u libstdc++.orig/include/bits/locale_facets.h libstdc++-v3/include/bits/locale_facets.h
--- libstdc++.orig/include/bits/locale_facets.h	Mon Jan  6 22:54:07 2003
+++ libstdc++-v3/include/bits/locale_facets.h	Wed Jan 15 23:59:44 2003
@@ -1,6 +1,6 @@
 // Locale support -*- C++ -*-
 
-// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
+// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
 // Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
@@ -55,9 +55,6 @@
 # define  _GLIBCPP_NUM_FACETS 14
 #endif
 
-  template<typename _CharT, typename _Traits>
-    struct __pad;
-
   // 22.2.1.1  Template class ctype
   // Include host and configuration specific ctype enums for ctype_base.
   #include <bits/ctype_base.h>
@@ -1805,6 +1802,167 @@
     inline _CharT 
     tolower(_CharT __c, const locale& __loc)
     { return use_facet<ctype<_CharT> >(__loc).tolower(__c); }
+
+
+  // Convert string to numeric value of type _Tv and store results.  
+  // NB: This is specialized for all required types, there is no
+  // generic definition.
+  template<typename _Tv>
+    void
+    __convert_to_v(const char* __in, _Tv& __out, ios_base::iostate& __err, 
+		   const __c_locale& __cloc, int __base = 10);
+
+  // NB: Of the two parameters, _CharT can be deduced from the
+  // function arguments. The other (_Traits) has to be explicitly specified.
+  template<typename _CharT, typename _Traits>
+    struct __pad
+    {
+      static void
+      _S_pad(ios_base& __io, _CharT __fill, _CharT* __news, 
+	     const _CharT* __olds, const streamsize __newlen, 
+	     const streamsize __oldlen, const bool __num);
+    };
+
+  // Used by both numeric and monetary facets.
+  // Check to make sure that the __grouping_tmp string constructed in
+  // money_get or num_get matches the canonical grouping for a given
+  // locale.
+  // __grouping_tmp is parsed L to R
+  // 1,222,444 == __grouping_tmp of "/1/3/3"
+  // __grouping is parsed R to L
+  // 1,222,444 == __grouping of "/3" == "/3/3/3"
+  template<typename _CharT>
+    bool
+    __verify_grouping(const basic_string<_CharT>& __grouping, 
+		      basic_string<_CharT>& __grouping_tmp);
+
+  // Used by both numeric and monetary facets.
+  // Inserts "group separator" characters into an array of characters.
+  // It's recursive, one iteration per group.  It moves the characters
+  // in the buffer this way: "xxxx12345" -> "12,345xxx".  Call this
+  // only with __gbeg != __gend.
+  template<typename _CharT>
+    _CharT*
+    __add_grouping(_CharT* __s, _CharT __sep,  
+		   const char* __gbeg, const char* __gend, 
+		   const _CharT* __first, const _CharT* __last);
+
+
+  // Cache for formatting data from several facets.
+
+  // _Format_cache holds the information extracted from the numpunct<>
+  // and moneypunct<> facets in a form optimized for parsing and
+  // formatting.  It is stored via a void* pointer in the pword()
+  // array of an iosbase object passed to the _get and _put facets.
+  // pword(0) is reserved for the cache.
+
+  // Its intent is to avoid the cost of creating a locale object and
+  // calling the virtual functions in locale facets.
+  template<typename _CharT>
+    class _Format_cache
+    {
+      // Types:
+      typedef _CharT                    char_type;
+      typedef char_traits<_CharT>       traits_type;
+      typedef basic_string<_CharT>	string_type;
+
+      // Forward decls and Friends:
+      friend class locale;
+      template<typename _Char, typename _InIter>
+        friend class _Numeric_get;
+      friend class num_get<_CharT>;
+      friend class time_get<_CharT>;
+      friend class money_get<_CharT>;
+      friend class num_put<_CharT>;
+      friend class time_put<_CharT>;
+      friend class money_put<_CharT>;
+
+    public: 
+      // Data Members:
+
+      // True iff data members are consistent with the current locale,
+      // i.e. imbue sets this to false.
+      bool                      _M_valid;
+
+      
+      // A list of valid numeric literals: for the standard "C" locale, this
+      // is "-+xX0123456789abcdef0123456789ABCDEF".  This array contains the
+      // chars after having been passed through the current locale's
+      // ctype<_CharT>.widen().
+      // 
+
+      // NB: code depends on the order of definitions of the names
+      // these are indices into _M_numeric_literals, below.
+      // This string is formatted for putting, not getting. (output, not input)
+      enum 
+      {  
+        _S_minus, 
+        _S_plus, 
+        _S_x, 
+        _S_X, 
+        _S_digits,
+        _S_digits_end = _S_digits + 16,
+        _S_udigits = _S_digits_end,  
+        _S_udigits_end = _S_udigits + 16,
+        _S_ee = _S_digits + 14, // For scientific notation, 'e'
+        _S_Ee = _S_udigits + 14 // For scientific notation, 'E'
+      };
+
+      _CharT                    _M_literals[_S_udigits_end];
+
+     
+      // The sign used to separate decimal values: for standard US
+      // locales, this would usually be: "."
+      // Abstracted from numpunct::decimal_point().
+      _CharT                    _M_decimal_point;
+
+      // The sign used to separate groups of digits into smaller
+      // strings that the eye can parse with less difficulty: for
+      // standard US locales, this would usually be: ","
+      // Abstracted from numpunct::thousands_sep().
+      _CharT                    _M_thousands_sep;
+      
+      // However the US's "false" and "true" are translated.
+      // From numpunct::truename() and numpunct::falsename(), respectively.
+      string_type 		_M_truename;
+      string_type 		_M_falsename;
+
+      // If we are checking groupings. This should be equivalent to 
+      // numpunct::groupings().size() != 0
+      bool                      _M_use_grouping;
+
+      // If we are using numpunct's groupings, this is the current grouping
+      // string in effect (from numpunct::grouping()).
+      string                    _M_grouping;
+
+      _Format_cache();
+
+      ~_Format_cache();
+
+      // Given a member of the ios heirarchy as an argument, extract out all
+      // the current formatting information into a _Format_cache object and
+      // return a pointer to it.  The __valid flag gives a way to force the
+      // cache to be reconstructed from the current locale.
+      static _Format_cache<_CharT>*
+      _S_get(ios_base& __ios, bool __valid=true);
+
+    private:
+      void 
+      _M_populate (ios_base&);
+
+      // Used to update the cache when ios_base::imbue(),basic_ios::copyfmt(),
+      // or ios_base::~ios_base() are called.
+      static void
+      _S_callback(ios_base::event __event, ios_base& __ios, int __ix) throw();
+
+    };
+
+  template<>
+    _Format_cache<char>::_Format_cache();
+#ifdef _G_USE_WCHAR_T
+  template<>
+    _Format_cache<wchar_t>::_Format_cache();
+#endif
 } // namespace std
 
 #endif
diff -r -u libstdc++.orig/include/bits/locale_facets.tcc libstdc++-v3/include/bits/locale_facets.tcc
--- libstdc++.orig/include/bits/locale_facets.tcc	Mon Jan  6 22:54:07 2003
+++ libstdc++-v3/include/bits/locale_facets.tcc	Thu Jan 16 00:00:05 2003
@@ -1,6 +1,6 @@
 // Locale support -*- C++ -*-
 
-// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
+// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
 // Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
@@ -686,39 +686,103 @@
 	return _M_widen_float(__s, __io, __fill, __cs, __len);
       }
 
+  // num_put::_M_convert_int is only ever templatized on long, unsigned long, long
+  // long, and unsigned long long.  These adapters permit calling into
+  // unsigned long and unsigned long long functions.
+  inline unsigned long __num_put_abs(long __v) { return -(unsigned long)__v; }
+  inline unsigned long __num_put_abs(unsigned long __v) { return __v; }
+  inline unsigned long __num_put_unsigned(long __v) { return (unsigned long)__v; }
+  inline unsigned long __num_put_unsigned(unsigned long __v) { return __v; }
+#ifdef _GLIBCPP_USE_LONG_LONG
+  inline unsigned long long __num_put_abs(long long __v) { return -(unsigned long long)__v; }
+  inline unsigned long long __num_put_abs(unsigned long long __v) { return __v; }
+  inline unsigned long long __num_put_unsigned(long long __v) { return -(unsigned long long)__v; }
+  inline unsigned long long __num_put_unsigned(unsigned long long __v) { return __v; }
+#endif
+
+  // Only called with unsigned long and unsigned long long
+  template<typename _CharT, typename _ValueT>
+    int
+    __convert_from_int(_CharT* __out, const int __size, _ValueT __v,
+		       const _CharT* __lit, ios_base::fmtflags __flags, 
+		       bool __neg)
+    {
+      _CharT* __bufptr = __out + __size - 1;
+      _CharT* __bufend = __out + __size;
+
+      if (__flags & ios_base::dec)
+	{
+	  // Decimal
+	  do {
+	    *__bufptr-- = __lit[(__v % 10) + _Format_cache<_CharT>::_S_digits];
+	    __v /= 10;
+	  } while (__v != 0);
+	  if (__neg)
+	    *__bufptr-- = __lit[_Format_cache<_CharT>::_S_minus];
+	  else if (__flags & ios_base::showpos)
+	    *__bufptr-- = __lit[_Format_cache<_CharT>::_S_plus];
+	}
+      else if (__flags & ios_base::oct)
+	{
+	  // Octal
+	  bool __showbase = ((__flags & ios_base::showbase) && __v); // Don't write base if already 0
+	  do {
+	    *__bufptr-- = __lit[(__v & 0x7) + _Format_cache<_CharT>::_S_digits];
+	    __v >>=3;
+	  } while (__v != 0);
+	  if (__showbase)
+	    *__bufptr-- = __lit[_Format_cache<_CharT>::_S_digits];
+	}
+      else
+	{
+	  // Hex
+	  int __case_offset = (__flags & ios_base::uppercase)
+	    ? _Format_cache<_CharT>::_S_udigits
+	    : _Format_cache<_CharT>::_S_digits;
+	  do {
+	    *__bufptr-- = __lit[(__v & 0xf) + __case_offset];
+	    __v >>=4;
+	  } while (__v != 0);
+	  if (__flags & ios_base::showbase)
+	    {
+	      // 'x' or 'X'
+	      *__bufptr-- = __lit[_Format_cache<_CharT>::_S_x +
+				  (int)(!!(__flags & ios_base::uppercase))];
+	      // '0'
+	      *__bufptr-- = __lit[_Format_cache<_CharT>::_S_digits];
+	    }
+	}
+      int __ret = __bufend - __bufptr - 1;
+      return __ret;
+    }
+
   template<typename _CharT, typename _OutIter>
     template<typename _ValueT>
       _OutIter
       num_put<_CharT, _OutIter>::
-      _M_convert_int(_OutIter __s, ios_base& __io, _CharT __fill, char __mod,
-		     char __modl, _ValueT __v) const
+      _M_convert_int(_OutIter __s, ios_base& __io, _CharT __fill, char,
+		     char, _ValueT __v) const
       {
 	// [22.2.2.2.2] Stage 1, numeric conversion to character.
 
-	// Long enough for the max format spec.
-	char __fbuf[16];
-	_S_format_int(__io, __fbuf, __mod, __modl);
-#ifdef _GLIBCPP_USE_C99
-	// First try a buffer perhaps big enough.
-	int __cs_size = 64;
-	char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
-	int __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, 
-				     _S_c_locale);
-	// If the buffer was not large enough, try again with the correct size.
-	if (__len >= __cs_size)
-	  {
-	    __cs_size = __len + 1;
-	    __cs = static_cast<char*>(__builtin_alloca(__cs_size));
-	    __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, 
-				     _S_c_locale);
-	  }
-#else
-	// Leave room for "+/-," "0x," and commas. This size is
-	// arbitrary, but should be largely sufficient.
-	char __cs[128];
-	int __len = __convert_from_v(__cs, 0, __fbuf, __v, _S_c_locale);
-#endif
-	return _M_widen_int(__s, __io, __fill, __cs, __len);
+	// Long enough to hold hex, dec, and octal representations.
+	int __cs_size = 4 * sizeof(_ValueT);
+	_CharT* __cs = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 
+							     * __cs_size));
+	_CharT* __lit = _Format_cache<_CharT>::_S_get(__io)->_M_literals;
+
+	int __len;
+	// Choose the adaptor required to convert the value for calling into
+	// an unsigned long (long) rendering function.  Result is returned
+	// right-justified in the buffer.
+	if (__v < 0)
+	  __len = __convert_from_int(&__cs[0], __cs_size, __num_put_abs(__v),
+				     __lit, __io.flags(), true);
+	else
+	  __len = __convert_from_int(&__cs[0], __cs_size, __num_put_unsigned(__v),
+				     __lit, __io.flags(), false);
+
+	return _M_widen_int(__s, __io, __fill, (char*)(__cs + __cs_size - __len), __len);
       }
 
   template<typename _CharT, typename _OutIter>
@@ -784,22 +848,21 @@
     {
       // [22.2.2.2.2] Stage 2, convert to char_type, using correct
       // numpunct.decimal_point() values for '.' and adding grouping.
-      const locale __loc = __io.getloc();
-      const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
-      _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 
-							   * __len));
+
+      _CharT* __ws = (_CharT*)__cs;
       // Grouping can add (almost) as many separators as the number of
       // digits, but no more.
       _CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 
 							    * __len * 2));
-      __ctype.widen(__cs, __cs + __len, __ws);
+
+      _Format_cache<_CharT>* __fc = _Format_cache<_CharT>::_S_get(__io);
+
 
       // Add grouping, if necessary. 
-      const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__loc);
-      const string __grouping = __np.grouping();
-      const ios_base::fmtflags __basefield = __io.flags() & ios_base::basefield;
-      if (__grouping.size())
+      if (__fc->_M_use_grouping)
 	{
+	  const ios_base::fmtflags __basefield = __io.flags() & ios_base::basefield;
+
 	  // By itself __add_grouping cannot deal correctly with __ws when
 	  // ios::showbase is set and ios_base::oct || ios_base::hex.
 	  // Therefore we take care "by hand" of the initial 0, 0x or 0X.
@@ -819,9 +882,9 @@
 		*(__ws2 + 1) = *(__ws + 1);
 	      }
 	  _CharT* __p;
-	  __p = __add_grouping(__ws2 + __off, __np.thousands_sep(), 
-			       __grouping.c_str(),
-			       __grouping.c_str() + __grouping.size(),
+	  __p = __add_grouping(__ws2 + __off, __fc->_M_thousands_sep, 
+			       __fc->_M_grouping.c_str(),
+			       __fc->_M_grouping.c_str() + __fc->_M_grouping.size(),
 			       __ws + __off, __ws + __len);
 	  __len = __p - __ws2;
 	  // Switch strings.
@@ -830,6 +893,32 @@
       return _M_insert(__s, __io, __fill, __ws, __len);
     }
 
+  
+  // This template permits specializing the stage 4 output code in _M_insert
+  // on ostreambuf_iterator.  For the streambufs, sputn is significantly more
+  // efficient than incrementing iterators.
+  template<typename _CharT>
+    inline
+    ostreambuf_iterator<_CharT>
+    __num_put_output (ostreambuf_iterator<_CharT> __s, const _CharT* __ws,
+		      int __len)
+    {
+      __s._M_sbuf->sputn(__ws, __len);
+      return __s;
+    }
+
+  // As far as I can tell, this more general form will never be invoked.
+  template<typename _CharT, typename _OutIter>
+    inline
+    _OutIter
+    __num_put_output(_OutIter __s, const _CharT* __ws, int __len)
+    {
+      for (int __i = 0; __i < __len; ++__i, ++__s)
+	*__s = __ws[__i];
+      return __s;
+    }
+
+
   // For use by integer and floating-point types after they have been
   // converted into a char_type string.
   template<typename _CharT, typename _OutIter>
@@ -855,9 +944,7 @@
 
       // [22.2.2.2.2] Stage 4.
       // Write resulting, fully-formatted string to output iterator.
-      for (int __j = 0; __j < __len; ++__j, ++__s)
-	*__s = __ws[__j];
-      return __s;
+      return __num_put_output(__s, __ws, __len);
     }
 
   template<typename _CharT, typename _OutIter>
@@ -1965,22 +2052,6 @@
       return static_cast<long>(__val);
     }
 
-  // Convert string to numeric value of type _Tv and store results.  
-  // NB: This is specialized for all required types, there is no
-  // generic definition.
-  template<typename _Tv>
-    void
-    __convert_to_v(const char* __in, _Tv& __out, ios_base::iostate& __err, 
-		   const __c_locale& __cloc, int __base = 10);
-
-  // Convert numeric value of type _Tv to string and return length of string.
-  // If snprintf is available use it, otherwise fall back to the unsafe sprintf
-  // which, in general, can be dangerous and should be avoided.
-  template<typename _Tv>
-    int
-    __convert_from_v(char* __out, const int __size, const char* __fmt,
-		     _Tv __v, const __c_locale&, int __prec = -1);
-
   // Construct correctly padded string, as per 22.2.2.2.2
   // Assumes 
   // __newlen > __oldlen
@@ -1989,18 +2060,6 @@
   // internal-adjusted objects are padded according to the rules below
   // concerning 0[xX] and +-, otherwise, exactly as right-adjusted
   // ones are.
-
-  // NB: Of the two parameters, _CharT can be deduced from the
-  // function arguments. The other (_Traits) has to be explicitly specified.
-  template<typename _CharT, typename _Traits>
-    struct __pad
-    {
-      static void
-      _S_pad(ios_base& __io, _CharT __fill, _CharT* __news, 
-	     const _CharT* __olds, const streamsize __newlen, 
-	     const streamsize __oldlen, const bool __num);
-    };
-
   template<typename _CharT, typename _Traits>
     void 
     __pad<_CharT, _Traits>::_S_pad(ios_base& __io, _CharT __fill, 
@@ -2079,14 +2138,6 @@
 			  __newlen - __beglen - __mod);
     }
 
-  // Used by both numeric and monetary facets.
-  // Check to make sure that the __grouping_tmp string constructed in
-  // money_get or num_get matches the canonical grouping for a given
-  // locale.
-  // __grouping_tmp is parsed L to R
-  // 1,222,444 == __grouping_tmp of "/1/3/3"
-  // __grouping is parsed R to L
-  // 1,222,444 == __grouping of "/3" == "/3/3/3"
   template<typename _CharT>
     bool
     __verify_grouping(const basic_string<_CharT>& __grouping, 
@@ -2111,11 +2162,6 @@
       return __test;
     }
 
-  // Used by both numeric and monetary facets.
-  // Inserts "group separator" characters into an array of characters.
-  // It's recursive, one iteration per group.  It moves the characters
-  // in the buffer this way: "xxxx12345" -> "12,345xxx".  Call this
-  // only with __gbeg != __gend.
   template<typename _CharT>
     _CharT*
     __add_grouping(_CharT* __s, _CharT __sep,  
@@ -2134,6 +2180,85 @@
 	*__s++ = *__first++;
       while (__first != __last);
       return __s;
+    }
+
+  template<typename _CharT>
+    _Format_cache<_CharT>::_Format_cache()
+    : _M_valid(false), _M_use_grouping(false)
+    { }
+
+  template<typename _CharT>
+    _Format_cache<_CharT>::~_Format_cache()
+    { }
+
+  template<typename _CharT>
+    void
+    _Format_cache<_CharT>::_M_populate(ios_base& __io)
+    {
+      static const char _S_numeric_literals[] = "-+xX0123456789abcdef0123456789ABCDEF";
+      static const int _S_literal_count = sizeof(_S_numeric_literals) - 1;
+
+      locale __loc = __io.getloc();
+      numpunct<_CharT> const& __np = use_facet<numpunct<_CharT> >(__loc);
+      _M_falsename = __np.falsename();
+      _M_truename = __np.truename();
+
+      ctype<_CharT> const& __ct = use_facet< ctype<_CharT> >(__loc);
+      __ct.widen(_S_numeric_literals, 
+                 _S_numeric_literals + _S_literal_count, _M_literals);
+      _M_thousands_sep = __np.thousands_sep();
+      _M_decimal_point = __np.decimal_point();
+      _M_grouping = __np.grouping();
+      _M_use_grouping = _M_grouping.size() != 0 && _M_grouping.data()[0] != 0;
+      _M_valid = true;
+    }
+
+  // This function is always called via a pointer installed in
+  // an ios_base by ios_base::register_callback.
+  template<typename _CharT>
+    void
+    _Format_cache<_CharT>::_S_callback(ios_base::event __ev,
+                                       ios_base& __ios, int __ix) throw()
+    {
+      void*& __p = __ios.pword(__ix);
+      switch (__ev)
+	{
+	case ios_base::erase_event:
+	  delete static_cast<_Format_cache<_CharT>*> (__p); __p = 0;   
+	  break;
+	case ios_base::copyfmt_event:
+	  // if just stored zero, the callback would get registered again
+	  try
+	    { 
+	      __p = new _Format_cache<_CharT>; 
+	    } 
+	  catch(...)
+	    { }      
+	  break;
+	case ios_base::imbue_event:
+	  static_cast<_Format_cache<_CharT>*>(__p)->_M_valid = false; 
+	  break;
+	}
+    }
+
+  template<typename _CharT>
+    _Format_cache<_CharT>*
+    _Format_cache<_CharT>::_S_get(ios_base& __ios, bool __valid)
+    {
+      const int _format_cache_pword_slot = 0;
+      void*& __p = __ios.pword(_format_cache_pword_slot);
+
+      if (__p == 0)  // XXX MT?  maybe sentry takes care of it
+	{
+	  auto_ptr<_Format_cache<_CharT> > __ap(new _Format_cache<_CharT>);
+	  __ios.register_callback (&_Format_cache<_CharT>::_S_callback,
+				   _format_cache_pword_slot);
+	  __p = __ap.release();
+	}
+      _Format_cache<_CharT>* __ncp = static_cast<_Format_cache<_CharT>*>(__p);
+
+      if (!__ncp->_M_valid || !__valid) __ncp->_M_populate(__ios);
+      return __ncp;
     }
 
   // Inhibit implicit instantiations for required instantiations,
diff -r -u libstdc++.orig/include/bits/streambuf_iterator.h libstdc++-v3/include/bits/streambuf_iterator.h
--- libstdc++.orig/include/bits/streambuf_iterator.h	Mon Jan  6 22:54:07 2003
+++ libstdc++-v3/include/bits/streambuf_iterator.h	Wed Jan 15 23:58:53 2003
@@ -1,6 +1,6 @@
 // Streambuf iterators
 
-// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
+// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
 // Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
@@ -191,6 +191,10 @@
       bool 
       failed() const throw()
       { return _M_failed; }
+
+      friend ostreambuf_iterator<_CharT>
+	__num_put_output<_CharT>(ostreambuf_iterator<_CharT> __s,
+				 const _CharT* __ws, int __len);
     };
 
   template<typename _CharT, typename _Traits>
diff -r -u libstdc++.orig/src/locale-inst.cc libstdc++-v3/src/locale-inst.cc
--- libstdc++.orig/src/locale-inst.cc	Mon Jan  6 22:54:07 2003
+++ libstdc++-v3/src/locale-inst.cc	Thu Jan 16 00:37:20 2003
@@ -46,6 +46,7 @@
   template class moneypunct_byname<char, true>;
   template class money_get<char, istreambuf_iterator<char> >;
   template class money_put<char, ostreambuf_iterator<char> >;
+  template class _Format_cache<char>;
 
 #ifdef _GLIBCPP_USE_WCHAR_T
   template class moneypunct<wchar_t, false>;
@@ -54,6 +55,7 @@
   template class moneypunct_byname<wchar_t, true>;
   template class money_get<wchar_t, istreambuf_iterator<wchar_t> >;
   template class money_put<wchar_t, ostreambuf_iterator<wchar_t> >;
+  template class _Format_cache<wchar_t>;
 #endif
 
   // numpunct, numpunct_byname, num_get, and num_put
@@ -451,6 +453,7 @@
     __convert_from_v(char*, const int, const char*, unsigned long, 
 		     const __c_locale&, int);
 
+#ifdef _GLIBCPP_USE_LONG_LONG
   template
     int
     __convert_from_v(char*, const int, const char*, long long, 
@@ -460,4 +463,35 @@
     int
     __convert_from_v(char*, const int, const char*, unsigned long long, 
 		     const __c_locale&, int);
+#endif
+
+  template
+    int
+    __convert_from_int(char* __out, const int __size, unsigned long __v,
+		       const char* __lit, ios_base::fmtflags __flags, 
+		       bool __neg);
+
+#ifdef _GLIBCPP_USE_WCHAR_T
+  template
+    int
+    __convert_from_int(wchar_t* __out, const int __size, unsigned long __v,
+		       const wchar_t* __lit, ios_base::fmtflags __flags, 
+		       bool __neg);
+#endif
+
+#ifdef _GLIBCPP_USE_LONG_LONG
+  template
+    int
+    __convert_from_int(char* __out, const int __size, unsigned long long __v,
+		       const char* __lit, ios_base::fmtflags __flags, 
+		       bool __neg);
+
+#ifdef _GLIBCPP_USE_WCHAR_T
+  template
+    int
+    __convert_from_int(wchar_t* __out, const int __size, unsigned long long __v,
+		       const wchar_t* __lit, ios_base::fmtflags __flags, 
+		       bool __neg);
+#endif
+#endif
 } // namespace std
diff -r -u libstdc++.orig/src/localename.cc libstdc++-v3/src/localename.cc
--- libstdc++.orig/src/localename.cc	Mon Jan  6 22:54:07 2003
+++ libstdc++-v3/src/localename.cc	Tue Jan 14 22:26:58 2003
@@ -350,4 +350,28 @@
 	  }
       }
   }
+
+  template<>
+    _Format_cache<char>::_Format_cache()
+    : _M_valid(true), _M_decimal_point('.'), _M_thousands_sep(','),
+      _M_truename("true"), _M_falsename("false"), _M_use_grouping(false)
+    {
+      static const char _S_numeric_literals[] = "-+xX0123456789abcdef0123456789ABCDEF";
+      static const int _S_literal_count = sizeof(_S_numeric_literals) - 1;
+
+      memcpy(_M_literals, _S_numeric_literals, _S_literal_count);
+    }
+ 
+#ifdef  _GLIBCPP_USE_WCHAR_T
+  template<>
+    _Format_cache<wchar_t>::_Format_cache()
+    : _M_valid(true), _M_decimal_point(L'.'), _M_thousands_sep(L','),
+      _M_truename(L"true"), _M_falsename(L"false"), _M_use_grouping(false)
+    {
+      static const wchar_t _S_numeric_literals[] = L"-+xX0123456789abcdef0123456789ABCDEF";
+      static const int _S_literal_count = sizeof(_S_numeric_literals) - 1;
+
+      memcpy(_M_literals, (char*)_S_numeric_literals, _S_literal_count);
+    }
+#endif
 } // namespace std


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]