This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]