[PATCH] libstdc++/8761 and libstdc++/7076

Jerry Quinn jlquinn@optonline.net
Fri Jan 10 06:52:00 GMT 2003


This patch provides specializations for integer formatting within libstdc++.
It nearly halves the time for the PR 8761 testcase from 21 seconds to 11
seconds.  The PR 7076 testcase reduces from 7 seconds to 5.6 with this patch.

Combined with http://gcc.gnu.org/ml/libstdc++/2003-01/msg00073.html, the
execution time for PR 8761 drops from 25 seconds to 11.

I believe I've put the specializations in the right place, but please verify.


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

        * config/locale/generic/c_locale.cc (__convert_from_v<long>,
	__convert_from_v<unsigned long>, __convert_from_v<long long>,
	__convert_from_v<unsigned long long>):  Add specializations.
	* config/locale/generic/c_locale.h:  Same.
	* include/bits/locale_facets.tcc:  Choose large enough buffer.
	Formatted text is now at the end of the buffer.

diff -r -u libstdc++.p1/config/locale/generic/c_locale.cc libstdc++-v3/config/locale/generic/c_locale.cc
--- libstdc++.p1/config/locale/generic/c_locale.cc	Wed Jan  8 18:06:24 2003
+++ libstdc++-v3/config/locale/generic/c_locale.cc	Thu Jan  9 15:18:51 2003
@@ -211,6 +211,251 @@
 	}
     }
 
