This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[libstdc++ PATCH] Specializations of std::char_traits
- From: Matt Austern <austern at apple dot com>
- To: Gabriel Dos Reis <gdr at integrable-solutions dot net>
- Cc: "B. Kosnik" <bkoz at nabi dot net>, libstdc++ at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Date: Thu, 24 Jul 2003 16:05:56 -0700
- Subject: [libstdc++ PATCH] Specializations of std::char_traits
On Friday, July 18, 2003, at 04:18 AM, Gabriel Dos Reis wrote:
Matt Austern <austern@apple.com> writes:
| 2. I deliberately avoided standard algorithms like std::copy and
| std::fill_n. Rationale: at present, bits/char_traits.h is almost
| self-contained. It depends on <cstring> and bits/fpos.h and nothing
| else. I don't want to introduce a new dependence unless there's a
| very strong reason for it.
The only way to get std::char_traits<> is by including <string>, which
already has much more dependencies. In fact, I'm not really
convinced by the dependency argument vs. reusing standard algorithms.
Actually, std::copy and std::fill_n already have logics in place to
provide better optimization where possible. I would not recommend we
don't take the opportunies to reuse them.
That's fair enough. In that case: here's my patch. Test case
included. It's similar to the existing test case for the wchar_t
specialization, but I extended it a bit on the grounds that the
the generic case needs to be tested more thoroughly: char and wchar_t
already get a fair amount of testing from the I/O and string
machinery.
The goal of this patch, again, is to allow users to write things like
std::basic_string<long>. The C++ standard doesn't guarantee that this
is possible, but it works on many systems and some users rely on it.
I've testing this on mainline. I don't have strong opinions about
whether it ought to go on the 3.3 branch as well.
OK to commit?
--Matt
Index: libstdc++-v3/include/bits/char_traits.h
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/include/bits/char_traits.h,v
retrieving revision 1.19
diff -u -r1.19 char_traits.h
--- libstdc++-v3/include/bits/char_traits.h 15 Jul 2003 17:30:10
-0000 1.19
+++ libstdc++-v3/include/bits/char_traits.h 24 Jul 2003 22:50:23 -0000
@@ -43,83 +43,200 @@
#pragma GCC system_header
#include <cstring> // For memmove, memset, memchr
+#include <bits/stl_algobase.h>// For copy, lexicographical_compare,
fill_n
#include <bits/fpos.h> // For streampos
-namespace std
+namespace __gnu_cxx
{
- // 21.1
+
/**
- * @brief Basis for explicit traits specializations.
+ * @brief Mapping from character type to associated types.
+ *
*
- * @note For any given actual character type, this definition is
- * probably wrong.
+ * @note This is an implementation class for the generic version
+ * of char_traits. It defines int_type, off_type, pos_type, and
+ * state_type. By default these are unsigned long, streamoff,
+ * streampos, and mbstate_t. Users who need a different set of
+ * types, but who don't need to change the definitions of any
function
+ * defined in char_traits, can specialize __gnu_cxx::_Char_types
+ * while leaving __gnu_cxx::char_traits alone. */
+ template <class _CharT>
+ struct _Char_types
+ {
+ typedef unsigned long int_type;
+ typedef std::streampos pos_type;
+ typedef std::streamoff off_type;
+ typedef std::mbstate_t state_type;
+ };
+
+
+ /**
+ * @brief Base class used to implement std::char_traits.
+ *
+ * @note For any given actual character type, this definition is
+ * probably wrong. (Most of the member functions are likely to be
+ * right, but the int_type and state_type typedefs, and the eof()
+ * member function, are likely to be wrong.) The reason this class
+ * exists is so users can specialize it. Classes in namespace std
+ * may not be specialized for fundamentl types, but classes in
+ * namespace __gnu_cxx may be.
*
* See
http://gcc.gnu.org/onlinedocs/libstdc++/21_strings/howto.html#5
* for advice on how to make use of this class for "unusual"
character
- * types. Also, check out include/ext/pod_char_traits.h.
- */
- template<class _CharT>
+ * types. Also, check out include/ext/pod_char_traits.h. */
+ template<typename _CharT>
struct char_traits
{
- typedef _CharT char_type;
- typedef unsigned long int_type;
- typedef streampos pos_type;
- typedef streamoff off_type;
- typedef mbstate_t state_type;
+ typedef _CharT char_type;
+ typedef typename _Char_types<_CharT>::int_type int_type;
+ typedef typename _Char_types<_CharT>::pos_type pos_type;
+ typedef typename _Char_types<_CharT>::off_type off_type;
+ typedef typename _Char_types<_CharT>::state_type state_type;
static void
- assign(char_type& __c1, const char_type& __c2);
+ assign(char_type& __c1, const char_type& __c2)
+ { __c1 = __c2; }
static bool
- eq(const char_type& __c1, const char_type& __c2);
+ eq(const char_type& __c1, const char_type& __c2)
+ { return __c1 == __c2; }
static bool
- lt(const char_type& __c1, const char_type& __c2);
+ lt(const char_type& __c1, const char_type& __c2)
+ { return __c1 < __c2; }
static int
- compare(const char_type* __s1, const char_type* __s2, size_t
__n);
+ compare(const char_type* __s1, const char_type* __s2,
std::size_t __n);
- static size_t
+ static std::size_t
length(const char_type* __s);
static const char_type*
- find(const char_type* __s, size_t __n, const char_type& __a);
+ find(const char_type* __s, std::size_t __n, const char_type&
__a);
static char_type*
- move(char_type* __s1, const char_type* __s2, size_t __n);
+ move(char_type* __s1, const char_type* __s2, std::size_t __n);
static char_type*
- copy(char_type* __s1, const char_type* __s2, size_t __n);
+ copy(char_type* __s1, const char_type* __s2, std::size_t __n);
static char_type*
- assign(char_type* __s, size_t __n, char_type __a);
+ assign(char_type* __s, std::size_t __n, char_type __a);
static char_type
- to_char_type(const int_type& __c);
+ to_char_type(const int_type& __c)
+ { return static_cast<char_type>(__c); }
static int_type
- to_int_type(const char_type& __c);
+ to_int_type(const char_type& __c)
+ { return static_cast<int_type>(__c); }
static bool
- eq_int_type(const int_type& __c1, const int_type& __c2);
+ eq_int_type(const int_type& __c1, const int_type& __c2)
+ { return __c1 == __c2; }
static int_type
- eof();
+ eof()
+ { return static_cast<int_type>(EOF); }
static int_type
- not_eof(const int_type& __c);
+ not_eof(const int_type& __c)
+ { return !eq_int_type(__c, eof()) ? __c : char_type(); }
};
+ template<typename _CharT>
+ int
+ char_traits<_CharT>::
+ compare(const char_type* __s1, const char_type* __s2, std::size_t
__n)
+ {
+ for (size_t __i = 0; __i < __n; ++__i)
+ if (lt(__s1[__i], __s2[__i]))
+ return -1;
+ else if (lt(__s2[__i], __s1[__i]))
+ return 1;
+ return 0;
+ }
+
+ template<typename _CharT>
+ std::size_t
+ char_traits<_CharT>::
+ length(const char_type* __p)
+ {
+ std::size_t __i = 0;
+ while (!eq(__p[__i], char_type()))
+ ++__i;
+ return __i;
+ }
+
+ template<typename _CharT>
+ const typename char_traits<_CharT>::char_type*
+ char_traits<_CharT>::
+ find(const char_type* __s, std::size_t __n, const char_type& __a)
+ {
+ for (std::size_t __i = 0; __i < __n; ++__i)
+ if (eq(__s[__i], __a))
+ return __s + __i;
+ return 0;
+ }
+
+ template<typename _CharT>
+ typename char_traits<_CharT>::char_type*
+ char_traits<_CharT>::
+ move(char_type* __s1, const char_type* __s2, std::size_t __n)
+ {
+ return static_cast<_CharT*>(std::memmove(__s1, __s2,
+ __n * sizeof(char_type)));
+ }
+
+ template<typename _CharT>
+ typename char_traits<_CharT>::char_type*
+ char_traits<_CharT>::
+ copy(char_type* __s1, const char_type* __s2, std::size_t __n)
+ {
+ std::copy(__s2, __s2 + __n, __s1);
+ return __s1;
+ }
+
+ template<typename _CharT>
+ typename char_traits<_CharT>::char_type*
+ char_traits<_CharT>::
+ assign(char_type* __s, std::size_t __n, char_type __a)
+ {
+ std::fill_n(__s, __n, __a);
+ return __s;
+ }
+}
+
+namespace std
+{
+ // 21.1
+ /**
+ * @brief Basis for explicit traits specializations.
+ *
+ * @note For any given actual character type, this definition is
+ * probably wrong. Since this is just a thin wrapper around
+ * __gnu_cxx::char_traits, it is possible to achieve a more
+ * appropriate definition by specializing __gnu_cxx::char_traits.
+ *
+ * See
http://gcc.gnu.org/onlinedocs/libstdc++/21_strings/howto.html#5
+ * for advice on how to make use of this class for "unusual"
character
+ * types. Also, check out include/ext/pod_char_traits.h.
+ */
+ template<class _CharT>
+ struct char_traits
+ : public __gnu_cxx::char_traits<_CharT>
+ { };
+
/// 21.1.3.1 char_traits specializations
template<>
struct char_traits<char>
{
- typedef char char_type;
- typedef int int_type;
- typedef streampos pos_type;
- typedef streamoff off_type;
- typedef mbstate_t state_type;
+ typedef char char_type;
+ typedef int int_type;
+ typedef streampos pos_type;
+ typedef streamoff off_type;
+ typedef mbstate_t state_type;
static void
assign(char_type& __c1, const char_type& __c2)
@@ -185,11 +302,11 @@
template<>
struct char_traits<wchar_t>
{
- typedef wchar_t char_type;
- typedef wint_t int_type;
- typedef streamoff off_type;
- typedef wstreampos pos_type;
- typedef mbstate_t state_type;
+ typedef wchar_t char_type;
+ typedef wint_t int_type;
+ typedef streamoff off_type;
+ typedef wstreampos pos_type;
+ typedef mbstate_t state_type;
static void
assign(char_type& __c1, const char_type& __c2)
Index:
libstdc++-v3/testsuite/21_strings/char_traits/requirements/short/1.cc
===================================================================
RCS file:
libstdc++-v3/testsuite/21_strings/char_traits/requirements/short/1.cc
diff -N
libstdc++-v3/testsuite/21_strings/char_traits/requirements/short/1.cc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++
libstdc++-v3/testsuite/21_strings/char_traits/requirements/short/1.cc
24 Jul 2003 22:50:24 -0000
@@ -0,0 +1,172 @@
+// 1999-06-03 bkoz
+// 2003-07-22 Matt Austern
+
+// Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
along
+// with this library; see the file COPYING. If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307,
+// USA.
+
+// 21.1.1 Character traits requirements
+// Make sure we can instantiate char_traits and basic_string for
+// charT = 'short', and make sure the char_traits memeber functions
+// satisfy the requirements of 21.1.1.
+
+#include <string>
+#include <testsuite_hooks.h>
+
+void test02(void)
+{
+ bool test = true;
+
+ // 21.1.1 character traits requirements
+
+ // Key for decoding what function signatures really mean:
+ // X == char_traits<_CharT>
+ // [c,d] == _CharT
+ // [p,q] == const _CharT*
+ // s == _CharT*
+ // [n,i,j] == size_t
+ // f == X::int_type
+ // pos == X::pos_type
+ // state == X::state_type
+
+ // void X::assign(short c, short d)
+ // assigns c = d;
+ short c1 = 'z';
+ short c2 = 'u';
+ VERIFY( c1 != c2 );
+ std::char_traits<short>::assign(c1,c2);
+ VERIFY( c1 == 'u' );
+
+ // bool X::eq(short c, short d)
+ c1 = 'z';
+ c2 = 'u';
+ VERIFY ( !std::char_traits<short>::eq(c1, c2) );
+ VERIFY ( std::char_traits<short>::eq(c1, c1) );
+ VERIFY ( std::char_traits<short>::eq(c2, c2) );
+
+ // bool X::lt(short c, short d)
+ c1 = 'z';
+ c2 = 'u';
+ VERIFY ( std::char_traits<short>::lt(c2, c1) );
+ VERIFY ( !std::char_traits<short>::lt(c1, c2) );
+ VERIFY ( !std::char_traits<short>::lt(c1, c1) );
+ VERIFY ( !std::char_traits<short>::lt(c2, c2) );
+
+ // short* X::move(short* s, const short* p, size_t n)
+ // for each i in [0,n) performs X::assign(s[i], p[i]). Copies
+ // correctly even where p is in [s, s + n), and yields s.
+ short array1[] = {'z', 'u', 'm', 'a', ' ', 'b', 'e', 'a', 'c', 'h',
0};
+ const std::basic_string<short> str_01(array1 + 0, array1 + 10);
+
+ const short str_lit1[] = {'m', 'o', 'n', 't', 'a', 'r', 'a', ' ',
'a', 'n', 'd', ' ', 'o', 'c', 'e', 'a', 'n', ' ', 'b', 'e', 'a', 'c',
'h', 0};
+
+ int len = sizeof(str_lit1)/sizeof(short) +
sizeof(array1)/sizeof(short) - 1;
+ // two terminating chars
+ short array2[len];
+
+ VERIFY( str_lit1[0] == 'm' );
+ c1 = array2[0];
+ c2 = str_lit1[0];
+ short c3 = array2[1];
+ short c4 = str_lit1[1];
+ std::char_traits<short>::move(array2, str_lit1, 0);
+ VERIFY( array2[0] == c1 );
+ VERIFY( str_lit1[0] == c2 );
+ std::char_traits<short>::move(array2, str_lit1, 1);
+ VERIFY( array2[0] == c2 );
+ VERIFY( str_lit1[0] == c2 );
+ VERIFY( array2[1] == c3 );
+ VERIFY( str_lit1[1] == c4 );
+ std::char_traits<short>::move(array2, str_lit1, 2);
+ VERIFY( array2[0] == c2 );
+ VERIFY( str_lit1[0] == c2 );
+ VERIFY( array2[1] == c4 );
+ VERIFY( str_lit1[1] == c4 );
+
+ short* pc1 = array1 + 1;
+ c1 = pc1[0];
+ c2 = array1[0];
+ VERIFY( c1 != c2 );
+ short* pc2 = std::char_traits<short>::move(array1, pc1, 0);
+ c3 = pc1[0];
+ c4 = array1[0];
+ VERIFY( c1 == c3 );
+ VERIFY( c2 == c4 );
+ VERIFY( pc2 == array1 );
+
+ c1 = pc1[0];
+ c2 = array1[0];
+ short* pc3 = pc1;
+ pc2 = std::char_traits<short>::move(array1, pc1, 10);
+ c3 = pc1[0];
+ c4 = array1[0];
+ VERIFY( c1 != c3 ); // underlying short array changed.
+ VERIFY( c4 != c3 );
+ VERIFY( pc2 == array1 );
+ VERIFY( pc3 == pc1 ); // but pointers o-tay
+ c1 = *(str_01.data());
+ c2 = array1[0];
+ VERIFY( c1 != c2 );
+
+ // size_t X::length(const short* p)
+ len = std::char_traits<short>::length(str_lit1);
+ VERIFY( len == sizeof(str_lit1) / sizeof(short) - 1 );
+
+ // const short* X::find(const short* s, size_t n, short c)
+ const int N4 = sizeof(str_lit1) / sizeof(short);
+ const short* pc4 = std::char_traits<short>::find(str_lit1, N4, 'a');
+ VERIFY( pc4 != 0 );
+ VERIFY( *pc4 == 'a' );
+
+ pc4 = std::char_traits<short>::find(str_lit1, N4, 0x0a73);
+ VERIFY( pc4 == 0 );
+
+ // short* X::assign(short* s, size_t n, short c)
+ len = sizeof(array2) / sizeof(short);
+ memset(array2, 0xaf, len * sizeof(short));
+ VERIFY( array2[0] != 0x15a8 );
+
+ pc1 = std::char_traits<short>::assign (array2, len, 0x15a8);
+ VERIFY( pc1 == array2 );
+ for (int i = 0; i < len; ++i)
+ VERIFY( array2[i] == 0x15a8 );
+
+ // short* X::copy(short* s, const short* p, size_t n)
+ int n1 = sizeof(str_lit1) / sizeof(short);
+ pc1 = std::char_traits<short>::copy(array2, str_lit1, n1);
+ len = std::char_traits<short>::length(array2);
+ VERIFY( len == n1 - 1 );
+ for (int i = 0; i < len; ++i)
+ VERIFY( str_lit1[i] == array2[i] );
+
+ // int X::compare(const short* p, const short* q, size_t n)
+ const short* pconst1 = str_01.data();
+ const short* pconst2 = str_lit1;
+
+ VERIFY( std::char_traits<short>::compare(pconst1, pconst2, 10) > 0 );
+ VERIFY( std::char_traits<short>::compare(pconst2, pconst1, 10) < 0 );
+ VERIFY( std::char_traits<short>::compare(pconst1, pconst1, 10) == 0
);
+ VERIFY( std::char_traits<short>::compare(pconst2, pconst2, 10) == 0
);
+}
+
+
+
+int main()
+{
+ test02();
+ return 0;
+}