locale_facets.tcc (money_put<>::_M_insert): Restructure formatting of value component...

2004-02-22  Paolo Carlini  <pcarlini@suse.de>

	* include/bits/locale_facets.tcc (money_put<>::_M_insert):
	Restructure formatting of value component, first dealing with
	the non-decimal digits; use reserve.

2004-02-22  Paolo Carlini  <pcarlini@suse.de>

	* include/bits/locale_facets.h (class money_get): Inherit
	from money_base too; tweak declaration of _M_extract, now
	parameterized on _Intl too.
	* include/bits/locale_facets.tcc (money_get<>::_M_extract):
	Update definition to use the cache; call reserve on __res to
	avoid multiple reallocations; fix parsing of sign component
	according to 22.2.6.1.2, p3.
	(money_get<>::do_get(long double&),
	money_get<>::do_get(string_type&)): Update calls of _M_extract.
	* src/locale-inst.cc:  Add instantiations of
	money_get::_M_extract<false> and money_get::_M_extract<true>.
	* testsuite/22_locale/money_get/get/char/14.cc: New.
	* testsuite/22_locale/money_get/get/wchar_t/14.cc: Ditto.

From-SVN: r78253
This commit is contained in:
Paolo Carlini 2004-02-22 11:13:27 +00:00 committed by Paolo Carlini
parent 5904e65f29
commit 20da06efdc
6 changed files with 399 additions and 241 deletions

View File

@ -1,3 +1,25 @@
2004-02-22 Paolo Carlini <pcarlini@suse.de>
* include/bits/locale_facets.tcc (money_put<>::_M_insert):
Restructure formatting of value component, first dealing with
the non-decimal digits; use reserve.
2004-02-22 Paolo Carlini <pcarlini@suse.de>
* include/bits/locale_facets.h (class money_get): Inherit
from money_base too; tweak declaration of _M_extract, now
parameterized on _Intl too.
* include/bits/locale_facets.tcc (money_get<>::_M_extract):
Update definition to use the cache; call reserve on __res to
avoid multiple reallocations; fix parsing of sign component
according to 22.2.6.1.2, p3.
(money_get<>::do_get(long double&),
money_get<>::do_get(string_type&)): Update calls of _M_extract.
* src/locale-inst.cc: Add instantiations of
money_get::_M_extract<false> and money_get::_M_extract<true>.
* testsuite/22_locale/money_get/get/char/14.cc: New.
* testsuite/22_locale/money_get/get/wchar_t/14.cc: Ditto.
2004-02-21 Mark Mitchell <mark@codesourcery.com>
* libsupc++/vterminate.cc
@ -180,13 +202,13 @@
2004-02-12 Paolo Carlini <pcarlini@suse.de>
PR libstdc++/13731 (final part: writev)
* config/io/basic_file_stdio.cc (__gnu_internal::xwrite):
* config/io/basic_file_stdio.cc (__gnu_internal::xwritev):
New, a wrapper around writev() handling partial writes.
(__basic_file<char>::xwrite): Move to __gnu_internal and make
static.
(__basic_file<char>::xsputn): Update call.
(__basic_file<char>::xsputn_2): Likewise.
* config/io/basic_file_stdio.h (__basic_file<char>::write):
* config/io/basic_file_stdio.h (__basic_file<char>::xwrite):
Don't declare, now static.
2004-02-11 Stefan Olsson <stefan@xapa.se>

View File

@ -4012,7 +4012,7 @@ namespace std
* the money_get facet.
*/
template<typename _CharT, typename _InIter>
class money_get : public locale::facet
class money_get : public locale::facet, public money_base
{
public:
// Types:
@ -4125,9 +4125,10 @@ namespace std
do_get(iter_type __s, iter_type __end, bool __intl, ios_base& __io,
ios_base::iostate& __err, string_type& __digits) const;
iter_type
_M_extract(iter_type __s, iter_type __end, bool __intl, ios_base& __io,
ios_base::iostate& __err, string_type& __digits) const;
template<bool _Intl>
iter_type
_M_extract(iter_type __s, iter_type __end, ios_base& __io,
ios_base::iostate& __err, string_type& __digits) const;
};
template<typename _CharT, typename _InIter>

View File

