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;
}

Reply via email to