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