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

Reply via email to