re PR libstdc++/12750 (time_get::_M_extract_via_format doesn't deal with 'e')

2003-10-27  Paolo Carlini  <pcarlini@suse.de>

	PR libstdc++/12750
	* include/bits/locale_facets.tcc
	(time_get::_M_extract_via_format): Deal with code 'e'.
	* testsuite/22_locale/time_get/get_date/char/12750.cc: New.
	* testsuite/22_locale/time_get/get_date/wchar_t/12750.cc: Ditto.

	* include/bits/locale_facets.tcc
	(time_get::_M_extract_via_format): Tweak to absolutely avoid
	dereferencing end iterators.

	* include/bits/locale_facets.h (__verify_grouping):
	Const-ify second parameter.
	* include/bits/locale_facets.tcc (__verify_grouping): Ditto.
	* src/locale-inst.cc (__verify_grouping): Ditto.

2003-10-27  Paolo Carlini  <pcarlini@suse.de>

	* include/bits/locale_facets.tcc (num_get::_M_extract_float):
	Various things: 1- Avoid absolutely end iterator dereferences;
	2- Improve performance-wise the code skipping leading zeros;
	3- Fix two bugs wrt early bail out in case of parsing errors
	(see testcases); 4- General clean up.
	(num_get::_M_extract_int): Likewise, except 3-. Additionally,
	use __builtin_expect to favor base 10 inputs.
	* testsuite/22_locale/num_get/get/char/7.cc: New.
	* testsuite/22_locale/num_get/get/wchar_t/7.cc: Ditto.

From-SVN: r72987
This commit is contained in:
Paolo Carlini 2003-10-27 16:21:14 +00:00 committed by Paolo Carlini
parent 436d77152e
commit f20d2b7871
8 changed files with 402 additions and 83 deletions

View File

@ -1,3 +1,32 @@
2003-10-27 Paolo Carlini <pcarlini@suse.de>
PR libstdc++/12750
* include/bits/locale_facets.tcc
(time_get::_M_extract_via_format): Deal with code 'e'.
* testsuite/22_locale/time_get/get_date/char/12750.cc: New.
* testsuite/22_locale/time_get/get_date/wchar_t/12750.cc: Ditto.
* include/bits/locale_facets.tcc
(time_get::_M_extract_via_format): Tweak to absolutely avoid
dereferencing end iterators.
* include/bits/locale_facets.h (__verify_grouping):
Const-ify second parameter.
* include/bits/locale_facets.tcc (__verify_grouping): Ditto.
* src/locale-inst.cc (__verify_grouping): Ditto.
2003-10-27 Paolo Carlini <pcarlini@suse.de>
* include/bits/locale_facets.tcc (num_get::_M_extract_float):
Various things: 1- Avoid absolutely end iterator dereferences;
2- Improve performance-wise the code skipping leading zeros;
3- Fix two bugs wrt early bail out in case of parsing errors
(see testcases); 4- General clean up.
(num_get::_M_extract_int): Likewise, except 3-. Additionally,
use __builtin_expect to favor base 10 inputs.
* testsuite/22_locale/num_get/get/char/7.cc: New.
* testsuite/22_locale/num_get/get/wchar_t/7.cc: Ditto.
2003-10-26 Paolo Carlini <pcarlini@suse.de>
* testsuite/22_locale/money_put/put/char/1.cc: Clean up.

View File

@ -125,7 +125,7 @@ namespace std
template<typename _CharT>
bool
__verify_grouping(const basic_string<_CharT>& __grouping,
basic_string<_CharT>& __grouping_tmp);
const basic_string<_CharT>& __grouping_tmp);
// Used by both numeric and monetary facets.
// Inserts "group separator" characters into an array of characters.

View File

