From 669df123648aaa6aeccc70206b5417bc48b4e9ae Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Fri, 18 Apr 2014 17:26:50 +0200 Subject: 5.19 --- zen/string_base.h | 61 ++++++++++++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 37 deletions(-) (limited to 'zen/string_base.h') diff --git a/zen/string_base.h b/zen/string_base.h index 591ed62b..31a09e63 100644 --- a/zen/string_base.h +++ b/zen/string_base.h @@ -21,7 +21,7 @@ namespace zen Allocator Policy: ----------------- void* allocate(size_t size) //throw std::bad_alloc - void deallocate(void* ptr) + void deallocate(void* ptr) //must handle deallocate(nullptr)! size_t calcCapacity(size_t length) */ class AllocatorOptimalSpeed //exponential growth + min size @@ -30,8 +30,9 @@ 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(std::max(16, length), length + length / 2); } //size_t might overflow! - //any growth rate should not exceed golden ratio: 1.618033989 + static size_t calcCapacity(size_t length) { return std::max(16, std::max(length + length / 2, length)); } + //- size_t might overflow! => better catch here than return a too small size covering up the real error: a way too large length! + //- any growth rate should not exceed golden ratio: 1.618033989 }; @@ -52,7 +53,7 @@ template capacity; } @@ -141,6 +142,7 @@ protected: static void destroy(Char* ptr) { + if (!ptr) return; //support destroy(nullptr) assert(descr(ptr)->refCount > 0); if (--descr(ptr)->refCount == 0) //operator--() is overloaded to decrement and evaluate in a single atomic operation! { @@ -251,7 +253,7 @@ public: private: Zbase(int); // - Zbase& operator=(int); //detect usage errors + Zbase& operator=(int); //detect usage errors by creating an intentional ambiguity with "Char" Zbase& operator+=(int); // void push_back(int); // @@ -292,15 +294,6 @@ template class SP, class AP> inline Zbase::Zbase(const Zbase& source) template class SP, class AP> inline Zbase::Zbase(Zbase&& tmp) { - if (this->canWrite(tmp.rawStr, 0)) //perf: following optimization saves about 4% - { - //do not increment ref-count of an unshared string! We'd lose optimization opportunity of reusing its memory! - //instead create a dummy string and swap: - rawStr = this->create(0); //no perf issue! see comment in default constructor - rawStr[0] = 0; - swap(tmp); - } - else //shared representation: yet another "add ref" won't hurt - rawStr = this->clone(tmp.rawStr); + rawStr = tmp.rawStr; + tmp.rawStr = nullptr; //usually nullptr would violate the class invarants, but it is good enough for the destructor! + //caveat: do not increment ref-count of an unshared string! We'd lose optimization opportunity of reusing its memory! } @@ -388,7 +374,7 @@ Zbase::Zbase(const S& other, typename S::value_type) template class SP, class AP> inline Zbase::~Zbase() { - this->destroy(rawStr); + this->destroy(rawStr); //rawStr may be nullptr; see move constructor! } @@ -499,25 +485,25 @@ Zbase& Zbase::replace(size_t pos1, size_t n1, const template class SP, class AP> inline void Zbase::resize(size_t newSize, Char fillChar) { + const size_t oldSize = length(); if (this->canWrite(rawStr, newSize)) { - if (length() < newSize) - std::fill(rawStr + length(), rawStr + newSize, fillChar); + if (oldSize < newSize) + std::fill(rawStr + oldSize, rawStr + newSize, fillChar); rawStr[newSize] = 0; - this->setLength(rawStr, newSize); //keep after call to length() + this->setLength(rawStr, newSize); } else { Char* newStr = this->create(newSize); - newStr[newSize] = 0; - - if (length() < newSize) + if (oldSize < newSize) { - std::copy(rawStr, rawStr + length(), newStr); - std::fill(newStr + length(), newStr + newSize, fillChar); + std::copy(rawStr, rawStr + oldSize, newStr); + std::fill(newStr + oldSize, newStr + newSize, fillChar); } else std::copy(rawStr, rawStr + newSize, newStr); + newStr[newSize] = 0; this->destroy(rawStr); rawStr = newStr; @@ -614,7 +600,7 @@ void Zbase::clear() { if (this->canWrite(rawStr, 0)) { - rawStr[0] = 0; //keep allocated memory + rawStr[0] = 0; //keep allocated memory this->setLength(rawStr, 0); // } else @@ -636,8 +622,9 @@ void Zbase::reserve(size_t minCapacity) //make unshared and check if (!this->canWrite(rawStr, minCapacity)) { //allocate a new string - Char* newStr = this->create(length(), std::max(minCapacity, length())); //reserve() must NEVER shrink the string: logical const! - std::copy(rawStr, rawStr + length() + 1, newStr); //include 0-termination + const size_t len = length(); + Char* newStr = this->create(len, std::max(len, minCapacity)); //reserve() must NEVER shrink the string: logical const! + std::copy(rawStr, rawStr + len + 1, newStr); //include 0-termination this->destroy(rawStr); rawStr = newStr; -- cgit