user-defined types and basic_string

Martin Sebor sebor@roguewave.com
Fri Aug 23 11:08:00 GMT 2002


Benjamin Kosnik wrote:

> Here's an example of how to do a portable, standards-conformant string
> class with underlying type of unsigned short. This also works for
> things like unsigned char. Comments welcome.


You'd need to get rid of the character ctors to make it conforming and
portable (the type must be a POD), but other than that it looks pretty
close to our charT that we test string and iostreams with (see below) :)

> 
> As Matt pointed out, doing the locale work is a bit tricky. I intend
> to do that as well, but thought I'd post this first.


You must have a lot of time on your hands ;-) Are you really willing
to rewrite all facets as an exercise? I think the only feasible approach
would be to either add a traits template parameter to them or diligently
use char_traits<char_type> in all facets and hope that the user
specializes it rather than creating their own (unrelated) class.

Martin



struct C   // user-defined character type (must be POD)
{
#ifndef _RWSTD_NO_LONG_DOUBLE
     long double f;    // exercise correct alignment
#else
     double f;
#endif   // _RWSTD_NO_LONG_DOUBLE

     unsigned char c;   // underlying character representation

     // definition of a POD-struct (9, p4):
     // A POD-struct is an aggregate class that has no non-static data
     // members of type pointer to member, non-POD-struct, non-POD-union
     // (or array of such types) or reference, and has no user-defined
     // copy assign-ment operator and no user-defined destructor.

     // definition of an aggregate (8.5.1, p1):
     // An aggregate is an array or a class (clause 9) with no user-declared
     // constructors (12.1), no private or protected non-static data members
     // (clause 11), no base classes (clause 10), and no virtual functions
     // (10.3).
};


struct I   // user-defined int type (must be POD)
{
     int i;         // underlying int representation

     void* dummy;   // waste space
};


struct C_traits   // user-defined character traits
{
     typedef C   char_type;
     typedef I   int_type;

     // avoid any dependency on the library
     typedef int                   off_type;     // std::streamoff
     typedef int                   state_type;   // std::mbstate_t
     typedef std::fpos<state_type> pos_type;     // std::fpos<state_type>

     // accesses to the char_type::f member may trigger a SIGBUS
     // on some architectures (e.g., PA or SPARC) if the member
     // isn't appropriately aligned
     static void assign (char_type& c1, const char_type& c2) {
         c1.f = c2.f;
         c1.c = c2.c;
     }

     static bool eq (const char_type& c1, const char_type& c2) {
         return c1.f == c2.f && c1.c == c2.c;
     }

     static bool lt (const char_type& c1, const char_type& c2) {
         return c1.f < c2.f || c1.f == c2.f && c1.c < c2.c;
     }

     static int compare (const char_type* s1, const char_type* s2, 
unsigned n) {
         unsigned i = 0;
         while (i < n) {
             if (!eq (s1[i], s2[i])) {
                 return lt (s1[i], s2[i]) ? -1 : 1;
             }
             ++i;
         }
         return 0;
     }

     static unsigned length (const char_type *s) {
         unsigned len = 0;
         while (!eq (*s++, char_type ()))
             ++len;
         return len;
     }

     static const char_type*
     find (const char_type* s, unsigned n, const char_type& c) {
         while (n-- > 0 && !eq (*s, c) )
             ++s;
         return  eq (*s, c) ? s : 0;
     }

     static char_type* move (char_type* s1, const char_type* s2, 
unsigned n) {
         if (s1 < s2)
             copy (s1, s2, n);
         else if (s1 > s2) {
             s1 += n;
             s2 += n;
             for (unsigned i = 0; i < n; ++i)
                 assign (*--s1, *--s2);
         }
         return s1;
     }

     static char_type* copy (char_type *dst, const char_type *src, 
unsigned n) {
         for (; n--; *dst++ = *src++);
         return dst;
     }

     static char_type*  assign (char_type* s, unsigned n, char_type c) {
         char_type* tmp = s;
         while (n-- > 0)
             assign (*tmp++, c);
         return s;
     }

     static int_type not_eof (const int_type& i) {
         I tmp = { -1 == i.i ? 0 : i.i, 0};
         return tmp;
     }

     static char_type to_char_type (const int_type& i) {
         C tmp = { 0.0, i.i };
         return tmp;
     }

     static int_type to_int_type (const char_type& c) {
         I tmp = { c.c, 0 };
         return tmp;
     }

     static bool eq_int_type (const int_type& i1, const int_type& i2) {
         return i1.i == i2.i;
     }

     static int_type eof () {
         I tmp = { -1, 0 };
         return tmp;
     }
};



More information about the Libstdc++ mailing list