@ -144,51 +144,50 @@ namespace std
const _CharT* __lit = __lc->_M_atoms_in;
// First check for sign.
int __pos = 0;
char_type __c = *__beg;
const bool __plus = __traits_type::eq(__c, __lit[_S_iplus]);
if ((__plus || __traits_type::eq(__c, __lit[_S_iminus]))
&& __beg != __end)
if (__beg != __end)
{
__xtrc += __plus ? _S_atoms_in[_S_iplus] : _S_atoms_in[_S_iminus];
++__pos;
__c = *(++__beg);
const char_type __c = *__beg;
const bool __plus = __traits_type::eq(__c, __lit[_S_iplus]);
if (__plus || __traits_type::eq(__c, __lit[_S_iminus]))
{
__xtrc += __plus ? _S_atoms_in[_S_iplus]
: _S_atoms_in[_S_iminus];
++__beg;
}
}
// Next, strip leading zeros.
bool __found_zero = false;
while (__traits_type::eq(__c, __lit[_S_izero]) && __beg != __end)
{
__c = *(++__beg);
__found_zero = true;
}
if (__found_zero)
// Next, look for a zero...
bool __found_mantissa = false;
if (__beg != __end && __traits_type::eq(*__beg, __lit[_S_izero]))
{
__xtrc += _S_atoms_in[_S_izero];
++__pos;
__found_mantissa = true;
++__beg;
// ... and skip the additional ones.
for (; __beg != __end
&& __traits_type::eq(*__beg, __lit[_S_izero]); ++__beg);
}
// Only need acceptable digits for floating point numbers.
bool __found_dec = false;
bool __found_sci = false;
string __found_grouping;
const size_t __len = _S_iE - _S_izero + 1;
int __sep_pos = 0;
bool __e;
while (__beg != __end)
{
// Only look in digits.
const char_type __c = *__beg;
const char_type* __p = __traits_type::find(__lit + _S_izero, 10,
__c);
// NB: strchr returns true for __c == 0x0
// NB: strchr returns true for *__beg == 0x0
if (__p && !__traits_type::eq(__c, char_type()))
{
// Try first for acceptable digit; record it if found.
++__pos;
__xtrc += _S_atoms_in[__p - __lit];
__found_mantissa = true;
++__sep_pos;
__c = *(++__beg);
++__beg;
}
else if (__traits_type::eq(__c, __lc->_M_thousands_sep)
&& __lc->_M_use_grouping && !__found_dec)
@ -199,7 +198,7 @@ namespace std
{
__found_grouping += static_cast<char>(__sep_pos);
__sep_pos = 0;
__c = *(++__beg);
++__beg;
}
else
{
@ -215,28 +214,28 @@ namespace std
// must be adjusted only if __dec comes after some __sep.
if (__found_grouping.size())
__found_grouping += static_cast<char>(__sep_pos);
++__pos;
__xtrc += '.';
__c = *(++__beg);
__found_dec = true;
++__beg;
}
else if ((__e = __traits_type::eq(__c, __lit[_S_ie])
|| __traits_type::eq(__c, __lit[_S_iE]))
&& !__found_sci && __pos)
&& __found_mantissa && !__found_sci)
{
// Scientific notation.
++__pos;
__xtrc += __e ? _S_atoms_in[_S_ie] : _S_atoms_in[_S_iE];
__c = *(++__beg);
++__beg;
// Remove optional plus or minus sign, if they exist.
const bool __plus = __traits_type::eq(__c, __lit[_S_iplus]);
if (__plus || __traits_type::eq(__c, __lit[_S_iminus]))
if (__beg != __end)
{
++__pos;
__xtrc += __plus ? _S_atoms_in[_S_iplus]
: _S_atoms_in[_S_iminus];
__c = *(++__beg);
const bool __plus = __traits_type::eq(*__beg, __lit[_S_iplus]);
if (__plus || __traits_type::eq(*__beg, __lit[_S_iminus]))
{
__xtrc += __plus ? _S_atoms_in[_S_iplus]
: _S_atoms_in[_S_iminus];
++__beg;
}
}
__found_sci = true;
}
@ -288,55 +287,62 @@ namespace std
__base = 10;
// First check for sign.
char_type __c = *__beg;
const bool __plus = __traits_type::eq(__c, __lit[_S_iplus]);
if ((__plus || __traits_type::eq(__c, __lit[_S_iminus]))
&& __beg != __end)
if (__beg != __end)
{
__xtrc += __plus ? _S_atoms_in[_S_iplus] : _S_atoms_in[_S_iminus];
__c = *(++__beg);
const char_type __c = *__beg;
const bool __plus = __traits_type::eq(__c, __lit[_S_iplus]);
if (__plus || __traits_type::eq(__c, __lit[_S_iminus]))
{
__xtrc += __plus ? _S_atoms_in[_S_iplus]
: _S_atoms_in[_S_iminus];
++__beg;
}
}
// Next, strip leading zeros and check required digits for base formats.
if (__base == 10)
// Next, look for leading zeros and check required digits for base formats.
if (__builtin_expect(__base == 10, true))
{
bool __found_zero = false;
while (__traits_type::eq(__c, __lit[_S_izero]) && __beg != __end)
{
__c = *(++__beg);
__found_zero = true;
}
if (__found_zero)
// Look for a zero...
if (__beg != __end && __traits_type::eq(*__beg, __lit[_S_izero]))
{
__xtrc += _S_atoms_in[_S_izero];
if (__basefield == 0)
{
const bool __x = __traits_type::eq(__c, __lit[_S_ix]);
if ((__x || __traits_type::eq(__c, __lit[_S_iX]))
&& __beg != __end)
++__beg;
// ... and skip the additional ones.
for (; __beg != __end
&& __traits_type::eq(*__beg, __lit[_S_izero]); ++__beg);
// Check required digits.
if (__beg != __end && __basefield == 0)
{
const bool __x = __traits_type::eq(*__beg, __lit[_S_ix]);
if (__x || __traits_type::eq(*__beg, __lit[_S_iX]))
{
__xtrc += __x ? _S_atoms_in[_S_ix] : _S_atoms_in[_S_iX];
__c = *(++__beg);
__xtrc += __x ? _S_atoms_in[_S_ix]
: _S_atoms_in[_S_iX];
__base = 16;
++__beg;
}
else
__base = 8;
}
}
}
}
else if (__base == 16)
{
if (__traits_type::eq(__c, __lit[_S_izero]) && __beg != __end)
if (__beg != __end && __traits_type::eq(*__beg, __lit[_S_izero]))
{
__xtrc += _S_atoms_in[_S_izero];
__c = *(++__beg);
const bool __x = __traits_type::eq(__c, __lit[_S_ix]);
if ((__x || __traits_type::eq(__c, __lit[_S_iX]))
&& __beg != __end)
++__beg;
if (__beg != __end)
{
__xtrc += __x ? _S_atoms_in[_S_ix] : _S_atoms_in[_S_iX];
__c = *(++__beg);
const bool __x = __traits_type::eq(*__beg, __lit[_S_ix]);
if (__x || __traits_type::eq(*__beg, __lit[_S_iX]))
{
__xtrc += __x ? _S_atoms_in[_S_ix]
: _S_atoms_in[_S_iX];
++__beg;
}
}
}
}
@ -347,22 +353,21 @@ namespace std
// Extract.
string __found_grouping;
const char_type __sep = __lc->_M_thousands_sep;
int __sep_pos = 0;
while (__beg != __end)
for (; __beg != __end; ++__beg)
{
const char_type* __p = __traits_type::find(__lit + _S_izero,
__len, __c);
const char_type __c = *__beg;
const char_type* __p = __traits_type::find(__lit + _S_izero,
__len, __c);
// NB: strchr returns true for __c == 0x0
if (__p && !__traits_type::eq(__c, char_type()))
{
// Try first for acceptable digit; record it if found.
__xtrc += _S_atoms_in[__p - __lit];
++__sep_pos;
__c = *(++__beg);
}
else if (__traits_type::eq(__c, __sep) && __lc->_M_use_grouping)
else if (__traits_type::eq(__c, __lc->_M_thousands_sep)
&& __lc->_M_use_grouping)
{
// NB: Thousands separator at the beginning of a string
// is a no-no, as is two consecutive thousands separators.
@ -370,7 +375,6 @@ namespace std
{
__found_grouping += static_cast<char>(__sep_pos);
__sep_pos = 0;
__c = *(++__beg);
}
else
{
@ -1609,6 +1613,18 @@ namespace std
_M_extract_num(__beg, __end, __tm->tm_mday, 1, 31, 2,
__ctype, __err);
break;
case 'e':
// Day [1, 31], with single digits preceded by
// space. [tm_mday]
if (__ctype.is(ctype_base::space, *__beg))
_M_extract_num(++__beg, __end, __tm->tm_mday, 1, 9, 1,
__ctype, __err);
else if (*__beg != __ctype.widen('0'))
_M_extract_num(__beg, __end, __tm->tm_mday, 10, 31, 2,
__ctype, __err);
else
__err |= ios_base::failbit;
break;
case 'D':
// Equivalent to %m/%d/%y.[tm_mon, tm_mday, tm_year]
__cs = "%m/%d/%y";
@ -1660,7 +1676,7 @@ namespace std
if (__ctype.narrow(*__beg, 0) == '\t')
++__beg;
else
__err |= ios_base::failbit;
__err |= ios_base::failbit;
break;
case 'T':
// Equivalent to (%H:%M:%S).
@ -1707,10 +1723,9 @@ namespace std
14, __err);
// GMT requires special effort.
char_type __c = *__beg;
if (!__err && __tmp == 0
&& (__c == __ctype.widen('-')
|| __c == __ctype.widen('+')))
if (__beg != __end && !__err && __tmp == 0
&& (*__beg == __ctype.widen('-')
|| *__beg == __ctype.widen('+')))
{
_M_extract_num(__beg, __end, __tmp, 0, 23, 2,
__ctype, __err);
@ -2245,7 +2260,7 @@ namespace std
template<typename _CharT>
bool
__verify_grouping(const basic_string<_CharT>& __grouping,
basic_string<_CharT>& __grouping_tmp)
const basic_string<_CharT>& __grouping_tmp)
{
size_t __i = 0;
size_t __j = 0;

View File

@ -233,7 +233,8 @@ namespace std
template
bool
__verify_grouping<C>(const basic_string<C>&, basic_string<C>&);
__verify_grouping<C>(const basic_string<C>&,
const basic_string<C>&);
template class __pad<C, char_traits<C> >;

View File

@ -0,0 +1,58 @@
// 2003-10-25 Paolo Carlini <pcarlini@suse.de>
// Copyright (C) 2003 Free Software Foundation
//
// 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
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING. If not, write to the Free
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
// 22.2.2.1.1 num_get members
#include <locale>
#include <sstream>
#include <testsuite_hooks.h>
void test01()
{
using namespace std;
typedef istreambuf_iterator<char> iterator_type;
bool test __attribute__((unused)) = true;
// cache the num_get facet
istringstream iss;
const num_get<char>& ng = use_facet<num_get<char> >(iss.getloc());
ios_base::iostate err = ios_base::goodbit;
iterator_type end;
double d;
iss.str("+e3");
end = ng.get(iss.rdbuf(), 0, iss, err, d);
VERIFY( err == ios_base::failbit );
VERIFY( *end == 'e' );
iss.str(".e+1");
iss.clear();
err = ios_base::goodbit;
end = ng.get(iss.rdbuf(), 0, iss, err, d);
VERIFY( err == ios_base::failbit );
VERIFY( *end == 'e' );
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,58 @@
// 2003-10-25 Paolo Carlini <pcarlini@suse.de>
// Copyright (C) 2003 Free Software Foundation
//
// 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
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING. If not, write to the Free
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
// 22.2.2.1.1 num_get members
#include <locale>
#include <sstream>
#include <testsuite_hooks.h>
void test01()
{
using namespace std;
typedef istreambuf_iterator<wchar_t> iterator_type;
bool test __attribute__((unused)) = true;
// cache the num_get facet
wistringstream iss;
const num_get<wchar_t>& ng = use_facet<num_get<wchar_t> >(iss.getloc());
ios_base::iostate err = ios_base::goodbit;
iterator_type end;
double d;
iss.str(L"+e3");
end = ng.get(iss.rdbuf(), 0, iss, err, d);
VERIFY( err == ios_base::failbit );
VERIFY( *end == L'e' );
iss.str(L".e+1");
iss.clear();
err = ios_base::goodbit;
end = ng.get(iss.rdbuf(), 0, iss, err, d);
VERIFY( err == ios_base::failbit );
VERIFY( *end == L'e' );
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,79 @@
// 2003-10-27 Paolo Carlini <pcarlini@suse.de>
// Copyright (C) 2003 Free Software Foundation
//
// 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
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING. If not, write to the Free
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
// 22.2.5.1.1 time_get members
#include <locale>
#include <sstream>
#include <testsuite_hooks.h>
// libstdc++/12750
void test01()
{
using namespace std;
typedef istreambuf_iterator<char> iterator_type;
bool test __attribute__((unused)) = true;
// basic construction
locale loc_is = __gnu_test::try_named_locale("is_IS");
// create an ostream-derived object, cache the time_get facet
iterator_type end;
istringstream iss;
const time_get<char>& tim_get = use_facet<time_get<char> >(iss.getloc());
const ios_base::iostate good = ios_base::goodbit;
ios_base::iostate errorstate = good;
// create "C" time objects
const tm time_bday01 = { 0, 0, 12, 2, 9, 103, 4, 274, -1 };
const tm time_bday02 = { 0, 0, 12, 26, 9, 103, 0, 298, -1 };
// inspection of named locales, is_IS
iss.imbue(loc_is);
iss.str("Fim 2.Okt 2003");
iterator_type is_it01(iss);
tm time01;
errorstate = good;
tim_get.get_date(is_it01, end, iss, errorstate, &time01);
VERIFY( time01.tm_mon == time_bday01.tm_mon );
VERIFY( time01.tm_mday == time_bday01.tm_mday );
VERIFY( time01.tm_year == time_bday01.tm_year );
VERIFY( errorstate == ios_base::eofbit );
iss.str("Sun 26.Okt 2003");
iterator_type is_it02(iss);
tm time02;
errorstate = good;
tim_get.get_date(is_it02, end, iss, errorstate, &time02);
VERIFY( time02.tm_mon == time_bday02.tm_mon );
VERIFY( time02.tm_mday == time_bday02.tm_mday );
VERIFY( time02.tm_year == time_bday02.tm_year );
VERIFY( errorstate == ios_base::eofbit );
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,79 @@
// 2003-10-27 Paolo Carlini <pcarlini@suse.de>
// Copyright (C) 2003 Free Software Foundation
//
// 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
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING. If not, write to the Free
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
// 22.2.5.1.1 time_get members
#include <locale>
#include <sstream>
#include <testsuite_hooks.h>
// libstdc++/12750
void test01()
{
using namespace std;
typedef istreambuf_iterator<wchar_t> iterator_type;
bool test __attribute__((unused)) = true;
// basic construction
locale loc_is = __gnu_test::try_named_locale("is_IS");
// create an ostream-derived object, cache the time_get facet
iterator_type end;
wistringstream iss;
const time_get<wchar_t>& tim_get = use_facet<time_get<wchar_t> >(iss.getloc());
const ios_base::iostate good = ios_base::goodbit;
ios_base::iostate errorstate = good;
// create "C" time objects
const tm time_bday01 = { 0, 0, 12, 2, 9, 103, 4, 274, -1 };
const tm time_bday02 = { 0, 0, 12, 26, 9, 103, 0, 298, -1 };
// inspection of named locales, is_IS
iss.imbue(loc_is);
iss.str(L"Fim 2.Okt 2003");
iterator_type is_it01(iss);
tm time01;
errorstate = good;
tim_get.get_date(is_it01, end, iss, errorstate, &time01);
VERIFY( time01.tm_mon == time_bday01.tm_mon );
VERIFY( time01.tm_mday == time_bday01.tm_mday );
VERIFY( time01.tm_year == time_bday01.tm_year );
VERIFY( errorstate == ios_base::eofbit );
iss.str(L"Sun 26.Okt 2003");
iterator_type is_it02(iss);
tm time02;
errorstate = good;
tim_get.get_date(is_it02, end, iss, errorstate, &time02);
VERIFY( time02.tm_mon == time_bday02.tm_mon );
VERIFY( time02.tm_mday == time_bday02.tm_mday );
VERIFY( time02.tm_year == time_bday02.tm_year );
VERIFY( errorstate == ios_base::eofbit );
}
int main()
{
test01();
return 0;
}