diff options
-rw-r--r-- | include/fud_string.hpp | 34 | ||||
-rw-r--r-- | include/fud_vector.hpp | 5 | ||||
-rw-r--r-- | source/fud_string.cpp | 71 |
3 files changed, 77 insertions, 33 deletions
diff --git a/include/fud_string.hpp b/include/fud_string.hpp index 59c434a..86261c4 100644 --- a/include/fud_string.hpp +++ b/include/fud_string.hpp @@ -251,6 +251,17 @@ class String { return SsoBufSize - 1U; } + /** \brief Returns the remaining capacity for characters excluding the null + * terminating byte. */ + [[nodiscard]] size_t remainingCapacity() const + { + if (length() > capacity()) { + return 0; + } + + return capacity() - length(); + } + /** \brief The underlying data, guaranteed to have c string representation. */ [[nodiscard]] const utf8* data() const { @@ -263,6 +274,11 @@ class String { return reinterpret_cast<const char*>(data()); } + [[nodiscard]] inline StringView asView() const + { + return StringView(*this); + } + /** \brief Indicates if the contents of the string form a valid sequence of * UTF8 code points. */ [[nodiscard]] bool utf8Valid() const; @@ -274,22 +290,6 @@ class String { * greater than zero. */ [[nodiscard]] Option<utf8> back(); - /** \brief Returns the remaining capacity for characters excluding the null - * terminating byte. */ - [[nodiscard]] size_t remainingLength() const - { - if (length() > capacity()) { - return 0; - } - - return capacity() - length(); - } - - [[nodiscard]] inline StringView asView() const - { - return StringView(*this); - } - FudStatus pushBack(char letter); FudStatus pushBack(utf8 letter); @@ -358,6 +358,8 @@ class String { FudStatus resize(size_t newCapacity); + FudStatus grow(); + /** \brief The allocator used to get storage for characters when the string * is large. */ uintptr_t m_allocator{reinterpret_cast<uintptr_t>(&globalFudAllocator)}; diff --git a/include/fud_vector.hpp b/include/fud_vector.hpp index 53b2625..a2a0984 100644 --- a/include/fud_vector.hpp +++ b/include/fud_vector.hpp @@ -647,8 +647,9 @@ class Vector { { // See https://github.com/facebook/folly/blob/main/folly/docs/FBVector.md size_t additional = m_capacity < 2 ? 1 : m_capacity / 2; - if (SIZE_MAX - additional * ElementSize < m_capacity * ElementSize) { - additional = SIZE_MAX - m_capacity * ElementSize / 2; + constexpr auto maxSize = std::numeric_limits<size_t>::max(); + if (maxSize - additional * ElementSize < m_capacity * ElementSize) { + additional = maxSize - m_capacity * ElementSize / 2; } while (additional > 0) { auto reserveStatus = reserve(additional + m_capacity); diff --git a/source/fud_string.cpp b/source/fud_string.cpp index 4dddedb..33e41c3 100644 --- a/source/fud_string.cpp +++ b/source/fud_string.cpp @@ -327,6 +327,42 @@ FudStatus String::nullTerminate() return FudStatus::StringInvalid; } +FudStatus String::grow() +{ + auto cap = capacity(); + if (cap >= maxStringLength) { + return FudStatus::Full; + } + size_t additional = cap / 2; + if (maxStringLength - additional < cap) { + additional = maxStringLength - cap; + } + + FudStatus reserveStatus{}; + while (additional > 0) { + reserveStatus = reserve(additional + cap); + if (reserveStatus == FudStatus::Success) { + break; + } + if (reserveStatus == FudStatus::AllocFailure) { + additional /= 2; + } else { + return reserveStatus; + } + } + if (reserveStatus != FudStatus::Success) { + return reserveStatus; + } + + auto newCapacity = cap < maxStringLength / 2 ? cap * 2 : maxStringLength - 1U; + const auto resizeStatus = resize(newCapacity); + if (resizeStatus != FudStatus::Success) { + return resizeStatus; + } + fudAssert(isLarge()); + fudAssert(m_repr.large.capacity == newCapacity); +} + FudStatus String::reserve(size_t newCapacity) { if (!valid()) { @@ -391,15 +427,12 @@ FudStatus String::pushBack(utf8 letter) return FudStatus::StringInvalid; } - if (remainingLength() < 1) { - auto cap = capacity() + 1U; - auto newCapacity = cap < maxStringLength / 2 ? cap * 2 : maxStringLength - 1U; - const auto resizeStatus = resize(newCapacity); - if (resizeStatus != FudStatus::Success) { - return resizeStatus; + if (remainingCapacity() < 1) { + auto growStatus = grow(); + if (growStatus != FudStatus::Success) { + return growStatus; } fudAssert(isLarge()); - fudAssert(m_repr.large.capacity == newCapacity); } if (isLarge()) { @@ -431,7 +464,15 @@ FudStatus String::pushBack(const FudUtf8& letter) } auto letterSize = letter.size(); - if (remainingLength() < letterSize) { + if (remainingCapacity() < letterSize) { + auto growStatus = grow(); + if (growStatus != FudStatus::Success) { + return growStatus; + } + fudAssert(isLarge()); + } + + if (remainingCapacity() < letterSize) { auto cap = capacity() + 1U; auto newCapacity = cap < maxStringLength / 2 ? cap * 2 : maxStringLength - 1U; if ((newCapacity - cap) < (letterSize + 1)) { @@ -445,7 +486,7 @@ FudStatus String::pushBack(const FudUtf8& letter) fudAssert(m_repr.large.capacity == newCapacity); } - auto copyStatus = copyMem(dataMut() + length(), remainingLength(), letterData, letterSize); + auto copyStatus = copyMem(dataMut() + length(), remainingCapacity(), letterData, letterSize); if (copyStatus != FudStatus::Success) { return copyStatus; @@ -506,7 +547,7 @@ FudStatus String::append(StringView source) } auto* destPtr = dataMut() + length(); - auto status = copyMem(destPtr, remainingLength(), source.data(), source.length()); + auto status = copyMem(destPtr, remainingCapacity(), source.data(), source.length()); fudAssert(status == FudStatus::Success); addToLength(source.length()); @@ -551,13 +592,13 @@ DrainResult String::drain(StringView source) return result; } - if (remainingLength() > 0) { + if (remainingCapacity() > 0) { StringView firstPart{source}; - if (source.length() > remainingLength()) { - firstPart.m_length = remainingLength(); + if (source.length() > remainingCapacity()) { + firstPart.m_length = remainingCapacity(); } auto* destPtr = dataMut() + length(); - auto status = copyMem(destPtr, remainingLength(), firstPart.m_data, firstPart.m_length); + auto status = copyMem(destPtr, remainingCapacity(), firstPart.m_data, firstPart.m_length); fudAssert(status == FudStatus::Success); addToLength(firstPart.m_length); result.bytesDrained += firstPart.m_length; @@ -592,7 +633,7 @@ DrainResult String::drain(StringView source) } auto* destPtr = dataMut() + length(); - result.status = copyMem(destPtr, remainingLength(), source.data(), source.length()); + result.status = copyMem(destPtr, remainingCapacity(), source.data(), source.length()); fudAssert(result.status == FudStatus::Success); result.bytesDrained += source.length(); |