From 8a27fa9c617533e76673ce61a65e2ba869b52208 Mon Sep 17 00:00:00 2001 From: B Stack Date: Mon, 31 Aug 2020 20:07:13 -0400 Subject: add upstream 11.1 --- zen/string_base.h | 64 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 25 deletions(-) (limited to 'zen/string_base.h') diff --git a/zen/string_base.h b/zen/string_base.h index 615c7d2c..1052de56 100644 --- a/zen/string_base.h +++ b/zen/string_base.h @@ -8,23 +8,19 @@ #define STRING_BASE_H_083217454562342526 #include -#include -#include #include - #include #include "string_tools.h" + //Zbase - a policy based string class optimizing performance and flexibility namespace zen { -/* -Allocator Policy: ------------------ +/* Allocator Policy: + ----------------- void* allocate(size_t size) //throw std::bad_alloc void deallocate(void* ptr) - size_t calcCapacity(size_t length) -*/ + size_t calcCapacity(size_t length) */ class AllocatorOptimalSpeed //exponential growth + min size { protected: @@ -45,20 +41,18 @@ protected: static size_t calcCapacity(size_t length) { return length; } }; -/* -Storage Policy: ---------------- -template //Allocator Policy +/* Storage Policy: + --------------- + template //Allocator Policy - Char* create(size_t size) - Char* create(size_t size, size_t minCapacity) - Char* clone(Char* ptr) - void destroy(Char* ptr) //must handle "destroy(nullptr)"! - 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) -*/ + Char* create(size_t size) + Char* create(size_t size, size_t minCapacity) + Char* clone(Char* ptr) + void destroy(Char* ptr) //must handle "destroy(nullptr)"! + 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 //Allocator Policy @@ -135,6 +129,12 @@ protected: { assert(size <= minCapacity); + if (minCapacity == 0) //perf: avoid memory allocation for empty string + { + ++globalEmptyString.descr.refCount; + return &globalEmptyString.nullTerm; + } + const size_t newCapacity = AP::calcCapacity(minCapacity); assert(newCapacity >= minCapacity); @@ -186,20 +186,30 @@ protected: private: struct Descriptor { - Descriptor(size_t len, size_t cap) : + constexpr Descriptor(size_t len, size_t cap) : length (static_cast(len)), capacity(static_cast(cap)) { static_assert(decltype(refCount)::is_always_lock_free); } - std::atomic refCount { 1 }; //std:atomic is uninitialized by default! + std::atomic refCount{1}; //std:atomic is uninitialized by default! uint32_t length; const uint32_t capacity; //allocated size without null-termination }; static Descriptor* descr( Char* ptr) { return reinterpret_cast< Descriptor*>(ptr) - 1; } static const Descriptor* descr(const Char* ptr) { return reinterpret_cast(ptr) - 1; } + + struct GlobalEmptyString + { + Descriptor descr{0 /*length*/, 0 /*capacity*/}; + Char nullTerm = 0; + }; + static_assert(offsetof(GlobalEmptyString, nullTerm) - offsetof(GlobalEmptyString, descr) == sizeof(Descriptor), "no gap!"); + static_assert(std::is_trivially_destructible_v, "this memory needs to live forever"); + + inline static constinit2 GlobalEmptyString globalEmptyString; //constinit: dodge static initialization order fiasco! }; @@ -331,7 +341,6 @@ template class SP> inline Zbase operator template class SP> inline Zbase::Zbase() { - //resist the temptation to avoid this allocation by referencing a static global: NO performance advantage, MT issues! rawStr_ = this->create(0); rawStr_[0] = 0; } @@ -612,6 +621,7 @@ Zbase& Zbase::append(InputIterator first, InputIterator last } +//don't use unifying assignment but save one move-construction in the r-value case instead! template class SP> inline Zbase& Zbase::operator=(const Zbase& str) { @@ -623,10 +633,14 @@ Zbase& Zbase::operator=(const Zbase& str) template class SP> inline Zbase& Zbase::operator=(Zbase&& tmp) noexcept { - swap(tmp); //don't use unifying assignment but save one move-construction in the r-value case instead! + //don't use swap() but end rawStr_ life time immediately + this->destroy(rawStr_); + rawStr_ = tmp.rawStr_; + tmp.rawStr_ = nullptr; return *this; } + template class SP> inline void Zbase::pop_back() { -- cgit