diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:08:42 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:08:42 +0200 |
commit | c32707148292d104c66276b43796d6057c8c7a5d (patch) | |
tree | bb83513f4aff24153e21a4ec92e34e4c27651b1f /shared/zbase.h | |
parent | 3.9 (diff) | |
download | FreeFileSync-c32707148292d104c66276b43796d6057c8c7a5d.tar.gz FreeFileSync-c32707148292d104c66276b43796d6057c8c7a5d.tar.bz2 FreeFileSync-c32707148292d104c66276b43796d6057c8c7a5d.zip |
3.10
Diffstat (limited to 'shared/zbase.h')
-rw-r--r-- | shared/zbase.h | 1162 |
1 files changed, 1162 insertions, 0 deletions
diff --git a/shared/zbase.h b/shared/zbase.h new file mode 100644 index 00000000..efaa103c --- /dev/null +++ b/shared/zbase.h @@ -0,0 +1,1162 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** +// +#ifndef Z_BASE_H_INCLUDED +#define Z_BASE_H_INCLUDED + +#include <cstddef> //size_t +#include <cctype> //isspace +#include <cwctype> //iswspace +#include <cassert> +#include <vector> +#include <sstream> +#include <algorithm> + + +/* +Allocator Policy: +----------------- + void* allocate(size_t size) //throw (std::bad_alloc) + void deallocate(void* ptr) +*/ +class AllocatorFreeStore //same performance characterisics like malloc()/free() +{ +public: + static void* allocate(size_t size) //throw (std::bad_alloc) + { + return ::operator new(size); + } + + static void deallocate(void* ptr) + { + ::operator delete(ptr); + } +}; + + +/* +Storage Policy: +--------------- +template <typename T, //Character Type + class AP> //Allocator Policy + + T* create(size_t size) + T* create(size_t size, size_t minCapacity) + T* clone(T* ptr) + void destroy(T* ptr) + bool canWrite(const T* ptr, size_t minCapacity) //needs to be checked before writing to "ptr" + size_t length(const T* ptr) + void setLength(T* ptr, size_t newLength) +*/ + +template <typename T, //Character Type + class AP> //Allocator Policy +class StorageDeepCopy : public AP +{ +protected: + ~StorageDeepCopy() {} + + static T* create(size_t size) + { + return create(size, size); + } + + static T* create(size_t size, size_t minCapacity) + { + const size_t newCapacity = calcCapacity(minCapacity); + assert(newCapacity >= minCapacity); + assert(minCapacity >= size); + + Descriptor* const newDescr = static_cast<Descriptor*>(AP::allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(T))); + + newDescr->length = size; + newDescr->capacity = newCapacity; + + return reinterpret_cast<T*>(newDescr + 1); + } + + static T* clone(T* ptr) + { + T* newData = create(length(ptr)); + std::copy(ptr, ptr + length(ptr) + 1, newData); + return newData; + } + + static void destroy(T* ptr) + { + AP::deallocate(descr(ptr)); + } + + static bool canWrite(const T* ptr, size_t minCapacity) //needs to be checked before writing to "ptr" + { + return minCapacity <= descr(ptr)->capacity; + } + + static size_t length(const T* ptr) + { + return descr(ptr)->length; + } + + static void setLength(T* ptr, size_t newLength) + { + assert(canWrite(ptr, newLength)); + descr(ptr)->length = newLength; + } + +private: + struct Descriptor + { + size_t length; + size_t capacity; //allocated size without null-termination + }; + + static Descriptor* descr(T* ptr) + { + return reinterpret_cast<Descriptor*>(ptr) - 1; + } + + static const Descriptor* descr(const T* ptr) + { + return reinterpret_cast<const Descriptor*>(ptr) - 1; + } + + static size_t calcCapacity(size_t length) + { + return (length + (19 - length % 16)); //allocate some additional length to speed up concatenation + } +}; + + +template <typename T, //Character Type + class AP> //Allocator Policy +class StorageRefCount : public AP +{ +protected: + ~StorageRefCount() {} + + static T* create(size_t size) + { + return create(size, size); + } + + static T* create(size_t size, size_t minCapacity) + { + const size_t newCapacity = calcCapacity(minCapacity); + assert(newCapacity >= minCapacity); + assert(minCapacity >= size); + + Descriptor* const newDescr = static_cast<Descriptor*>(AP::allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(T))); + + newDescr->refCount = 1; + newDescr->length = size; + newDescr->capacity = newCapacity; + + return reinterpret_cast<T*>(newDescr + 1); + } + + static T* clone(T* ptr) + { + assert(descr(ptr)->refCount > 0); + ++descr(ptr)->refCount; + return ptr; + } + + static void destroy(T* ptr) + { + if (--descr(ptr)->refCount == 0) + AP::deallocate(descr(ptr)); + } + + static bool canWrite(const T* ptr, size_t minCapacity) //needs to be checked before writing to "ptr" + { + assert(descr(ptr)->refCount > 0); + return descr(ptr)->refCount == 1 && minCapacity <= descr(ptr)->capacity; + } + + static size_t length(const T* ptr) + { + return descr(ptr)->length; + } + + static void setLength(T* ptr, size_t newLength) + { + assert(canWrite(ptr, newLength)); + descr(ptr)->length = newLength; + } + +private: + struct Descriptor + { + size_t refCount; + size_t length; + size_t capacity; //allocated size without null-termination + }; + + static Descriptor* descr(T* ptr) + { + return reinterpret_cast<Descriptor*>(ptr) - 1; + } + + static const Descriptor* descr(const T* ptr) + { + return reinterpret_cast<const Descriptor*>(ptr) - 1; + } + + static size_t calcCapacity(size_t length) + { + return (length + (19 - length % 16)); //allocate some additional length to speed up concatenation + } +}; + + +template <class T, //Character Type + template <class, class> class SP = StorageRefCount, //Storage Policy + class AP = AllocatorFreeStore> //Allocator Policy +class Zbase : public SP<T, AP> +{ +public: + Zbase(); + Zbase(T source); + Zbase(const T* source); + Zbase(const T* source, size_t length); + Zbase(const Zbase& source); + ~Zbase(); + + operator const T*() const; //implicit conversion to C-string + + //STL accessors + const T* begin() const; + const T* end() const; + T* begin(); + T* end(); + + //wxString-like functions + bool StartsWith(const Zbase& prefix) const; + bool StartsWith(const T* prefix) const; + bool StartsWith(T prefix) const; + bool EndsWith(const Zbase& postfix) const; + bool EndsWith(const T* postfix) const; + bool EndsWith(T postfix) const; + Zbase& Truncate(size_t newLen); + Zbase& Replace(const T* old, const T* replacement, bool replaceAll = true); + Zbase AfterLast( T ch) const; //returns the whole string if "ch" not found + Zbase BeforeLast( T ch) const; //returns empty string if "ch" not found + Zbase AfterFirst( T ch) const; //returns empty string if "ch" not found + Zbase BeforeFirst(T ch) const; //returns the whole string if "ch" not found + Zbase& Trim(bool fromLeft = true, bool fromRight = true); + std::vector<Zbase> Split(T delimiter) const; + + //std::string functions + size_t length() const; + size_t size() const; + const T* c_str() const; //C-string format with NULL-termination + const T* data() const; //internal representation, NULL-termination not guaranteed + const T operator[](size_t pos) const; + Zbase substr(size_t pos = 0, size_t len = npos) const; + bool empty() const; + void clear(); + size_t find(const Zbase& str, size_t pos = 0) const; // + size_t find(const T* str, size_t pos = 0) const; //returns "npos" if not found + size_t find(T ch, size_t pos = 0) const; // + size_t rfind(T ch, size_t pos = npos) const; // + Zbase& replace(size_t pos1, size_t n1, const T* str, size_t n2); + void reserve(size_t minCapacity); + Zbase& assign(const T* source, size_t len); + void resize(size_t newSize, T fillChar = 0); + void swap(Zbase& other); + + //number conversion + template <class N> static Zbase fromNumber(N number); + template <class N> N toNumber() const; + + Zbase& operator=(const Zbase& source); + Zbase& operator=(const T* source); + Zbase& operator=(T source); + Zbase& operator+=(const Zbase& other); + Zbase& operator+=(const T* other); + Zbase& operator+=(T ch); + + static const size_t npos = static_cast<size_t>(-1); + +private: + Zbase(int); //detect usage errors + Zbase& operator=(int); // + + T* rawStr; +}; + +template <class T, template <class, class> class SP, class AP> bool operator==(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> bool operator==(const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> bool operator==(const T* lhs, const Zbase<T, SP, AP>& rhs); + +template <class T, template <class, class> class SP, class AP> bool operator!=(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> bool operator!=(const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> bool operator!=(const T* lhs, const Zbase<T, SP, AP>& rhs); + +template <class T, template <class, class> class SP, class AP> bool operator< (const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> bool operator< (const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> bool operator< (const T* lhs, const Zbase<T, SP, AP>& rhs); + +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const T* lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+( T lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, T rhs); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +//################################# inline implementation ######################################## +namespace z_impl +{ +//-------------C-string helper functions --------------------------------------------------------- +template <class T> +inline +size_t cStringLength(const T* input) //strlen() +{ + const T* iter = input; + while (*iter != 0) + ++iter; + return iter - input; +} +} + + +//-------------------------------------------------------------------------------------------------- +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::Zbase() +{ + //resist the temptation to avoid this allocation by referening a static global: NO performance advantage, MT issues! + rawStr = this->create(0); + rawStr[0] = 0; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::Zbase(T source) +{ + rawStr = this->create(1); + rawStr[0] = source; + rawStr[1] = 0; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::Zbase(const T* source) +{ + const size_t sourceLen = z_impl::cStringLength(source); + rawStr = this->create(sourceLen); + std::copy(source, source + sourceLen + 1, rawStr); //include null-termination +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::Zbase(const T* source, size_t sourceLen) +{ + rawStr = this->create(sourceLen); + std::copy(source, source + sourceLen, rawStr); + rawStr[sourceLen] = 0; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::Zbase(const Zbase<T, SP, AP>& source) +{ + rawStr = this->clone(source.rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::~Zbase() +{ + this->destroy(rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::operator const T*() const +{ + return rawStr; +} + + +// get all characters after the last occurence of ch +// (returns the whole string if ch not found) +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::AfterLast(T ch) const +{ + const size_t pos = rfind(ch, npos); + if (pos != npos ) + return Zbase(rawStr + pos + 1, length() - pos - 1); + else + return *this; +} + + +// get all characters before the last occurence of ch +// (returns empty string if ch not found) +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::BeforeLast(T ch) const +{ + const size_t pos = rfind(ch, npos); + if (pos != npos) + return Zbase(rawStr, pos); //data is non-empty string in this context: else ch would not have been found! + else + return Zbase(); +} + + +//returns empty string if ch not found +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::AfterFirst(T ch) const +{ + const size_t pos = find(ch, 0); + if (pos != npos) + return Zbase(rawStr + pos + 1, length() - pos - 1); + else + return Zbase(); + +} + +//returns the whole string if ch not found +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::BeforeFirst(T ch) const +{ + const size_t pos = find(ch, 0); + if (pos != npos) + return Zbase(rawStr, pos); //data is non-empty string in this context: else ch would not have been found! + else + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::StartsWith(const T* prefix) const +{ + const size_t pfLength = z_impl::cStringLength(prefix); + if (length() < pfLength) + return false; + + return std::equal(rawStr, rawStr + pfLength, + prefix); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::StartsWith(T prefix) const +{ + return length() != 0 && operator[](0) == prefix; +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::StartsWith(const Zbase<T, SP, AP>& prefix) const +{ + if (length() < prefix.length()) + return false; + + return std::equal(rawStr, rawStr + prefix.length(), + prefix.rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::EndsWith(const T* postfix) const +{ + const size_t pfLength = z_impl::cStringLength(postfix); + if (length() < pfLength) + return false; + + const T* cmpBegin = rawStr + length() - pfLength; + return std::equal(cmpBegin, cmpBegin + pfLength, + postfix); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::EndsWith(T postfix) const +{ + const size_t len = length(); + return len != 0 && operator[](len - 1) == postfix; +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::EndsWith(const Zbase<T, SP, AP>& postfix) const +{ + if (length() < postfix.length()) + return false; + + const T* cmpBegin = rawStr + length() - postfix.length(); + return std::equal(cmpBegin, cmpBegin + postfix.length(), + postfix.rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::Truncate(size_t newLen) +{ + if (newLen < length()) + { + if (canWrite(rawStr, newLen)) + { + rawStr[newLen] = 0; + setLength(rawStr, newLen); + } + else + *this = Zbase(rawStr, newLen); + } + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::find(const Zbase& str, size_t pos) const +{ + assert(pos <= length()); + const T* thisEnd = end(); //respect embedded 0 + const T* iter = std::search(begin() + pos, thisEnd, + str.begin(), str.end()); + return iter == thisEnd ? npos : iter - begin(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::find(const T* str, size_t pos) const +{ + assert(pos <= length()); + const T* thisEnd = end(); //respect embedded 0 + const T* iter = std::search(begin() + pos, thisEnd, + str, str + z_impl::cStringLength(str)); + return iter == thisEnd ? npos : iter - begin(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::find(T ch, size_t pos) const +{ + assert(pos <= length()); + const T* thisEnd = end(); + const T* iter = std::find(begin() + pos, thisEnd, ch); //respect embedded 0 + return iter == thisEnd ? npos : iter - begin(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::rfind(T ch, size_t pos) const +{ + assert(pos == npos || pos <= length()); + + const size_t thisLen = length(); + if (thisLen == 0) return npos; + pos = std::min(thisLen - 1, pos); //handle "npos" and "pos == length()" implicitly + + while (rawStr[pos] != ch) //pos points to last char of the string + { + if (pos == 0) + return npos; + --pos; + } + return pos; +} + + +template <class T, template <class, class> class SP, class AP> +Zbase<T, SP, AP>& Zbase<T, SP, AP>::replace(size_t pos1, size_t n1, const T* str, size_t n2) +{ + assert(str < rawStr || rawStr + length() < str); //str mustn't point to data in this string + assert(pos1 + n1 <= length()); + + const size_t oldLen = length(); + if (oldLen == 0) + return *this = Zbase(str, n2); + + const size_t newLen = oldLen - n1 + n2; + + if (canWrite(rawStr, newLen)) + { + if (n1 < n2) //move remainder right -> std::copy_backward + { + std::copy_backward(rawStr + pos1 + n1, rawStr + oldLen + 1, rawStr + newLen + 1); //include null-termination + setLength(rawStr, newLen); + } + else if (n1 > n2) //shift left -> std::copy + { + std::copy(rawStr + pos1 + n1, rawStr + oldLen + 1, rawStr + pos1 + n2); //include null-termination + setLength(rawStr, newLen); + } + + std::copy(str, str + n2, rawStr + pos1); + } + else + { + //copy directly into new string + T* const newStr = this->create(newLen); + + std::copy(rawStr, rawStr + pos1, newStr); + std::copy(str, str + n2, newStr + pos1); + std::copy(rawStr + pos1 + n1, rawStr + oldLen + 1, newStr + pos1 + n2); //include null-termination + + destroy(rawStr); + rawStr = newStr; + } + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::Replace(const T* old, const T* replacement, bool replaceAll) +{ + const size_t oldLen = z_impl::cStringLength(old); + const size_t replacementLen = z_impl::cStringLength(replacement); + + size_t pos = 0; + while ((pos = find(old, pos)) != npos) + { + replace(pos, oldLen, replacement, replacementLen); + pos += replacementLen; //move past the string that was replaced + + if (!replaceAll) + break; + } + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +void Zbase<T, SP, AP>::resize(size_t newSize, T fillChar) +{ + if (canWrite(rawStr, newSize)) + { + if (length() < newSize) + std::fill(rawStr + length(), rawStr + newSize, fillChar); + rawStr[newSize] = 0; + setLength(rawStr, newSize); //keep after call to length() + } + else + { + T* newStr = this->create(newSize); + newStr[newSize] = 0; + + if (length() < newSize) + { + std::copy(rawStr, rawStr + length(), newStr); + std::fill(newStr + length(), newStr + newSize, fillChar); + } + else + std::copy(rawStr, rawStr + newSize, newStr); + + destroy(rawStr); + rawStr = newStr; + } +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator==(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) +{ + return lhs.length() == rhs.length() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); //respect embedded 0 +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator==(const Zbase<T, SP, AP>& lhs, const T* rhs) +{ + return lhs.length() == z_impl::cStringLength(rhs) && std::equal(lhs.begin(), lhs.end(), rhs); //respect embedded 0 +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator==(const T* lhs, const Zbase<T, SP, AP>& rhs) +{ + return operator==(rhs, lhs); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator!=(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) +{ + return !operator==(lhs, rhs); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator!=(const Zbase<T, SP, AP>& lhs, const T* rhs) +{ + return !operator==(lhs, rhs); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator!=(const T* lhs, const Zbase<T, SP, AP>& rhs) +{ + return !operator==(lhs, rhs); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator<(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) +{ + return std::lexicographical_compare(lhs.begin(), lhs.end(), //respect embedded 0 + rhs.begin(), rhs.end()); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator<(const Zbase<T, SP, AP>& lhs, const T* rhs) +{ + return std::lexicographical_compare(lhs.begin(), lhs.end(), //respect embedded 0 + rhs, rhs + z_impl::cStringLength(rhs)); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator<(const T* lhs, const Zbase<T, SP, AP>& rhs) +{ + return std::lexicographical_compare(lhs, lhs + z_impl::cStringLength(lhs), //respect embedded 0 + rhs.begin(), rhs.end()); +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::length() const +{ + return SP<T, AP>::length(rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::size() const +{ + return length(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +const T* Zbase<T, SP, AP>::c_str() const +{ + return rawStr; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const T* Zbase<T, SP, AP>::data() const +{ + return rawStr; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const T Zbase<T, SP, AP>::operator[](size_t pos) const +{ + assert(pos < length()); + return rawStr[pos]; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const T* Zbase<T, SP, AP>::begin() const +{ + return rawStr; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const T* Zbase<T, SP, AP>::end() const +{ + return rawStr + length(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +T* Zbase<T, SP, AP>::begin() +{ + reserve(length()); + return rawStr; +} + + +template <class T, template <class, class> class SP, class AP> +inline +T* Zbase<T, SP, AP>::end() +{ + return begin() + length(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::empty() const +{ + return length() == 0; +} + + +template <class T, template <class, class> class SP, class AP> +inline +void Zbase<T, SP, AP>::clear() +{ + if (!empty()) + { + if (canWrite(rawStr, 0)) + { + rawStr[0] = 0; //keep allocated memory + setLength(rawStr, 0); // + } + else + *this = Zbase(); + } +} + + +template <class T, template <class, class> class SP, class AP> +inline +const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) +{ + return Zbase<T, SP, AP>(lhs) += rhs; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const T* rhs) +{ + return Zbase<T, SP, AP>(lhs) += rhs; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const Zbase<T, SP, AP> operator+(const T* lhs, const Zbase<T, SP, AP>& rhs) +{ + return Zbase<T, SP, AP>(lhs) += rhs; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const Zbase<T, SP, AP> operator+(T lhs, const Zbase<T, SP, AP>& rhs) +{ + return Zbase<T, SP, AP>(lhs) += rhs; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, T rhs) +{ + return Zbase<T, SP, AP>(lhs) += rhs; +} + + +template <class T, template <class, class> class SP, class AP> +inline +void Zbase<T, SP, AP>::swap(Zbase<T, SP, AP>& other) +{ + std::swap(rawStr, other.rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::substr(size_t pos, size_t len) const +{ + assert(pos + (len == npos ? 0 : len) <= length()); + return Zbase(rawStr + pos, len == npos ? length() - pos : len); +} + + +template <class T, template <class, class> class SP, class AP> +inline +void Zbase<T, SP, AP>::reserve(size_t minCapacity) //make unshared and check capacity +{ + if (!canWrite(rawStr, minCapacity)) + { + //allocate a new string + T* newStr = create(length(), std::max(minCapacity, length())); //reserve() must NEVER shrink the string: logical const! + std::copy(rawStr, rawStr + length() + 1, newStr); //include NULL-termination + + destroy(rawStr); + rawStr = newStr; + } +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::assign(const T* source, size_t len) +{ + if (canWrite(rawStr, len)) + { + std::copy(source, source + len, rawStr); + rawStr[len] = 0; //include null-termination + setLength(rawStr, len); + } + else + *this = Zbase(source, len); + + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator=(const Zbase<T, SP, AP>& source) +{ + Zbase(source).swap(*this); + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator=(const T* source) +{ + return assign(source, z_impl::cStringLength(source)); +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator=(T source) +{ + if (canWrite(rawStr, 1)) + { + rawStr[0] = source; + rawStr[1] = 0; //include null-termination + setLength(rawStr, 1); + } + else + *this = Zbase(source); + + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator+=(const Zbase<T, SP, AP>& other) +{ + const size_t thisLen = length(); + const size_t otherLen = other.length(); + reserve(thisLen + otherLen); //make unshared and check capacity + + std::copy(other.rawStr, other.rawStr + otherLen + 1, rawStr + thisLen); //include null-termination + setLength(rawStr, thisLen + otherLen); + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator+=(const T* other) +{ + const size_t thisLen = length(); + const size_t otherLen = z_impl::cStringLength(other); + reserve(thisLen + otherLen); //make unshared and check capacity + + std::copy(other, other + otherLen + 1, rawStr + thisLen); //include null-termination + setLength(rawStr, thisLen + otherLen); + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator+=(T ch) +{ + const size_t thisLen = length(); + reserve(thisLen + 1); //make unshared and check capacity + rawStr[thisLen] = ch; + rawStr[thisLen + 1] = 0; + setLength(rawStr, thisLen + 1); + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +template <class N> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::fromNumber(N number) +{ + std::basic_ostringstream<T> ss; + ss << number; + return Zbase<T, SP, AP>(ss.str().c_str()); +} + + +template <class T, template <class, class> class SP, class AP> +template <class N> +inline +N Zbase<T, SP, AP>::toNumber() const +{ + std::basic_istringstream<T> ss(std::basic_string<T>(rawStr)); + T number = 0; + ss >> number; + return number; +} + + +namespace z_impl +{ +template <class T> +bool cStringWhiteSpace(T ch); + +template <> +inline +bool cStringWhiteSpace(char ch) +{ + return std::isspace(static_cast<unsigned char>(ch)) != 0; //some compilers (e.g. VC++ 6.0) return true for a call to isspace('\xEA'); but no issue with newer versions of MSVC +} + + +template <> +inline +bool cStringWhiteSpace(wchar_t ch) +{ + return std::iswspace(ch) != 0; //some compilers (e.g. VC++ 6.0) return true for a call to isspace('\xEA'); but no issue with newer versions of MSVC +} +} + + +template <class T, template <class, class> class SP, class AP> +Zbase<T, SP, AP>& Zbase<T, SP, AP>::Trim(bool fromLeft, bool fromRight) +{ + assert(fromLeft || fromRight); + + const T* newBegin = rawStr; + const T* newEnd = rawStr + length(); + + if (fromRight) + while (newBegin != newEnd && z_impl::cStringWhiteSpace(newEnd[-1])) + --newEnd; + + if (fromLeft) + while (newBegin != newEnd && z_impl::cStringWhiteSpace(*newBegin)) + ++newBegin; + + const size_t newLength = newEnd - newBegin; + if (newLength != length()) + { + if (canWrite(rawStr, newLength)) + { + std::copy(newBegin, newBegin + newLength, rawStr); //shift left => std::copy, shift right std::copy_backward + rawStr[newLength] = 0; + setLength(rawStr, newLength); + } + else + *this = Zbase(newBegin, newLength); + } + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +std::vector<Zbase<T, SP, AP> > Zbase<T, SP, AP>::Split(T delimiter) const +{ + std::vector<Zbase> output; + + const size_t thisLen = length(); + size_t startPos = 0; + for (;;) //make MSVC happy + { + size_t endPos = find(delimiter, startPos); + if (endPos == npos) + endPos = thisLen; + + if (startPos != endPos) //do not add empty strings + { + Zbase newEntry = substr(startPos, endPos - startPos); + newEntry.Trim(); //remove whitespace characters + + if (!newEntry.empty()) + output.push_back(newEntry); + } + if (endPos == thisLen) + break; + + startPos = endPos + 1; //skip delimiter + } + + return output; +} + + +#endif //Z_BASE_H_INCLUDED |