class Nuller; // #define STRING_EXPERIMENTAL // activate experimental optimizations int wstrlen(const wchar *s); #ifdef PLATFORM_POSIX inline int stricmp(const char *a, const char *b) { return strcasecmp(a, b); } inline int strnicmp(const char *a, const char *b, int n) { return strncasecmp(a, b, n); } #endif #ifdef PLATFORM_WINCE inline int stricmp(const char *a, const char *b) { return _stricmp(a, b); } inline int strnicmp(const char *a, const char *b, int n) { return _strnicmp(a, b, n); } #endif template class AStringBuffer; inline int strlen__(const char *s) { return strlen(s); } inline int strlen__(const wchar *s) { return wstrlen(s); } template class AString : public Moveable { protected: struct Data { Atomic refcount; int length; int alloc; T *GetPtr() const { return (T*)(this + 1); } void Release() { ASSERT(refcount > 0); if(AtomicDec(refcount) == 0) delete[] (byte *)this; } void Retain() { ASSERT(refcount > 0); AtomicInc(refcount); } }; T *ptr; static Data *GetData(const T *ptr) { return (Data *)ptr - 1; } static Data *Alloc(int len); static Data *Clone(const Data *data, int newalloc); static T *CreateEmpty(Data *kind); static T *Create(int len); static T *Create(const T *data, int len); void Retain() const { GetData(ptr)->Retain(); } void Release() { GetData(ptr)->Release(); } void Chk() const { ASSERT(ptr && AtomicRead(GetData(ptr)->refcount) > 0); } void Cat(int c); void Cat(int c, int count); void Cat(const T *s, int len); void Insert(int at, int c); void Insert(int at, const T *s, int len); void Assign(const AString& s); void Assign(const T *s, int len); void DeepAssign(const AString& s); T *Mid(int pos, int length) const; T *Mid(int pos) const; T *Right(int count) const; T *Left(int count) const; bool IsEqual(const T *ptr, int len) const; AString(int, T *p) { ptr = p; } public: void Remove(int at, int count = 1); void Set(int at, int chr); void Trim(int at); int GetLength() const { return GetData(ptr)->length; } int GetCount() const { return GetData(ptr)->length; } bool IsEmpty() const { return GetCount() == 0; } int Find(int chr, int from = 0) const; int ReverseFind(int chr, int from) const; int ReverseFind(int chr) const; int Find(int len, const T *s, int from) const; int Find(const T *s, int from = 0) const; int Find(const S& s, int from = 0) const { return Find(s.GetCount(), s.Begin(), from); } bool StartsWith(const T *s, int len) const; bool StartsWith(const T *s) const { return StartsWith(s, strlen(s)); } bool StartsWith(const S& s) const { return StartsWith(s, s.GetLength()); } bool EndsWith(const T *s, int len) const; bool EndsWith(const T *s) const { return EndsWith(s, strlen(s)); } bool EndsWith(const S& s) const { return EndsWith(s, s.GetLength()); } void Clear(); void Shrink(); void Reserve(int len); int GetAlloc() const { return GetData(ptr)->alloc; } T *GetBuffer(int minlen); // deprecated !!! void ReleaseBuffer(int newlen = -1); // deprecated !!! AString() { ptr = S::CreateNull(); } AString(const AString& a) { ptr = a.ptr; Retain(); } AString(const T *s, int len) { ptr = Create(s, len); } AString(const T *s) { ptr = s ? Create(s, strlen__(s)) : S::CreateNull(); } AString(int chr, int count); ~AString() { Chk(); Release(); } typedef T ValueType; typedef const T* ConstIterator; const T *Begin() const { return ptr; } const T *End() const { return ptr + GetCount(); } const T *Last() const { return End() - 1; } const T *GetIter(int i) const { ASSERT(i >= 0 && i <= GetCount()); return ptr + i; } friend class AStringBuffer; friend bool operator<(const S& a, const S& b) { return a.Compare(b) < 0; } friend bool operator<(const S& a, const T *b) { return a.Compare(b) < 0; } friend bool operator<(const T *a, const S& b) { return b.Compare(a) > 0; } friend bool operator<=(const S& a, const S& b) { return a.Compare(b) <= 0; } friend bool operator<=(const S& a, const T *b) { return a.Compare(b) <= 0; } friend bool operator<=(const T *a, const S& b) { return b.Compare(a) >= 0; } friend bool operator>(const S& a, const S& b) { return a.Compare(b) > 0; } friend bool operator>(const S& a, const T *b) { return a.Compare(b) > 0; } friend bool operator>(const T *a, const S& b) { return b.Compare(a) < 0; } friend bool operator>=(const S& a, const S& b) { return a.Compare(b) >= 0; } friend bool operator>=(const S& a, const T *b) { return a.Compare(b) >= 0; } friend bool operator>=(const T *a, const S& b) { return b.Compare(a) <= 0; } #ifdef STRING_EXPERIMENTAL friend bool operator==(const S& a, const S& b) { return a.IsEqual(b); } friend bool operator!=(const S& a, const S& b) { return !a.IsEqual(b); } #else friend bool operator==(const S& a, const S& b) { return a.Compare(b) == 0; } friend bool operator!=(const S& a, const S& b) { return a.Compare(b) != 0; } #endif friend bool operator==(const S& a, const T *b) { return a.Compare(b) == 0; } friend bool operator==(const T *a, const S& b) { return b.Compare(a) == 0; } friend bool operator!=(const S& a, const T *b) { return a.Compare(b) != 0; } friend bool operator!=(const T *a, const S& b) { return b.Compare(a) != 0; } friend S operator+(const S& a, const S& b) { S c(a); c += b; return c; } friend S operator+(const S& a, const T *b) { S c(a); c += b; return c; } friend S operator+(const T *a, const S& b) { S c(a); c += b; return c; } friend S operator+(const S& a, int b) { S c(a); c += b; return c; } friend S operator+(int a, const S& b) { S c; c.Cat(a); c += b; return c; } friend S operator+(const S& a, T b) { S c(a); c += b; return c; } friend S operator+(T a, const S& b) { S c; c.Cat(a); c += b; return c; } }; template class AStringBuffer { protected: T *begin; T *end; T *alloc; void Reads() { typename S::Data *d = S::GetData(begin); end = begin + d->length; alloc = begin + d->alloc; } void Realloc(int newalloc); void Expand(int len); void Expand(); void Init(int len); void Init(S& text, int minalloc); void Free() { if(begin) S::GetData(begin)->Release(); } T *Get(); void Set(S& s); T *Ptr() { *end = '\0'; return begin; } friend class String; friend class WString; public: AStringBuffer(); AStringBuffer(int length) { Init(length); } AStringBuffer(S& text) { Init(text, text.GetCount()); } AStringBuffer(S& text, int length) { Init(text, length); end = begin + length; } operator T*() { return Ptr(); } operator void*() { return Ptr(); } T *operator~() { return Ptr(); } void Cat(int c) { if(end >= alloc) Expand(); *end++ = c; } void Cat(int c, int count) { if(end + count >= alloc) Expand(count); Fill(end, end + count, (T)c); end += count; } void Cat(const T *s, int len) { if(end + len >= alloc) Expand(len); memcpy(end, s, sizeof(T) * len); end += len; } int GetLength() const { return end - begin; } T *SetLength(int len); int GetCount() const { return GetLength(); } T *SetCount(int len) { return SetLength(len); } T *Begin() { return begin; } T *End() { return end; } void Clear(); void Reserve(int alloc); ~AStringBuffer(); private: AStringBuffer(const AStringBuffer&); void operator=(const AStringBuffer&); }; class WString; class String : public AString { typedef AString B; String(Data *data) { ptr = CreateEmpty(data); } String(int, char *p) : B(0, p) {} static Data *Void(); static Data *Zero(); static char *CreateNull(); void Slice(const char *a, int n); // friend class B; friend class AString; friend class AStringBuffer; public: class Buffer; friend class String::Buffer; void Cat(int c) { B::Cat(c); } void Cat(const char *s); void Cat(const String& s); void Cat(int c, int count) { B::Cat(c, count); } void Cat(const char *s, int len) { B::Cat(s, len); } void Cat(const char *s, const char *lim) { ASSERT(s <= lim); Cat(s, lim - s); } void Cat(const String& s, int len) { B::Cat(~s, len); } void Cat(const byte *s, int len) { B::Cat((const char *) s, len); } String& Cat() { return *this; } const String& operator+=(char c) { Cat(c); return *this; } const String& operator+=(const char *s) { Cat(s); return *this; } const String& operator+=(const String& s) { Cat(s); return *this; } String& operator=(const char *s); String& operator=(const String& s) { B::Assign(s); return *this; } String& operator=(Buffer& b) { *this = String(b); return *this; } String& operator<<=(const String& s) { B::DeepAssign(s); return *this; } void Insert(int at, int c) { B::Insert(at, c); } void Insert(int at, const String& s); void Insert(int at, const char *s, int l) { B::Insert(at, s, l); } void Insert(int at, const char *s); String Mid(int pos, int length) const { return String(0, B::Mid(pos, length)); } String Mid(int pos) const { return String(0, B::Mid(pos)); } String Right(int count) const { return String(0, B::Right(count)); } String Left(int count) const { return String(0, B::Left(count)); } bool IsEqual(const String& s) const; bool IsEqual(const char *s) const; int Compare(const String& s) const; int Compare(const char *s) const; const char *operator~() const { return B::ptr; } operator const char*() const { return B::ptr; } operator const void*() const { return B::ptr; } operator const byte*() const { return (byte *) B::ptr; } int operator*() const { return *B::ptr; } int operator[](int i) const { ASSERT(i <= B::GetLength()); return (byte)ptr[i]; } bool IsVoid() const; bool IsZero() const; static String GetVoid(); static String GetZero(); // operator WString() const; WString ToWString() const; const String& ToString() const { return *this; } String(); String(const Nuller&); String(const String& s); String(const char *s); String(const String& s, int n); String(const char *s, int n); String(const byte *s, int n); #ifdef STRING_EXPERIMENTAL String(const char *s, const char *lim) { Slice(s, lim - s); } #else String(const char *s, const char *lim); #endif String(int chr, int count); String(Buffer& b) : B(0, b.Get()) {}; ~String(); friend void Swap(String& a, String& b) { char *h = a.ptr; a.ptr = b.ptr; b.ptr = h; } class Buffer : public AStringBuffer { typedef AStringBuffer B; public: Buffer() {} Buffer(int length) : B(length) {} Buffer(String& text) : B(text) {} Buffer(String& text, int length) : B(text, length) {} void Cat(int c) { B::Cat(c); } void Cat(int c, int count) { B::Cat(c, count); } void Cat(const char *s, int len) { B::Cat(s, len); } void Cat(const char *s) { Cat(s, strlen(s)); } void Cat(const String& s) { Cat(s, s.GetLength()); } void Cat(const char *s, const char *lim) { ASSERT(s <= lim); Cat(s, lim - s); } void Cat(const String& s, int len) { Cat(~s, len); } void Cat(const byte *s, int len) { Cat((const char *) s, len); } void operator=(String& s) { Set(s); } void Strlen(); }; String(const std::string& s); operator std::string() const; }; typedef String::Buffer StringBuffer; inline bool IsEmpty(const String& s) { return s.IsEmpty(); } template bool IsNull(const T& x) { return x.IsNullInstance(); } String FormatPtr(const void *p); template inline String AsString(const T& x) { return x.ToString(); } /* template inline String AsString(T *x) { return FormatPtr(x); } */ #ifdef PLATFORM_MSC inline String AsString(const void *x) { return FormatPtr(x); } #endif inline String& operator<<(String& s, const char *x) { s.Cat(x); return s; } inline String& operator<<(String& s, char *x) { s.Cat(x); return s; } inline String& operator<<(String& s, const String &x) { s.Cat(x); return s; } inline String& operator<<(String& s, char x) { s.Cat((int) x); return s; } inline String& operator<<(String& s, const void *x) { s << FormatPtr(x); return s; } inline String& operator<<(String& s, void *x) { s << FormatPtr(x); return s; } template inline String& operator<<(String& s, const T& x) { s.Cat(AsString(x)); return s; } template<> inline String& operator<<(String& s, const char * const &x) { s.Cat(x); return s; } template<> inline String& operator<<(String& s, const String &x) { s.Cat(x); return s; } template<> inline String& operator<<(String& s, const char& x) { s.Cat(x); return s; } template<> inline bool IsNull(const String& s) { return s.IsEmpty(); } template<> inline String AsString(const String& s) { return s; } template<> inline unsigned GetHashValue(const String& s) { return memhash(~s, s.GetLength()); } int CompareNoCase(const String& a, const String& b, byte encoding = 0); int CompareNoCase(const String& a, const char *b, byte encoding = 0); inline int CompareNoCase(const char *a, const String& b, byte encoding = 0) { return -CompareNoCase(b, a, encoding); } String TrimLeft(const String& s); String TrimRight(const String& s); inline StringBuffer& operator<<(StringBuffer& s, const char *x) { s.Cat(x); return s; } inline StringBuffer& operator<<(StringBuffer& s, char *x) { s.Cat(x); return s; } inline StringBuffer& operator<<(StringBuffer& s, const String &x) { s.Cat(x); return s; } inline StringBuffer& operator<<(StringBuffer& s, char x) { s.Cat((int) x); return s; } inline StringBuffer& operator<<(StringBuffer& s, const void *x) { s << FormatPtr(x); return s; } inline StringBuffer& operator<<(StringBuffer& s, void *x) { s << FormatPtr(x); return s; } template inline StringBuffer& operator<<(StringBuffer& s, const T& x) { s.Cat(AsString(x)); return s; } template<> inline StringBuffer& operator<<(StringBuffer& s, const char * const &x) { s.Cat(x); return s; } template<> inline StringBuffer& operator<<(StringBuffer& s, const String &x) { s.Cat(x); return s; } template<> inline StringBuffer& operator<<(StringBuffer& s, const char& x) { s.Cat(x); return s; } class Value; class WString : public AString { typedef AString B; WString(Data *data) { ptr = CreateEmpty(data); } WString(int, wchar *p) : B(0, p) {} static Data *Void(); static Data *Zero(); static wchar *CreateNull(); // friend class B; friend class AString; friend class AStringBuffer; public: class Buffer; friend class WString::Buffer; void Cat(int c) { B::Cat(c); } void Cat(const wchar *s); void Cat(const WString& s); void Cat(int c, int count) { B::Cat(c, count); } void Cat(const wchar *s, int len) { B::Cat(s, len); } void Cat(const wchar *s, const wchar *lim) { ASSERT(s <= lim); Cat(s, lim - s); } void Cat(const WString& s, int len) { B::Cat(~s, len); } WString& Cat() { return *this; } const WString& operator+=(wchar c) { Cat(c); return *this; } const WString& operator+=(const wchar *s) { Cat(s); return *this; } const WString& operator+=(const WString& s) { Cat(s); return *this; } WString& operator<<(wchar c) { Cat(c); return *this; } WString& operator<<(const WString& s) { Cat(s); return *this; } WString& operator<<(const wchar *s) { Cat(s); return *this; } WString& operator=(const wchar *s); WString& operator=(const WString& s) { B::Assign(s); return *this; } WString& operator=(Buffer& b) { *this = WString(b); return *this; } WString& operator<<=(const WString& s) { B::DeepAssign(s); return *this; } void Insert(int at, int c) { B::Insert(at, c); } void Insert(int at, const WString& s); void Insert(int at, const wchar *s, int l) { B::Insert(at, s, l); } void Insert(int at, const wchar *s); WString Mid(int pos, int length) const { return WString(0, B::Mid(pos, length)); } WString Mid(int pos) const { return WString(0, B::Mid(pos)); } WString Right(int count) const { return WString(0, B::Right(count)); } WString Left(int count) const { return WString(0, B::Left(count)); } bool IsEqual(const WString& s) const; bool IsEqual(const wchar *s) const; int Compare(const WString& s) const; int Compare(const wchar *s) const; const wchar *operator~() const { return B::ptr; } operator const wchar*() const { return B::ptr; } operator const void*() const { return B::ptr; } int operator*() const { return *B::ptr; } int operator[](int i) const { ASSERT(i <= B::GetLength()); return ptr[i]; } bool IsVoid() const; bool IsZero() const; static WString GetVoid(); static WString GetZero(); String ToString() const; WString(); WString(const Nuller&); WString(const WString& s); WString(const wchar *s); WString(const WString& s, int n); WString(const wchar *s, int n); WString(const wchar *s, const wchar *lim); WString(const char *s); WString(const char *s, int n); WString(const char *s, const char *lim); WString(int chr, int count); WString(Buffer& b) : B(0, b.Get()) {}; ~WString(); friend void Swap(WString& a, WString& b) { wchar *h = a.ptr; a.ptr = b.ptr; b.ptr = h; } class Buffer : public AStringBuffer { typedef AStringBuffer B; public: Buffer() {} Buffer(int length) : B(length) {} Buffer(WString& text) : B(text) {} Buffer(WString& text, int length) : B(text, length) {} void Cat(int c) { B::Cat(c); } void Cat(int c, int count) { B::Cat(c, count); } void Cat(const wchar *s, int len) { B::Cat(s, len); } void Cat(const char *s) { Cat(WString(s)); } void Cat(const wchar *s) { Cat(s, wstrlen(s)); } void Cat(const WString& s) { Cat(s, s.GetLength()); } void Cat(const wchar *s, const wchar *lim) { ASSERT(s <= lim); Cat(s, lim - s); } void Cat(const WString& s, int len) { Cat(~s, len); } void operator=(WString& s) { Set(s); } void Strlen(); }; WString(const std::wstring& s); operator std::wstring() const; }; typedef WString::Buffer WStringBuffer; inline bool IsEmpty(const WString& s) { return s.IsEmpty(); } template<> inline bool IsNull(const WString& s) { return s.IsEmpty(); } //template<> //inline String AsString(const WString& s) { return s; } template<> inline unsigned GetHashValue(const WString& s) { return memhash(~s, 2 * s.GetLength()); } WString TrimLeft(const WString& str); WString TrimRight(const WString& s); int CompareNoCase(const WString& a, const WString& b); int CompareNoCase(const WString& a, const wchar *b); inline int CompareNoCase(const wchar *a, const WString& b) { return -CompareNoCase(b, a); } template<> inline String AsString(const char * const &s) { return s; } template<> inline String AsString(char * const &s) { return s; } template<> inline String AsString(const char& a) { return String(a, 1); } template<> inline String AsString(const signed char& a) { return String(a, 1); } template<> inline String AsString(const unsigned char& a) { return String(a, 1); } template<> inline String AsString(const bool& a) { return a ? "true" : "false"; } unsigned ctoi(int c); typedef int (*CharFilter)(int); int CharFilterAscii(int c); int CharFilterAscii128(int c); int CharFilterUnicode(int c); int CharFilterDigit(int c); int CharFilterWhitespace(int c); int CharFilterAlpha(int c); int CharFilterAlphaToUpper(int c); int CharFilterAlphaToLower(int c); int CharFilterInt(int c); int CharFilterDouble(int c); int CharFilterDefaultToUpperAscii(int c); String Filter(const char *s, int (*filter)(int)); String FilterWhile(const char *s, int (*filter)(int));