summaryrefslogtreecommitdiff
path: root/shared/zstring.h
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:00:17 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:00:17 +0200
commitfd0853d2623dd278b08288331ed42e3be59252fb (patch)
treea7645daeaef8bdbed064faf4eb88e72cee58726c /shared/zstring.h
parent2.1 (diff)
downloadFreeFileSync-fd0853d2623dd278b08288331ed42e3be59252fb.tar.gz
FreeFileSync-fd0853d2623dd278b08288331ed42e3be59252fb.tar.bz2
FreeFileSync-fd0853d2623dd278b08288331ed42e3be59252fb.zip
2.2
Diffstat (limited to 'shared/zstring.h')
-rw-r--r--shared/zstring.h734
1 files changed, 734 insertions, 0 deletions
diff --git a/shared/zstring.h b/shared/zstring.h
new file mode 100644
index 00000000..0403a00c
--- /dev/null
+++ b/shared/zstring.h
@@ -0,0 +1,734 @@
+/***************************************************************
+ * Purpose: High performance string class
+ * Author: ZenJu (zhnmju123@gmx.de)
+ * Created: Jan. 2009
+ **************************************************************/
+
+#ifndef ZSTRING_H_INCLUDED
+#define ZSTRING_H_INCLUDED
+
+#include <cstring>
+#include <cctype>
+#include <assert.h>
+#include <new>
+#ifdef __WXDEBUG__
+#include <set>
+#endif
+
+
+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, const int aCount = -1, const int bCount = -1);
+#endif //FFS_WIN
+}
+
+
+#ifdef ZSTRING_CHAR
+typedef char DefaultChar; //use char strings
+#elif defined ZSTRING_WIDE_CHAR
+typedef wchar_t DefaultChar; //use wide character strings
+#endif
+
+class Zsubstr;
+
+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();
+
+ operator const DefaultChar*() const; //implicit conversion to C string
+
+ //wxWidgets functions
+ bool StartsWith(const DefaultChar* begin) const;
+ bool StartsWith(const Zstring& begin) const;
+ bool EndsWith(const DefaultChar* end) const;
+ bool EndsWith(const DefaultChar end) const;
+ bool EndsWith(const Zstring& end) const;
+ Zstring& Truncate(size_t newLen);
+#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;
+ Zstring& Replace(const DefaultChar* old, const DefaultChar* replacement, bool replaceAll = true);
+ Zstring AfterLast(DefaultChar ch) const; //returns the whole string if ch not found
+ Zstring BeforeLast(DefaultChar ch) const; //returns empty string if ch not found
+ size_t Find(DefaultChar ch, bool fromEnd) const;
+ bool Matches(const DefaultChar* mask) const;
+ static bool Matches(const DefaultChar* name, const DefaultChar* mask);
+ 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; //allocate new string
+ Zsubstr zsubstr(size_t pos = 0) const; //use ref-counting!
+ bool empty() const;
+ void clear();
+ 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);
+ size_t size() const;
+
+ Zstring& operator=(const Zstring& source);
+ Zstring& operator=(const DefaultChar* source);
+
+ bool operator == (const Zstring& other) const;
+ bool operator == (const DefaultChar* other) const;
+ bool operator < (const Zstring& other) const;
+ bool operator < (const DefaultChar* other) const;
+ bool operator != (const Zstring& other) const;
+ bool operator != (const DefaultChar* other) const;
+
+ const DefaultChar operator[](const size_t pos) const;
+
+ Zstring& operator+=(const Zstring& other);
+ Zstring& operator+=(const DefaultChar* other);
+ Zstring& operator+=(DefaultChar ch);
+
+ const Zstring operator+(const Zstring& string2) const;
+ const Zstring operator+(const DefaultChar* string2) const;
+ const Zstring operator+(const DefaultChar ch) const;
+
+ static const size_t npos = static_cast<size_t>(-1);
+
+private:
+ Zstring(int); //indicates usage error
+
+ void initAndCopy(const DefaultChar* source, size_t length);
+ void incRef() const; //support for reference-counting
+ void decRef(); //
+ void copyBeforeWrite(const size_t capacityNeeded); //and copy-on-write
+
+ struct StringDescriptor
+ {
+ mutable unsigned int refCount;
+ size_t length;
+ size_t capacity; //allocated length without null-termination
+ };
+ static void allocate(const size_t newLength, StringDescriptor*& newDescr, DefaultChar*& newData);
+
+ StringDescriptor* descr;
+ DefaultChar* data;
+};
+
+
+class Zsubstr //ref-counted substring of a Zstring
+{
+public:
+ Zsubstr();
+ Zsubstr(const Zstring& ref, const size_t pos);
+
+ const DefaultChar* c_str() const;
+ size_t length() const;
+ bool StartsWith(const Zstring& begin) const;
+ size_t findFromEnd(const DefaultChar ch) const;
+
+private:
+ Zstring m_ref;
+ const DefaultChar* m_data;
+ size_t m_length;
+};
+
+
+//#######################################################################################
+//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 ((unsigned char)ch < 128) && isspace((unsigned char)ch) != 0;
+}
+
+inline
+char defaultToLower(const char ch)
+{
+ return tolower((unsigned char)ch); //caution: although tolower() has int as input parameter it expects unsigned chars!
+}
+
+#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
+const wchar_t* defaultStrFind(const wchar_t* str1, const wchar_t* str2)
+{
+ return wcsstr(str1, str2);
+}
+
+inline
+const wchar_t* defaultStrFind(const wchar_t* str1, wchar_t 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__
+class AllocationCount //small test for memory leaks in Zstring
+{
+public:
+ void inc(const DefaultChar* object)
+ {
+ activeStrings.insert(object);
+ }
+
+ void dec(const DefaultChar* object)
+ {
+ activeStrings.erase(object);
+ }
+
+ static AllocationCount& getInstance();
+
+private:
+ AllocationCount() {}
+ ~AllocationCount();
+
+ std::set<const DefaultChar*> activeStrings;
+};
+#endif
+
+
+inline
+size_t getCapacityToAllocate(const size_t length)
+{
+ return (length + (19 - length % 16)); //allocate some additional length to speed up concatenation
+}
+
+
+inline
+void Zstring::allocate(const size_t newLength,
+ StringDescriptor*& newDescr,
+ DefaultChar*& newData)
+{ //allocate and set data for new string
+ const size_t newCapacity = getCapacityToAllocate(newLength);
+ assert(newCapacity);
+
+ newDescr = static_cast<StringDescriptor*>(operator new [] (sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(DefaultChar)));
+ newData = reinterpret_cast<DefaultChar*>(newDescr + 1);
+
+ newDescr->refCount = 1;
+ newDescr->length = newLength;
+ newDescr->capacity = newCapacity;
+
+#ifdef __WXDEBUG__
+ AllocationCount::getInstance().inc(newData); //test Zstring for memory leaks
+#endif
+}
+
+
+inline
+Zstring::Zstring()
+{
+ //static (dummy) empty Zstring
+#ifdef ZSTRING_CHAR
+ static Zstring emptyString("");
+#elif defined ZSTRING_WIDE_CHAR
+ static Zstring emptyString(L"");
+#endif
+
+ emptyString.incRef();
+ descr = emptyString.descr;
+ data = emptyString.data;
+}
+
+
+inline
+Zstring::Zstring(const DefaultChar* source)
+{
+ initAndCopy(source, defaultLength(source));
+}
+
+
+inline
+Zstring::Zstring(const DefaultChar* source, size_t sourceLen)
+{
+ initAndCopy(source, sourceLen);
+}
+
+
+inline
+Zstring::Zstring(const Zstring& source)
+{
+ descr = source.descr;
+ data = source.data;
+ incRef(); //reference counting!
+}
+
+
+inline
+Zstring::~Zstring()
+{
+ decRef();
+}
+
+
+inline
+void Zstring::initAndCopy(const DefaultChar* source, size_t sourceLen)
+{
+ allocate(sourceLen, descr, data);
+ memcpy(data, source, sourceLen * sizeof(DefaultChar));
+ data[sourceLen] = 0;
+}
+
+
+inline
+void Zstring::incRef() const
+{
+ assert(descr);
+ ++descr->refCount;
+}
+
+
+inline
+void Zstring::decRef()
+{
+ assert(descr && descr->refCount >= 1); //descr points to the begin of the allocated memory block
+ if (--descr->refCount == 0)
+ {
+ operator delete [] (descr); //this must NEVER be changed!! E.g. Trim() relies on descr being start of allocated memory block
+ descr = NULL;
+#ifdef __WXDEBUG__
+ AllocationCount::getInstance().dec(data); //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(), length(), other.length()); //way faster than wxString::CmpNoCase()!!
+}
+#endif
+
+
+inline
+Zstring::operator const DefaultChar*() const
+{
+ return c_str();
+}
+
+
+inline
+Zstring& Zstring::operator=(const Zstring& source)
+{
+ source.incRef(); //implicitly handle case "this == &source" and avoid this check
+ decRef(); //
+ descr = source.descr;
+ data = source.data;
+
+ 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 DefaultChar end) const
+{
+ const size_t len = length();
+ return len && (this->operator[](len - 1) == end);
+}
+
+
+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
+Zstring& Zstring::Truncate(size_t newLen)
+{
+ if (newLen < length())
+ {
+ if (descr->refCount > 1) //allocate new string
+ return *this = Zstring(c_str(), newLen);
+ else //overwrite this string
+ {
+ descr->length = newLen;
+ data[newLen] = DefaultChar(0);
+ }
+ }
+
+ return *this;
+}
+
+
+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
+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 length() != other.length() ? false : defaultCompare(c_str(), other.c_str()) == 0;
+}
+
+
+inline
+bool Zstring::operator == (const DefaultChar* other) const
+{
+ return defaultCompare(c_str(), other) == 0; //overload using strcmp(char*, char*) should be fastest!
+}
+
+
+inline
+bool Zstring::operator < (const Zstring& other) const
+{
+ return defaultCompare(c_str(), other.c_str()) < 0;
+}
+
+
+inline
+bool Zstring::operator < (const DefaultChar* other) const
+{
+ return defaultCompare(c_str(), other) < 0; //overload using strcmp(char*, char*) should be fastest!
+}
+
+
+inline
+bool Zstring::operator != (const Zstring& other) const
+{
+ return length() != other.length() ? true: defaultCompare(c_str(), other.c_str()) != 0;
+}
+
+
+inline
+bool Zstring::operator != (const DefaultChar* other) const
+{
+ return defaultCompare(c_str(), other) != 0; //overload using strcmp(char*, char*) should be fastest!
+}
+
+
+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
+size_t Zstring::size() const
+{
+ return descr->length;
+}
+
+
+inline
+const DefaultChar* Zstring::c_str() const
+{
+ return data;
+}
+
+
+inline
+bool Zstring::empty() const
+{
+ return descr->length == 0;
+}
+
+
+inline
+void Zstring::clear()
+{
+ *this = Zstring();
+}
+
+
+inline
+const DefaultChar Zstring::operator[](const size_t pos) const
+{
+ assert(pos < length());
+ return data[pos];
+}
+
+
+inline
+const Zstring Zstring::operator+(const Zstring& string2) const
+{
+ return Zstring(*this)+=string2;
+}
+
+
+inline
+const Zstring Zstring::operator+(const DefaultChar* string2) const
+{
+ return Zstring(*this)+=string2;
+}
+
+
+inline
+const Zstring Zstring::operator+(const DefaultChar ch) const
+{
+ return Zstring(*this)+=ch;
+}
+
+//##################### Zsubstr #############################
+inline
+Zsubstr Zstring::zsubstr(size_t pos) const
+{
+ assert(pos <= length());
+ return Zsubstr(*this, pos); //return reference counted string
+}
+
+
+inline
+Zsubstr::Zsubstr()
+{
+ m_data = m_ref.c_str();
+ m_length = 0;
+}
+
+
+inline
+Zsubstr::Zsubstr(const Zstring& ref, const size_t pos) :
+ m_ref(ref),
+ m_data(ref.c_str() + pos),
+ m_length(ref.length() - pos) {}
+
+
+inline
+const DefaultChar* Zsubstr::c_str() const
+{
+ return m_data;
+}
+
+
+inline
+size_t Zsubstr::length() const
+{
+ return m_length;
+}
+
+
+inline
+bool Zsubstr::StartsWith(const Zstring& begin) const
+{
+ const size_t beginLength = begin.length();
+ if (length() < beginLength)
+ return false;
+
+ return defaultCompare(m_data, begin.c_str(), beginLength) == 0;
+}
+
+
+inline
+size_t Zsubstr::findFromEnd(const DefaultChar ch) const
+{
+ size_t pos = length();
+ while (--pos != static_cast<size_t>(-1))
+ {
+ if (m_data[pos] == ch)
+ return pos;
+ }
+ return Zstring::npos;
+}
+
+
+
+#endif // ZSTRING_H_INCLUDED
bgstack15