summaryrefslogtreecommitdiff
path: root/zen/string_base.h
diff options
context:
space:
mode:
Diffstat (limited to 'zen/string_base.h')
-rw-r--r--zen/string_base.h72
1 files changed, 45 insertions, 27 deletions
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<Descriptor*>(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<Descriptor*>(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<Char> view) : Zbase(view.begin(), view.end()) {}
Zbase(size_t count, Char fillChar);
- template <class InputIterator>
- Zbase(InputIterator first, InputIterator last);
+ template <class RandomAccessIterator>
+ 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<Char>() const& noexcept { return {data(), size()}; }
- operator std::basic_string_view<Char>() const&& = delete; //=> probably a bug!
+ //operator std::basic_string_view<Char>() 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 <class InputIterator> Zbase& assign(InputIterator first, InputIterator last);
- template <class InputIterator> Zbase& append(InputIterator first, InputIterator last);
+ template <class RandomAccessIterator> Zbase& assign(RandomAccessIterator first, RandomAccessIterator last);
+ template <class RandomAccessIterator> 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<Char> str) { return append(str.begin(), str.end()); }
static const size_t npos = static_cast<size_t>(-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<Char> 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 Char, template <class> class SP> std::strong_ordering operator<=
template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs) { return Zbase<Char, SP>(lhs) += rhs; }
template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, const Char* rhs) { return Zbase<Char, SP>(lhs) += rhs; }
template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, Char rhs) { return Zbase<Char, SP>(lhs) += rhs; }
+template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, const std::basic_string_view<Char> rhs) { return Zbase<Char, SP>(lhs) += rhs; }
//don't use unified first argument but save one move-construction in the r-value case instead!
template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(Zbase<Char, SP>&& lhs, const Zbase<Char, SP>& rhs) { return std::move(lhs += rhs); } //the move *is* needed!!!
template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(Zbase<Char, SP>&& lhs, const Char* rhs) { return std::move(lhs += rhs); } //lhs, is an l-value parameter...
template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(Zbase<Char, SP>&& lhs, Char rhs) { return std::move(lhs += rhs); } //and not a local variable => no copy elision
-
-template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Char* lhs, const Zbase<Char, SP>& rhs) { return Zbase<Char, SP>(lhs ) += rhs; }
-template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+( Char lhs, const Zbase<Char, SP>& rhs) { return Zbase<Char, SP>(&lhs, 1) += rhs; }
+template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(Zbase<Char, SP>&& lhs, const std::basic_string_view<Char> rhs) { return std::move(lhs += rhs); }
template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>&, int) = delete; //detect usage errors
template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(int, const Zbase<Char, SP>&) = delete; //
@@ -359,8 +368,8 @@ Zbase<Char, SP>::Zbase()
template <class Char, template <class> class SP>
-template <class InputIterator> inline
-Zbase<Char, SP>::Zbase(InputIterator first, InputIterator last)
+template <class RandomAccessIterator> inline
+Zbase<Char, SP>::Zbase(RandomAccessIterator first, RandomAccessIterator last)
{
rawStr_ = this->create(last - first);
*std::copy(first, last, rawStr_) = 0;
@@ -393,6 +402,15 @@ Zbase<Char, SP>::Zbase(Zbase<Char, SP>&& tmp) noexcept
template <class Char, template <class> class SP> inline
+Zbase<Char, SP>::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 Char, template <class> class SP> inline
Zbase<Char, SP>::~Zbase()
{
static_assert(noexcept(this->~Zbase())); //has exception spec of compiler-generated destructor by default
@@ -568,7 +586,7 @@ void Zbase<Char, SP>::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<Char, SP>::reserve(size_t minCapacity) //make unshared and check capa
template <class Char, template <class> class SP>
-template <class InputIterator> inline
-Zbase<Char, SP>& Zbase<Char, SP>::assign(InputIterator first, InputIterator last)
+template <class RandomAccessIterator> inline
+Zbase<Char, SP>& Zbase<Char, SP>::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<Char, SP>& Zbase<Char, SP>::assign(InputIterator first, InputIterator last
template <class Char, template <class> class SP>
-template <class InputIterator> inline
-Zbase<Char, SP>& Zbase<Char, SP>::append(InputIterator first, InputIterator last)
+template <class RandomAccessIterator> inline
+Zbase<Char, SP>& Zbase<Char, SP>::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<Char, SP>& Zbase<Char, SP>::operator=(const Zbase<Char, SP>& str)
template <class Char, template <class> class SP> inline
Zbase<Char, SP>& Zbase<Char, SP>::operator=(Zbase<Char, SP>&& 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);
bgstack15