On Fri, Nov 10, 2006 at 07:16:03PM +0100, Enrico Forestieri wrote: > On Fri, Nov 10, 2006 at 06:43:58PM +0100, Georg Baum wrote: > > Enrico Forestieri wrote: > > > > > On Fri, Nov 10, 2006 at 05:45:18PM +0100, Georg Baum wrote: > > >> Enrico Forestieri wrote: > > >> > > >> > I am going to shove in the attached. There's a small optimization with > > >> > respect to the previous version. > > >> > > >> Can you explain why you implemented two facets? I would expect only one > > >> (with ascii_num_put_facet as name, since it can only cope with pure > > >> ascii). > > > > > > Strictly speaking, only the odocstream_num_put_facet would be needed. > > > I used the ascii_num_put_facet in order to have a number formatted as a > > > string using the already existing facets for basic_string<char>::iterator > > > instead of rolling out my own versions. > > > > I can understand that, but why do you not use std::num_put<char, > > std::basic_string<char>::iterator> directly? > > Because when I did that (as done in the attached patch) I got the > following error: > > g++ -DHAVE_CONFIG_H -I. -I../../../src/support -I../../src > -I../../../src/support/.. -I../../../boost -Wno-uninitialized -funsigned-char > -O2 -MT docstring.lo -MD -MP -MF .deps/docstring.Tpo -c > ../../../src/support/docstring.C -o docstring.o > ../../../src/support/docstring.C: In member function `virtual > std::ostreambuf_iterator<lyx::char_type, std::char_traits<lyx::char_type> > > lyx::ascii_num_put_facet::do_put(std::ostreambuf_iterator<lyx::char_type, > std::char_traits<lyx::char_type> >, std::ios_base&, lyx::char_type, long int) > const': > /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/locale_facets.h:2404: > error: `std::num_put<_CharT, _OutIter>::~num_put() [with _CharT = char, > _OutIter = __gnu_cxx::__normal_iterator<char*, std::basic_string<char, > std::char_traits<char>, std::allocator<char> > >]' is protected > ../../../src/support/docstring.C:407: error: within this context > make[5]: *** [docstring.lo] Error 1 > > > I really would prefer if > > odocstream_num_put_facet would be called ascii_num_put_facet, since that > > makes very clear that it can only deal with ASCII. For the same reason I > > would prefer to assert on fill < 0x80 instead of silently changing it to a > > space. > > Or maybe throw num_put_failure() ? > > > I don't think that we are using a different fill character anywhere, > > but if somebody does that it is better to crash than to silently alter the > > result. Your current ascii_num_put_facet is only an implementation detail, > > so I'd like that to be hidden in the num_put method. > > In order to do that I have to avoid the above error. Any suggestions?
What about the attached? I renamed the facets and buried the facet doing the real work in the ascii_num_put_facet (which was formerly called odocstream_num_put_facet). Now an explicative message will be printed if the fill character is not in the ascii range. -- Enrico
Index: src/support/docstring.C =================================================================== --- src/support/docstring.C (revision 15838) +++ src/support/docstring.C (working copy) @@ -14,6 +14,7 @@ #include "unicode.h" #include <locale> +#include <iostream> #include <boost/assert.hpp> @@ -208,6 +209,17 @@ public: }; +class num_put_failure : public std::bad_cast { +public: + num_put_failure() throw() : std::bad_cast() {} + virtual ~num_put_failure() throw() {} + virtual const char* what() const throw() + { + return "The num_put locale facet does only support ASCII characters on this platform."; + } +}; + + /// ctype facet for UCS4 characters. The implementation does only support pure /// ASCII, since we do not need anything else for now. /// The code is partly stolen from std::ctype<wchar_t> from gcc. @@ -388,21 +400,59 @@ protected: }; -/// class to add our ascii_ctype_facet to the global locale +/// Facet for outputting numbers to odocstreams as ascii. +/// Here we simply need defining the virtual do_put functions. +class ascii_num_put_facet : public std::num_put<lyx::char_type, std::ostreambuf_iterator<lyx::char_type, std::char_traits<lyx::char_type> > > +{ + typedef std::ostreambuf_iterator<lyx::char_type, std::char_traits<lyx::char_type> > iter_type; +public: + ascii_num_put_facet(size_t refs = 0) : std::num_put<lyx::char_type, iter_type>(refs) {} + + /// Facet for converting numbers to ascii strings. + class string_num_put_facet : public std::num_put<char, std::basic_string<char>::iterator> + { + public: + string_num_put_facet() : std::num_put<char, std::basic_string<char>::iterator>(1) {} + }; + +protected: + iter_type + do_put(iter_type oit, std::ios_base & b, char_type fill, long v) const + { + if (fill >= 0x80) + throw num_put_failure(); + + std::string s; + // 64 is large enough + s.resize(64); + string_num_put_facet f; + std::string::const_iterator cit = s.begin(); + std::string::const_iterator end = + f.put(s.begin(), b, fill, v); + for (; cit != end; ++cit, ++oit) + *oit = *cit; + + return oit; + } +}; + + +/// class to add our facets to the global locale class locale_initializer { public: locale_initializer() { std::locale global; - std::locale const loc(global, new ascii_ctype_facet); - std::locale::global(loc); + std::locale const loc1(global, new ascii_ctype_facet); + std::locale const loc2(loc1, new ascii_num_put_facet); + std::locale::global(loc2); } }; namespace { -/// make sure that our ascii_ctype_facet gets used +/// make sure that our facets gets used static locale_initializer initializer; }