+  template<>
+    int
+    __convert_from_v(char* __out, const int __size, const char* __fmt,
+		     long __v, const __c_locale&, int)
+    {
+      char* __bufptr = __out + __size - 1;
+      char* __bufend = __out + __size;
+
+      // Ick.  But until we pass the flags in directly, this does the job.
+      bool __showpos=false;
+      bool __showbase=false;
+      __fmt++;			// Skip '%'
+      if (*__fmt == '+')
+	__showpos=true, __fmt++;
+      if (*__fmt == '#')
+	__showbase=true, __fmt++;
+      __fmt++;			// Skip 'l'
+
+      if (*__fmt == 'd')
+	{
+	  // Decimal
+	  unsigned long __uv = (unsigned long)__v;
+	  bool __neg = false;
+	  if (__v < 0)
+	    __uv = -((unsigned long)__v), __neg = true;
+	  do {
+	    *__bufptr-- = (__uv % 10) + '0';
+	    __uv /= 10;
+	  } while (__uv != 0);
+	  if (__neg)
+	    *__bufptr-- = '-';
+	  else if (__showpos)
+	    *__bufptr-- = '+';
+	}
+      else if (*__fmt == 'o')
+	{
+	  // Octal
+	  __showbase = (__v && __showbase); // Don't write base if already 0
+	  do {
+	    *__bufptr-- = (__v & 0x8) + '0';
+	    __v >>=3;
+	  } while (__v != 0);
+	  if (__showbase)
+	    *__bufptr-- = '0';
+	}
+      else
+	{
+	  // Hex
+	  static const char __syms[] = "0123456789abcdef0123456789ABCDEF";
+	  int __case_offset = (*__fmt == 'X') ? 16 : 0;
+	  do {
+	    *__bufptr-- = __syms[(__v & 0xf) + __case_offset];
+	    __v >>=4;
+	  } while (__v != 0);
+	  if (__showbase)
+	    {
+	      *__bufptr-- = *__fmt;
+	      *__bufptr-- = '0';
+	    }
+	}
+      int __ret = __bufend - __bufptr - 1;
+      return __ret;
+    }
+
+  template<>
+    int
+    __convert_from_v(char* __out, const int __size, const char* __fmt,
+		     unsigned long __v, const __c_locale&, int)
+    {
+      char* __bufptr = __out + __size - 1;
+      char* __bufend = __out + __size;
+
+      // Ick.  But until we pass the flags in directly, this does the job.
+      bool __showpos=false;
+      bool __showbase=false;
+      __fmt++;			// Skip '%'
+      if (*__fmt == '+')
+	__showpos=true, __fmt++;
+      if (*__fmt == '#')
+	__showbase=true, __fmt++;
+      __fmt++;			// Skip 'l'
+
+      if (*__fmt == 'u')
+	{
+	  // Decimal
+	  do {
+	    *__bufptr-- = (__v % 10) + '0';
+	    __v /= 10;
+	  } while (__v != 0);
+	  if (__showpos)
+	    *__bufptr-- = '+';
+	}
+      else if (*__fmt == 'o')
+	{
+	  // Octal
+	  __showbase = (__v && __showbase); // Don't write base if already 0
+	  do {
+	    *__bufptr-- = (__v & 0x8) + '0';
+	    __v >>=3;
+	  } while (__v != 0);
+	  if (__showbase)
+	    *__bufptr-- = '0';
+	}
+      else
+	{
+	  // Hex
+	  static const char __syms[] = "0123456789abcdef0123456789ABCDEF";
+	  int __case_offset = (*__fmt == 'X') ? 16 : 0;
+	  do {
+	    *__bufptr-- = __syms[(__v & 0xf) + __case_offset];
+	    __v >>=4;
+	  } while (__v != 0);
+	  if (__showbase)
+	    {
+	      *__bufptr-- = *__fmt;
+	      *__bufptr-- = '0';
+	    }
+	}
+      int __ret = __bufend - __bufptr - 1;
+      return __ret;
+    }
+
+  template<>
+    int
+    __convert_from_v(char* __out, const int __size, const char* __fmt,
+		     long long __v, const __c_locale&, int)
+    {
+      char* __bufptr = __out + __size - 1;
+      char* __bufend = __out + __size;
+
+      // Ick.  But until we pass the flags in directly, this does the job.
+      bool __showpos=false;
+      bool __showbase=false;
+      __fmt++;			// Skip '%'
+      if (*__fmt == '+')
+	__showpos=true, __fmt++;
+      if (*__fmt == '#')
+	__showbase=true, __fmt++;
+      __fmt += 2;		// Skip 'll'
+
+      if (*__fmt == 'd')
+	{
+	  // Decimal
+	  unsigned long long __uv = (unsigned long long)__v;
+	  bool __neg = false;
+	  if (__v < 0)
+	    __uv = -((unsigned long long)__v), __neg = true;
+	  // Could optimize this to work on long once value is small enough
+	  do {
+	    *__bufptr-- = (__uv % 10) + '0';
+	    __uv /= 10;
+	  } while (__uv != 0);
+	  if (__neg)
+	    *__bufptr-- = '-';
+	  else if (__showpos)
+	    *__bufptr-- = '+';
+	}
+      else if (*__fmt == 'o')
+	{
+	  // Octal
+	  __showbase = (__v && __showbase); // Don't write base if already 0
+	  do {
+	    *__bufptr-- = (__v & 0x8) + '0';
+	    __v >>=3;
+	  } while (__v != 0);
+	  if (__showbase)
+	    *__bufptr-- = '0';
+	}
+      else
+	{
+	  // Hex
+	  static const char __syms[] = "0123456789abcdef0123456789ABCDEF";
+	  int __case_offset = (*__fmt == 'X') ? 16 : 0;
+	  do {
+	    *__bufptr-- = __syms[(__v & 0xf) + __case_offset];
+	    __v >>=4;
+	  } while (__v != 0);
+	  if (__showbase)
+	    {
+	      *__bufptr-- = *__fmt;
+	      *__bufptr-- = '0';
+	    }
+	}
+      int __ret = __bufend - __bufptr - 1;
+      return __ret;
+    }
+
+  template<>
+    int
+    __convert_from_v(char* __out, const int __size, const char* __fmt,
+		     unsigned long long __v, const __c_locale&, int)
+    {
+      char* __bufptr = __out + __size - 1;
+      char* __bufend = __out + __size;
+
+      // Ick.  But until we pass the flags in directly, this does the job.
+      bool __showpos=false;
+      bool __showbase=false;
+      __fmt++;			// Skip '%'
+      if (*__fmt == '+')
+	__showpos=true, __fmt++;
+      if (*__fmt == '#')
+	__showbase=true, __fmt++;
+      __fmt++;			// Skip 'l'
+
+      if (*__fmt == 'u')
+	{
+	  // Decimal
+	  do {
+	    *__bufptr-- = (__v % 10) + '0';
+	    __v /= 10;
+	  } while (__v != 0);
+	  if (__showpos)
+	    *__bufptr-- = '+';
+	}
+      else if (*__fmt == 'o')
+	{
+	  // Octal
+	  __showbase = (__v && __showbase); // Don't write base if already 0
+	  do {
+	    *__bufptr-- = (__v & 0x8) + '0';
+	    __v >>=3;
+	  } while (__v != 0);
+	  if (__showbase)
+	    *__bufptr-- = '0';
+	}
+      else
+	{
+	  // Hex
+	  static const char __syms[] = "0123456789abcdef0123456789ABCDEF";
+	  int __case_offset = (*__fmt == 'X') ? 16 : 0;
+	  do {
+	    *__bufptr-- = __syms[(__v & 0xf) + __case_offset];
+	    __v >>=4;
+	  } while (__v != 0);
+	  if (__showbase)
+	    {
+	      *__bufptr-- = *__fmt;
+	      *__bufptr-- = '0';
+	    }
+	}
+      int __ret = __bufend - __bufptr - 1;
+      return __ret;
+    }
+
   void
   locale::facet::_S_create_c_locale(__c_locale& __cloc, const char*, 
 				    __c_locale)
