[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