diff options
author | Mike Buland <eichlan@xagasoft.com> | 2019-05-13 19:47:19 -0700 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2019-05-13 19:47:19 -0700 |
commit | d605d6c3c04c1e26121f9b1c5c1d2dbcc5f7bc37 (patch) | |
tree | 0cd21d420fc67ae757ec2475610c4624fd714363 | |
parent | 62753c815b5ec34ebfae37a3c89187a01cc17160 (diff) | |
download | libbu++-d605d6c3c04c1e26121f9b1c5c1d2dbcc5f7bc37.tar.gz libbu++-d605d6c3c04c1e26121f9b1c5c1d2dbcc5f7bc37.tar.bz2 libbu++-d605d6c3c04c1e26121f9b1c5c1d2dbcc5f7bc37.tar.xz libbu++-d605d6c3c04c1e26121f9b1c5c1d2dbcc5f7bc37.zip |
UtfString & Json overhaul.
UtfString supports a load of new stuff, and Json uses UtfString
exclusively now.
-rw-r--r-- | src/tools/jsontool.cpp | 4 | ||||
-rw-r--r-- | src/unstable/json.cpp | 95 | ||||
-rw-r--r-- | src/unstable/json.h | 67 | ||||
-rw-r--r-- | src/unstable/utfstring.cpp | 255 | ||||
-rw-r--r-- | src/unstable/utfstring.h | 23 |
5 files changed, 343 insertions, 101 deletions
diff --git a/src/tools/jsontool.cpp b/src/tools/jsontool.cpp index 4b6f232..e086fb8 100644 --- a/src/tools/jsontool.cpp +++ b/src/tools/jsontool.cpp | |||
@@ -16,8 +16,8 @@ void printThing( Bu::Json &j, int iDepth=0 ) | |||
16 | case Bu::Json::Object: | 16 | case Bu::Json::Object: |
17 | Bu::println("<object>"); | 17 | Bu::println("<object>"); |
18 | { | 18 | { |
19 | Bu::StringList lKeys = j.getKeys(); | 19 | Bu::UtfStringList lKeys = j.getKeys(); |
20 | for( Bu::StringList::iterator i = lKeys.begin(); i; i++ ) | 20 | for( Bu::UtfStringList::iterator i = lKeys.begin(); i; i++ ) |
21 | { | 21 | { |
22 | for(int k = 0; k < iDepth+1; k++ ) | 22 | for(int k = 0; k < iDepth+1; k++ ) |
23 | Bu::print(" "); | 23 | Bu::print(" "); |
diff --git a/src/unstable/json.cpp b/src/unstable/json.cpp index d7e84d9..b1414a9 100644 --- a/src/unstable/json.cpp +++ b/src/unstable/json.cpp | |||
@@ -15,7 +15,7 @@ Bu::Json::Json() : | |||
15 | 15 | ||
16 | Bu::Json::Json( const Bu::UtfString &sValue ) : | 16 | Bu::Json::Json( const Bu::UtfString &sValue ) : |
17 | eType( String ), | 17 | eType( String ), |
18 | uDat( sValue.get() ) | 18 | uDat( sValue ) |
19 | { | 19 | { |
20 | } | 20 | } |
21 | 21 | ||
@@ -57,7 +57,7 @@ Bu::Json::Json( Type eType ) : | |||
57 | break; | 57 | break; |
58 | 58 | ||
59 | case String: | 59 | case String: |
60 | uDat.pString = new Bu::String(); | 60 | uDat.pString = new Bu::UtfString(); |
61 | break; | 61 | break; |
62 | 62 | ||
63 | case Number: | 63 | case Number: |
@@ -75,7 +75,7 @@ Bu::Json::Json( Bu::Stream &sInput ) : | |||
75 | parse( sInput ); | 75 | parse( sInput ); |
76 | } | 76 | } |
77 | 77 | ||
78 | Bu::Json::Json( char &c, Bu::Stream &sInput ) : | 78 | Bu::Json::Json( Bu::UtfChar &c, Bu::Stream &sInput ) : |
79 | eType( Invalid ) | 79 | eType( Invalid ) |
80 | { | 80 | { |
81 | parse( c, sInput ); | 81 | parse( c, sInput ); |
@@ -97,7 +97,7 @@ Bu::Json::Type Bu::Json::getType() const | |||
97 | return eType; | 97 | return eType; |
98 | } | 98 | } |
99 | 99 | ||
100 | Bu::String Bu::Json::getString() const | 100 | Bu::UtfString Bu::Json::getString() const |
101 | { | 101 | { |
102 | if( eType != String ) | 102 | if( eType != String ) |
103 | throw Bu::ExceptionBase( | 103 | throw Bu::ExceptionBase( |
@@ -132,7 +132,7 @@ bool Bu::Json::isNull() const | |||
132 | return eType == Null; | 132 | return eType == Null; |
133 | } | 133 | } |
134 | 134 | ||
135 | Bu::Json &Bu::Json::operator[]( const Bu::String &sKey ) const | 135 | Bu::Json &Bu::Json::operator[]( const Bu::UtfString &sKey ) const |
136 | { | 136 | { |
137 | if( eType != Object ) | 137 | if( eType != Object ) |
138 | throw Bu::ExceptionBase( | 138 | throw Bu::ExceptionBase( |
@@ -158,15 +158,13 @@ int Bu::Json::getSize() const | |||
158 | return uDat.pObject->getSize(); | 158 | return uDat.pObject->getSize(); |
159 | else if( eType == Array ) | 159 | else if( eType == Array ) |
160 | return uDat.pArray->getSize(); | 160 | return uDat.pArray->getSize(); |
161 | else if( eType == String ) | ||
162 | return uDat.pString->getSize(); | ||
163 | else | 161 | else |
164 | throw Bu::ExceptionBase( | 162 | throw Bu::ExceptionBase( |
165 | "Size requseted from json type that doesn't support it." | 163 | "Size requseted from json type that doesn't support it." |
166 | ); | 164 | ); |
167 | } | 165 | } |
168 | 166 | ||
169 | Bu::StringList Bu::Json::getKeys() const | 167 | Bu::UtfStringList Bu::Json::getKeys() const |
170 | { | 168 | { |
171 | return uDat.pObject->getKeys(); | 169 | return uDat.pObject->getKeys(); |
172 | } | 170 | } |
@@ -196,33 +194,40 @@ bool Bu::Json::has( const Bu::String &sKey ) const | |||
196 | return uDat.pObject->has( sKey ); | 194 | return uDat.pObject->has( sKey ); |
197 | } | 195 | } |
198 | 196 | ||
199 | void Bu::Json::insert( const Bu::String &sKey, Bu::Json *pObj ) | 197 | Bu::Json &Bu::Json::insert( const Bu::String &sKey, Bu::Json *pObj ) |
200 | { | 198 | { |
201 | uDat.pObject->insert( sKey, pObj ); | 199 | uDat.pObject->insert( sKey, pObj ); |
200 | return *this; | ||
202 | } | 201 | } |
203 | void Bu::Json::insert( const Bu::String &sKey, const Bu::Json &rObj ) | 202 | |
203 | Bu::Json &Bu::Json::insert( const Bu::String &sKey, const Bu::Json &rObj ) | ||
204 | { | 204 | { |
205 | uDat.pObject->insert( sKey, new Bu::Json( rObj ) ); | 205 | uDat.pObject->insert( sKey, new Bu::Json( rObj ) ); |
206 | return *this; | ||
206 | } | 207 | } |
207 | 208 | ||
208 | void Bu::Json::insert( const Bu::String &sKey, const Bu::String &sValue ) | 209 | Bu::Json &Bu::Json::insert( const Bu::String &sKey, const Bu::String &sValue ) |
209 | { | 210 | { |
210 | uDat.pObject->insert( sKey, new Json( sValue ) ); | 211 | uDat.pObject->insert( sKey, new Json( sValue ) ); |
212 | return *this; | ||
211 | } | 213 | } |
212 | 214 | ||
213 | void Bu::Json::insert( const Bu::String &sKey, const char *sValue ) | 215 | Bu::Json &Bu::Json::insert( const Bu::String &sKey, const char *sValue ) |
214 | { | 216 | { |
215 | uDat.pObject->insert( sKey, new Json( sValue ) ); | 217 | uDat.pObject->insert( sKey, new Json( sValue ) ); |
218 | return *this; | ||
216 | } | 219 | } |
217 | 220 | ||
218 | void Bu::Json::insert( const Bu::String &sKey, double dValue ) | 221 | Bu::Json &Bu::Json::insert( const Bu::String &sKey, double dValue ) |
219 | { | 222 | { |
220 | uDat.pObject->insert( sKey, new Json( dValue ) ); | 223 | uDat.pObject->insert( sKey, new Json( dValue ) ); |
224 | return *this; | ||
221 | } | 225 | } |
222 | 226 | ||
223 | void Bu::Json::insert( const Bu::String &sKey, bool bValue ) | 227 | Bu::Json &Bu::Json::insert( const Bu::String &sKey, bool bValue ) |
224 | { | 228 | { |
225 | uDat.pObject->insert( sKey, new Json( bValue ) ); | 229 | uDat.pObject->insert( sKey, new Json( bValue ) ); |
230 | return *this; | ||
226 | } | 231 | } |
227 | 232 | ||
228 | Bu::Json &Bu::Json::insertObject( const Bu::String &sKey ) | 233 | Bu::Json &Bu::Json::insertObject( const Bu::String &sKey ) |
@@ -239,29 +244,34 @@ Bu::Json &Bu::Json::insertArray( const Bu::String &sKey ) | |||
239 | return *pAr; | 244 | return *pAr; |
240 | } | 245 | } |
241 | 246 | ||
242 | void Bu::Json::append( Bu::Json *pObj ) | 247 | Bu::Json &Bu::Json::append( Bu::Json *pObj ) |
243 | { | 248 | { |
244 | uDat.pArray->append( pObj ); | 249 | uDat.pArray->append( pObj ); |
250 | return *this; | ||
245 | } | 251 | } |
246 | 252 | ||
247 | void Bu::Json::append( const Bu::String &sValue ) | 253 | Bu::Json &Bu::Json::append( const Bu::String &sValue ) |
248 | { | 254 | { |
249 | uDat.pArray->append( new Json( sValue ) ); | 255 | uDat.pArray->append( new Json( sValue ) ); |
256 | return *this; | ||
250 | } | 257 | } |
251 | 258 | ||
252 | void Bu::Json::append( const char *sValue ) | 259 | Bu::Json &Bu::Json::append( const char *sValue ) |
253 | { | 260 | { |
254 | uDat.pArray->append( new Json( sValue ) ); | 261 | uDat.pArray->append( new Json( sValue ) ); |
262 | return *this; | ||
255 | } | 263 | } |
256 | 264 | ||
257 | void Bu::Json::append( double dValue ) | 265 | Bu::Json &Bu::Json::append( double dValue ) |
258 | { | 266 | { |
259 | uDat.pArray->append( new Json( dValue ) ); | 267 | uDat.pArray->append( new Json( dValue ) ); |
268 | return *this; | ||
260 | } | 269 | } |
261 | 270 | ||
262 | void Bu::Json::append( bool bValue ) | 271 | Bu::Json &Bu::Json::append( bool bValue ) |
263 | { | 272 | { |
264 | uDat.pArray->append( new Json( bValue ) ); | 273 | uDat.pArray->append( new Json( bValue ) ); |
274 | return *this; | ||
265 | } | 275 | } |
266 | 276 | ||
267 | Bu::Json &Bu::Json::appendObject() | 277 | Bu::Json &Bu::Json::appendObject() |
@@ -282,7 +292,7 @@ void Bu::Json::parse( Bu::Stream &sInput ) | |||
282 | { | 292 | { |
283 | reset(); | 293 | reset(); |
284 | 294 | ||
285 | char c; | 295 | Bu::UtfChar c; |
286 | next("json"); | 296 | next("json"); |
287 | 297 | ||
288 | parse( c, sInput ); | 298 | parse( c, sInput ); |
@@ -294,7 +304,7 @@ void Bu::Json::parse( const Bu::String &sInput ) | |||
294 | parse( mb ); | 304 | parse( mb ); |
295 | } | 305 | } |
296 | 306 | ||
297 | void Bu::Json::parse( char &c, Bu::Stream &sInput ) | 307 | void Bu::Json::parse( Bu::UtfChar &c, Bu::Stream &sInput ) |
298 | { | 308 | { |
299 | while( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) | 309 | while( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) |
300 | { | 310 | { |
@@ -434,9 +444,9 @@ void Bu::Json::writeStable( Bu::Stream &sOutput ) const | |||
434 | { | 444 | { |
435 | sOutput.write("{", 1 ); | 445 | sOutput.write("{", 1 ); |
436 | bool bFirst = true; | 446 | bool bFirst = true; |
437 | Bu::List<Bu::String> lKey = uDat.pObject->getKeys(); | 447 | Bu::List<Bu::UtfString> lKey = uDat.pObject->getKeys(); |
438 | lKey.sort(); | 448 | lKey.sort(); |
439 | for( Bu::List<Bu::String>::iterator i = lKey.begin(); i; i++ ) | 449 | for( Bu::List<Bu::UtfString>::iterator i = lKey.begin(); i; i++ ) |
440 | { | 450 | { |
441 | if( bFirst == true ) | 451 | if( bFirst == true ) |
442 | bFirst = false; | 452 | bFirst = false; |
@@ -480,7 +490,7 @@ Bu::Json &Bu::Json::operator=( const Bu::Json &rSrc ) | |||
480 | break; | 490 | break; |
481 | 491 | ||
482 | case String: | 492 | case String: |
483 | uDat.pString = new Bu::String( *rSrc.uDat.pString ); | 493 | uDat.pString = new Bu::UtfString( *rSrc.uDat.pString ); |
484 | break; | 494 | break; |
485 | 495 | ||
486 | case Number: | 496 | case Number: |
@@ -513,7 +523,8 @@ Bu::Json &Bu::Json::operator=( const Bu::Json &rSrc ) | |||
513 | return *this; | 523 | return *this; |
514 | } | 524 | } |
515 | 525 | ||
516 | void Bu::Json::parseString( char &c, Bu::Stream &sInput, Bu::String &sOut ) | 526 | void Bu::Json::parseString( Bu::UtfChar &c, Bu::Stream &sInput, |
527 | Bu::UtfString &sOut ) | ||
517 | { | 528 | { |
518 | skipWs( c, sInput ); | 529 | skipWs( c, sInput ); |
519 | bool bEscape = false; | 530 | bool bEscape = false; |
@@ -577,14 +588,14 @@ void Bu::Json::parseString( char &c, Bu::Stream &sInput, Bu::String &sOut ) | |||
577 | } | 588 | } |
578 | } | 589 | } |
579 | 590 | ||
580 | void Bu::Json::parseString( char &c, Bu::Stream &sInput ) | 591 | void Bu::Json::parseString( Bu::UtfChar &c, Bu::Stream &sInput ) |
581 | { | 592 | { |
582 | eType = String; | 593 | eType = String; |
583 | uDat.pString = new Bu::String(); | 594 | uDat.pString = new Bu::UtfString(); |
584 | parseString( c, sInput, *uDat.pString ); | 595 | parseString( c, sInput, *uDat.pString ); |
585 | } | 596 | } |
586 | 597 | ||
587 | void Bu::Json::parseObject( char &c, Bu::Stream &sInput ) | 598 | void Bu::Json::parseObject( Bu::UtfChar &c, Bu::Stream &sInput ) |
588 | { | 599 | { |
589 | skipWs( c, sInput ); | 600 | skipWs( c, sInput ); |
590 | eType = Object; | 601 | eType = Object; |
@@ -602,7 +613,7 @@ void Bu::Json::parseObject( char &c, Bu::Stream &sInput ) | |||
602 | 613 | ||
603 | for(;;) | 614 | for(;;) |
604 | { | 615 | { |
605 | Bu::String sKey; | 616 | Bu::UtfString sKey; |
606 | parseString( c, sInput, sKey ); | 617 | parseString( c, sInput, sKey ); |
607 | skipWs( c, sInput ); | 618 | skipWs( c, sInput ); |
608 | if( c != ':' ) | 619 | if( c != ':' ) |
@@ -628,7 +639,7 @@ void Bu::Json::parseObject( char &c, Bu::Stream &sInput ) | |||
628 | } | 639 | } |
629 | } | 640 | } |
630 | 641 | ||
631 | void Bu::Json::parseArray( char &c, Bu::Stream &sInput ) | 642 | void Bu::Json::parseArray( Bu::UtfChar &c, Bu::Stream &sInput ) |
632 | { | 643 | { |
633 | skipWs( c, sInput ); | 644 | skipWs( c, sInput ); |
634 | 645 | ||
@@ -667,7 +678,7 @@ void Bu::Json::parseArray( char &c, Bu::Stream &sInput ) | |||
667 | } | 678 | } |
668 | } | 679 | } |
669 | 680 | ||
670 | void Bu::Json::parseNumber( char &c, Bu::Stream &sInput ) | 681 | void Bu::Json::parseNumber( Bu::UtfChar &c, Bu::Stream &sInput ) |
671 | { | 682 | { |
672 | skipWs( c, sInput ); | 683 | skipWs( c, sInput ); |
673 | 684 | ||
@@ -702,7 +713,7 @@ void Bu::Json::parseNumber( char &c, Bu::Stream &sInput ) | |||
702 | uDat.dNumber = atof( sBuf.getStr() ); | 713 | uDat.dNumber = atof( sBuf.getStr() ); |
703 | } | 714 | } |
704 | 715 | ||
705 | void Bu::Json::parseLiteral( char &c, Bu::Stream &sInput ) | 716 | void Bu::Json::parseLiteral( Bu::UtfChar &c, Bu::Stream &sInput ) |
706 | { | 717 | { |
707 | skipWs( c, sInput ); | 718 | skipWs( c, sInput ); |
708 | 719 | ||
@@ -736,27 +747,27 @@ void Bu::Json::parseLiteral( char &c, Bu::Stream &sInput ) | |||
736 | } | 747 | } |
737 | } | 748 | } |
738 | 749 | ||
739 | bool Bu::Json::readChar( char &c, Bu::Stream &sInput ) | 750 | bool Bu::Json::readChar( Bu::UtfChar &c, Bu::Stream &sInput ) |
740 | { | 751 | { |
741 | if( sInput.read( &c, 1 ) == 0 ) | 752 | if( Bu::UtfString::readPoint( sInput, c ) == 0 && sInput.isEos() ) |
742 | return false; | 753 | return false; |
743 | return true; | 754 | return true; |
744 | } | 755 | } |
745 | 756 | ||
746 | void Bu::Json::readChar( char &c, Bu::Stream &sInput, const char *sSection ) | 757 | void Bu::Json::readChar( Bu::UtfChar &c, Bu::Stream &sInput, const char *sSection ) |
747 | { | 758 | { |
748 | if( sInput.read( &c, 1 ) == 0 ) | 759 | if( Bu::UtfString::readPoint( sInput, c ) == 0 && sInput.isEos() ) |
749 | { | 760 | { |
750 | throw Bu::ExceptionBase( sSection ); | 761 | throw Bu::ExceptionBase( sSection ); |
751 | } | 762 | } |
752 | } | 763 | } |
753 | 764 | ||
754 | bool Bu::Json::isWs( char c ) | 765 | bool Bu::Json::isWs( Bu::UtfChar c ) |
755 | { | 766 | { |
756 | return c == ' ' || c == '\t' || c == '\r' || c == '\n'; | 767 | return c == ' ' || c == '\t' || c == '\r' || c == '\n'; |
757 | } | 768 | } |
758 | 769 | ||
759 | void Bu::Json::skipWs( char &c, Bu::Stream &sInput ) | 770 | void Bu::Json::skipWs( Bu::UtfChar &c, Bu::Stream &sInput ) |
760 | { | 771 | { |
761 | while( isWs( c ) ) | 772 | while( isWs( c ) ) |
762 | { | 773 | { |
@@ -764,10 +775,10 @@ void Bu::Json::skipWs( char &c, Bu::Stream &sInput ) | |||
764 | } | 775 | } |
765 | } | 776 | } |
766 | 777 | ||
767 | void Bu::Json::writeStr( const Bu::String &sStr, Bu::Stream &sOutput ) const | 778 | void Bu::Json::writeStr( const Bu::UtfString &sStr, Bu::Stream &sOutput ) const |
768 | { | 779 | { |
769 | sOutput.write("\"", 1 ); | 780 | sOutput.write("\"", 1 ); |
770 | for( Bu::String::const_iterator i = sStr.begin(); i; i++ ) | 781 | for( Bu::UtfString::const_iterator i = sStr.begin(); i; i++ ) |
771 | { | 782 | { |
772 | switch( *i ) | 783 | switch( *i ) |
773 | { | 784 | { |
@@ -807,12 +818,12 @@ void Bu::Json::writeStr( const Bu::String &sStr, Bu::Stream &sOutput ) const | |||
807 | if( *i < 32 ) | 818 | if( *i < 32 ) |
808 | sOutput.write( | 819 | sOutput.write( |
809 | Bu::String("\\u%1"). | 820 | Bu::String("\\u%1"). |
810 | arg( (int32_t)*i, Bu::Fmt::hex(4).fill('0') ). | 821 | arg( (uint32_t)*i, Bu::Fmt::hex(4).fill('0') ). |
811 | end().getStr(), | 822 | end().getStr(), |
812 | 6 | 823 | 6 |
813 | ); | 824 | ); |
814 | else | 825 | else |
815 | sOutput.write( &(*i), 1 ); | 826 | Bu::UtfString::writePoint( sOutput, *i ); |
816 | break; | 827 | break; |
817 | } | 828 | } |
818 | } | 829 | } |
diff --git a/src/unstable/json.h b/src/unstable/json.h index 4c85dd9..2ea62a2 100644 --- a/src/unstable/json.h +++ b/src/unstable/json.h | |||
@@ -10,12 +10,13 @@ | |||
10 | namespace Bu | 10 | namespace Bu |
11 | { | 11 | { |
12 | class Stream; | 12 | class Stream; |
13 | typedef Bu::List<Bu::UtfString> UtfStringList; | ||
13 | 14 | ||
14 | class Json | 15 | class Json |
15 | { | 16 | { |
16 | private: | 17 | private: |
17 | Json( char &c, Bu::Stream &sInput ); | 18 | Json( Bu::UtfChar &c, Bu::Stream &sInput ); |
18 | typedef Bu::Hash<Bu::String, Json *> JsonHash; | 19 | typedef Bu::Hash<Bu::UtfString, Json *> JsonHash; |
19 | typedef Bu::Array<Json *> JsonList; | 20 | typedef Bu::Array<Json *> JsonList; |
20 | 21 | ||
21 | public: | 22 | public: |
@@ -45,33 +46,33 @@ namespace Bu | |||
45 | virtual ~Json(); | 46 | virtual ~Json(); |
46 | 47 | ||
47 | Type getType() const; | 48 | Type getType() const; |
48 | Bu::String getString() const; | 49 | Bu::UtfString getString() const; |
49 | double getNumber() const; | 50 | double getNumber() const; |
50 | bool getBoolean() const; | 51 | bool getBoolean() const; |
51 | bool isNull() const; | 52 | bool isNull() const; |
52 | Json &operator[]( const Bu::String &sKey ) const; | 53 | Json &operator[]( const Bu::UtfString &sKey ) const; |
53 | Json &operator[]( int iIndex ) const; | 54 | Json &operator[]( int iIndex ) const; |
54 | int getSize() const; | 55 | int getSize() const; |
55 | Bu::StringList getKeys() const; | 56 | Bu::UtfStringList getKeys() const; |
56 | iterator begin(); | 57 | iterator begin(); |
57 | const_iterator begin() const; | 58 | const_iterator begin() const; |
58 | iterator end(); | 59 | iterator end(); |
59 | const_iterator end() const; | 60 | const_iterator end() const; |
60 | 61 | ||
61 | bool has( const Bu::String &sKey ) const; | 62 | bool has( const Bu::String &sKey ) const; |
62 | void insert( const Bu::String &sKey, Bu::Json *pObj ); | 63 | Json &insert( const Bu::String &sKey, Bu::Json *pObj ); |
63 | void insert( const Bu::String &sKey, const Bu::Json &rObj ); | 64 | Json &insert( const Bu::String &sKey, const Bu::Json &rObj ); |
64 | void insert( const Bu::String &sKey, const Bu::String &sValue ); | 65 | Json &insert( const Bu::String &sKey, const Bu::String &sValue ); |
65 | void insert( const Bu::String &sKey, const char *sValue ); | 66 | Json &insert( const Bu::String &sKey, const char *sValue ); |
66 | void insert( const Bu::String &sKey, double dValue ); | 67 | Json &insert( const Bu::String &sKey, double dValue ); |
67 | void insert( const Bu::String &sKey, bool bValue ); | 68 | Json &insert( const Bu::String &sKey, bool bValue ); |
68 | Json &insertObject( const Bu::String &sKey ); | 69 | Json &insertObject( const Bu::String &sKey ); |
69 | Json &insertArray( const Bu::String &sKey ); | 70 | Json &insertArray( const Bu::String &sKey ); |
70 | void append( Bu::Json *pObj ); | 71 | Json &append( Bu::Json *pObj ); |
71 | void append( const Bu::String &sValue ); | 72 | Json &append( const Bu::String &sValue ); |
72 | void append( const char *sValue ); | 73 | Json &append( const char *sValue ); |
73 | void append( double dValue ); | 74 | Json &append( double dValue ); |
74 | void append( bool bValue ); | 75 | Json &append( bool bValue ); |
75 | Json &appendObject(); | 76 | Json &appendObject(); |
76 | Json &appendArray(); | 77 | Json &appendArray(); |
77 | 78 | ||
@@ -87,18 +88,20 @@ namespace Bu | |||
87 | Bu::Json &operator=( const Bu::Json &rSrc ); | 88 | Bu::Json &operator=( const Bu::Json &rSrc ); |
88 | 89 | ||
89 | private: | 90 | private: |
90 | void parse( char &c, Bu::Stream &sInput ); | 91 | void parse( Bu::UtfChar &c, Bu::Stream &sInput ); |
91 | void parseString( char &c, Bu::Stream &sInput, Bu::String &sOut ); | 92 | void parseString( Bu::UtfChar &c, Bu::Stream &sInput, |
92 | void parseString( char &c, Bu::Stream &sInput ); | 93 | Bu::UtfString &sOut ); |
93 | void parseObject( char &c, Bu::Stream &sInput ); | 94 | void parseString( Bu::UtfChar &c, Bu::Stream &sInput ); |
94 | void parseArray( char &c, Bu::Stream &sInput ); | 95 | void parseObject( Bu::UtfChar &c, Bu::Stream &sInput ); |
95 | void parseNumber( char &c, Bu::Stream &sInput ); | 96 | void parseArray( Bu::UtfChar &c, Bu::Stream &sInput ); |
96 | void parseLiteral( char &c, Bu::Stream &sInput ); | 97 | void parseNumber( Bu::UtfChar &c, Bu::Stream &sInput ); |
97 | bool readChar( char &c, Bu::Stream &sInput ); | 98 | void parseLiteral( Bu::UtfChar &c, Bu::Stream &sInput ); |
98 | void readChar( char &c, Bu::Stream &sInput, const char *sSection ); | 99 | bool readChar( Bu::UtfChar &c, Bu::Stream &sInput ); |
99 | bool isWs( char c ); | 100 | void readChar( Bu::UtfChar &c, Bu::Stream &sInput, |
100 | void skipWs( char &c, Bu::Stream &sInput ); | 101 | const char *sSection ); |
101 | void writeStr( const Bu::String &sStr, Bu::Stream &sOutput ) const; | 102 | bool isWs( Bu::UtfChar c ); |
103 | void skipWs( Bu::UtfChar &c, Bu::Stream &sInput ); | ||
104 | void writeStr( const Bu::UtfString &sStr, Bu::Stream &sOutput ) const; | ||
102 | 105 | ||
103 | private: | 106 | private: |
104 | Type eType; | 107 | Type eType; |
@@ -106,14 +109,16 @@ namespace Bu | |||
106 | { | 109 | { |
107 | DatUnion() : pObject( NULL ) { } | 110 | DatUnion() : pObject( NULL ) { } |
108 | DatUnion( const Bu::String &sValue ) : | 111 | DatUnion( const Bu::String &sValue ) : |
109 | pString( new Bu::String( sValue ) ) { } | 112 | pString( new Bu::UtfString( sValue ) ) { } |
113 | DatUnion( const Bu::UtfString &sValue ) : | ||
114 | pString( new Bu::UtfString( sValue ) ) { } | ||
110 | DatUnion( const char *sValue ) : | 115 | DatUnion( const char *sValue ) : |
111 | pString( new Bu::String( sValue ) ) { } | 116 | pString( new Bu::UtfString( sValue ) ) { } |
112 | DatUnion( double dValue ) : dNumber( dValue ) { } | 117 | DatUnion( double dValue ) : dNumber( dValue ) { } |
113 | DatUnion( bool bValue ) : bBoolean( bValue ) { } | 118 | DatUnion( bool bValue ) : bBoolean( bValue ) { } |
114 | JsonHash *pObject; | 119 | JsonHash *pObject; |
115 | JsonList *pArray; | 120 | JsonList *pArray; |
116 | Bu::String *pString; | 121 | Bu::UtfString *pString; |
117 | double dNumber; | 122 | double dNumber; |
118 | bool bBoolean; | 123 | bool bBoolean; |
119 | } uDat; | 124 | } uDat; |
diff --git a/src/unstable/utfstring.cpp b/src/unstable/utfstring.cpp index f945725..46c78e6 100644 --- a/src/unstable/utfstring.cpp +++ b/src/unstable/utfstring.cpp | |||
@@ -12,8 +12,21 @@ | |||
12 | #include "bu/config.h" | 12 | #include "bu/config.h" |
13 | #include "bu/sio.h" | 13 | #include "bu/sio.h" |
14 | #include "bu/membuf.h" | 14 | #include "bu/membuf.h" |
15 | #include "bu/formatter.h" | ||
16 | |||
15 | using Bu::sio; | 17 | using Bu::sio; |
16 | 18 | ||
19 | uint8_t Bu::UtfString::utf8_lmask[8] = { | ||
20 | 0x00, | ||
21 | 0x01, | ||
22 | 0x03, | ||
23 | 0x07, | ||
24 | 0x0f, | ||
25 | 0x1f, | ||
26 | 0x3f, | ||
27 | 0x7f | ||
28 | }; | ||
29 | |||
17 | Bu::UtfString::UtfString() | 30 | Bu::UtfString::UtfString() |
18 | { | 31 | { |
19 | } | 32 | } |
@@ -111,27 +124,17 @@ void Bu::UtfString::append( const UtfString &rSrc ) | |||
111 | 124 | ||
112 | void Bu::UtfString::setUtf8( const Bu::String &sInput ) | 125 | void Bu::UtfString::setUtf8( const Bu::String &sInput ) |
113 | { | 126 | { |
114 | static uint8_t lmask[8] = { | ||
115 | 0x00, | ||
116 | 0x01, | ||
117 | 0x03, | ||
118 | 0x07, | ||
119 | 0x0f, | ||
120 | 0x1f, | ||
121 | 0x3f, | ||
122 | 0x7f | ||
123 | }; | ||
124 | for( Bu::String::const_iterator i = sInput.begin(); i; i++ ) | 127 | for( Bu::String::const_iterator i = sInput.begin(); i; i++ ) |
125 | { | 128 | { |
126 | if( ((int)(uint8_t)*i)&0x80 ) | 129 | if( ((int)(uint8_t)*i)&0x80 ) |
127 | { | 130 | { |
128 | int iBytes = 1; | 131 | int iBytes = 1; |
129 | for(; (((uint8_t)(*i))<<iBytes)&0x80; iBytes++ ) { } | 132 | for(; (((uint8_t)(*i))<<iBytes)&0x80; iBytes++ ) { } |
130 | Bu::UtfChar uPt = ((*i) & lmask[7-iBytes])<<(6*(iBytes-1)); | 133 | Bu::UtfChar uPt = ((*i) & utf8_lmask[7-iBytes])<<(6*(iBytes-1)); |
131 | for( iBytes--; iBytes >= 1; iBytes-- ) | 134 | for( iBytes--; iBytes >= 1; iBytes-- ) |
132 | { | 135 | { |
133 | i++; | 136 | i++; |
134 | uPt |= ((*i)&lmask[6])<<(6*(iBytes-1)); | 137 | uPt |= ((*i)&utf8_lmask[6])<<(6*(iBytes-1)); |
135 | } | 138 | } |
136 | append( uPt ); | 139 | append( uPt ); |
137 | } | 140 | } |
@@ -321,6 +324,133 @@ void Bu::UtfString::write( Bu::Stream &sOut, Encoding eEnc ) const | |||
321 | } | 324 | } |
322 | } | 325 | } |
323 | 326 | ||
327 | int Bu::UtfString::readPoint( Bu::Stream &sIn, Bu::UtfChar &c, | ||
328 | Bu::UtfString::Encoding sEnc ) | ||
329 | { | ||
330 | switch( sEnc ) | ||
331 | { | ||
332 | case Utf8: | ||
333 | { | ||
334 | uint8_t i; | ||
335 | int iRead = 1; | ||
336 | if( sIn.read( &i, 1 ) < 1 ) | ||
337 | return 0; | ||
338 | if( ((int)i)&0x80 ) | ||
339 | { | ||
340 | int iBytes = 1; | ||
341 | for(; (((uint8_t)i)<<iBytes)&0x80; iBytes++ ) { } | ||
342 | iRead = iBytes; | ||
343 | c = (i & utf8_lmask[7-iBytes])<<(6*(iBytes-1)); | ||
344 | for( iBytes--; iBytes >= 1; iBytes-- ) | ||
345 | { | ||
346 | if( sIn.read( &i, 1 ) < 1 ) | ||
347 | return 0; | ||
348 | c |= (i&utf8_lmask[6])<<(6*(iBytes-1)); | ||
349 | } | ||
350 | return iRead; | ||
351 | } | ||
352 | else | ||
353 | { | ||
354 | c = (Bu::UtfChar)i; | ||
355 | return 1; | ||
356 | } | ||
357 | } | ||
358 | break; | ||
359 | |||
360 | case Utf16: | ||
361 | case Utf16be: | ||
362 | case Utf16le: | ||
363 | case Utf32: | ||
364 | case Utf32be: | ||
365 | case Utf32le: | ||
366 | case Ucs2: | ||
367 | case Ucs4: | ||
368 | case GuessEncoding: | ||
369 | throw Bu::ExceptionBase("Not implemented."); | ||
370 | break; | ||
371 | } | ||
372 | return -1; | ||
373 | } | ||
374 | |||
375 | int Bu::UtfString::writePoint( Bu::Stream &sOut, const Bu::UtfChar &c, | ||
376 | Bu::UtfString::Encoding sEnc ) | ||
377 | { | ||
378 | switch( sEnc ) | ||
379 | { | ||
380 | case Utf8: | ||
381 | { | ||
382 | uint8_t uByte; | ||
383 | if( c >= 0x010000 ) | ||
384 | { | ||
385 | // Four bytes | ||
386 | // 111 111111 111111 111111 | ||
387 | uByte = (c>>18)|0xF0; | ||
388 | sOut.write( &uByte, 1 ); | ||
389 | uByte = ((c>>12)&0x3F)|0x80; | ||
390 | sOut.write( &uByte, 1 ); | ||
391 | uByte = ((c>>6)&0x3F)|0x80; | ||
392 | sOut.write( &uByte, 1 ); | ||
393 | uByte = (c&0x3F)|0x80; | ||
394 | sOut.write( &uByte, 1 ); | ||
395 | return 4; | ||
396 | } | ||
397 | else if( c >= 0x800 ) | ||
398 | { | ||
399 | // Three bytes | ||
400 | // 1111 111111 111111 | ||
401 | uByte = (c>>12)|0xE0; | ||
402 | sOut.write( &uByte, 1 ); | ||
403 | uByte = ((c>>6)&0x3F)|0x80; | ||
404 | sOut.write( &uByte, 1 ); | ||
405 | uByte = (c&0x3F)|0x80; | ||
406 | sOut.write( &uByte, 1 ); | ||
407 | return 3; | ||
408 | } | ||
409 | else if( c >= 0x80 ) | ||
410 | { | ||
411 | // Two bytes | ||
412 | // 11111 111111 | ||
413 | uByte = (c>>6)|0xC0; | ||
414 | sOut.write( &uByte, 1 ); | ||
415 | uByte = (c&0x3F)|0x80; | ||
416 | sOut.write( &uByte, 1 ); | ||
417 | return 2; | ||
418 | } | ||
419 | else | ||
420 | { | ||
421 | // One byte | ||
422 | uByte = c; | ||
423 | sOut.write( &uByte, 1 ); | ||
424 | return 1; | ||
425 | } | ||
426 | } | ||
427 | break; | ||
428 | |||
429 | case Utf16: | ||
430 | case Utf16be: | ||
431 | case Utf16le: | ||
432 | case Utf32: | ||
433 | case Utf32be: | ||
434 | case Utf32le: | ||
435 | case Ucs2: | ||
436 | case Ucs4: | ||
437 | case GuessEncoding: | ||
438 | throw Bu::ExceptionBase("Not implemented."); | ||
439 | break; | ||
440 | } | ||
441 | return -1; | ||
442 | } | ||
443 | |||
444 | int32_t Bu::UtfString::toInt32( int iRadix ) const | ||
445 | { | ||
446 | return strtol( get().getStr(), NULL, iRadix ); | ||
447 | } | ||
448 | |||
449 | int64_t Bu::UtfString::toInt64( int iRadix ) const | ||
450 | { | ||
451 | return strtoll( get().getStr(), NULL, iRadix ); | ||
452 | } | ||
453 | |||
324 | void Bu::UtfString::writeUtf8( Bu::Stream &sOut ) const | 454 | void Bu::UtfString::writeUtf8( Bu::Stream &sOut ) const |
325 | { | 455 | { |
326 | int iPos = 0; | 456 | int iPos = 0; |
@@ -496,6 +626,33 @@ bool Bu::UtfString::operator==( const Bu::UtfString &rhs ) const | |||
496 | return aData == rhs.aData; | 626 | return aData == rhs.aData; |
497 | } | 627 | } |
498 | 628 | ||
629 | bool Bu::UtfString::operator==( const Bu::String &rhs ) const | ||
630 | { | ||
631 | // Nieve comparison | ||
632 | if( aData.getSize() != rhs.getSize() ) | ||
633 | return false; | ||
634 | |||
635 | for( int j = 0; j < aData.getSize(); j++ ) | ||
636 | { | ||
637 | if( aData[j] != rhs[j] ) | ||
638 | return false; | ||
639 | } | ||
640 | |||
641 | return true; | ||
642 | } | ||
643 | |||
644 | bool Bu::UtfString::operator==( const char *rhs ) const | ||
645 | { | ||
646 | // Nieve comparison | ||
647 | for( int j = 0; j < aData.getSize(); j++ ) | ||
648 | { | ||
649 | if( rhs[j] == '\0' || aData[j] != rhs[j] ) | ||
650 | return false; | ||
651 | } | ||
652 | |||
653 | return true; | ||
654 | } | ||
655 | |||
499 | Bu::UtfString &Bu::UtfString::operator+=( const Bu::UtfString &rhs ) | 656 | Bu::UtfString &Bu::UtfString::operator+=( const Bu::UtfString &rhs ) |
500 | { | 657 | { |
501 | append( rhs ); | 658 | append( rhs ); |
@@ -508,6 +665,56 @@ Bu::UtfString &Bu::UtfString::operator+=( const UtfChar &rhs ) | |||
508 | return *this; | 665 | return *this; |
509 | } | 666 | } |
510 | 667 | ||
668 | bool Bu::UtfString::operator<( const Bu::UtfString &rhs ) const | ||
669 | { | ||
670 | for( int j = 0; j < aData.getSize() && j < rhs.aData.getSize(); j++ ) | ||
671 | { | ||
672 | if( aData[j] != rhs.aData[j] ) | ||
673 | return aData[j] < rhs.aData[j]; | ||
674 | } | ||
675 | |||
676 | return false; | ||
677 | } | ||
678 | |||
679 | bool Bu::UtfString::operator<=( const Bu::UtfString &rhs ) const | ||
680 | { | ||
681 | for( int j = 0; j < aData.getSize() && j < rhs.aData.getSize(); j++ ) | ||
682 | { | ||
683 | if( aData[j] != rhs.aData[j] ) | ||
684 | return aData[j] < rhs.aData[j]; | ||
685 | } | ||
686 | |||
687 | if( aData.getSize() == rhs.aData.getSize() ) | ||
688 | return true; | ||
689 | |||
690 | return false; | ||
691 | } | ||
692 | |||
693 | bool Bu::UtfString::operator>( const Bu::UtfString &rhs ) const | ||
694 | { | ||
695 | for( int j = 0; j < aData.getSize() && j < rhs.aData.getSize(); j++ ) | ||
696 | { | ||
697 | if( aData[j] != rhs.aData[j] ) | ||
698 | return aData[j] > rhs.aData[j]; | ||
699 | } | ||
700 | |||
701 | return false; | ||
702 | } | ||
703 | |||
704 | bool Bu::UtfString::operator>=( const Bu::UtfString &rhs ) const | ||
705 | { | ||
706 | for( int j = 0; j < aData.getSize() && j < rhs.aData.getSize(); j++ ) | ||
707 | { | ||
708 | if( aData[j] != rhs.aData[j] ) | ||
709 | return aData[j] > rhs.aData[j]; | ||
710 | } | ||
711 | |||
712 | if( aData.getSize() == rhs.aData.getSize() ) | ||
713 | return true; | ||
714 | |||
715 | return false; | ||
716 | } | ||
717 | |||
511 | Bu::String Bu::UtfString::get( Encoding eEnc ) const | 718 | Bu::String Bu::UtfString::get( Encoding eEnc ) const |
512 | { | 719 | { |
513 | Bu::MemBuf mb; | 720 | Bu::MemBuf mb; |
@@ -537,16 +744,6 @@ void Bu::UtfString::debug() const | |||
537 | /* | 744 | /* |
538 | void Bu::UtfString::debugUtf8( const Bu::String &sUtf8 ) | 745 | void Bu::UtfString::debugUtf8( const Bu::String &sUtf8 ) |
539 | { | 746 | { |
540 | static uint8_t lmask[8] = { | ||
541 | 0x00, | ||
542 | 0x01, | ||
543 | 0x03, | ||
544 | 0x07, | ||
545 | 0x0f, | ||
546 | 0x1f, | ||
547 | 0x3f, | ||
548 | 0x7f | ||
549 | }; | ||
550 | for( Bu::String::const_iterator i = sUtf8.begin(); i; i++ ) | 747 | for( Bu::String::const_iterator i = sUtf8.begin(); i; i++ ) |
551 | { | 748 | { |
552 | if( i != sUtf8.begin() ) | 749 | if( i != sUtf8.begin() ) |
@@ -558,9 +755,9 @@ void Bu::UtfString::debugUtf8( const Bu::String &sUtf8 ) | |||
558 | int iBytes = 1; | 755 | int iBytes = 1; |
559 | for(; (((uint8_t)(*i))<<iBytes)&0x80; iBytes++ ) { } | 756 | for(; (((uint8_t)(*i))<<iBytes)&0x80; iBytes++ ) { } |
560 | // sio << "iBytes = " << iBytes << sio.nl; | 757 | // sio << "iBytes = " << iBytes << sio.nl; |
561 | Bu::UtfChar uPt = ((*i) & lmask[7-iBytes])<<(6*(iBytes-1)); | 758 | Bu::UtfChar uPt = ((*i) & utf8_lmask[7-iBytes])<<(6*(iBytes-1)); |
562 | // sio << "mask: " << Bu::Fmt().radix(2).width(8).fill('0') | 759 | // sio << "mask: " << Bu::Fmt().radix(2).width(8).fill('0') |
563 | // << (int)lmask[7-iBytes] << sio.nl; | 760 | // << (int)utf8_lmask[7-iBytes] << sio.nl; |
564 | for( iBytes--; iBytes >= 1; iBytes-- ) | 761 | for( iBytes--; iBytes >= 1; iBytes-- ) |
565 | { | 762 | { |
566 | // sio << "iBytes = " << iBytes << ", shift = " << (6*(iBytes-1)) | 763 | // sio << "iBytes = " << iBytes << ", shift = " << (6*(iBytes-1)) |
@@ -568,9 +765,9 @@ void Bu::UtfString::debugUtf8( const Bu::String &sUtf8 ) | |||
568 | // sio << "next: " << Bu::Fmt().radix(2).width(8).fill('0') | 765 | // sio << "next: " << Bu::Fmt().radix(2).width(8).fill('0') |
569 | // << (int)(uint8_t)*i << sio.nl | 766 | // << (int)(uint8_t)*i << sio.nl |
570 | // << "mask: " << Bu::Fmt().radix(2).width(8).fill('0') | 767 | // << "mask: " << Bu::Fmt().radix(2).width(8).fill('0') |
571 | // << (int)lmask[6] << sio.nl; | 768 | // << (int)utf8_lmask[6] << sio.nl; |
572 | i++; | 769 | i++; |
573 | uPt |= ((*i)&lmask[6])<<(6*(iBytes-1)); | 770 | uPt |= ((*i)&utf8_lmask[6])<<(6*(iBytes-1)); |
574 | } | 771 | } |
575 | sio << uPt; | 772 | sio << uPt; |
576 | // sio << " (" << Bu::Fmt( 8, 2 ).fill('0') | 773 | // sio << " (" << Bu::Fmt( 8, 2 ).fill('0') |
@@ -602,3 +799,9 @@ template<> bool Bu::__cmpHashKeys<Bu::UtfString>( | |||
602 | { | 799 | { |
603 | return a == b; | 800 | return a == b; |
604 | } | 801 | } |
802 | |||
803 | Bu::Formatter Bu::operator<<( Bu::Formatter &f, const Bu::UtfString &s ) | ||
804 | { | ||
805 | return f << s.get(); | ||
806 | } | ||
807 | |||
diff --git a/src/unstable/utfstring.h b/src/unstable/utfstring.h index 5085ec0..285b680 100644 --- a/src/unstable/utfstring.h +++ b/src/unstable/utfstring.h | |||
@@ -191,6 +191,18 @@ namespace Bu | |||
191 | void write( Bu::Stream &sOut, Encoding eEnc=Utf8 ) const; | 191 | void write( Bu::Stream &sOut, Encoding eEnc=Utf8 ) const; |
192 | 192 | ||
193 | /** | 193 | /** |
194 | * Reads as many bytes from the given stream, starting at the current | ||
195 | * position, as required to read a single UtfChar (code point). | ||
196 | */ | ||
197 | static int readPoint( Bu::Stream &sIn, UtfChar &c, | ||
198 | Encoding sEnc=Utf8 ); | ||
199 | static int writePoint( Bu::Stream &sOut, const UtfChar &c, | ||
200 | Encoding sEnc=Utf8 ); | ||
201 | |||
202 | int32_t toInt32( int iRadix=10 ) const; | ||
203 | int64_t toInt64( int iRadix=10 ) const; | ||
204 | |||
205 | /** | ||
194 | * This encodes the UtfString in the given encoding and returns it as | 206 | * This encodes the UtfString in the given encoding and returns it as |
195 | * a binary Bu::String. Like write, this also includes the proper BOM | 207 | * a binary Bu::String. Like write, this also includes the proper BOM |
196 | * at the begining. | 208 | * at the begining. |
@@ -216,9 +228,16 @@ namespace Bu | |||
216 | UtfChar nextChar( int &iIndex ) const; | 228 | UtfChar nextChar( int &iIndex ) const; |
217 | 229 | ||
218 | bool operator==( const Bu::UtfString &rhs ) const; | 230 | bool operator==( const Bu::UtfString &rhs ) const; |
231 | bool operator==( const Bu::String &rhs ) const; | ||
232 | bool operator==( const char *rhs ) const; | ||
219 | UtfString &operator+=( const Bu::UtfString &rhs ); | 233 | UtfString &operator+=( const Bu::UtfString &rhs ); |
220 | UtfString &operator+=( const UtfChar &rhs ); | 234 | UtfString &operator+=( const UtfChar &rhs ); |
221 | 235 | ||
236 | bool operator<( const Bu::UtfString &rhs ) const; | ||
237 | bool operator<=( const Bu::UtfString &rhs ) const; | ||
238 | bool operator>( const Bu::UtfString &rhs ) const; | ||
239 | bool operator>=( const Bu::UtfString &rhs ) const; | ||
240 | |||
222 | private: | 241 | private: |
223 | void append16( uint16_t i ) { aData.append( i ); } | 242 | void append16( uint16_t i ) { aData.append( i ); } |
224 | 243 | ||
@@ -237,6 +256,7 @@ namespace Bu | |||
237 | void writeUtf32le( Bu::Stream &sOut ) const; | 256 | void writeUtf32le( Bu::Stream &sOut ) const; |
238 | 257 | ||
239 | private: | 258 | private: |
259 | static uint8_t utf8_lmask[8]; | ||
240 | Bu::Array<uint16_t> aData; | 260 | Bu::Array<uint16_t> aData; |
241 | int iRawLen; | 261 | int iRawLen; |
242 | int iCharLen; | 262 | int iCharLen; |
@@ -254,6 +274,9 @@ namespace Bu | |||
254 | template<> uint32_t __calcHashCode<UtfString>( const UtfString &k ); | 274 | template<> uint32_t __calcHashCode<UtfString>( const UtfString &k ); |
255 | template<> bool __cmpHashKeys<UtfString>( | 275 | template<> bool __cmpHashKeys<UtfString>( |
256 | const UtfString &a, const UtfString &b ); | 276 | const UtfString &a, const UtfString &b ); |
277 | |||
278 | class Formatter; | ||
279 | Bu::Formatter operator<<( Bu::Formatter &f, const Bu::UtfString &s ); | ||
257 | }; | 280 | }; |
258 | 281 | ||
259 | #endif | 282 | #endif |