From d35a4795f16e51f5773d00dce796f6948f82dae2 Mon Sep 17 00:00:00 2001 From: "B. Stack" Date: Fri, 16 Dec 2022 21:08:02 -0500 Subject: add upstream 11.29 --- zen/string_base.h | 72 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 27 deletions(-) (limited to 'zen/string_base.h') diff --git a/zen/string_base.h b/zen/string_base.h index 3ebf848a..676d7f7f 100644 --- a/zen/string_base.h +++ b/zen/string_base.h @@ -61,11 +61,11 @@ protected: ~StorageDeepCopy() {} Char* create(size_t size) { return create(size, size); } - Char* create(size_t size, size_t capacity) + Char* create(size_t size, size_t minCapacity) { - assert(size <= capacity); - const size_t newCapacity = AP::calcCapacity(capacity); - assert(newCapacity >= capacity); + assert(size <= minCapacity); + const size_t newCapacity = AP::calcCapacity(minCapacity); + assert(newCapacity >= minCapacity); Descriptor* const newDescr = static_cast(this->allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(Char))); //throw std::bad_alloc new (newDescr) Descriptor(size, newCapacity); @@ -124,18 +124,18 @@ protected: ~StorageRefCountThreadSafe() {} Char* create(size_t size) { return create(size, size); } - Char* create(size_t size, size_t capacity) + Char* create(size_t size, size_t minCapacity) { - assert(size <= capacity); + assert(size <= minCapacity); - if (capacity == 0) //perf: avoid memory allocation for empty string + if (minCapacity == 0) //perf: avoid memory allocation for empty string { ++globalEmptyString.descr.refCount; return &globalEmptyString.nullTerm; } - const size_t newCapacity = AP::calcCapacity(capacity); - assert(newCapacity >= capacity); + const size_t newCapacity = AP::calcCapacity(minCapacity); + assert(newCapacity >= minCapacity); Descriptor* const newDescr = static_cast(this->allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(Char))); //throw std::bad_alloc new (newDescr) Descriptor(size, newCapacity); @@ -230,8 +230,8 @@ public: Zbase(const Char* str, size_t len) : Zbase(str, str + len) {} explicit Zbase(const std::basic_string_view view) : Zbase(view.begin(), view.end()) {} Zbase(size_t count, Char fillChar); - template - Zbase(InputIterator first, InputIterator last); + template + Zbase(RandomAccessIterator first, RandomAccessIterator last); Zbase(const Zbase& str); Zbase(Zbase&& tmp) noexcept; //explicit Zbase(Char ch); //dangerous if implicit: Char buffer[]; return buffer[0]; ups... forgot &, but not a compiler error! //-> non-standard extension!!! @@ -241,7 +241,7 @@ public: //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*... operator std::basic_string_view() const& noexcept { return {data(), size()}; } - operator std::basic_string_view() const&& = delete; //=> probably a bug! + //operator std::basic_string_view() const&& = delete; //=> probably a bug! //STL accessors using iterator = Char*; @@ -281,8 +281,8 @@ public: Zbase& assign(const Char* str, size_t len) { return assign(str, str + len); } Zbase& append(const Char* str, size_t len) { return append(str, str + len); } - template Zbase& assign(InputIterator first, InputIterator last); - template Zbase& append(InputIterator first, InputIterator last); + template Zbase& assign(RandomAccessIterator first, RandomAccessIterator last); + template Zbase& append(RandomAccessIterator first, RandomAccessIterator last); void resize(size_t newSize, Char fillChar = 0); void swap(Zbase& str) { std::swap(rawStr_, str.rawStr_); } @@ -296,21 +296,31 @@ public: Zbase& operator+=(const Zbase& str) { return append(str.c_str(), str.size()); } Zbase& operator+=(const Char* str) { return append(str, strLength(str)); } Zbase& operator+=(Char ch) { return append(&ch, 1); } + Zbase& operator+=(const std::basic_string_view str) { return append(str.begin(), str.end()); } static const size_t npos = static_cast(-1); + inline friend Zbase operator+( const Char* lhs, const Zbase& rhs) { return Zbase(lhs, strLength(lhs), rhs.c_str(), rhs.size()); } + inline friend Zbase operator+( Char lhs, const Zbase& rhs) { return Zbase(&lhs, 1, rhs.c_str(), rhs.size()); } + inline friend Zbase operator+(const std::basic_string_view lhs, const Zbase& rhs) { return Zbase(lhs.data(), lhs.size(), rhs.c_str(), rhs.size()); } + private: Zbase (int) = delete; // Zbase(size_t count, int) = delete; // Zbase& operator= (int) = delete; //detect usage errors by creating an intentional ambiguity with "Char" Zbase& operator+= (int) = delete; // void push_back (int) = delete; // + Zbase (std::nullptr_t) = delete; Zbase(size_t count, std::nullptr_t) = delete; Zbase& operator= (std::nullptr_t) = delete; Zbase& operator+= (std::nullptr_t) = delete; void push_back (std::nullptr_t) = delete; + //not part of std::string API => private: + Zbase(const Char* str1, size_t len1, const Char* str2, size_t len2); + //alternative: Zbase() + reserve() + 2 x append() + Char* rawStr_; }; @@ -328,14 +338,13 @@ template class SP> std::strong_ordering operator<= template class SP> inline Zbase operator+(const Zbase& lhs, const Zbase& rhs) { return Zbase(lhs) += rhs; } template class SP> inline Zbase operator+(const Zbase& lhs, const Char* rhs) { return Zbase(lhs) += rhs; } template class SP> inline Zbase operator+(const Zbase& lhs, Char rhs) { return Zbase(lhs) += rhs; } +template class SP> inline Zbase operator+(const Zbase& lhs, const std::basic_string_view rhs) { return Zbase(lhs) += rhs; } //don't use unified first argument but save one move-construction in the r-value case instead! template class SP> inline Zbase operator+(Zbase&& lhs, const Zbase& rhs) { return std::move(lhs += rhs); } //the move *is* needed!!! template class SP> inline Zbase operator+(Zbase&& lhs, const Char* rhs) { return std::move(lhs += rhs); } //lhs, is an l-value parameter... template class SP> inline Zbase operator+(Zbase&& lhs, Char rhs) { return std::move(lhs += rhs); } //and not a local variable => no copy elision - -template class SP> inline Zbase operator+(const Char* lhs, const Zbase& rhs) { return Zbase(lhs ) += rhs; } -template class SP> inline Zbase operator+( Char lhs, const Zbase& rhs) { return Zbase(&lhs, 1) += rhs; } +template class SP> inline Zbase operator+(Zbase&& lhs, const std::basic_string_view rhs) { return std::move(lhs += rhs); } template class SP> inline Zbase operator+(const Zbase&, int) = delete; //detect usage errors template class SP> inline Zbase operator+(int, const Zbase&) = delete; // @@ -359,8 +368,8 @@ Zbase::Zbase() template class SP> -template inline -Zbase::Zbase(InputIterator first, InputIterator last) +template inline +Zbase::Zbase(RandomAccessIterator first, RandomAccessIterator last) { rawStr_ = this->create(last - first); *std::copy(first, last, rawStr_) = 0; @@ -392,6 +401,15 @@ Zbase::Zbase(Zbase&& tmp) noexcept } +template class SP> inline +Zbase::Zbase(const Char* str1, size_t len1, const Char* str2, size_t len2) +{ + rawStr_ = this->create(len1 + len2); + std::copy (str1, str1 + len1, rawStr_); + *std::copy(str2, str2 + len2, rawStr_ + len1) = 0; +} + + template class SP> inline Zbase::~Zbase() { @@ -568,7 +586,7 @@ void Zbase::reserve(size_t minCapacity) //make unshared and check capa //allocate a new string const size_t len = size(); Char* newStr = this->create(len, std::max(len, minCapacity)); //reserve() must NEVER shrink the string: logical const! - std::copy(rawStr_, rawStr_ + len + 1 /*0-termination*/, newStr); + *std::copy(rawStr_, rawStr_ + len , newStr) = 0; this->destroy(rawStr_); rawStr_ = newStr; @@ -577,10 +595,10 @@ void Zbase::reserve(size_t minCapacity) //make unshared and check capa template class SP> -template inline -Zbase& Zbase::assign(InputIterator first, InputIterator last) +template inline +Zbase& Zbase::assign(RandomAccessIterator first, RandomAccessIterator last) { - const size_t len = std::distance(first, last); + const size_t len = last - first; if (this->canWrite(rawStr_, len)) { *std::copy(first, last, rawStr_) = 0; @@ -594,10 +612,10 @@ Zbase& Zbase::assign(InputIterator first, InputIterator last template class SP> -template inline -Zbase& Zbase::append(InputIterator first, InputIterator last) +template inline +Zbase& Zbase::append(RandomAccessIterator first, RandomAccessIterator last) { - const size_t len = std::distance(first, last); + const size_t len = last - first; //std::distance(first, last); if (len > 0) //avoid making this string unshared for no reason { const size_t thisLen = size(); @@ -622,7 +640,7 @@ Zbase& Zbase::operator=(const Zbase& str) template class SP> inline Zbase& Zbase::operator=(Zbase&& tmp) noexcept { - //don't use swap() but end rawStr_ life time immediately + //don't swap() but end rawStr_ life time immediately this->destroy(rawStr_); rawStr_ = std::exchange(tmp.rawStr_, nullptr); -- cgit