@ -1159,212 +1159,209 @@ namespace std
};
template<typename _CharT, typename _InIter>
_InIter
money_get<_CharT, _InIter>::
_M_extract(iter_type __beg, iter_type __end, bool __intl, ios_base& __io,
ios_base::iostate& __err, string_type& __units) const
{
// These contortions are quite unfortunate.
typedef moneypunct<_CharT, true> __money_true;
typedef moneypunct<_CharT, false> __money_false;
typedef money_base::part part;
typedef typename string_type::size_type size_type;
template<bool _Intl>
_InIter
money_get<_CharT, _InIter>::
_M_extract(iter_type __beg, iter_type __end, ios_base& __io,
ios_base::iostate& __err, string_type& __units) const
{
typedef typename string_type::size_type size_type;
typedef money_base::part part;
typedef moneypunct<_CharT, _Intl> __moneypunct_type;
typedef typename __moneypunct_type::__cache_type __cache_type;
const locale& __loc = __io._M_getloc();
const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
const locale __loc = __io.getloc();
const __money_true& __mpt = use_facet<__money_true>(__loc);
const __money_false& __mpf = use_facet<__money_false>(__loc);
const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
__use_cache<__cache_type> __uc;
const __cache_type* __lc = __uc(__loc);
const char_type* __lit = __lc->_M_atoms;
const money_base::pattern __p = __intl ? __mpt.neg_format()
: __mpf.neg_format();
const money_base::pattern __p = __lc->_M_neg_format;
const string_type __pos_sign = __intl ? __mpt.positive_sign()
: __mpf.positive_sign();
const string_type __neg_sign = __intl ? __mpt.negative_sign()
: __mpf.negative_sign();
const char_type __d = __intl ? __mpt.decimal_point()
: __mpf.decimal_point();
const char_type __sep = __intl ? __mpt.thousands_sep()
: __mpf.thousands_sep();
// Deduced sign.
bool __negative = false;
// True for more than one character long sign.
bool __long_sign = false;
// String of grouping info from thousands_sep plucked from __units.
string __grouping_tmp;
// Marker for thousands_sep position.
int __sep_pos = 0;
// If input iterator is in a valid state.
bool __testvalid = true;
// Flag marking when a decimal point is found.
bool __testdecfound = false;
const string __grouping = __intl ? __mpt.grouping() : __mpf.grouping();
// The tentative returned string is stored here.
string_type __res;
__res.reserve(20);
// Set to deduced positive or negative sign, depending.
string_type __sign;
// String of grouping info from thousands_sep plucked from __units.
string __grouping_tmp;
// Marker for thousands_sep position.
int __sep_pos = 0;
// If input iterator is in a valid state.
bool __testvalid = true;
// Flag marking when a decimal point is found.
bool __testdecfound = false;
// The tentative returned string is stored here.
string_type __tmp_units;
for (int __i = 0; __beg != __end && __i < 4 && __testvalid; ++__i)
{
char_type __c;
const part __which = static_cast<part>(__p.field[__i]);
switch (__which)
{
case money_base::symbol:
if (__io.flags() & ios_base::showbase
|| __i < 2 || __sign.size() > 1
|| ((static_cast<part>(__p.field[3]) != money_base::none)
&& __i == 2))
{
// According to 22.2.6.1.2, p2, symbol is required
// if (__io.flags() & ios_base::showbase),
// otherwise is optional and consumed only if
// other characters are needed to complete the
// format.
const string_type __symbol = __intl ? __mpt.curr_symbol()
: __mpf.curr_symbol();
const size_type __len = __symbol.size();
size_type __j = 0;
for (; __beg != __end && __j < __len
&& *__beg == __symbol[__j]; ++__beg, ++__j);
// When (__io.flags() & ios_base::showbase)
// symbol is required.
if (__j != __len && (__io.flags() & ios_base::showbase))
for (int __i = 0; __beg != __end && __i < 4 && __testvalid; ++__i)
{
char_type __c;
const part __which = static_cast<part>(__p.field[__i]);
switch (__which)
{
case money_base::symbol:
if (__io.flags() & ios_base::showbase
|| __i < 2 || __long_sign
|| ((static_cast<part>(__p.field[3]) != money_base::none)
&& __i == 2))
{
// According to 22.2.6.1.2, p2, symbol is required
// if (__io.flags() & ios_base::showbase),
// otherwise is optional and consumed only if
// other characters are needed to complete the
// format.
const size_type __len = __lc->_M_curr_symbol_size;
size_type __j = 0;
for (; __beg != __end && __j < __len
&& *__beg == __lc->_M_curr_symbol[__j];
++__beg, ++__j);
// When (__io.flags() & ios_base::showbase)
// symbol is required.
if (__j != __len && (__io.flags() & ios_base::showbase))
__testvalid = false;
}
break;
case money_base::sign:
// Sign might not exist, or be more than one character long.
if (__lc->_M_positive_sign_size
&& *__beg == __lc->_M_positive_sign[0])
{
if (__lc->_M_positive_sign_size > 1)
__long_sign = true;
++__beg;
}
else if (__lc->_M_negative_sign_size
&& *__beg == __lc->_M_negative_sign[0])
{
__negative = true;
if (__lc->_M_negative_sign_size > 1)
__long_sign = true;
++__beg;
}
else if (__lc->_M_positive_sign_size
&& !__lc->_M_negative_sign_size)
// "... if no sign is detected, the result is given the sign
// that corresponds to the source of the empty string"
__negative = true;
else if (__lc->_M_positive_sign_size
&& __lc->_M_negative_sign_size)
{
// Sign is mandatory.
__testvalid = false;
}
break;
case money_base::sign:
// Sign might not exist, or be more than one character long.
if (__pos_sign.size() && *__beg == __pos_sign[0])
{
__sign = __pos_sign;
++__beg;
}
else if (__neg_sign.size() && *__beg == __neg_sign[0])
{
__sign = __neg_sign;
++__beg;
}
else if (__pos_sign.size() && __neg_sign.size())
{
// Sign is mandatory.
__testvalid = false;
}
break;
case money_base::value:
// Extract digits, remove and stash away the
// grouping of found thousands separators.
for (; __beg != __end; ++__beg)
if (__ctype.is(ctype_base::digit, __c = *__beg))
{
__tmp_units += __c;
++__sep_pos;
}
else if (__c == __d && !__testdecfound)
{
// If no grouping chars are seen, no grouping check
// is applied. Therefore __grouping_tmp is adjusted
// only if decimal_point comes after some thousands_sep.
if (__grouping_tmp.size())
__grouping_tmp += static_cast<char>(__sep_pos);
__sep_pos = 0;
__testdecfound = true;
}
else if (__c == __sep && !__testdecfound)
{
if (__grouping.size())
{
// Mark position for later analysis.
break;
case money_base::value:
// Extract digits, remove and stash away the
// grouping of found thousands separators.
for (; __beg != __end; ++__beg)
if (__ctype.is(ctype_base::digit, __c = *__beg))
{
__res += __c;
++__sep_pos;
}
else if (__c == __lc->_M_decimal_point && !__testdecfound)
{
// If no grouping chars are seen, no grouping check
// is applied. Therefore __grouping_tmp is adjusted
// only if decimal_point comes after some thousands_sep.
if (__grouping_tmp.size())
__grouping_tmp += static_cast<char>(__sep_pos);
__sep_pos = 0;
}
else
{
__testvalid = false;
break;
}
}
else
break;
break;
case money_base::space:
case money_base::none:
// Only if not at the end of the pattern.
if (__i != 3)
for (; __beg != __end
&& __ctype.is(ctype_base::space, *__beg); ++__beg);
break;
}
}
__sep_pos = 0;
__testdecfound = true;
}
else if (__c == __lc->_M_thousands_sep && !__testdecfound)
{
if (__lc->_M_grouping_size)
{
// Mark position for later analysis.
__grouping_tmp += static_cast<char>(__sep_pos);
__sep_pos = 0;
}
else
{
__testvalid = false;
break;
}
}
else
break;
break;
case money_base::space:
case money_base::none:
// Only if not at the end of the pattern.
if (__i != 3)
for (; __beg != __end
&& __ctype.is(ctype_base::space, *__beg); ++__beg);
break;
}
}
// Need to get the rest of the sign characters, if they exist.
if (__sign.size() > 1)
{
const size_type __len = __sign.size();
size_type __i = 1;
for (; __beg != __end && __i < __len
&& *__beg == __sign[__i]; ++__beg, ++__i);
// Need to get the rest of the sign characters, if they exist.
if (__long_sign)
{
const char_type* __sign = __negative ? __lc->_M_negative_sign
: __lc->_M_positive_sign;
const size_type __len = __negative ? __lc->_M_negative_sign_size
: __lc->_M_positive_sign_size;
size_type __i = 1;
for (; __beg != __end && __i < __len
&& *__beg == __sign[__i]; ++__beg, ++__i);
if (__i != __len)
__testvalid = false;
}
if (__i != __len)
__testvalid = false;
}
if (__testvalid && __res.size())
{
// Strip leading zeros.
if (__res.size() > 1)
{
size_type __first = __res.find_first_not_of(__lit[_S_zero]);
const bool __only_zeros = __first == string_type::npos;
if (__first)
__res.erase(0, __only_zeros ? __res.size() - 1 : __first);
}
if (__testvalid && __tmp_units.size())
{
const char_type __zero = __ctype.widen('0');
// Strip leading zeros.
if (__tmp_units.size() > 1)
{
const size_type __first = __tmp_units.find_first_not_of(__zero);
const bool __only_zeros = __first == string_type::npos;
if (__first)
__tmp_units.erase(0, __only_zeros ? __tmp_units.size() - 1
: __first);
}
// 22.2.6.1.2, p4
if (__sign.size() && __sign == __neg_sign
&& __tmp_units[0] != __zero)
__tmp_units.insert(__tmp_units.begin(), __ctype.widen('-'));
// Test for grouping fidelity.
if (__grouping_tmp.size())
{
// Add the ending grouping if a decimal wasn't found.
if (!__testdecfound)
__grouping_tmp += static_cast<char>(__sep_pos);
if (!std::__verify_grouping(__grouping.data(),
__grouping.size(),
__grouping_tmp))
__testvalid = false;
}
// Iff not enough digits were supplied after the decimal-point.
if (__testdecfound)
{
const int __frac = __intl ? __mpt.frac_digits()
: __mpf.frac_digits();
if (__frac > 0 && __sep_pos != __frac)
__testvalid = false;
}
}
else
__testvalid = false;
// Iff no more characters are available.
if (__beg == __end)
__err |= ios_base::eofbit;
// Iff valid sequence is not recognized.
if (!__testvalid)
__err |= ios_base::failbit;
else
// Use the "swap trick" to copy __tmp_units into __units.
__tmp_units.swap(__units);
return __beg;
}
// 22.2.6.1.2, p4
if (__negative && __res[0] != __lit[_S_zero])
__res.insert(__res.begin(), __lit[_S_minus]);
// Test for grouping fidelity.
if (__grouping_tmp.size())
{
// Add the ending grouping if a decimal wasn't found.
if (!__testdecfound)
__grouping_tmp += static_cast<char>(__sep_pos);
if (!std::__verify_grouping(__lc->_M_grouping,
__lc->_M_grouping_size,
__grouping_tmp))
__testvalid = false;
}
// Iff not enough digits were supplied after the decimal-point.
if (__testdecfound && __lc->_M_frac_digits > 0
&& __sep_pos != __lc->_M_frac_digits)
__testvalid = false;
}
else
__testvalid = false;
// Iff no more characters are available.
if (__beg == __end)
__err |= ios_base::eofbit;
// Iff valid sequence is not recognized.
if (!__testvalid)
__err |= ios_base::failbit;
else
__units.assign(__res.data(), __res.size());
return __beg;
}
template<typename _CharT, typename _InIter>
_InIter
@ -1373,7 +1370,10 @@ namespace std
ios_base::iostate& __err, long double& __units) const
{
string_type __str;
__beg = _M_extract(__beg, __end, __intl, __io, __err, __str);
if (__intl)
__beg = _M_extract<true>(__beg, __end, __io, __err, __str);
else
__beg = _M_extract<false>(__beg, __end, __io, __err, __str);
const int __cs_size = __str.size() + 1;
char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
@ -1390,7 +1390,8 @@ namespace std
money_get<_CharT, _InIter>::
do_get(iter_type __beg, iter_type __end, bool __intl, ios_base& __io,
ios_base::iostate& __err, string_type& __units) const
{ return _M_extract(__beg, __end, __intl, __io, __err, __units); }
{ return __intl ? _M_extract<true>(__beg, __end, __io, __err, __units)
: _M_extract<false>(__beg, __end, __io, __err, __units); }
template<typename _CharT, typename _OutIter>
template<bool _Intl>
@ -1440,56 +1441,54 @@ namespace std
// Assume valid input, and attempt to format.
// Break down input numbers into base components, as follows:
// final_value = grouped units + (decimal point) + (digits)
string_type __res;
string_type __value;
size_type __len = __end - __beg;
__value.reserve(2 * __len);
// Add thousands separators to non-decimal digits, per
// grouping rules.
const int __paddec = __lc->_M_frac_digits - __len;
if (__paddec < 0)
{
if (__lc->_M_grouping_size)
{
_CharT* __ws =
static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
* 2 * __len));
_CharT* __ws_end =
std::__add_grouping(__ws, __lc->_M_thousands_sep,
__lc->_M_grouping,
__lc->_M_grouping_size,
__beg, __end - __lc->_M_frac_digits);
__value.assign(__ws, __ws_end - __ws);
}
else
__value.assign(__beg, -__paddec);
}
// Deal with decimal point, decimal digits.
if (__lc->_M_frac_digits > 0)
{
if (__end - __beg >= __lc->_M_frac_digits)
{
__value = string_type(__end - __lc->_M_frac_digits, __end);
__value.insert(__value.begin(), __lc->_M_decimal_point);
__end -= __lc->_M_frac_digits;
}
__value += __lc->_M_decimal_point;
if (__paddec <= 0)
__value.append(__end - __lc->_M_frac_digits,
__lc->_M_frac_digits);
else
{
// Have to pad zeros in the decimal position.
__value = string_type(__beg, __end);
const int __paddec = __lc->_M_frac_digits - (__end - __beg);
__value.insert(__value.begin(), __paddec, __lit[_S_zero]);
__value.insert(__value.begin(), __lc->_M_decimal_point);
__beg = __end;
__value.append(__paddec, __lit[_S_zero]);
__value.append(__beg, __len);
}
}
// Add thousands separators to non-decimal digits, per
// grouping rules.
if (__beg != __end)
{
if (__lc->_M_grouping_size)
{
const int __n = (__end - __beg) * 2;
_CharT* __ws2 =
static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
* __n));
_CharT* __ws_end =
std::__add_grouping(__ws2, __lc->_M_thousands_sep,
__lc->_M_grouping,
__lc->_M_grouping_size,
__beg, __end);
__value.insert(0, __ws2, __ws_end - __ws2);
}
else
__value.insert(0, string_type(__beg, __end));
}
}
// Calculate length of resulting string.
const ios_base::fmtflags __f = __io.flags() & ios_base::adjustfield;
size_type __len = __value.size() + __sign_size;
__len = __value.size() + __sign_size;
__len += ((__io.flags() & ios_base::showbase)
? __lc->_M_curr_symbol_size : 0);
__res.reserve(__len);
string_type __res;
__res.reserve(2 * __len);
const size_type __width = static_cast<size_type>(__io.width());
const bool __testipad = (__f == ios_base::internal

View File

@ -50,6 +50,18 @@ namespace std
template class moneypunct_byname<C, true>;
template class money_get<C, istreambuf_iterator<C> >;
template class money_put<C, ostreambuf_iterator<C> >;
template
istreambuf_iterator<C>
money_get<C, istreambuf_iterator<C> >::
_M_extract<true>(istreambuf_iterator<C>, istreambuf_iterator<C>,
ios_base&, ios_base::iostate&, string_type&) const;
template
istreambuf_iterator<C>
money_get<C, istreambuf_iterator<C> >::
_M_extract<false>(istreambuf_iterator<C>, istreambuf_iterator<C>,
ios_base&, ios_base::iostate&, string_type&) const;
template
ostreambuf_iterator<C>
money_put<C, ostreambuf_iterator<C> >::

View File

@ -0,0 +1,62 @@
// 2004-02-21 Paolo Carlini <pcarlini@suse.de>
// Copyright (C) 2004 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.6.1.1 money_get members
#include <locale>
#include <sstream>
#include <testsuite_hooks.h>
struct My_money : public std::moneypunct<char, false>
{
std::string do_positive_sign() const { return "+"; }
std::string do_negative_sign() const { return ""; }
};
void test01()
{
using namespace std;
typedef istreambuf_iterator<char> InIt;
bool test __attribute__((unused)) = true;
locale loc(locale::classic(), new My_money);
string buffer("69");
InIt iend;
ios_base::iostate err;
string val;
const money_get<char, InIt>& mg =
use_facet<money_get<char, InIt> >(loc);
istringstream fmt(buffer);
fmt.imbue(loc);
InIt ibeg(fmt);
mg.get(ibeg, iend, false, fmt, err, val);
VERIFY( val == "-69" );
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,62 @@
// 2004-02-21 Paolo Carlini <pcarlini@suse.de>
// Copyright (C) 2004 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.6.1.1 money_get members
#include <locale>
#include <sstream>
#include <testsuite_hooks.h>
struct My_money : public std::moneypunct<wchar_t, false>
{
std::wstring do_positive_sign() const { return L"+"; }
std::wstring do_negative_sign() const { return L""; }
};
void test01()
{
using namespace std;
typedef istreambuf_iterator<wchar_t> InIt;
bool test __attribute__((unused)) = true;
locale loc(locale::classic(), new My_money);
wstring buffer(L"69");
InIt iend;
ios_base::iostate err;
wstring val;
const money_get<wchar_t, InIt>& mg =
use_facet<money_get<wchar_t, InIt> >(loc);
wistringstream fmt(buffer);
fmt.imbue(loc);
InIt ibeg(fmt);
mg.get(ibeg, iend, false, fmt, err, val);
VERIFY( val == L"-69" );
}
int main()
{
test01();
return 0;
}