diff options
Diffstat (limited to 'zen/string_base.h')
-rw-r--r-- | zen/string_base.h | 497 |
1 files changed, 237 insertions, 260 deletions
diff --git a/zen/string_base.h b/zen/string_base.h index 914e0434..ffc2f839 100644 --- a/zen/string_base.h +++ b/zen/string_base.h @@ -12,9 +12,11 @@ #include "string_tools.h" #include <boost/detail/atomic_count.hpp> -//Zbase - a policy based string class +//Zbase - a policy based string class optimizing performance and genericity +namespace zen +{ /* Allocator Policy: ----------------- @@ -28,7 +30,7 @@ public: //::operator new/ ::operator delete show same performance characterisics like malloc()/free()! static void* allocate(size_t size) { return ::operator new(size); } //throw (std::bad_alloc) static void deallocate(void* ptr) { ::operator delete(ptr); } - static size_t calcCapacity(size_t length) { return std::max<size_t>(16, length + length / 2); } + static size_t calcCapacity(size_t length) { return std::max<size_t>(16, length + length / 2); } //any growth rate should not exceed golden ratio: 1.618033989 }; @@ -43,54 +45,54 @@ public: /* 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 Char, //Character Type + class AP> //Allocator Policy + + Char* create(size_t size) + Char* create(size_t size, size_t minCapacity) + Char* clone(Char* ptr) + void destroy(Char* ptr) + bool canWrite(const Char* ptr, size_t minCapacity) //needs to be checked before writing to "ptr" + size_t length(const Char* ptr) + void setLength(Char* ptr, size_t newLength) */ -template <typename T, //Character Type - class AP> //Allocator Policy +template <typename Char, //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) + static Char* create(size_t size) { return create(size, size); } + static Char* create(size_t size, size_t minCapacity) { const size_t newCapacity = AP::calcCapacity(minCapacity); assert(newCapacity >= minCapacity); assert(minCapacity >= size); - Descriptor* const newDescr = static_cast<Descriptor*>(AP::allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(T))); + Descriptor* const newDescr = static_cast<Descriptor*>(AP::allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(Char))); newDescr->length = size; newDescr->capacity = newCapacity; - return reinterpret_cast<T*>(newDescr + 1); + return reinterpret_cast<Char*>(newDescr + 1); } - static T* clone(T* ptr) + static Char* clone(Char* ptr) { - T* newData = create(length(ptr)); + Char* newData = create(length(ptr)); std::copy(ptr, ptr + length(ptr) + 1, newData); return newData; } - static void destroy(T* ptr) { AP::deallocate(descr(ptr)); } + static void destroy(Char* ptr) { AP::deallocate(descr(ptr)); } //this needs to be checked before writing to "ptr" - static bool canWrite(const T* ptr, size_t minCapacity) { return minCapacity <= descr(ptr)->capacity; } - static size_t length(const T* ptr) { return descr(ptr)->length; } + static bool canWrite(const Char* ptr, size_t minCapacity) { return minCapacity <= descr(ptr)->capacity; } + static size_t length(const Char* ptr) { return descr(ptr)->length; } - static void setLength(T* ptr, size_t newLength) + static void setLength(Char* ptr, size_t newLength) { assert(canWrite(ptr, newLength)); descr(ptr)->length = newLength; @@ -103,43 +105,43 @@ private: 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 Descriptor* descr( Char* ptr) { return reinterpret_cast< Descriptor*>(ptr) - 1; } + static const Descriptor* descr(const Char* ptr) { return reinterpret_cast<const Descriptor*>(ptr) - 1; } }; -template <typename T, //Character Type - class AP> //Allocator Policy +template <typename Char, //Character Type + class AP> //Allocator Policy class StorageRefCountThreadSafe : public AP { protected: ~StorageRefCountThreadSafe() {} - static T* create(size_t size) + static Char* create(size_t size) { return create(size, size); } - static T* create(size_t size, size_t minCapacity) + static Char* create(size_t size, size_t minCapacity) { const size_t newCapacity = AP::calcCapacity(minCapacity); assert(newCapacity >= minCapacity); assert(minCapacity >= size); - Descriptor* const newDescr = static_cast<Descriptor*>(AP::allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(T))); + Descriptor* const newDescr = static_cast<Descriptor*>(AP::allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(Char))); new (newDescr) Descriptor(1, size, newCapacity); - return reinterpret_cast<T*>(newDescr + 1); + return reinterpret_cast<Char*>(newDescr + 1); } - static T* clone(T* ptr) + static Char* clone(Char* ptr) { assert(descr(ptr)->refCount > 0); ++descr(ptr)->refCount; return ptr; } - static void destroy(T* ptr) + static void destroy(Char* ptr) { if (--descr(ptr)->refCount == 0) { @@ -148,18 +150,18 @@ protected: } } - static bool canWrite(const T* ptr, size_t minCapacity) //needs to be checked before writing to "ptr" + static bool canWrite(const Char* 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) + static size_t length(const Char* ptr) { return descr(ptr)->length; } - static void setLength(T* ptr, size_t newLength) + static void setLength(Char* ptr, size_t newLength) { assert(canWrite(ptr, newLength)); descr(ptr)->length = newLength; @@ -175,97 +177,99 @@ private: 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 Descriptor* descr( Char* ptr) { return reinterpret_cast< Descriptor*>(ptr) - 1; } + static const Descriptor* descr(const Char* ptr) { return reinterpret_cast<const Descriptor*>(ptr) - 1; } }; //################################################################################################################################################################ //perf note: interstingly StorageDeepCopy and StorageRefCountThreadSafe show same performance in FFS comparison -template <class T, //Character Type +template <class Char, //Character Type template <class, class> class SP = StorageRefCountThreadSafe, //Storage Policy - class AP = AllocatorOptimalSpeed> //Allocator Policy -class Zbase : public SP<T, AP> + class AP = AllocatorOptimalSpeed> //Allocator Policy +class Zbase : public SP<Char, AP> { public: Zbase(); - Zbase(const T* source); //implicit conversion from a C-string - Zbase(const T* source, size_t length); + Zbase(const Char* source); //implicit conversion from a C-string + Zbase(const Char* source, size_t length); Zbase(const Zbase& source); Zbase(Zbase&& tmp); - explicit Zbase(T source); //dangerous if implicit: T buffer[]; Zbase name = buffer; ups... + explicit Zbase(Char source); //dangerous if implicit: Char buffer[]; Zbase name = buffer; ups... //allow explicit construction from different string type, prevent ambiguity via SFINAE template <class S> explicit Zbase(const S& other, typename S::value_type = 0); ~Zbase(); - //operator const T* () const; //NO implicit conversion to a C-string!! Many problems... one of them: if we forget to provide operator overloads, it'll just work with a T*... + //operator const Char* () const; //NO implicit conversion to a C-string!! Many problems... one of them: if we forget to provide operator overloads, it'll just work with a Char*... //STL accessors - typedef T* iterator; - typedef const T* const_iterator; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - const T* begin() const; - const T* end() const; - T* begin(); - T* end(); + typedef Char* iterator; + typedef const Char* const_iterator; + typedef Char& reference; + typedef const Char& const_reference; + typedef Char value_type; + const Char* begin() const; + const Char* end() const; + Char* begin(); + Char* end(); //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; + const Char* c_str() const; //C-string format with NULL-termination + const Char* data() const; //internal representation, NULL-termination not guaranteed + const Char operator[](size_t pos) 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; // - size_t rfind(const T* str, size_t pos = npos) const; // + size_t find (const Zbase& str, size_t pos = 0) const; // + size_t find (const Char* str, size_t pos = 0) const; //returns "npos" if not found + size_t find (Char ch, size_t pos = 0) const; // + size_t rfind(Char ch, size_t pos = npos) const; // + size_t rfind(const Char* str, size_t pos = npos) const; // Zbase& replace(size_t pos1, size_t n1, const Zbase& str); void reserve(size_t minCapacity); - Zbase& assign(const T* source, size_t len); - void resize(size_t newSize, T fillChar = 0); + Zbase& assign(const Char* source, size_t len); + Zbase& append(const Char* source, size_t len); + void resize(size_t newSize, Char fillChar = 0); void swap(Zbase& other); - void push_back(T val); //STL access + void push_back(Char val); //STL access - Zbase& operator=(const Zbase& source); - Zbase& operator=(Zbase&& tmp); - Zbase& operator=(const T* source); - Zbase& operator=(T source); + Zbase& operator=(Zbase source); + Zbase& operator=(const Char* source); + Zbase& operator=(Char source); Zbase& operator+=(const Zbase& other); - Zbase& operator+=(const T* other); - Zbase& operator+=(T ch); + Zbase& operator+=(const Char* other); + Zbase& operator+=(Char ch); static const size_t npos = static_cast<size_t>(-1); private: - Zbase(int); //detect usage errors - Zbase& operator=(int); // + Zbase(int); // + Zbase& operator=(int); //detect usage errors + Zbase& operator+=(int); // + void push_back(int); // - T* rawStr; + Char* 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 Char, template <class, class> class SP, class AP> bool operator==(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs); +template <class Char, template <class, class> class SP, class AP> bool operator==(const Zbase<Char, SP, AP>& lhs, const Char* rhs); +template <class Char, template <class, class> class SP, class AP> bool operator==(const Char* lhs, const Zbase<Char, 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 Char, template <class, class> class SP, class AP> bool operator!=(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs); +template <class Char, template <class, class> class SP, class AP> bool operator!=(const Zbase<Char, SP, AP>& lhs, const Char* rhs); +template <class Char, template <class, class> class SP, class AP> bool operator!=(const Char* lhs, const Zbase<Char, 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 Char, template <class, class> class SP, class AP> bool operator< (const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs); +template <class Char, template <class, class> class SP, class AP> bool operator< (const Zbase<Char, SP, AP>& lhs, const Char* rhs); +template <class Char, template <class, class> class SP, class AP> bool operator< (const Char* lhs, const Zbase<Char, 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); +template <class Char, template <class, class> class SP, class AP> const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs); +template <class Char, template <class, class> class SP, class AP> const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, const Char* rhs); +template <class Char, template <class, class> class SP, class AP> const Zbase<Char, SP, AP> operator+(const Char* lhs, const Zbase<Char, SP, AP>& rhs); +template <class Char, template <class, class> class SP, class AP> const Zbase<Char, SP, AP> operator+( Char lhs, const Zbase<Char, SP, AP>& rhs); +template <class Char, template <class, class> class SP, class AP> const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, Char rhs); @@ -304,8 +308,8 @@ template <class T, template <class, class> class SP, class AP> const Zbase<T, SP //################################# inline implementation ######################################## -template <class T, template <class, class> class SP, class AP> inline -Zbase<T, SP, AP>::Zbase() +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>::Zbase() { //resist the temptation to avoid this allocation by referening a static global: NO performance advantage, MT issues! rawStr = this->create(0); @@ -313,8 +317,8 @@ Zbase<T, SP, AP>::Zbase() } -template <class T, template <class, class> class SP, class AP> inline -Zbase<T, SP, AP>::Zbase(T source) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>::Zbase(Char source) { rawStr = this->create(1); rawStr[0] = source; @@ -322,17 +326,17 @@ Zbase<T, SP, AP>::Zbase(T source) } -template <class T, template <class, class> class SP, class AP> inline -Zbase<T, SP, AP>::Zbase(const T* source) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>::Zbase(const Char* source) { - const size_t sourceLen = zen::strLength(source); + const size_t sourceLen = strLength(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) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>::Zbase(const Char* source, size_t sourceLen) { rawStr = this->create(sourceLen); std::copy(source, source + sourceLen, rawStr); @@ -340,23 +344,23 @@ Zbase<T, SP, AP>::Zbase(const T* source, size_t sourceLen) } -template <class T, template <class, class> class SP, class AP> inline -Zbase<T, SP, AP>::Zbase(const Zbase<T, SP, AP>& source) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>::Zbase(const Zbase<Char, SP, AP>& source) { rawStr = this->clone(source.rawStr); } -template <class T, template <class, class> class SP, class AP> inline -Zbase<T, SP, AP>::Zbase(Zbase<T, SP, AP>&& tmp) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>::Zbase(Zbase<Char, SP, AP>&& tmp) { rawStr = this->clone(tmp.rawStr); //for a ref-counting string there probably isn't a faster way, even with r-value references } -template <class T, template <class, class> class SP, class AP> +template <class Char, template <class, class> class SP, class AP> template <class S> inline -Zbase<T, SP, AP>::Zbase(const S& other, typename S::value_type) +Zbase<Char, SP, AP>::Zbase(const S& other, typename S::value_type) { const size_t sourceLen = other.size(); rawStr = this->create(sourceLen); @@ -365,80 +369,73 @@ Zbase<T, SP, AP>::Zbase(const S& other, typename S::value_type) } -template <class T, template <class, class> class SP, class AP> inline -Zbase<T, SP, AP>::~Zbase() +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>::~Zbase() { this->destroy(rawStr); } -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 +template <class Char, template <class, class> class SP, class AP> inline +size_t Zbase<Char, 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()); + const Char* thisEnd = end(); //respect embedded 0 + const Char* 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 +template <class Char, template <class, class> class SP, class AP> inline +size_t Zbase<Char, SP, AP>::find(const Char* 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 + zen::strLength(str)); + const Char* thisEnd = end(); //respect embedded 0 + const Char* iter = std::search(begin() + pos, thisEnd, + str, str + strLength(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 +template <class Char, template <class, class> class SP, class AP> inline +size_t Zbase<Char, SP, AP>::find(Char ch, size_t pos) const { assert(pos <= length()); - const T* thisEnd = end(); - const T* iter = std::find(begin() + pos, thisEnd, ch); //respect embedded 0 + const Char* thisEnd = end(); + const Char* 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 +template <class Char, template <class, class> class SP, class AP> inline +size_t Zbase<Char, SP, AP>::rfind(Char 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 + const Char* currEnd = pos == npos ? end() : begin() + std::min(pos + 1, length()); - while (rawStr[pos] != ch) //pos points to last char of the string - { - if (pos == 0) - return npos; - --pos; - } - return pos; + const Char* iter = find_last(begin(), currEnd, ch); + return iter == currEnd ? npos : iter - begin(); } -template <class T, template <class, class> class SP, class AP> inline -size_t Zbase<T, SP, AP>::rfind(const T* str, size_t pos) const +template <class Char, template <class, class> class SP, class AP> inline +size_t Zbase<Char, SP, AP>::rfind(const Char* str, size_t pos) const { assert(pos == npos || pos <= length()); - const size_t strLen = zen::strLength(str); - const T* currEnd = pos == npos ? end() : begin() + std::min(pos + strLen, length()); + const size_t strLen = strLength(str); + const Char* currEnd = pos == npos ? end() : begin() + std::min(pos + strLen, length()); - const T* iter = std::find_end(begin(), currEnd, - str, str + strLen); + const Char* iter = search_last(begin(), currEnd, + str, str + strLen); return iter == currEnd ? npos : iter - begin(); } -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 Zbase& str) +template <class Char, template <class, class> class SP, class AP> +Zbase<Char, SP, AP>& Zbase<Char, SP, AP>::replace(size_t pos1, size_t n1, const Zbase& str) { assert(str.data() < rawStr || rawStr + length() < str.data()); //str mustn't point to data in this string assert(pos1 + n1 <= length()); @@ -469,7 +466,7 @@ Zbase<T, SP, AP>& Zbase<T, SP, AP>::replace(size_t pos1, size_t n1, const Zbase& else { //copy directly into new string - T* const newStr = this->create(newLen); + Char* const newStr = this->create(newLen); std::copy(rawStr, rawStr + pos1, newStr); std::copy(str.data(), str.data() + n2, newStr + pos1); @@ -482,8 +479,8 @@ Zbase<T, SP, AP>& Zbase<T, SP, AP>::replace(size_t pos1, size_t n1, const Zbase& } -template <class T, template <class, class> class SP, class AP> inline -void Zbase<T, SP, AP>::resize(size_t newSize, T fillChar) +template <class Char, template <class, class> class SP, class AP> inline +void Zbase<Char, SP, AP>::resize(size_t newSize, Char fillChar) { if (canWrite(rawStr, newSize)) { @@ -494,7 +491,7 @@ void Zbase<T, SP, AP>::resize(size_t newSize, T fillChar) } else { - T* newStr = this->create(newSize); + Char* newStr = this->create(newSize); newStr[newSize] = 0; if (length() < newSize) @@ -511,153 +508,153 @@ void Zbase<T, SP, AP>::resize(size_t newSize, T fillChar) } -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) +template <class Char, template <class, class> class SP, class AP> inline +bool operator==(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, 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) +template <class Char, template <class, class> class SP, class AP> inline +bool operator==(const Zbase<Char, SP, AP>& lhs, const Char* rhs) { - return lhs.length() == zen::strLength(rhs) && std::equal(lhs.begin(), lhs.end(), rhs); //respect embedded 0 + return lhs.length() == strLength(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) +template <class Char, template <class, class> class SP, class AP> inline +bool operator==(const Char* lhs, const Zbase<Char, 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) +template <class Char, template <class, class> class SP, class AP> inline +bool operator!=(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, 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) +template <class Char, template <class, class> class SP, class AP> inline +bool operator!=(const Zbase<Char, SP, AP>& lhs, const Char* 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) +template <class Char, template <class, class> class SP, class AP> inline +bool operator!=(const Char* lhs, const Zbase<Char, 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) +template <class Char, template <class, class> class SP, class AP> inline +bool operator<(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, 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) +template <class Char, template <class, class> class SP, class AP> inline +bool operator<(const Zbase<Char, SP, AP>& lhs, const Char* rhs) { return std::lexicographical_compare(lhs.begin(), lhs.end(), //respect embedded 0 - rhs, rhs + zen::strLength(rhs)); + rhs, rhs + strLength(rhs)); } -template <class T, template <class, class> class SP, class AP> inline -bool operator<(const T* lhs, const Zbase<T, SP, AP>& rhs) +template <class Char, template <class, class> class SP, class AP> inline +bool operator<(const Char* lhs, const Zbase<Char, SP, AP>& rhs) { - return std::lexicographical_compare(lhs, lhs + zen::strLength(lhs), //respect embedded 0 + return std::lexicographical_compare(lhs, lhs + strLength(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 +template <class Char, template <class, class> class SP, class AP> inline +size_t Zbase<Char, SP, AP>::length() const { - return SP<T, AP>::length(rawStr); + return SP<Char, AP>::length(rawStr); } -template <class T, template <class, class> class SP, class AP> inline -size_t Zbase<T, SP, AP>::size() const +template <class Char, template <class, class> class SP, class AP> inline +size_t Zbase<Char, 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 +template <class Char, template <class, class> class SP, class AP> inline +const Char* Zbase<Char, 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 +template <class Char, template <class, class> class SP, class AP> inline +const Char* Zbase<Char, 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 +template <class Char, template <class, class> class SP, class AP> inline +const Char Zbase<Char, 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 +template <class Char, template <class, class> class SP, class AP> inline +const Char* Zbase<Char, 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 +template <class Char, template <class, class> class SP, class AP> inline +const Char* Zbase<Char, SP, AP>::end() const { return rawStr + length(); } -template <class T, template <class, class> class SP, class AP> inline -T* Zbase<T, SP, AP>::begin() +template <class Char, template <class, class> class SP, class AP> inline +Char* Zbase<Char, SP, AP>::begin() { - reserve(length()); + reserve(length()); //make unshared! return rawStr; } -template <class T, template <class, class> class SP, class AP> inline -T* Zbase<T, SP, AP>::end() +template <class Char, template <class, class> class SP, class AP> inline +Char* Zbase<Char, SP, AP>::end() { return begin() + length(); } -template <class T, template <class, class> class SP, class AP> inline -void Zbase<T, SP, AP>::push_back(T val) +template <class Char, template <class, class> class SP, class AP> inline +void Zbase<Char, SP, AP>::push_back(Char val) { operator+=(val); } -template <class T, template <class, class> class SP, class AP> inline -bool Zbase<T, SP, AP>::empty() const +template <class Char, template <class, class> class SP, class AP> inline +bool Zbase<Char, SP, AP>::empty() const { return length() == 0; } -template <class T, template <class, class> class SP, class AP> inline -void Zbase<T, SP, AP>::clear() +template <class Char, template <class, class> class SP, class AP> inline +void Zbase<Char, SP, AP>::clear() { if (!empty()) { @@ -672,55 +669,55 @@ void Zbase<T, SP, AP>::clear() } -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) +template <class Char, template <class, class> class SP, class AP> inline +const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs) { - return Zbase<T, SP, AP>(lhs) += rhs; + return Zbase<Char, 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) +template <class Char, template <class, class> class SP, class AP> inline +const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, const Char* rhs) { - return Zbase<T, SP, AP>(lhs) += rhs; + return Zbase<Char, 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) +template <class Char, template <class, class> class SP, class AP> inline +const Zbase<Char, SP, AP> operator+(const Char* lhs, const Zbase<Char, SP, AP>& rhs) { - return Zbase<T, SP, AP>(lhs) += rhs; + return Zbase<Char, 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) +template <class Char, template <class, class> class SP, class AP> inline +const Zbase<Char, SP, AP> operator+(Char lhs, const Zbase<Char, SP, AP>& rhs) { - return (Zbase<T, SP, AP>() += lhs) += rhs; + return Zbase<Char, 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) +template <class Char, template <class, class> class SP, class AP> inline +const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, Char rhs) { - return Zbase<T, SP, AP>(lhs) += rhs; + return Zbase<Char, 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) +template <class Char, template <class, class> class SP, class AP> inline +void Zbase<Char, SP, AP>::swap(Zbase<Char, SP, AP>& other) { std::swap(rawStr, other.rawStr); } -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 +template <class Char, template <class, class> class SP, class AP> inline +void Zbase<Char, 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! + Char* 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); @@ -729,8 +726,8 @@ void Zbase<T, SP, AP>::reserve(size_t minCapacity) //make unshared and check cap } -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) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>& Zbase<Char, SP, AP>::assign(const Char* source, size_t len) { if (canWrite(rawStr, len)) { @@ -745,80 +742,60 @@ Zbase<T, SP, AP>& Zbase<T, SP, AP>::assign(const T* source, size_t len) } -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) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>& Zbase<Char, SP, AP>::append(const Char* source, size_t len) { - Zbase(source).swap(*this); + const size_t thisLen = length(); + reserve(thisLen + len); //make unshared and check capacity + + std::copy(source, source + len, rawStr + thisLen); + rawStr[thisLen + len] = 0; + setLength(rawStr, thisLen + len); return *this; } -template <class T, template <class, class> class SP, class AP> inline -Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator=(Zbase<T, SP, AP>&& tmp) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>& Zbase<Char, SP, AP>::operator=(Zbase<Char, SP, AP> other) //unifying assignment: no need for r-value reference optimization! { - swap(tmp); + swap(other); 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) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>& Zbase<Char, SP, AP>::operator=(const Char* source) { - return assign(source, zen::strLength(source)); + return assign(source, strLength(source)); } -template <class T, template <class, class> class SP, class AP> inline -Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator=(T source) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>& Zbase<Char, SP, AP>::operator=(Char ch) { - if (canWrite(rawStr, 1)) - { - rawStr[0] = source; - rawStr[1] = 0; //include null-termination - setLength(rawStr, 1); - } - else - *this = Zbase(source); - - return *this; + return assign(&ch, 1); } -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) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>& Zbase<Char, SP, AP>::operator+=(const Zbase<Char, 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; + return append(other.c_str(), other.length()); } -template <class T, template <class, class> class SP, class AP> inline -Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator+=(const T* other) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>& Zbase<Char, SP, AP>::operator+=(const Char* other) { - const size_t thisLen = length(); - const size_t otherLen = zen::strLength(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; + return append(other, strLength(other)); } -template <class T, template <class, class> class SP, class AP> inline -Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator+=(T ch) +template <class Char, template <class, class> class SP, class AP> inline +Zbase<Char, SP, AP>& Zbase<Char, SP, AP>::operator+=(Char 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; + return append(&ch, 1); +} } #endif //Z_BASE_H_INCLUDED |