Am Mittwoch, 13. September 2006 22:37 schrieb Angus Leeming:
> Georg Baum <[EMAIL PROTECTED]> writes:
> > Try this one. On linux the output is:
> >
> > global has std::codecvt<boost::uint32_t> facet: 0
> > global has std::ctype<boost::uint32_t> facet: 0
> > global has std::num_put<boost::uint32_t> facet: 0
> > terminate called after throwing an instance of 'std::bad_cast'
> > what(): St8bad_cast
>
> Hmmmm. So it throws when filling the
basic_ostringstream<boost::uint32_t>?
Yes. Because of missing ctype:
#0 0xffffe410 in __kernel_vsyscall ()
#1 0xa7d15821 in raise () from /lib/tls/i686/cmov/libc.so.6
#2 0xa7d16fb9 in abort () from /lib/tls/i686/cmov/libc.so.6
#3 0xa7f04aa4 in __gnu_cxx::__verbose_terminate_handler ()
from /usr/lib/libstdc++.so.6
#4 0xa7f024c5 in std::set_unexpected () from /usr/lib/libstdc++.so.6
#5 0xa7f02502 in std::terminate () from /usr/lib/libstdc++.so.6
#6 0xa7f0263a in __cxa_throw () from /usr/lib/libstdc++.so.6
#7 0xa7e96b25 in std::__throw_bad_cast () from /usr/lib/libstdc++.so.6
#8 0x0804cd15 in std::__check_facet<std::ctype<unsigned int> > (__f=0x0)
at
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/localefwd.h:187
#9 0x0804cd3c in std::basic_ios<unsigned int, std::char_traits<unsigned
int> >::widen (this=0xafbc1848, __c=120 'x')
at
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/basic_ios.tcc:122
#10 0x0804d48c in std::operator<< <unsigned int, std::char_traits<unsigned
int> > ([EMAIL PROTECTED], __c=120 'x')
at /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/ostream:429
#11 0x08049168 in main () at locale-test.cpp:16
The attached version prints this:
global has std::codecvt<boost::uint32_t> facet: 0
global has std::ctype<boost::uint32_t> facet: 0
global has std::num_put<boost::uint32_t> facet: 0
newlocale has std::codecvt<boost::uint32_t> facet: 0
newlocale has std::ctype<boost::uint32_t> facet: 1
newlocale has std::num_put<boost::uint32_t> facet: 0
stringstream test:
It does still not work, this time because of num_put (it does not throw,
because the exception is caught in operator<<.
> Incidentally, I don't think that you mean this:
> std::cerr << "global has std::num_put<boost::uint32_t> facet: "
> << std::has_facet<std::ctype<boost::uint32_t> >(global)
> << std::endl;
Well spotted, thanks. Enrico, please use the attached version for testing.
Georg
#include <boost/cstdint.hpp>
#include <iostream>
#include <locale>
#include <sstream>
#ifdef __GNUC__
namespace std {
template<> ctype<boost::uint32_t>::~ctype() {}
template<> bool
ctype<boost::uint32_t>::do_is(ctype<boost::uint32_t>::mask, boost::uint32_t) const { return false; }
template<> boost::uint32_t const *
ctype<boost::uint32_t>::do_is(const boost::uint32_t *, const boost::uint32_t *, ctype<boost::uint32_t>::mask *) const { return 0; }
template<> const boost::uint32_t *
ctype<boost::uint32_t>::do_scan_is(ctype<boost::uint32_t>::mask, const boost::uint32_t *, const boost::uint32_t *) const { return 0; }
template<> const boost::uint32_t *
ctype<boost::uint32_t>::do_scan_not(ctype<boost::uint32_t>::mask, const boost::uint32_t *, const boost::uint32_t *) const { return 0; }
template<> boost::uint32_t ctype<boost::uint32_t>::do_toupper(boost::uint32_t) const { return 0; }
template<> const boost::uint32_t * ctype<boost::uint32_t>::do_toupper(boost::uint32_t *, boost::uint32_t const *) const { return 0; }
template<> boost::uint32_t ctype<boost::uint32_t>::do_tolower(boost::uint32_t) const { return 0; }
template<> const boost::uint32_t * ctype<boost::uint32_t>::do_tolower(boost::uint32_t *, boost::uint32_t const *) const { return 0; }
template<> boost::uint32_t ctype<boost::uint32_t>::do_widen(char) const { return 0; }
template<> const char *
ctype<boost::uint32_t>::do_widen(const char *, const char *, boost::uint32_t *) const { return 0; }
template<> char
ctype<boost::uint32_t>::do_narrow(const boost::uint32_t, char) const { return 0; }
template<> const boost::uint32_t *
ctype<boost::uint32_t>::do_narrow(const boost::uint32_t *, const boost::uint32_t *, char, char *) const { return 0; }
}
#endif
class ascii_ctype_facet : public std::ctype<boost::uint32_t>
{
public:
typedef boost::uint32_t char_type;
typedef wctype_t wmask_type;
explicit ascii_ctype_facet(size_t refs = 0) : std::ctype<char_type>(refs)
{
_M_initialize_ctype();
}
protected:
bool M_narrow_ok;
char M_narrow[128];
wint_t M_widen[1 + static_cast<unsigned char>(-1)];
mask M_bit[16];
wmask_type M_wmask[16];
wmask_type M_convert_to_wmask(const mask m) const
{
wmask_type ret;
switch (m) {
case space: ret = wctype("space"); break;
case print: ret = wctype("print"); break;
case cntrl: ret = wctype("cntrl"); break;
case upper: ret = wctype("upper"); break;
case lower: ret = wctype("lower"); break;
case alpha: ret = wctype("alpha"); break;
case digit: ret = wctype("digit"); break;
case punct: ret = wctype("punct"); break;
case xdigit: ret = wctype("xdigit"); break;
case alnum: ret = wctype("alnum"); break;
case graph: ret = wctype("graph"); break;
default: ret = wmask_type();
}
return ret;
}
void _M_initialize_ctype()
{
wint_t i;
for (i = 0; i < 128; ++i) {
const int c = wctob(i);
if (c == EOF)
break;
else
M_narrow[i] = static_cast<char>(c);
}
if (i == 128)
M_narrow_ok = true;
else
M_narrow_ok = false;
for (size_t i = 0; i < sizeof(M_widen) / sizeof(wint_t); ++i)
M_widen[i] = btowc(i);
for (size_t i = 0; i <= 15; ++i) {
M_bit[i] = static_cast<mask>(1 << i);
M_wmask[i] = M_convert_to_wmask(M_bit[i]);
}
}
virtual ~ascii_ctype_facet() {}
char_type do_toupper(char_type c) const { return towupper(c); }
char_type const * do_toupper(char_type * lo, char_type const * hi) const
{
while (lo < hi) {
*lo = towupper(*lo);
++lo;
}
return hi;
}
char_type do_tolower(char_type c) const { return towlower(c); }
char_type const * do_tolower(char_type * lo, char_type const * hi) const
{
while (lo < hi) {
*lo = towlower(*lo);
++lo;
}
return hi;
}
bool do_is(mask m, char_type c) const
{
bool ret = false;
// Generically, 15 (instead of 10) since we don't know the numerical
// encoding of the various categories in /usr/include/ctype.h.
const size_t bitmasksize = 15;
for (size_t bitcur = 0; bitcur <= bitmasksize; ++bitcur)
if (m & M_bit[bitcur] && iswctype(c, M_wmask[bitcur])) {
ret = true;
break;
}
return ret;
}
char_type const * do_is(char_type const * lo, char_type const * hi, mask * vec) const
{
for (;lo < hi; ++vec, ++lo) {
// Generically, 15 (instead of 10) since we don't know the numerical
// encoding of the various categories in /usr/include/ctype.h.
const size_t bitmasksize = 15;
mask m = 0;
for (size_t bitcur = 0; bitcur <= bitmasksize; ++bitcur)
if (iswctype(*lo, M_wmask[bitcur]))
m |= M_bit[bitcur];
*vec = m;
}
return hi;
}
char_type const * do_scan_is(mask m, char_type const * lo, char_type const * hi) const
{
while (lo < hi && !this->do_is(m, *lo))
++lo;
return lo;
}
char_type const * do_scan_not(mask m, char_type const * lo, char_type const * hi) const
{
while (lo < hi && this->do_is(m, *lo) != 0)
++lo;
return lo;
}
virtual char_type do_widen(char c) const
{
if (static_cast<unsigned char>(c) < 128)
return c;
throw std::bad_cast();
}
virtual const char* do_widen(const char* lo, const char* hi, char_type* dest) const
{
while (lo < hi) {
if (static_cast<unsigned char>(*lo) >= 128)
throw std::bad_cast();
*dest = *lo;
++lo;
++dest;
}
return hi;
}
virtual char do_narrow(char_type wc, char) const
{
if (wc < 128)
return static_cast<char>(wc);
throw std::bad_cast();
}
virtual const char_type * do_narrow(const char_type * lo, const char_type * hi, char, char * dest) const
{
while (lo < hi) {
if (*lo < 128)
*dest = static_cast<char>(*lo);
else
throw std::bad_cast();
++lo;
++dest;
}
return hi;
}
};
void testlocale(char const * const name, std::locale const & l)
{
std::cerr << name << " has std::codecvt<boost::uint32_t> facet: "
<< std::has_facet<std::codecvt<boost::uint32_t, char, std::mbstate_t> >(l)
<< std::endl;
std::cerr << name << " has std::ctype<boost::uint32_t> facet: "
<< std::has_facet<std::ctype<boost::uint32_t> >(l)
<< std::endl;
std::cerr << name << " has std::num_put<boost::uint32_t> facet: "
<< std::has_facet<std::num_put<boost::uint32_t> >(l)
<< std::endl;
}
int main()
{
std::locale const global;
testlocale("global", global);
std::locale const newlocale(global, new ascii_ctype_facet);
testlocale("newlocale", newlocale);
std::locale::global(newlocale);
std::basic_ostringstream<boost::uint32_t> os;
os << 'x' << 11 << ' ' << 3.0;
std::basic_string<boost::uint32_t> const s(os.str());
std::cerr << "stringstream test: ";
for (size_t i = 0; i < s.size(); ++i)
std::cerr << s[i];
std::cerr << '\n';
return 0;
}