summaryrefslogtreecommitdiff
path: root/library/zstring.h
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 16:55:48 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 16:55:48 +0200
commitdaea231de0ae28fc8343f29f09d0457cc0591461 (patch)
treea1d572442d2c903e40741a859ad47c8b0d740969 /library/zstring.h
parent1.13 (diff)
downloadFreeFileSync-daea231de0ae28fc8343f29f09d0457cc0591461.tar.gz
FreeFileSync-daea231de0ae28fc8343f29f09d0457cc0591461.tar.bz2
FreeFileSync-daea231de0ae28fc8343f29f09d0457cc0591461.zip
1.14
Diffstat (limited to 'library/zstring.h')
-rw-r--r--library/zstring.h580
1 files changed, 580 insertions, 0 deletions
diff --git a/library/zstring.h b/library/zstring.h
new file mode 100644
index 00000000..00590d4f
--- /dev/null
+++ b/library/zstring.h
@@ -0,0 +1,580 @@
+/***************************************************************
+ * Purpose: High performance string class
+ * Author: ZenJu (zhnmju123@gmx.de)
+ * Created: Jan. 2009
+ **************************************************************/
+
+#ifndef ZSTRING_H_INCLUDED
+#define ZSTRING_H_INCLUDED
+
+#include <wx/string.h>
+
+namespace FreeFileSync
+{
+#ifdef FFS_WIN
+ //super fast case-insensitive string comparison: way faster than wxString::CmpNoCase()!!!
+ int compareStringsWin32(const wchar_t* a, const wchar_t* b);
+ int compareStringsWin32(const wchar_t* a, const wchar_t* b, const int aCount, const int bCount);
+#endif //FFS_WIN
+}
+
+#ifdef FFS_WIN
+#define ZSTRING_WIDE_CHAR //use wide character strings
+
+#elif defined FFS_LINUX
+#define ZSTRING_CHAR //use char strings
+#endif
+
+
+#ifdef ZSTRING_CHAR
+typedef char defaultChar;
+#elif defined ZSTRING_WIDE_CHAR
+typedef wchar_t defaultChar;
+#endif
+
+class Zstring
+{
+public:
+ Zstring();
+ Zstring(const defaultChar* source); //string is copied: O(length)
+ Zstring(const defaultChar* source, size_t length); //string is copied: O(length)
+ Zstring(const Zstring& source); //reference-counting => O(1)
+ Zstring(const wxString& source); //string is copied: O(length)
+ ~Zstring();
+
+ operator const defaultChar*() const; //implicit conversion to C string
+ operator const wxString() const; //implicit conversion to wxString
+
+ //wxWidgets functions
+ bool StartsWith(const defaultChar* begin) const;
+ bool StartsWith(const Zstring& begin) const;
+ bool EndsWith(const defaultChar* end) const;
+ bool EndsWith(const Zstring& end) const;
+#ifdef FFS_WIN
+ int CmpNoCase(const defaultChar* other) const;
+ int CmpNoCase(const Zstring& other) const;
+#endif
+ int Cmp(const defaultChar* other) const;
+ int Cmp(const Zstring& other) const;
+ size_t Replace(const defaultChar* old, const defaultChar* replacement, bool replaceAll = true);
+ Zstring AfterLast(defaultChar ch) const;
+ Zstring BeforeLast(defaultChar ch) const;
+ size_t Find(defaultChar ch, bool fromEnd) const;
+ bool Matches(const defaultChar* mask) const;
+ Zstring& Trim(bool fromRight); //from right or left
+ Zstring& MakeLower();
+
+ //std::string functions
+ size_t length() const;
+ const defaultChar* c_str() const;
+ Zstring substr(size_t pos = 0, size_t len = npos) const;
+ bool empty() const;
+ int compare(const defaultChar* other) const;
+ int compare(const Zstring& other) const;
+ int compare(const size_t pos1, const size_t n1, const defaultChar* other) const;
+ size_t find(const defaultChar* str, const size_t pos = 0 ) const;
+ size_t find(const defaultChar ch, const size_t pos = 0) const;
+ size_t rfind(const defaultChar ch, size_t pos = npos) const;
+ Zstring& replace(size_t pos1, size_t n1, const defaultChar* str, size_t n2);
+
+ Zstring& operator=(const Zstring& source);
+ Zstring& operator=(const defaultChar* source);
+
+ bool operator==(const Zstring& other) const;
+ bool operator==(const defaultChar* other) const;
+
+ Zstring& operator+=(const Zstring& other);
+ Zstring& operator+=(const defaultChar* other);
+ Zstring& operator+=(defaultChar ch);
+
+ Zstring operator+(const Zstring& string2) const;
+ Zstring operator+(const defaultChar* string2) const;
+ Zstring operator+(const defaultChar ch) const;
+
+ static const size_t npos = static_cast<size_t>(-1);
+
+private:
+ void initAndCopy(const defaultChar* source, size_t length);
+ void incRef(); //support for reference-counting
+ void decRef(); //
+ void copyBeforeWrite(const size_t capacityNeeded); //and copy-on-write
+
+ struct StringDescriptor
+ {
+ StringDescriptor(const unsigned int refC, const size_t len, const size_t cap) : refCount(refC), length(len), capacity(cap) {}
+ unsigned int refCount;
+ size_t length;
+ size_t capacity; //allocated length without null-termination
+ };
+ static void allocate(const unsigned int newRefCount, const size_t newLength, const size_t newCapacity, Zstring::StringDescriptor*& newDescr, defaultChar*& newData);
+
+ StringDescriptor* descr;
+ defaultChar* data;
+};
+
+
+//#######################################################################################
+//begin of implementation
+
+#ifdef ZSTRING_CHAR
+inline
+size_t defaultLength(const char* input)
+{
+ return strlen(input);
+}
+
+inline
+int defaultCompare(const char* str1, const char* str2)
+{
+ return strcmp(str1, str2);
+}
+
+inline
+int defaultCompare(const char* str1, const char* str2, const size_t count)
+{
+ return strncmp(str1, str2, count);
+}
+
+inline
+char* defaultStrFind(const char* str1, const char* str2)
+{
+ return strstr(str1, str2);
+}
+
+inline
+char* defaultStrFind(const char* str1, int ch)
+{
+ return strchr(str1, ch);
+}
+
+inline
+bool defaultIsWhiteSpace(const char ch)
+{
+ // some compilers (e.g. VC++ 6.0) return true for a call to isspace('\xEA') => exclude char(128) to char(255)
+ return (ch < 128) && isspace(ch) != 0;
+}
+
+inline
+char defaultToLower(const char ch)
+{
+ return tolower(ch);
+}
+
+#elif defined ZSTRING_WIDE_CHAR
+inline
+size_t defaultLength(const wchar_t* input)
+{
+ return wcslen(input);
+}
+
+inline
+int defaultCompare(const wchar_t* str1, const wchar_t* str2)
+{
+ return wcscmp(str1, str2);
+}
+
+inline
+int defaultCompare(const wchar_t* str1, const wchar_t* str2, const size_t count)
+{
+ return wcsncmp(str1, str2, count);
+}
+
+inline
+wchar_t* defaultStrFind(const wchar_t* str1, const wchar_t* str2)
+{
+ return wcsstr(str1, str2);
+}
+
+inline
+wchar_t* defaultStrFind(const wchar_t* str1, int ch)
+{
+ return wcschr(str1, ch);
+}
+
+inline
+bool defaultIsWhiteSpace(const wchar_t ch)
+{
+ // some compilers (e.g. VC++ 6.0) return true for a call to isspace('\xEA') => exclude char(128) to char(255)
+ return (ch < 128 || ch > 255) && iswspace(ch) != 0;
+}
+
+inline
+wchar_t defaultToLower(const wchar_t ch)
+{
+ return towlower(ch);
+}
+#endif
+
+
+#ifdef __WXDEBUG__
+extern int allocCount; //test Zstring for memory leaks
+void testZstringForMemoryLeak();
+#endif
+
+
+inline
+void Zstring::allocate(const unsigned int newRefCount,
+ const size_t newLength,
+ const size_t newCapacity,
+ StringDescriptor*& newDescr,
+ defaultChar*& newData)
+{ //allocate and set data for new string
+ if (newCapacity)
+ {
+ newDescr = (StringDescriptor*) malloc( sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(defaultChar));
+ if (newDescr == NULL)
+ throw; //std::bad_alloc& e
+ newData = (defaultChar*)(newDescr + 1);
+ }
+ else
+ {
+ newDescr = (StringDescriptor*) malloc( sizeof(StringDescriptor));
+ if (newDescr == NULL)
+ throw; //std::bad_alloc& e
+ newData = NULL;
+ }
+
+ newDescr->refCount = newRefCount;
+ newDescr->length = newLength;
+ newDescr->capacity = newCapacity;
+
+#ifdef __WXDEBUG__
+ ++allocCount; //test Zstring for memory leaks
+
+ static bool isRegistered = false;
+ if (!isRegistered)
+ {
+ isRegistered = true;
+ atexit(testZstringForMemoryLeak);
+ }
+#endif
+}
+
+
+inline
+Zstring::Zstring()
+{
+ allocate(1, 0, 0, descr, data);
+}
+
+
+inline
+Zstring::Zstring(const defaultChar* source)
+{
+ initAndCopy(source, defaultLength(source));
+}
+
+
+inline
+Zstring::Zstring(const defaultChar* source, size_t length)
+{
+ initAndCopy(source, length);
+}
+
+
+inline
+Zstring::Zstring(const Zstring& source)
+{
+ descr = source.descr;
+ data = source.data;
+ incRef(); //reference counting!
+}
+
+
+inline
+Zstring::Zstring(const wxString& source)
+{
+ initAndCopy(source.c_str(), source.length());
+}
+
+
+inline
+Zstring::~Zstring()
+{
+ decRef();
+}
+
+
+inline
+size_t getCapacityToAllocate(const size_t length)
+{
+ return (length + (19 - length % 16)); //allocate some additional length to speed up concatenation
+}
+
+
+inline
+void Zstring::initAndCopy(const defaultChar* source, size_t length)
+{
+ const size_t newCapacity = getCapacityToAllocate(length);
+ allocate(1, length, newCapacity, descr, data);
+ memcpy(data, source, length * sizeof(defaultChar));
+ data[length] = 0;
+}
+
+
+inline
+void Zstring::incRef()
+{
+ assert(descr);
+ ++descr->refCount;
+}
+
+
+inline
+void Zstring::decRef()
+{
+ assert(descr && descr->refCount >= 1);
+ if (--descr->refCount == 0)
+ {
+ assert(descr); //descr points to the begin of the allocated memory block
+ free(descr); //this must NEVER be changed!! E.g. Trim() relies on descr being start of allocated memory block
+#ifdef __WXDEBUG__
+ --allocCount; //test Zstring for memory leaks
+#endif
+ }
+}
+
+
+#ifdef FFS_WIN
+inline
+int Zstring::CmpNoCase(const defaultChar* other) const
+{
+ return FreeFileSync::compareStringsWin32(c_str(), other); //way faster than wxString::CmpNoCase()!!
+}
+
+
+inline
+int Zstring::CmpNoCase(const Zstring& other) const
+{
+ return FreeFileSync::compareStringsWin32(c_str(), other.c_str()); //way faster than wxString::CmpNoCase()!!
+}
+#endif
+
+
+inline
+Zstring::operator const defaultChar*() const
+{
+ return c_str();
+}
+
+
+inline
+Zstring& Zstring::operator=(const Zstring& source)
+{
+ if (this != &source)
+ {
+ decRef();
+ descr = source.descr;
+ data = source.data;
+ incRef();
+ }
+ return *this;
+}
+
+
+inline
+size_t Zstring::Find(defaultChar ch, bool fromEnd) const
+{
+ if (fromEnd)
+ return rfind(ch, npos);
+ else
+ return find(ch, 0);
+}
+
+
+// get all characters after the last occurence of ch
+// (returns the whole string if ch not found)
+inline
+Zstring Zstring::AfterLast(defaultChar ch) const
+{
+ size_t pos = rfind(ch, npos);
+ if (pos == npos )
+ return *this;
+ else
+ return c_str() + pos + 1;
+}
+
+
+// get all characters before the last occurence of ch
+// (returns empty string if ch not found)
+inline
+Zstring Zstring::BeforeLast(defaultChar ch) const
+{
+ size_t pos = rfind(ch, npos);
+
+ if (pos != npos && pos != 0 )
+ return Zstring(data, pos); //data is non-empty string in this context: else ch would not have been found!
+ else
+ return Zstring();
+}
+
+
+inline
+bool Zstring::StartsWith(const defaultChar* begin) const
+{
+ const size_t beginLength = defaultLength(begin);
+ if (length() < beginLength)
+ return false;
+ return compare(0, beginLength, begin) == 0;
+}
+
+
+inline
+bool Zstring::StartsWith(const Zstring& begin) const
+{
+ const size_t beginLength = begin.length();
+ if (length() < beginLength)
+ return false;
+ return compare(0, beginLength, begin) == 0;
+}
+
+
+inline
+bool Zstring::EndsWith(const defaultChar* end) const
+{
+ const size_t thisLength = length();
+ const size_t endLength = defaultLength(end);
+ if (thisLength < endLength)
+ return false;
+ return compare(thisLength - endLength, endLength, end) == 0;
+}
+
+
+inline
+bool Zstring::EndsWith(const Zstring& end) const
+{
+ const size_t thisLength = length();
+ const size_t endLength = end.length();
+ if (thisLength < endLength)
+ return false;
+ return compare(thisLength - endLength, endLength, end) == 0;
+}
+
+
+inline
+size_t Zstring::find(const defaultChar* str, const size_t pos) const
+{
+ assert(pos <= length());
+ const defaultChar* thisStr = c_str();
+ const defaultChar* found = defaultStrFind(thisStr + pos, str);
+ return found == NULL ? npos : found - thisStr;
+}
+
+
+inline
+size_t Zstring::find(const defaultChar ch, const size_t pos) const
+{
+ assert(pos <= length());
+ const defaultChar* thisStr = c_str();
+ const defaultChar* found = defaultStrFind(thisStr + pos, ch);
+ return found == NULL ? npos : found - thisStr;
+}
+
+
+inline
+Zstring::operator const wxString() const
+{
+ return wxString(c_str());
+}
+
+
+inline
+int Zstring::Cmp(const defaultChar* other) const
+{
+ return compare(other);
+}
+
+
+inline
+int Zstring::Cmp(const Zstring& other) const
+{
+ return defaultCompare(c_str(), other.c_str()); //overload using strcmp(char*, char*) should be fastest!
+}
+
+
+inline
+bool Zstring::operator==(const Zstring& other) const
+{
+ return defaultCompare(c_str(), other.c_str()) == 0; //overload using strcmp(char*, char*) should be fastest!
+}
+
+
+inline
+bool Zstring::operator==(const defaultChar* other) const
+{
+ return compare(other) == 0;
+}
+
+
+inline
+int Zstring::compare(const Zstring& other) const
+{
+ return defaultCompare(c_str(), other.c_str()); //overload using strcmp(char*, char*) should be fastest!
+}
+
+
+inline
+int Zstring::compare(const defaultChar* other) const
+{
+ return defaultCompare(c_str(), other); //overload using strcmp(char*, char*) should be fastest!
+}
+
+
+inline
+int Zstring::compare(const size_t pos1, const size_t n1, const defaultChar* other) const
+{
+ assert(length() - pos1 >= n1);
+ return defaultCompare(c_str() + pos1, other, n1);
+}
+
+
+inline
+size_t Zstring::length() const
+{
+ return descr->length;
+}
+
+
+inline
+const defaultChar* Zstring::c_str() const
+{
+ if (length())
+ return data;
+ else
+#ifdef ZSTRING_CHAR
+ return "";
+#elif defined ZSTRING_WIDE_CHAR
+ return L"";
+#endif
+}
+
+
+inline
+bool Zstring::empty() const
+{
+ return length() == 0;
+}
+
+
+inline
+Zstring Zstring::operator+(const Zstring& string2) const
+{
+ return Zstring(*this)+=string2;
+}
+
+
+inline
+Zstring Zstring::operator+(const defaultChar* string2) const
+{
+ return Zstring(*this)+=string2;
+}
+
+
+inline
+Zstring Zstring::operator+(const defaultChar ch) const
+{
+ return Zstring(*this)+=ch;
+}
+
+
+#endif // ZSTRING_H_INCLUDED
bgstack15