00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef MuscleString_h
00013 #define MuscleString_h
00014
00015 #include <ctype.h>
00016 #include "support/Flattenable.h"
00017 #include "system/GlobalMemoryAllocator.h"
00018
00019 BEGIN_NAMESPACE(muscle);
00020
00021 #ifndef SMALL_MUSCLE_STRING_LENGTH
00022 # define SMALL_MUSCLE_STRING_LENGTH 7 // strings shorter than this length can be stored inline, without requiring an extra new[].
00023 #endif
00024
00026 uint32 CStringHashFunc(const char * str);
00027
00029 class String : public Flattenable
00030 {
00031 public:
00038 String(const char * str = NULL, uint32 maxLen = MUSCLE_NO_LIMIT) : Flattenable(), _buffer(NULL), _bufferLen(0), _length(0) {if (str) (void) SetCstr(str, maxLen); else _smallBuffer[0] = '\0';}
00039
00043 String(const String & str) : Flattenable(), _buffer(NULL), _bufferLen(0), _length(0) {(void) SetFromString(str);}
00044
00051 String(const String & str, uint32 beginIndex, uint32 endIndex=MUSCLE_NO_LIMIT) : Flattenable(), _buffer(NULL), _bufferLen(0), _length(0) {(void) SetFromString(str, beginIndex, endIndex);}
00052
00054 virtual ~String() {if (_buffer != _smallBuffer) muscleFree(_buffer);}
00055
00059 String & operator = (char val) {(void) SetCstr(&val, 1); return *this;}
00060
00064 String & operator = (const char * val) {(void) SetCstr(val); return *this;}
00065
00069 String & operator = (const String &rhs) {(void) SetFromString(rhs); return *this;}
00070
00074 String & operator += (const String &rhs);
00075
00079 String & operator += (const char * rhs);
00080
00084 String & operator += (char ch)
00085 {
00086 if (EnsureBufferSize(Length()+2, true) == B_NO_ERROR)
00087 {
00088 _buffer[_length++] = ch;
00089 _buffer[_length] = '\0';
00090 }
00091 return *this;
00092 }
00093
00099 String & operator -= (const String &rhs);
00100
00106 String & operator -= (const char ch);
00107
00112 String & operator << (const String& rhs) {return (*this += rhs);}
00113
00118 String & operator << (const char* rhs) {return (*this += rhs);}
00119
00124 String & operator << (int rhs);
00125
00130 String & operator << (float rhs);
00131
00136 String & operator << (bool rhs);
00137
00141 bool operator == (const String &rhs) const {return ((this == &rhs)||((Length() == rhs.Length())&&(strcmp(Cstr(), rhs.Cstr()) == 0)));}
00142
00146 bool operator == (const char * rhs) const {return (strcmp(Cstr(), rhs?rhs:"") == 0);}
00147
00151 bool operator != (const String &rhs) const {return !(*this == rhs);}
00152
00156 bool operator != (const char * rhs) const {return (strcmp(Cstr(), rhs?rhs:"") != 0);}
00157
00161 bool operator < (const String &rhs) const {return (this == &rhs) ? false : (strcmp(Cstr(), rhs.Cstr()) < 0);}
00162
00166 bool operator < (const char * rhs) const {return (strcmp(Cstr(), rhs?rhs:"") < 0);}
00167
00171 bool operator > (const String &rhs) const {return (this == &rhs) ? false : (strcmp(Cstr(), rhs.Cstr()) > 0);}
00172
00176 bool operator > (const char * rhs) const {return (strcmp(Cstr(), rhs?rhs:"") > 0);}
00177
00181 bool operator <= (const String &rhs) const {return (this == &rhs) ? true : (strcmp(Cstr(), rhs.Cstr()) <= 0);}
00182
00186 bool operator <= (const char * rhs) const {return (strcmp(Cstr(), rhs?rhs:"") <= 0);}
00187
00191 bool operator >= (const String &rhs) const {return (this == &rhs) ? true : (strcmp(Cstr(), rhs.Cstr()) >= 0);}
00192
00196 bool operator >= (const char * rhs) const {return (strcmp(Cstr(), rhs?rhs:"") >= 0);}
00197
00201 char operator [] (uint32 index) const {VerifyIndex(index); return _buffer[index];}
00202
00206 char & operator [] (uint32 index) {VerifyIndex(index); return _buffer[index];}
00207
00212 char CharAt(uint32 index) const {return operator[](index);}
00213
00217 int CompareTo(const String & rhs) const {return strcmp(Cstr(), rhs.Cstr());}
00218
00222 int CompareTo(const char * rhs) const {return strcmp(Cstr(), rhs?rhs:"");}
00223
00225 const char * Cstr() const {return _buffer ? _buffer : "";}
00226
00228 const char * operator()() const {return Cstr();}
00229
00231 void Clear() {if (_buffer) _buffer[0] = '\0'; _length = 0;}
00232
00239 status_t SetCstr(const char * str, uint32 maxLen = MUSCLE_NO_LIMIT);
00240
00251 status_t SetFromString(const String & str, uint32 beginIndex = 0, uint32 endIndex = MUSCLE_NO_LIMIT);
00252
00254 bool IsEmpty() const {return (_length == 0);}
00255
00257 bool HasChars() const {return (_length > 0);}
00258
00262 bool EndsWith(char c) const {return (_length > 0)&&(_buffer[_length-1] == c);}
00263
00267 bool EndsWith(const String &suffix) const {return (Length() < suffix.Length()) ? false : (strcmp(Cstr()+(Length()-suffix.Length()), suffix.Cstr()) == 0);}
00268
00272 bool EndsWith(const char * suffix) const
00273 {
00274 if (suffix == NULL) suffix = "";
00275 uint32 suffixLen = strlen(suffix);
00276 return (Length() < suffixLen) ? false : (strcmp(Cstr()+(Length()-suffixLen), suffix) == 0);
00277 }
00278
00282 bool Equals(const String & str) const {return (*this == str);}
00283
00287 bool Equals(const char * str) const {return (*this == str);}
00288
00292 bool Equals(char c) const {return (_length == 1)&&(_buffer[0] == c);}
00293
00298 int IndexOf(char ch, uint32 fromIndex = 0) const
00299 {
00300 const char * temp = (fromIndex < Length()) ? strchr(Cstr()+fromIndex, ch) : NULL;
00301 return temp ? (temp - Cstr()) : -1;
00302 }
00303
00308 int IndexOf(const String &str, uint32 fromIndex = 0) const
00309 {
00310 const char * temp = (fromIndex < Length()) ? strstr(Cstr()+fromIndex, str()) : NULL;
00311 return temp ? (temp - Cstr()) : -1;
00312 }
00313
00318 int IndexOf(const char * str, uint32 fromIndex = 0) const
00319 {
00320 const char * temp = (fromIndex < Length()) ? strstr(Cstr()+fromIndex, str?str:"") : NULL;
00321 return temp ? (temp - Cstr()) : -1;
00322 }
00323
00328 int LastIndexOf(char ch, uint32 fromIndex = 0) const
00329 {
00330 const char * lio = (fromIndex < Length()) ? strrchr(Cstr()+fromIndex, ch) : NULL;
00331 return lio ? (lio - Cstr()) : -1;
00332 }
00333
00337 int LastIndexOf(const String &str) const {return (str.Length() <= Length()) ? LastIndexOf(str, Length()-str.Length()) : -1;}
00338
00342 int LastIndexOf(const char * str) const
00343 {
00344 if (str == NULL) str = "";
00345 uint32 strLen = strlen(str);
00346 return (strLen <= Length()) ? LastIndexOf(str, Length()-strLen) : -1;
00347 }
00348
00353 int LastIndexOf(const String &str, uint32 fromIndex) const;
00354
00359 int LastIndexOf(const char * str, uint32 fromIndex) const;
00360
00362 uint32 Length() const {return _length;}
00363
00367 uint32 GetNumInstancesOf(char ch) const;
00368
00372 uint32 GetNumInstancesOf(const String & substring) const;
00373
00377 uint32 GetNumInstancesOf(const char * substring) const;
00378
00382 bool StartsWith(char c) const {return (_length > 0)&&(_buffer[0] == c);}
00383
00387 bool StartsWith(const String &prefix) const {return ((Length() >= prefix.Length())&&(strncmp(Cstr(), prefix(), prefix.Length()) == 0));}
00388
00392 bool StartsWith(const char * prefix) const
00393 {
00394 if (prefix == NULL) prefix = "";
00395 uint32 prefixLen = strlen(prefix);
00396 return (Length() < prefixLen) ? false : (strncmp(Cstr(), prefix, prefixLen) == 0);
00397 }
00398
00400 bool StartsWith(const String &prefix, uint32 offset) const {return ((offset+prefix.Length()<=Length())&&(strncmp(Cstr()+offset, prefix.Cstr(), prefix.Length()) == 0));}
00401
00406 bool StartsWith(const char * prefix, uint32 offset) const
00407 {
00408 if (prefix == NULL) prefix = "";
00409 uint32 prefixLen = strlen(prefix);
00410 return ((offset+prefixLen<=Length())&&(strncmp(Cstr()+offset, prefix, prefixLen) == 0));
00411 }
00412
00414 String Prepend(const String & str, uint32 count = 1) const;
00415
00420 String Prepend(const char * str, uint32 count = 1) const;
00421
00423 String Append(const String & str, uint32 count = 1) const;
00424
00429 String Append(const char * str, uint32 count = 1) const;
00430
00437 String Pad(uint32 minLength, bool padOnRight = false, char padChar = ' ') const;
00438
00440 String Substring(uint32 beginIndex) const {return String(*this, beginIndex);}
00441
00443 String Substring(uint32 beginIndex, uint32 endIndex) const {return String(*this, beginIndex, endIndex);}
00444
00450 String Substring(const String & markerString) const
00451 {
00452 int idx = LastIndexOf(markerString);
00453 return (idx >= 0) ? String(*this, idx+markerString.Length()) : *this;
00454 }
00455
00457 String Substring(const char * markerString) const
00458 {
00459 int idx = LastIndexOf(markerString);
00460 return (idx >= 0) ? String(*this, idx+strlen(markerString)) : *this;
00461 }
00462
00468 String Substring(uint32 beginIndex, const String & markerString) const {return String(*this, beginIndex, (uint32) IndexOf(markerString, beginIndex));}
00469
00471 String Substring(uint32 beginIndex, const char * markerString) const {return String(*this, beginIndex, (uint32) IndexOf(markerString, beginIndex));}
00472
00474 String ToLowerCase() const;
00475
00477 String ToUpperCase() const;
00478
00480 String Trim() const;
00481
00483 void SwapContents(String & swapWithMe);
00484
00486 int CompareToIgnoreCase(const String &s) const {return ToLowerCase().CompareTo(s.ToLowerCase());}
00487
00489 bool EndsWithIgnoreCase(char c) const {return (_length > 0)&&(tolower(_buffer[_length-1]) == tolower(c));}
00490
00492 bool EndsWithIgnoreCase(const String &s) const {return ToLowerCase().EndsWith(s.ToLowerCase());}
00493
00495 bool EqualsIgnoreCase(const String &s) const {return ToLowerCase().Equals(s.ToLowerCase());}
00496
00498 bool EqualsIgnoreCase(char c) const {return (_length==1)&&(tolower(_buffer[0])==tolower(c));}
00499
00501 int IndexOfIgnoreCase(const String &s) const {return ToLowerCase().IndexOf(s.ToLowerCase());}
00502
00504 int IndexOfIgnoreCase(const String &s, uint32 f) const {return ToLowerCase().IndexOf(s.ToLowerCase(),f);}
00505
00507 int IndexOfIgnoreCase(char ch) const {return ToLowerCase().IndexOf((char)tolower(ch));}
00508
00510 int IndexOfIgnoreCase(char ch, uint32 f) const {return ToLowerCase().IndexOf((char)tolower(ch),f);}
00511
00513 int LastIndexOfIgnoreCase(const String &s) const {return ToLowerCase().LastIndexOf(s.ToLowerCase());}
00514
00516 int LastIndexOfIgnoreCase(const String &s, uint32 f) const {return ToLowerCase().LastIndexOf(s.ToLowerCase(),f);}
00517
00519 int LastIndexOfIgnoreCase(char ch) const {return ToLowerCase().LastIndexOf((char)tolower(ch));}
00520
00522 int LastIndexOfIgnoreCase(char ch, uint32 f) const {return ToLowerCase().LastIndexOf((char)tolower(ch),f);}
00523
00525 bool StartsWithIgnoreCase(char c) const {return (_length > 0)&&(tolower(_buffer[0]) == tolower(c));}
00526
00528 bool StartsWithIgnoreCase(const String &s) const {return ToLowerCase().StartsWith(s.ToLowerCase());}
00529
00531 bool StartsWithIgnoreCase(const String &s, uint32 o) const {return ToLowerCase().StartsWith(s.ToLowerCase(),o);}
00532
00534 inline uint32 HashCode() const {return CStringHashFunc(Cstr());}
00535
00541 uint32 Replace(char replaceMe, char withMe);
00542
00549 int32 Replace(const String & replaceMe, const String & withMe);
00550
00552 void Reverse();
00553
00557 virtual bool IsFixedSize() const {return false;}
00558
00562 virtual uint32 TypeCode() const {return B_STRING_TYPE;}
00563
00567 virtual uint32 FlattenedSize() const;
00568
00575 virtual void Flatten(uint8 *buffer) const;
00576
00582 virtual status_t Unflatten(const uint8 *buf, uint32 size);
00583
00590 status_t Prealloc(uint32 numChars) {return EnsureBufferSize(numChars+1, true);}
00591
00604 String Arg(int8 value, const char * fmt = "%i") const;
00605
00607 String Arg(uint8 value, const char * fmt = "%u") const;
00608
00610 String Arg(int16 value, const char * fmt = "%i") const;
00611
00613 String Arg(uint16 value, const char * fmt = "%u") const;
00614
00616 String Arg(int32 value, const char * fmt = INT32_FORMAT_SPEC) const;
00617
00619 String Arg(uint32 value, const char * fmt = UINT32_FORMAT_SPEC) const;
00620
00622 String Arg(int64 value, const char * fmt = INT64_FORMAT_SPEC) const;
00623
00625 String Arg(uint64 value, const char * fmt = UINT64_FORMAT_SPEC) const;
00626
00628 String Arg(double value, const char * fmt = "%f") const;
00629
00631 String Arg(const String & value) const;
00632
00634 String Arg(const char * value) const;
00635
00639 #ifdef MUSCLE_AVOID_NAMESPACES
00640 uint32 CalculateChecksum() const {return ::CalculateChecksum((const uint8 *) Cstr(), Length());}
00641 #else
00642 uint32 CalculateChecksum() const {return muscle::CalculateChecksum((const uint8 *) Cstr(), Length());}
00643 #endif
00644
00645 private:
00646 bool IsSpaceChar(char c) const {return ((c==' ')||(c=='\t')||(c=='\r')||(c=='\n'));}
00647 status_t EnsureBufferSize(uint32 newBufLen, bool retainValue);
00648 String ArgAux(const char * buf) const;
00649
00650 char _smallBuffer[SMALL_MUSCLE_STRING_LENGTH+1];
00651 char * _buffer;
00652 uint32 _bufferLen;
00653 uint32 _length;
00654
00655 void VerifyIndex(uint32 index) const
00656 {
00657 #ifdef MUSCLE_AVOID_ASSERTIONS
00658 (void) index;
00659 #else
00660 MASSERT(index < _length, "Index Out Of Bounds Exception");
00661 #endif
00662 }
00663 };
00664 DECLARE_HASHTABLE_KEY_CLASS(String);
00665
00666
00667 template <> class HashFunctor<const char *>
00668 {
00669 public:
00673 uint32 operator () (const char * str) const {return CStringHashFunc(str);}
00674 };
00675
00677 const String & GetEmptyString();
00678
00680 int StringCompareFunc(const String &, const String &, void *);
00681
00683 int StringCompareFunc(const String * const &, const String * const &, void *);
00684
00686 int CStringCompareFunc(const char * const &, const char * const &, void *);
00687
00688 inline String operator+(const String & lhs, const String &rhs) {String ret(lhs); ret += rhs; return ret;}
00689 inline String operator+(const String & lhs, const char *rhs) {String ret(lhs); ret += rhs; return ret;}
00690 inline String operator+(const char * lhs, const String & rhs) {String ret(lhs); ret += rhs; return ret;}
00691 inline String operator+(const String & lhs, char rhs) {String ret(lhs); ret += rhs; return ret;}
00692 inline String operator-(const String & lhs, const String &rhs) {String ret(lhs); ret -= rhs; return ret;}
00693 inline String operator-(const String & lhs, const char *rhs) {String ret(lhs); ret -= rhs; return ret;}
00694 inline String operator-(const char *lhs, const String &rhs) {String ret(lhs); ret -= rhs; return ret;}
00695 inline String operator-(const String & lhs, char rhs) {String ret(lhs); ret -= rhs; return ret;}
00696
00697 END_NAMESPACE(muscle);
00698
00699 #endif