From 20ff0f89fe19bbd5bf4b582dc24e287bfddf615b Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Fri, 3 May 2024 20:31:40 -0500 Subject: [PATCH] [ox/std] Rework itoa --- deps/ox/src/ox/std/CMakeLists.txt | 1 + deps/ox/src/ox/std/cstrops.hpp | 34 ------------------- deps/ox/src/ox/std/fmt.hpp | 11 ++++--- deps/ox/src/ox/std/istring.hpp | 55 +++++++++++++++++++++++-------- deps/ox/src/ox/std/strconv.hpp | 44 +++++++++++++++++++++++++ deps/ox/src/ox/std/string.hpp | 20 +++++------ deps/ox/src/ox/std/strops.hpp | 32 ------------------ deps/ox/src/ox/std/vector.hpp | 11 +++---- 8 files changed, 107 insertions(+), 101 deletions(-) create mode 100644 deps/ox/src/ox/std/strconv.hpp diff --git a/deps/ox/src/ox/std/CMakeLists.txt b/deps/ox/src/ox/std/CMakeLists.txt index 6c88ca49..93dd0d75 100644 --- a/deps/ox/src/ox/std/CMakeLists.txt +++ b/deps/ox/src/ox/std/CMakeLists.txt @@ -124,6 +124,7 @@ install( stringliteral.hpp stringview.hpp strongint.hpp + strconv.hpp strops.hpp trace.hpp typeinfo.hpp diff --git a/deps/ox/src/ox/std/cstrops.hpp b/deps/ox/src/ox/std/cstrops.hpp index ceac63c2..c86cacb3 100644 --- a/deps/ox/src/ox/std/cstrops.hpp +++ b/deps/ox/src/ox/std/cstrops.hpp @@ -112,38 +112,4 @@ constexpr int lastIndexOf(const auto &str, int character, std::size_t maxLen = 0 return retval; } -template -constexpr T itoa(Integer v, T str) noexcept { - if (v) { - ox::ResizedInt_t mod = 1000000000000000000; - ox::ResizedInt_t val = v; - constexpr auto base = 10; - auto it = 0; - if (val < 0) { - str[static_cast(it)] = '-'; - it++; - } - while (mod) { - auto digit = val / mod; - val %= mod; - mod /= base; - if (it || digit) { - ox::ResizedInt_t start = '0'; - if (digit >= 10) { - start = 'a'; - digit -= 10; - } - str[static_cast(it)] = static_cast::type>(start + digit); - it++; - } - } - str[static_cast(it)] = 0; - } else { - // 0 is a special case - str[0] = '0'; - str[1] = 0; - } - return str; -} - } diff --git a/deps/ox/src/ox/std/fmt.hpp b/deps/ox/src/ox/std/fmt.hpp index c3579e45..2cdab425 100644 --- a/deps/ox/src/ox/std/fmt.hpp +++ b/deps/ox/src/ox/std/fmt.hpp @@ -75,14 +75,17 @@ constexpr StringView toStringView(const auto&) noexcept requires(force) { class FmtArg { private: - char dataStr[10] = {}; + static constexpr auto DataSz = 23; + char dataStr[DataSz] = {}; template constexpr StringView sv(const T &v, char *dataStr) noexcept { if constexpr(is_bool_v) { return v ? "true" : "false"; } else if constexpr(is_integer_v) { - return ox::itoa(v, dataStr); + ox::CharBuffWriter w(dataStr, DataSz); + std::ignore = ox::writeItoa(v, w); + return dataStr; } else { return toStringView(v); } @@ -197,13 +200,13 @@ constexpr StringType sfmt(StringView fmt, Args&&... args) noexcept { for (size_t i = 0; i < fmtSegments.size - 1; ++i) { std::ignore = out.append(elements[i].out); const auto &s = fmtSegments.segments[i + 1]; - std::ignore = out.append(s.str); + std::ignore = out.append(s.str, s.length); } return out; } template -constexpr Result join(auto d, const auto &list) { +constexpr Result join(auto const&d, auto const&list) { if (!list.size()) { return T(""); } diff --git a/deps/ox/src/ox/std/istring.hpp b/deps/ox/src/ox/std/istring.hpp index 37be9cd6..30ee64f5 100644 --- a/deps/ox/src/ox/std/istring.hpp +++ b/deps/ox/src/ox/std/istring.hpp @@ -9,10 +9,15 @@ #pragma once #include "array.hpp" +#include "concepts.hpp" +#include "cstrops.hpp" #include "memops.hpp" -#include "ox/std/error.hpp" +#include "error.hpp" +#include "buffer.hpp" +#include "ignore.hpp" #include "stringview.hpp" #include "typetraits.hpp" +#include "strconv.hpp" namespace ox { @@ -20,8 +25,8 @@ namespace ox { template class IString { private: - ox::Array m_buff; size_t m_size{}; + ox::Array m_buff; public: constexpr IString() noexcept; @@ -34,8 +39,6 @@ class IString { constexpr IString &operator=(const char *str) noexcept; - constexpr IString &operator=(char *str) noexcept; - constexpr IString &operator=(Integer_c auto i) noexcept; @@ -101,9 +104,11 @@ constexpr IString::IString(const char *str) noexcept: m_buff{{0}} { template constexpr IString &IString::operator=(Integer_c auto i) noexcept { - ox::Array str{}; - ox::itoa(i, str.data()); - return this->operator=(str.data()); + ox::Array s; + ox::CharBuffWriter w(s); + std::ignore = ox::writeItoa(i, w); + this->operator=({s.data(), w.tellp()}); + return *this; } template @@ -132,11 +137,6 @@ constexpr IString &IString::operator=(const char *str) noexcept { return *this; } -template -constexpr IString &IString::operator=(char *str) noexcept { - return *this = static_cast(str); -} - template constexpr bool IString::operator==(const char *other) const noexcept { return ox::StringView(*this) == other; @@ -239,9 +239,12 @@ constexpr std::size_t IString::bytes() const noexcept { template constexpr ox::Error IString::resize(size_t sz) noexcept { - if (sz > StrCap) { + if (sz > StrCap) [[unlikely]] { return OxError(1, "Trying to extend IString beyond its cap"); } + for (auto i = m_size; i < sz; ++i) { + m_buff[i] = 0; + } m_size = sz; return {}; } @@ -256,4 +259,30 @@ struct MaybeView> { using type = ox::StringView; }; + +template +[[nodiscard]] +constexpr auto itoa(Integer v) noexcept { + constexpr auto Cap = [] { + auto out = 0; + switch (sizeof(Integer)) { + case 1: + out = 3; + case 2: + out = 5; + case 4: + out = 10; + case 8: + out = 21; + } + return out + ox::is_signed_v; + }(); + ox::IString out; + std::ignore = out.resize(out.cap()); + ox::CharBuffWriter w(out.data(), out.cap()); + std::ignore = writeItoa(v, w); + std::ignore = out.resize(w.tellp()); + return out; +} + } diff --git a/deps/ox/src/ox/std/strconv.hpp b/deps/ox/src/ox/std/strconv.hpp new file mode 100644 index 00000000..f976366e --- /dev/null +++ b/deps/ox/src/ox/std/strconv.hpp @@ -0,0 +1,44 @@ + +#pragma once + +#include "error.hpp" +#include "types.hpp" +#include "writer.hpp" + +namespace ox { + +template +constexpr ox::Error writeItoa(Integer v, ox::Writer_c auto &writer) noexcept { + if (v) { + ox::ResizedInt_t mod = 1000000000000000000; + ox::ResizedInt_t val = v; + constexpr auto base = 10; + auto it = 0; + if (val < 0) { + oxReturnError(writer.put('-')); + ++it; + } + while (mod) { + auto digit = val / mod; + val %= mod; + mod /= base; + if (it || digit) { + ox::ResizedInt_t start = '0'; + if (digit >= 10) { + start = 'a'; + digit -= 10; + } + oxReturnError(writer.put(static_cast(start + digit))); + ++it; + } + } + } else { + // 0 is a special case + oxReturnError(writer.put('0')); + } + return {}; +} + +} + +#include "istring.hpp" diff --git a/deps/ox/src/ox/std/string.hpp b/deps/ox/src/ox/std/string.hpp index 7448934f..90a71341 100644 --- a/deps/ox/src/ox/std/string.hpp +++ b/deps/ox/src/ox/std/string.hpp @@ -16,6 +16,7 @@ #include "ignore.hpp" #include "memops.hpp" #include "serialize.hpp" +#include "strconv.hpp" #include "stringliteral.hpp" #include "stringview.hpp" #include "strops.hpp" @@ -23,6 +24,9 @@ namespace ox { +template +constexpr ox::IString<21> itoa(Integer v) noexcept; + template class BasicString { private: @@ -327,17 +331,13 @@ constexpr BasicString &BasicString::operat template constexpr BasicString &BasicString::operator=(int64_t i) noexcept { - ox::Array str{}; - ox::itoa(i, str.data()); - set(str.data()); + set(ox::itoa(i)); return *this; } template constexpr BasicString &BasicString::operator=(uint64_t i) noexcept { - ox::Array str{}; - ox::itoa(i, str.data()); - set(str.data()); + set(ox::itoa(i)); return *this; } @@ -383,9 +383,8 @@ constexpr BasicString &BasicString::operat template constexpr BasicString &BasicString::operator+=(Integer_c auto i) noexcept { - char str[65] = {}; - ox::itoa(i, str); - return this->operator+=(str); + auto const str = ox::itoa(i); + return this->operator+=(str.c_str()); } template @@ -427,8 +426,7 @@ constexpr BasicString BasicString::operato template constexpr BasicString BasicString::operator+(Integer_c auto i) const noexcept { - char str[65] = {}; - ox::itoa(i, str); + auto const str = ox::itoa(i); return *this + str; } diff --git a/deps/ox/src/ox/std/strops.hpp b/deps/ox/src/ox/std/strops.hpp index 25acc74d..ef0dfa20 100644 --- a/deps/ox/src/ox/std/strops.hpp +++ b/deps/ox/src/ox/std/strops.hpp @@ -33,38 +33,6 @@ constexpr ox::StringView substr(ox::StringView const&str, std::size_t start, std return {}; } -template -constexpr ox::Error writeItoa(Integer v, ox::Writer_c auto &writer) noexcept { - if (v) { - ox::ResizedInt_t mod = 1000000000000000000; - ox::ResizedInt_t val = v; - constexpr auto base = 10; - auto it = 0; - if (val < 0) { - oxReturnError(writer.put('-')); - ++it; - } - while (mod) { - auto digit = val / mod; - val %= mod; - mod /= base; - if (it || digit) { - ox::ResizedInt_t start = '0'; - if (digit >= 10) { - start = 'a'; - digit -= 10; - } - oxReturnError(writer.put(static_cast(start + digit))); - ++it; - } - } - } else { - // 0 is a special case - oxReturnError(writer.put('0')); - } - return {}; -} - [[nodiscard]] constexpr bool beginsWith(CRStringView base, CRStringView beginning) noexcept { const auto beginningLen = ox::min(beginning.len(), base.len()); diff --git a/deps/ox/src/ox/std/vector.hpp b/deps/ox/src/ox/std/vector.hpp index 7d649c91..2d8fee01 100644 --- a/deps/ox/src/ox/std/vector.hpp +++ b/deps/ox/src/ox/std/vector.hpp @@ -30,7 +30,6 @@ struct VectorAllocator { static_assert(alignof(AllocAlias) == alignof(T)); private: ox::Array, Size> m_data = {}; - Allocator m_allocator; protected: constexpr VectorAllocator() noexcept = default; constexpr VectorAllocator(const VectorAllocator&) noexcept = default; @@ -39,7 +38,7 @@ struct VectorAllocator { constexpr void allocate(T **items, std::size_t cap) noexcept { // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr if (std::is_constant_evaluated() || cap > Size) { - *items = m_allocator.allocate(cap); + *items = Allocator{}.allocate(cap); } else { *items = reinterpret_cast(m_data.data()); } @@ -87,7 +86,7 @@ struct VectorAllocator { // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr if (std::is_constant_evaluated()) { if (items && static_cast(items) != static_cast(m_data.data())) { - m_allocator.deallocate(items, cap); + Allocator{}.deallocate(items, cap); } } } @@ -96,15 +95,13 @@ struct VectorAllocator { template struct VectorAllocator { - private: - Allocator m_allocator; protected: constexpr VectorAllocator() noexcept = default; constexpr VectorAllocator(const VectorAllocator&) noexcept = default; constexpr VectorAllocator(VectorAllocator&&) noexcept = default; constexpr void allocate(T **items, std::size_t cap) noexcept { - *items = m_allocator.allocate(cap); + *items = Allocator{}.allocate(cap); } [[maybe_unused]] @@ -121,7 +118,7 @@ struct VectorAllocator { constexpr void deallocate(T *items, std::size_t cap) noexcept { if (items) { - m_allocator.deallocate(items, cap); + Allocator{}.deallocate(items, cap); } }