blob: bc57ba09abdca2620dbcfd766cb35041931a60a6 [file] [log] [blame]
/**************************************************************************
*
* rw_char.h - defines a User Defined Character type and its traits
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 2004-2006 Rogue Wave Software.
*
**************************************************************************/
#ifndef RW_CHAR_INCLUDED
#define RW_CHAR_INCLUDED
// avoid dependencies on any library headers
// to prevent the pollution of the namespace(s)
#include <rw/_traits.h>
#include <testdefs.h>
struct UserChar // user-defined character type (must be POD)
{
#if !defined (_RWSTD_NO_LONG_DOUBLE) \
&& !defined (__SUNPRO_CC) || __SUNPRO_CC > 0x540
long double f; // exercise correct alignment
#else
// cannot use long double with SunPro due to a compiler
// bug that prevents assignments of UserChar() (PR #28328)
double f;
#endif // _RWSTD_NO_LONG_DOUBLE
unsigned char c; // underlying character representation
static UserChar eos () {
// use UserChar::eos() instead of UserChar() to work around broken
// compilers (e.g., MSVC 6) that do not zero out POD structs
// on default construction
const UserChar tmp = { 0, 0 };
return tmp;
}
// 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).
};
inline UserChar make_char (char c, UserChar*)
{
const UserChar ch = { 0.0, c };
return ch;
}
inline char make_char (char c, char*)
{
return c;
}
#ifndef _RWSTD_NO_WCHAR_T
inline wchar_t make_char (char c, wchar_t*)
{
typedef unsigned char UChar;
return wchar_t (UChar (c));
}
#endif // _RWSTD_NO_WCHAR_T
///////////////////////////////////////////////////////////////////////////
// 21.1.2, p2 of C++ 03:
//
// typedef INT_T int_type;
//
// -2- Requires: For a certain character container type char_type, a related
// container type INT_T shall be a type or class which can represent all
// of the valid characters converted from the corresponding char_type
// values, as well as an end-of-file value, eof(). The type int_type
// represents a character container type which can hold end-of-file to
// be used as a return type of the iostream class member functions.224)
// ____________
// Footnote 224: If eof() can be held in char_type then some iostreams
// operations may give surprising results.
class UserInt
{
void* ptr_; // to check validity
int i_; // underlying int representation
// valid values are 0 through 256 with 256 representing EOF
public:
// default ctor creates a valid object but assigns it an invalid
// value so that the only legal operations on it are assignment
// and copy
UserInt (): ptr_ (&i_ /* valid */), i_ (-1 /* invalid */) { /* empty */ }
UserInt (const UserInt &rhs)
: ptr_ (&i_), i_ (rhs.i_) {
// verify rhs is valid
// const_cast used to avoid MSVC 7.0 error C2446:
// '==' : no conversion from 'const int *' to 'void *const '
RW_ASSERT (_RWSTD_CONST_CAST (const void*, rhs.ptr_) == &rhs.i_);
RW_ASSERT (-1 <= rhs.i_ && rhs.i_ < 257); // i may be invalid
}
// (almost) assignable; i.e., returns void instead of UserInt&
// for extra robustness
void operator= (const UserInt &rhs) {
RW_ASSERT (ptr_ == &i_); // verify *this is valid
// verify rhs is valid
RW_ASSERT (_RWSTD_CONST_CAST (const void*, rhs.ptr_) == &rhs.i_);
RW_ASSERT (-1 <= i_ && i_ < 257); // i may be invalid
RW_ASSERT (-1 < rhs.i_ && rhs.i_ < 257); // rhs.i must ve valid
i_ = rhs.i_;
}
static UserInt eof () {
UserInt tmp;
tmp.i_ = 256; // EOF
return tmp;
}
static UserInt from_char (const UserChar &c) {
UserInt tmp;
tmp.i_ = int (c.c);
return tmp;
}
UserChar to_char () const {
// working around an Intel C++ 9.1 bug #380635
/* const */ UserChar tmp /* = { 0, i_ }*/;
tmp.f = 0;
tmp.c = (unsigned char)(i_);
return tmp;
}
~UserInt () {
RW_ASSERT (ptr_ == &i_); // verify *this is valid
RW_ASSERT (-1 <= i_ == i_ < 257); // i may be invalid
i_ = _RWSTD_INT_MIN; // invalidate
ptr_ = &ptr_; // invalidate
}
bool equal (const UserInt &rhs) const {
// verify *this is valid
RW_ASSERT (_RWSTD_CONST_CAST (const void*, ptr_) == &i_);
// verify rhs is valid
RW_ASSERT (_RWSTD_CONST_CAST (const void*, rhs.ptr_) == &rhs.i_);
RW_ASSERT (-1 < i_ && i_ < 257); // i must ve valid
RW_ASSERT (-1 < rhs.i_ && rhs.i_ < 257); // rhs.i must be valid
return i_ == rhs.i_;
}
};
// user-defined character traits template
// (declared but not defined)
template <class charT>
struct UserTraits;
struct TraitsMemFunc
{
enum {
assign, eq, lt, compare, length, find, copy, move,
assign2, not_eof, to_char_type, to_int_type, eq_int_type,
eof,
n_funs
};
};
// required specialization on char
_RWSTD_SPECIALIZED_CLASS
struct _TEST_EXPORT UserTraits<char>: std::char_traits<char>
{
typedef std::char_traits<char> Base;
typedef Base::char_type char_type;
typedef Base::int_type int_type;
typedef TraitsMemFunc MemFun;
// 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>
static void
assign (char_type&, const char_type&);
static bool
eq (const char_type&, const char_type&);
static bool
lt (const char_type&, const char_type&);
static int
compare (const char_type*, const char_type*, _RWSTD_SIZE_T);
static _RWSTD_SIZE_T
length (const char_type*);
static const char_type*
find (const char_type*, _RWSTD_SIZE_T, const char_type&);
static char_type*
copy (char_type*, const char_type*, _RWSTD_SIZE_T);
static char_type*
move (char_type*, const char_type*, _RWSTD_SIZE_T);
static char_type*
assign (char_type*, _RWSTD_SIZE_T, char_type);
static int_type
not_eof (const int_type&);
static char_type
to_char_type (const int_type&);
static int_type
to_int_type (const char_type&);
static bool
eq_int_type (const int_type&, const int_type&);
static int_type
eof ();
static _RWSTD_SIZE_T n_calls_ [];
static int_type eof_;
private:
// not defined to detect bad assumptions made by the library
UserTraits ();
~UserTraits ();
void operator= (UserTraits&);
};
#ifndef _RWSTD_NO_WCHAR_T
// required specialization on wchar_t
_RWSTD_SPECIALIZED_CLASS
struct _TEST_EXPORT UserTraits<wchar_t>: std::char_traits<wchar_t>
{
typedef std::char_traits<wchar_t> Base;
typedef Base::char_type char_type;
typedef Base::int_type int_type;
typedef TraitsMemFunc MemFun;
// 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>
static void
assign (char_type&, const char_type&);
static bool
eq (const char_type&, const char_type&);
static bool
lt (const char_type&, const char_type&);
static int
compare (const char_type*, const char_type*, _RWSTD_SIZE_T);
static _RWSTD_SIZE_T
length (const char_type*);
static const char_type*
find (const char_type*, _RWSTD_SIZE_T, const char_type&);
static char_type*
copy (char_type*, const char_type*, _RWSTD_SIZE_T);
static char_type*
move (char_type*, const char_type*, _RWSTD_SIZE_T);
static char_type*
assign (char_type*, _RWSTD_SIZE_T, char_type);
static int_type
not_eof (const int_type&);
static char_type
to_char_type (const int_type&);
static int_type
to_int_type (const char_type&);
static bool
eq_int_type (const int_type&, const int_type&);
static int_type
eof ();
static _RWSTD_SIZE_T n_calls_ [];
static int_type eof_;
private:
// not defined to detect bad assumptions made by the library
UserTraits ();
~UserTraits ();
void operator= (UserTraits&);
};
#endif // _RWSTD_NO_WCHAR_T
_RWSTD_SPECIALIZED_CLASS
struct _TEST_EXPORT UserTraits<UserChar> // user-defined character traits
{
typedef TraitsMemFunc MemFun;
typedef UserChar char_type;
typedef UserInt 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&, const char_type&);
static bool eq (const char_type&, const char_type&);
static bool lt (const char_type&, const char_type&);
static int
compare (const char_type*, const char_type*, _RWSTD_SIZE_T);
static _RWSTD_SIZE_T length (const char_type*);
static const char_type*
find (const char_type*, _RWSTD_SIZE_T, const char_type&);
static char_type*
copy (char_type*, const char_type*, _RWSTD_SIZE_T);
static char_type*
move (char_type*, const char_type*, _RWSTD_SIZE_T);
static char_type*
assign (char_type*, _RWSTD_SIZE_T, char_type);
static int_type not_eof (const int_type&);
static char_type to_char_type (const int_type&);
static int_type to_int_type (const char_type&);
static bool eq_int_type (const int_type&, const int_type&);
static int_type eof ();
static _RWSTD_SIZE_T n_calls_ [];
private:
// not defined to detect bad assumptions made by the library
UserTraits ();
~UserTraits ();
void operator= (UserTraits&);
};
// rw_widen() widens successive elements of src into the buffer dst
// when (dst != 0) the last character in the buffer is guaranteed to be NUL,
// regardless of the value of str [len]
// when (len == SIZE_MAX && src != 0), computes len as if by evaluating
// len = strlen(src)
// when (src == 0 && len < SIZE_MAX), initializes the first len elements
// of dst to NUL (i.e., such a call is the equivalent of calling
// memset(dst, 0, len * sizeof *dst))
// returns dst
_TEST_EXPORT char*
rw_widen (char* /* dst */,
const char* /* src */,
_RWSTD_SIZE_T /* len */ = _RWSTD_SIZE_MAX);
// rw_expand() interprets string src as a sequence of directives and
// widens the result of their processing into the provided buffer dst
// when (dst != 0), otherwise into a dynamically allocated buffer of
// sufficient size
// each directive consists of a character C, optionally followed by
// the '@' sign followed by a non-negative decimal number N; the result
// of the processing of a directive is N consecutive copies of the
// character C where (N = 1) when the '@' is absent
// when (dst_len != 0) the function sets *dst_len to the number of
// produced characters not counting the terminating NUL
// the function returns the dynamically allocated buffer; the caller
// must deallocate the buffer using the delete expression
_TEST_EXPORT char*
rw_expand (char* /* dst */,
const char* /* src */,
_RWSTD_SIZE_T /* src_len */ = _RWSTD_SIZE_MAX,
_RWSTD_SIZE_T* /* dst_len */ = 0);
// rw_narrow() narrows successive elements of src into the buffer dst
// (see rw_widen() for details)
_TEST_EXPORT char*
rw_narrow (char* /* dst */,
const char* /* src */,
_RWSTD_SIZE_T /* len */ = _RWSTD_SIZE_MAX);
// rw_match() compares up to len successive elements of s1 and s2 for
// equality until it finds a pair that do not compare equal or until
// len comparisons has been made
// if (len == SIZE_MAX) is true elements are compared until the first
// mismatch is found or until the NUL character is encountered
// returns the number of matching elements
_TEST_EXPORT _RWSTD_SIZE_T
rw_match (const char* /* s1 */,
const char* /* s2 */,
_RWSTD_SIZE_T /* len */ = _RWSTD_SIZE_MAX);
#ifndef _RWSTD_WCHAR_T
_TEST_EXPORT wchar_t*
rw_widen (wchar_t*, const char*, _RWSTD_SIZE_T = _RWSTD_SIZE_MAX);
_TEST_EXPORT wchar_t*
rw_expand (wchar_t* /* dst */,
const char* /* src */,
_RWSTD_SIZE_T /* src_len */ = _RWSTD_SIZE_MAX,
_RWSTD_SIZE_T* /* dst_len */ = 0);
_TEST_EXPORT char*
rw_narrow (char*, const wchar_t*, _RWSTD_SIZE_T = _RWSTD_SIZE_MAX);
_TEST_EXPORT _RWSTD_SIZE_T
rw_match (const char*, const wchar_t*,
_RWSTD_SIZE_T = _RWSTD_SIZE_MAX);
#endif // _RWSTD_WCHAR_T
_TEST_EXPORT UserChar*
rw_widen (UserChar*, const char*, _RWSTD_SIZE_T = _RWSTD_SIZE_MAX);
_TEST_EXPORT UserChar*
rw_expand (UserChar* /* dst */,
const char* /* src */,
_RWSTD_SIZE_T /* src_len */ = _RWSTD_SIZE_MAX,
_RWSTD_SIZE_T* /* dst_len */ = 0);
_TEST_EXPORT char*
rw_narrow (char*, const UserChar*, _RWSTD_SIZE_T = _RWSTD_SIZE_MAX);
_TEST_EXPORT _RWSTD_SIZE_T
rw_match (const char*, const UserChar*, _RWSTD_SIZE_T = _RWSTD_SIZE_MAX);
// accessors to n_calls array, if present
template <class charT>
inline _RWSTD_SIZE_T*
rw_get_call_counters (std::char_traits<charT>*, charT*)
{
return 0;
}
template <class charT>
inline _RWSTD_SIZE_T*
rw_get_call_counters (UserTraits<charT>*, charT*)
{
return UserTraits<charT>::n_calls_;
}
static const struct _TEST_EXPORT UserCharFmatInit {
UserCharFmatInit ();
} _rw_user_char_fmat_init;
#endif // RW_CHAR_INCLUDED