Back to index

lightning-sunbird  0.9+nobinonly
nsCharTraits.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Scott Collins <scc@mozilla.org> (original author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #ifndef nsCharTraits_h___
00040 #define nsCharTraits_h___
00041 
00042 #include <ctype.h>
00043   // for |EOF|, |WEOF|
00044 
00045 #define FORCED_CPP_2BYTE_WCHAR_T
00046   // disable special optimizations for now through this hack
00047 
00048 #if defined(HAVE_CPP_2BYTE_WCHAR_T) && !defined(FORCED_CPP_2BYTE_WCHAR_T)
00049 #define USE_CPP_WCHAR_FUNCS
00050 #endif
00051 
00052 #ifdef USE_CPP_WCHAR_FUNCS
00053 #include <wchar.h>
00054   // for |wmemset|, et al
00055 #endif
00056 
00057 #include <string.h>
00058   // for |memcpy|, et al
00059 
00060 #ifndef nscore_h___
00061 #include "nscore.h"
00062   // for |PRUnichar|
00063 #endif
00064 
00065 #ifndef nsDebug_h__
00066 #include "nsDebug.h"
00067   // for NS_ASSERTION
00068 #endif
00069 
00070 #ifdef HAVE_CPP_BOOL
00071   typedef bool nsCharTraits_bool;
00072 #else
00073   typedef PRBool nsCharTraits_bool;
00074 #endif
00075 
00076 // Some macros for working with PRUnichar
00077 #define PLANE1_BASE          PRUint32(0x00010000)
00078 // High surrogates are in the range 0xD800 -- OxDBFF
00079 #define IS_HIGH_SURROGATE(u) ((PRUnichar(u) & 0xFC00) == 0xD800)
00080 // Low surrogates are in the range 0xDC00 -- 0xDFFF
00081 #define IS_LOW_SURROGATE(u)  ((PRUnichar(u) & 0xFC00) == 0xDC00)
00082 // Faster than testing IS_HIGH_SURROGATE || IS_LOW_SURROGATE
00083 #define IS_SURROGATE(u)      ((PRUnichar(u) & 0xF800) == 0xD800)
00084 
00085 // Everything else is not a surrogate: 0x000 -- 0xD7FF, 0xE000 -- 0xFFFF
00086 
00087 // N = (H - 0xD800) * 0x400 + 0x10000 + (L - 0xDC00)
00088 // I wonder whether we could somehow assert that H is a high surrogate
00089 // and L is a low surrogate
00090 #define SURROGATE_TO_UCS4(h, l) (((PRUint32(h) & 0x03FF) << 10) + \
00091                                  (PRUint32(l) & 0x03FF) + PLANE1_BASE)
00092 
00093 // Extract surrogates from a UCS4 char
00094 // See unicode specification 3.7 for following math.
00095 #define H_SURROGATE(c) PRUnichar(PRUnichar((PRUint32(c) - PLANE1_BASE) >> 10) | \
00096                                  PRUnichar(0xD800))
00097 #define L_SURROGATE(c) PRUnichar(PRUnichar((PRUint32(c) - PLANE1_BASE) & 0x03FF) | \
00098                                  PRUnichar(0xDC00))
00099 
00100 #define IS_IN_BMP(ucs) (PRUint32(ucs) < PLANE1_BASE)
00101 #define UCS2_REPLACEMENT_CHAR PRUnichar(0xFFFD)
00102 
00103 #define UCS_END PRUint32(0x00110000)
00104 #define IS_VALID_CHAR(c) ((PRUint32(c) < UCS_END) && !IS_SURROGATE(c))
00105 #define ENSURE_VALID_CHAR(c) (IS_VALID_CHAR(c) ? (c) : UCS2_REPLACEMENT_CHAR)
00106 
00107 template <class CharT> struct nsCharTraits {};
00108 
00109 NS_SPECIALIZE_TEMPLATE
00110 struct nsCharTraits<PRUnichar>
00111   {
00112     typedef PRUnichar char_type;
00113     typedef PRUint16  unsigned_char_type;
00114     typedef char      incompatible_char_type;
00115 
00116     NS_COM static const char_type *sEmptyBuffer;
00117 
00118     static
00119     void
00120     assign( char_type& lhs, char_type rhs )
00121       {
00122         lhs = rhs;
00123       }
00124 
00125 
00126       // integer representation of characters:
00127 
00128 #ifdef USE_CPP_WCHAR_FUNCS
00129     typedef wint_t int_type;
00130 #else
00131     typedef int int_type;
00132 #endif
00133 
00134     static
00135     char_type
00136     to_char_type( int_type c )
00137       {
00138         return char_type(c);
00139       }
00140 
00141     static
00142     int_type
00143     to_int_type( char_type c )
00144       {
00145         return int_type( NS_STATIC_CAST(unsigned_char_type, c) );
00146       }
00147 
00148     static
00149     nsCharTraits_bool
00150     eq_int_type( int_type lhs, int_type rhs )
00151       {
00152         return lhs == rhs;
00153       }
00154 
00155 
00156       // |char_type| comparisons:
00157 
00158     static
00159     nsCharTraits_bool
00160     eq( char_type lhs, char_type rhs )
00161       {
00162         return lhs == rhs;
00163       }
00164 
00165     static
00166     nsCharTraits_bool
00167     lt( char_type lhs, char_type rhs )
00168       {
00169         return lhs < rhs;
00170       }
00171 
00172 
00173       // operations on s[n] arrays:
00174 
00175     static
00176     char_type*
00177     move( char_type* s1, const char_type* s2, size_t n )
00178       {
00179         return NS_STATIC_CAST(char_type*, memmove(s1, s2, n * sizeof(char_type)));
00180       }
00181 
00182     static
00183     char_type*
00184     copy( char_type* s1, const char_type* s2, size_t n )
00185       {
00186         return NS_STATIC_CAST(char_type*, memcpy(s1, s2, n * sizeof(char_type)));
00187       }
00188 
00189     static
00190     char_type*
00191     copyASCII( char_type* s1, const char* s2, size_t n )
00192       {
00193         for (char_type* s = s1; n--; ++s, ++s2) {
00194           NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character");
00195           *s = *s2;
00196         }
00197         return s1;
00198       }
00199 
00200     static
00201     char_type*
00202     assign( char_type* s, size_t n, char_type c )
00203       {
00204 #ifdef USE_CPP_WCHAR_FUNCS
00205         return NS_STATIC_CAST(char_type*, wmemset(s, to_int_type(c), n));
00206 #else
00207         char_type* result = s;
00208         while ( n-- )
00209           assign(*s++, c);
00210         return result;
00211 #endif
00212       }
00213 
00214     static
00215     int
00216     compare( const char_type* s1, const char_type* s2, size_t n )
00217       {
00218 #ifdef USE_CPP_WCHAR_FUNCS
00219         return wmemcmp(s1, s2, n);
00220 #else
00221         for ( ; n--; ++s1, ++s2 )
00222           {
00223             if ( !eq(*s1, *s2) )
00224               return to_int_type(*s1) - to_int_type(*s2);
00225           }
00226 
00227         return 0;
00228 #endif
00229       }
00230 
00231     static
00232     int
00233     compareASCII( const char_type* s1, const char* s2, size_t n )
00234       {
00235         for ( ; n--; ++s1, ++s2 )
00236           {
00237             NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character");
00238             if ( !eq_int_type(to_int_type(*s1), to_int_type(*s2)) )
00239               return to_int_type(*s1) - to_int_type(*s2);
00240           }
00241 
00242         return 0;
00243       }
00244 
00245     // this version assumes that s2 is null-terminated and s1 has length n.
00246     // if s1 is shorter than s2 then we return -1; if s1 is longer than s2,
00247     // we return 1.
00248     static
00249     int
00250     compareASCIINullTerminated( const char_type* s1, size_t n, const char* s2 )
00251       {
00252         for ( ; n--; ++s1, ++s2 )
00253           {
00254             if ( !*s2 )
00255               return 1;
00256             NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character");
00257             if ( !eq_int_type(to_int_type(*s1), to_int_type(*s2)) )
00258               return to_int_type(*s1) - to_int_type(*s2);
00259           }
00260 
00261         if ( *s2 )
00262           return -1;
00263 
00264         return 0;
00265       }
00266 
00275     static
00276     char_type
00277     ASCIIToLower( char_type c )
00278       {
00279         if (c < 0x100)
00280           return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
00281         else
00282           {
00283             if (c == 0x212A) // KELVIN SIGN
00284               return 'k';
00285             if (c == 0x0130) // LATIN CAPITAL LETTER I WITH DOT ABOVE
00286               return 'i';
00287             return c;
00288           }
00289       }
00290 
00291     static
00292     int
00293     compareLowerCaseToASCII( const char_type* s1, const char* s2, size_t n )
00294       {
00295         for ( ; n--; ++s1, ++s2 )
00296           {
00297             NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character");
00298             NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'),
00299                          "Unexpected uppercase character");
00300             char_type lower_s1 = ASCIIToLower(*s1);
00301             if ( lower_s1 != to_char_type(*s2) )
00302               return to_int_type(lower_s1) - to_int_type(*s2);
00303           }
00304 
00305         return 0;
00306       }
00307 
00308     // this version assumes that s2 is null-terminated and s1 has length n.
00309     // if s1 is shorter than s2 then we return -1; if s1 is longer than s2,
00310     // we return 1.
00311     static
00312     int
00313     compareLowerCaseToASCIINullTerminated( const char_type* s1, size_t n, const char* s2 )
00314       {
00315         for ( ; n--; ++s1, ++s2 )
00316           {
00317             if ( !*s2 )
00318               return 1;
00319             NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character");
00320             NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'),
00321                          "Unexpected uppercase character");
00322             char_type lower_s1 = ASCIIToLower(*s1);
00323             if ( lower_s1 != to_char_type(*s2) )
00324               return to_int_type(lower_s1) - to_int_type(*s2);
00325           }
00326 
00327         if ( *s2 )
00328           return -1;
00329 
00330         return 0;
00331       }
00332 
00333     static
00334     size_t
00335     length( const char_type* s )
00336       {
00337 #ifdef USE_CPP_WCHAR_FUNCS
00338         return wcslen(s);
00339 #else
00340         size_t result = 0;
00341         while ( !eq(*s++, char_type(0)) )
00342           ++result;
00343         return result;
00344 #endif
00345       }
00346 
00347     static
00348     const char_type*
00349     find( const char_type* s, size_t n, char_type c )
00350       {
00351 #ifdef USE_CPP_WCHAR_FUNCS
00352         return NS_REINTERPRET_CAST(const char_type*, wmemchr(s, to_int_type(c), n));
00353 #else
00354         while ( n-- )
00355           {
00356             if ( eq(*s, c) )
00357               return s;
00358             ++s;
00359           }
00360 
00361         return 0;
00362 #endif
00363       }
00364 
00365 #if 0
00366       // I/O related:
00367 
00368     typedef streamoff off_type;
00369     typedef streampos pos_type;
00370     typedef mbstate_t state_type;
00371 
00372     static
00373     int_type
00374     eof()
00375       {
00376 #ifdef USE_CPP_WCHAR_FUNCS
00377         return WEOF;
00378 #else
00379         return EOF;
00380 #endif
00381       }
00382 
00383     static
00384     int_type
00385     not_eof( int_type c )
00386       {
00387         return eq_int_type(c, eof()) ? ~eof() : c;
00388       }
00389 
00390     // static state_type get_state( pos_type );
00391 #endif
00392   };
00393 
00394 NS_SPECIALIZE_TEMPLATE
00395 struct nsCharTraits<char>
00396   {
00397     typedef char           char_type;
00398     typedef unsigned char  unsigned_char_type;
00399     typedef PRUnichar      incompatible_char_type;
00400 
00401     NS_COM static const char_type *sEmptyBuffer;
00402 
00403     static
00404     void
00405     assign( char_type& lhs, char_type rhs )
00406       {
00407         lhs = rhs;
00408       }
00409 
00410 
00411       // integer representation of characters:
00412 
00413     typedef int int_type;
00414 
00415     static
00416     char_type
00417     to_char_type( int_type c )
00418       {
00419         return char_type(c);
00420       }
00421 
00422     static
00423     int_type
00424     to_int_type( char_type c )
00425       {
00426         return int_type( NS_STATIC_CAST(unsigned_char_type, c) );
00427       }
00428 
00429     static
00430     nsCharTraits_bool
00431     eq_int_type( int_type lhs, int_type rhs )
00432       {
00433         return lhs == rhs;
00434       }
00435 
00436 
00437       // |char_type| comparisons:
00438 
00439     static
00440     nsCharTraits_bool
00441     eq( char_type lhs, char_type rhs )
00442       {
00443         return lhs == rhs;
00444       }
00445 
00446     static
00447     nsCharTraits_bool
00448     lt( char_type lhs, char_type rhs )
00449       {
00450         return lhs < rhs;
00451       }
00452 
00453 
00454       // operations on s[n] arrays:
00455 
00456     static
00457     char_type*
00458     move( char_type* s1, const char_type* s2, size_t n )
00459       {
00460         return NS_STATIC_CAST(char_type*, memmove(s1, s2, n * sizeof(char_type)));
00461       }
00462 
00463     static
00464     char_type*
00465     copy( char_type* s1, const char_type* s2, size_t n )
00466       {
00467         return NS_STATIC_CAST(char_type*, memcpy(s1, s2, n * sizeof(char_type)));
00468       }
00469 
00470     static
00471     char_type*
00472     copyASCII( char_type* s1, const char* s2, size_t n )
00473       {
00474         return copy(s1, s2, n);
00475       }
00476 
00477     static
00478     char_type*
00479     assign( char_type* s, size_t n, char_type c )
00480       {
00481         return NS_STATIC_CAST(char_type*, memset(s, to_int_type(c), n));
00482       }
00483 
00484     static
00485     int
00486     compare( const char_type* s1, const char_type* s2, size_t n )
00487       {
00488         return memcmp(s1, s2, n);
00489       }
00490 
00491     static
00492     int
00493     compareASCII( const char_type* s1, const char* s2, size_t n )
00494       {
00495 #ifdef DEBUG
00496         for (size_t i = 0; i < n; ++i)
00497           {
00498             NS_ASSERTION(!(s2[i] & ~0x7F), "Unexpected non-ASCII character");
00499           }
00500 #endif
00501         return compare(s1, s2, n);
00502       }
00503 
00504     // this version assumes that s2 is null-terminated and s1 has length n.
00505     // if s1 is shorter than s2 then we return -1; if s1 is longer than s2,
00506     // we return 1.
00507     static
00508     int
00509     compareASCIINullTerminated( const char_type* s1, size_t n, const char* s2 )
00510       {
00511         // can't use strcmp here because we don't want to stop when s1
00512         // contains a null
00513         for ( ; n--; ++s1, ++s2 )
00514           {
00515             if ( !*s2 )
00516               return 1;
00517             NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character");
00518             if ( *s1 != *s2 )
00519               return to_int_type(*s1) - to_int_type(*s2);
00520           }
00521 
00522         if ( *s2 )
00523           return -1;
00524 
00525         return 0;
00526       }
00527 
00531     static
00532     char_type
00533     ASCIIToLower( char_type c )
00534       {
00535         return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
00536       }
00537 
00538     static
00539     int
00540     compareLowerCaseToASCII( const char_type* s1, const char* s2, size_t n )
00541       {
00542         for ( ; n--; ++s1, ++s2 )
00543           {
00544             NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character");
00545             NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'),
00546                          "Unexpected uppercase character");
00547             char_type lower_s1 = ASCIIToLower(*s1);
00548             if ( lower_s1 != *s2 )
00549               return to_int_type(lower_s1) - to_int_type(*s2);
00550           }
00551         return 0;
00552       }
00553 
00554     // this version assumes that s2 is null-terminated and s1 has length n.
00555     // if s1 is shorter than s2 then we return -1; if s1 is longer than s2,
00556     // we return 1.
00557     static
00558     int
00559     compareLowerCaseToASCIINullTerminated( const char_type* s1, size_t n, const char* s2 )
00560       {
00561         for ( ; n--; ++s1, ++s2 )
00562           {
00563             if ( !*s2 )
00564               return 1;
00565             NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character");
00566             NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'),
00567                          "Unexpected uppercase character");
00568             char_type lower_s1 = ASCIIToLower(*s1);
00569             if ( lower_s1 != *s2 )
00570               return to_int_type(lower_s1) - to_int_type(*s2);
00571           }
00572 
00573         if ( *s2 )
00574           return -1;
00575 
00576         return 0;
00577       }
00578 
00579     static
00580     size_t
00581     length( const char_type* s )
00582       {
00583         return strlen(s);
00584       }
00585 
00586     static
00587     const char_type*
00588     find( const char_type* s, size_t n, char_type c )
00589       {
00590         return NS_REINTERPRET_CAST(const char_type*, memchr(s, to_int_type(c), n));
00591       }
00592 
00593 #if 0
00594       // I/O related:
00595 
00596     typedef streamoff off_type;
00597     typedef streampos pos_type;
00598     typedef mbstate_t state_type;
00599 
00600     static
00601     int_type
00602     eof()
00603       {
00604         return EOF;
00605       }
00606 
00607     static
00608     int_type
00609     not_eof( int_type c )
00610       {
00611         return eq_int_type(c, eof()) ? ~eof() : c;
00612       }
00613 
00614     // static state_type get_state( pos_type );
00615 #endif
00616   };
00617 
00618 template <class InputIterator>
00619 struct nsCharSourceTraits
00620   {
00621     typedef typename InputIterator::difference_type difference_type;
00622 
00623     static
00624     PRUint32
00625     readable_distance( const InputIterator& first, const InputIterator& last )
00626       {
00627         // assumes single fragment
00628         return last.get() - first.get();
00629       }
00630 
00631     static
00632     const typename InputIterator::value_type*
00633     read( const InputIterator& iter )
00634       {
00635         return iter.get();
00636       }
00637 
00638     static
00639     void
00640     advance( InputIterator& s, difference_type n )
00641       {
00642         s.advance(n);
00643       }
00644   };
00645 
00646 #ifdef HAVE_CPP_PARTIAL_SPECIALIZATION
00647 
00648 template <class CharT>
00649 struct nsCharSourceTraits<CharT*>
00650   {
00651     typedef ptrdiff_t difference_type;
00652 
00653     static
00654     PRUint32
00655     readable_distance( CharT* s )
00656       {
00657         return PRUint32(nsCharTraits<CharT>::length(s));
00658 //      return numeric_limits<PRUint32>::max();
00659       }
00660 
00661     static
00662     PRUint32
00663     readable_distance( CharT* first, CharT* last )
00664       {
00665         return PRUint32(last-first);
00666       }
00667 
00668     static
00669     const CharT*
00670     read( CharT* s )
00671       {
00672         return s;
00673       }
00674 
00675     static
00676     void
00677     advance( CharT*& s, difference_type n )
00678       {
00679         s += n;
00680       }
00681   };
00682 
00683 #else
00684 
00685 NS_SPECIALIZE_TEMPLATE
00686 struct nsCharSourceTraits<const char*>
00687   {
00688     typedef ptrdiff_t difference_type;
00689 
00690     static
00691     PRUint32
00692     readable_distance( const char* s )
00693       {
00694         return PRUint32(nsCharTraits<char>::length(s));
00695 //      return numeric_limits<PRUint32>::max();
00696       }
00697 
00698     static
00699     PRUint32
00700     readable_distance( const char* first, const char* last )
00701       {
00702         return PRUint32(last-first);
00703       }
00704 
00705     static
00706     const char*
00707     read( const char* s )
00708       {
00709         return s;
00710       }
00711 
00712     static
00713     void
00714     advance( const char*& s, difference_type n )
00715       {
00716         s += n;
00717       }
00718  };
00719 
00720 
00721 NS_SPECIALIZE_TEMPLATE
00722 struct nsCharSourceTraits<const PRUnichar*>
00723   {
00724     typedef ptrdiff_t difference_type;
00725 
00726     static
00727     PRUint32
00728     readable_distance( const PRUnichar* s )
00729       {
00730         return PRUint32(nsCharTraits<PRUnichar>::length(s));
00731 //      return numeric_limits<PRUint32>::max();
00732       }
00733 
00734     static
00735     PRUint32
00736     readable_distance( const PRUnichar* first, const PRUnichar* last )
00737       {
00738         return PRUint32(last-first);
00739       }
00740 
00741     static
00742     const PRUnichar*
00743     read( const PRUnichar* s )
00744       {
00745         return s;
00746       }
00747 
00748     static
00749     void
00750     advance( const PRUnichar*& s, difference_type n )
00751       {
00752         s += n;
00753       }
00754  };
00755 
00756 #endif
00757 
00758 
00759 template <class OutputIterator>
00760 struct nsCharSinkTraits
00761   {
00762     static
00763     PRUint32
00764     write( OutputIterator& iter, const typename OutputIterator::value_type* s, PRUint32 n )
00765       {
00766         return iter.write(s, n);
00767       }
00768   };
00769 
00770 #ifdef HAVE_CPP_PARTIAL_SPECIALIZATION
00771 
00772 template <class CharT>
00773 struct nsCharSinkTraits<CharT*>
00774   {
00775     static
00776     PRUint32
00777     write( CharT*& iter, const CharT* s, PRUint32 n )
00778       {
00779         nsCharTraits<CharT>::move(iter, s, n);
00780         iter += n;
00781         return n;
00782       }
00783   };
00784 
00785 #else
00786 
00787 NS_SPECIALIZE_TEMPLATE
00788 struct nsCharSinkTraits<char*>
00789   {
00790     static
00791     PRUint32
00792     write( char*& iter, const char* s, PRUint32 n )
00793       {
00794         nsCharTraits<char>::move(iter, s, n);
00795         iter += n;
00796         return n;
00797       }
00798   };
00799 
00800 NS_SPECIALIZE_TEMPLATE
00801 struct nsCharSinkTraits<PRUnichar*>
00802   {
00803     static
00804     PRUint32
00805     write( PRUnichar*& iter, const PRUnichar* s, PRUint32 n )
00806       {
00807         nsCharTraits<PRUnichar>::move(iter, s, n);
00808         iter += n;
00809         return n;
00810       }
00811   };
00812 
00813 #endif
00814 
00815 #endif // !defined(nsCharTraits_h___)