diff -r -u libstdc++.p1/config/locale/generic/c_locale.h libstdc++-v3/config/locale/generic/c_locale.h
--- libstdc++.p1/config/locale/generic/c_locale.h	Wed Jan  8 18:06:24 2003
+++ libstdc++-v3/config/locale/generic/c_locale.h	Thu Jan  9 09:03:45 2003
@@ -68,4 +68,24 @@
       free(__sav);
       return __ret;
     }
+
+  template<>
+    int
+    __convert_from_v<long>(char* __out, const int __size, const char* __fmt,
+			   long __v, const __c_locale&, int __prec);
+
+  template<>
+    int
+    __convert_from_v<unsigned long>(char* __out, const int __size, const char* __fmt,
+				    unsigned long __v, const __c_locale&, int __prec);
+
+  template<>
+    int
+    __convert_from_v<long long>(char* __out, const int __size, const char* __fmt,
+				long long __v, const __c_locale&, int __prec);
+
+  template<>
+    int
+    __convert_from_v<unsigned long long>(char* __out, const int __size, const char* __fmt,
+					 unsigned long long __v, const __c_locale&, int __prec);
 }
diff -r -u libstdc++.p1/include/bits/locale_facets.tcc libstdc++-v3/include/bits/locale_facets.tcc
--- libstdc++.p1/include/bits/locale_facets.tcc	Wed Jan  8 18:06:25 2003
+++ libstdc++-v3/include/bits/locale_facets.tcc	Fri Jan 10 01:32:02 2003
@@ -698,27 +698,13 @@
 	// 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));
+	// Long enough to hold hex, dec, and octal representations.
+	int __cs_size = 4 * sizeof(_ValueT);
+	char __cs[__cs_size];
+	// Integer specializations write into end of buffer
 	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);
+	return _M_widen_int(__s, __io, __fill, __cs + __cs_size - __len, __len);
       }
 
   template<typename _CharT, typename _OutIter>
@@ -795,7 +781,7 @@
 
       __fc->_M_ctype->widen(__cs, __cs + __len, __ws);
 
-      
+
 
       // Add grouping, if necessary. 
       if (__fc->_M_use_grouping)



More information about the Libstdc++ mailing list