diff --git a/deps/ox/src/ox/std/basestringview.hpp b/deps/ox/src/ox/std/basestringview.hpp new file mode 100644 index 00000000..241fec68 --- /dev/null +++ b/deps/ox/src/ox/std/basestringview.hpp @@ -0,0 +1,217 @@ +/* + * Copyright 2015 - 2023 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "bit.hpp" +#include "cstrops.hpp" +#include "iterator.hpp" + +namespace ox::detail { + +class BaseStringView { + public: + template + struct iterator: public Iterator { + private: + PtrType m_t = nullptr; + std::size_t m_offset = 0; + std::size_t m_max = 0; + + public: + constexpr iterator() noexcept = default; + + constexpr iterator(PtrType t, std::size_t offset, std::size_t max) noexcept { + m_t = t; + m_offset = offset; + m_max = max; + } + + [[nodiscard]] + constexpr auto offset() const noexcept { + return m_offset; + } + + constexpr iterator operator+(std::size_t s) const noexcept { + if constexpr(reverse) { + return iterator(m_t, max(m_offset - s, 0), m_max); + } else { + return iterator(m_t, min(m_offset + s, m_max), m_max); + } + } + + constexpr auto operator-(const iterator &other) const noexcept { + if constexpr(reverse) { + return m_offset + other.m_offset; + } else { + return m_offset - other.m_offset; + } + } + + constexpr iterator operator-(std::size_t s) const noexcept { + if constexpr(reverse) { + return iterator(m_t, min(m_offset + s, m_max), m_max); + } else { + return iterator(m_t, max(m_offset - s, 0), m_max); + } + } + + constexpr iterator &operator+=(std::size_t s) noexcept { + if constexpr(reverse) { + m_offset = max(m_offset - s, 0); + } else { + m_offset = min(m_offset + s, m_max); + } + return *this; + } + + constexpr iterator &operator-=(std::size_t s) noexcept { + if constexpr(reverse) { + m_offset = min(m_offset + s, m_max); + } else { + m_offset = max(m_offset - s, 0); + } + return *this; + } + + constexpr iterator &operator++() noexcept { + return operator+=(1); + } + + constexpr iterator &operator--() noexcept { + return operator-=(1); + } + + constexpr RefType operator*() const noexcept { + return m_t[m_offset]; + } + + constexpr RefType operator[](std::size_t s) const noexcept { + return m_t[s]; + } + + constexpr bool operator<(const iterator &other) const noexcept { + return m_offset < other.m_offset; + } + + constexpr bool operator>(const iterator &other) const noexcept { + return m_offset > other.m_offset; + } + + constexpr bool operator<=(const iterator &other) const noexcept { + return m_offset <= other.m_offset; + } + + constexpr bool operator>=(const iterator &other) const noexcept { + return m_offset >= other.m_offset; + } + + constexpr bool operator==(const iterator &other) const noexcept { + return m_t == other.m_t && m_offset == other.m_offset && m_max == other.m_max; + } + + constexpr bool operator!=(const iterator &other) const noexcept { + return m_t != other.m_t || m_offset != other.m_offset || m_max != other.m_max; + } + + }; + + private: + const char *m_str = nullptr; + std::size_t m_len = 0; + protected: + constexpr BaseStringView() noexcept = default; + + constexpr BaseStringView(BaseStringView const&sv) noexcept = default; + + constexpr explicit BaseStringView(std::nullptr_t) noexcept {} + + constexpr explicit BaseStringView(const char *str) noexcept: m_str(str), m_len(str ? ox_strlen(str) : 0) {} + + constexpr explicit BaseStringView(const char *str, std::size_t len) noexcept: m_str(str), m_len(len) {} + + public: + [[nodiscard]] + constexpr iterator begin() const noexcept { + return {m_str, 0, m_len}; + } + + [[nodiscard]] + constexpr iterator end() const noexcept { + return {m_str, m_len, m_len}; + } + + [[nodiscard]] + constexpr iterator cbegin() const noexcept { + return {m_str, 0, m_len}; + } + + [[nodiscard]] + constexpr iterator cend() const noexcept { + return {m_str, m_len, m_len}; + } + + [[nodiscard]] + constexpr iterator crbegin() const noexcept { + return {m_str, m_len - 1, m_len}; + } + + [[nodiscard]] + constexpr iterator crend() const noexcept { + return {m_str, MaxValue, m_len}; + } + + [[nodiscard]] + constexpr iterator rbegin() const noexcept { + return {m_str, m_len - 1, m_len}; + } + + [[nodiscard]] + constexpr iterator rend() const noexcept { + return {m_str, MaxValue, m_len}; + } + + [[nodiscard]] + constexpr auto bytes() const noexcept { + return m_len; + } + + [[nodiscard]] + constexpr auto len() const noexcept { + return m_len; + } + + [[nodiscard]] + constexpr auto *data() const noexcept { + return &m_str[0]; + } + + [[nodiscard]] + constexpr auto &front() const noexcept { + return m_str[0]; + } + + [[nodiscard]] + constexpr auto &back() const noexcept { + return m_str[m_len - 1]; + } + + [[nodiscard]] + constexpr auto operator[](std::size_t i) const noexcept { + return m_str[i]; + } + + protected: + constexpr void set(const char *str, std::size_t len) noexcept { + m_str = str; + m_len = len; + } + +}; + +} diff --git a/deps/ox/src/ox/std/cstringview.hpp b/deps/ox/src/ox/std/cstringview.hpp new file mode 100644 index 00000000..7abd7e98 --- /dev/null +++ b/deps/ox/src/ox/std/cstringview.hpp @@ -0,0 +1,54 @@ +/* + * Copyright 2015 - 2023 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#ifdef OX_USE_STDLIB +#include +#endif + +#include "basestringview.hpp" +#include "bstring.hpp" +#include "string.hpp" + +namespace ox { + +class CStringView: public detail::BaseStringView { + public: + constexpr CStringView() noexcept = default; + + constexpr CStringView(CStringView const&sv) noexcept = default; + + template + constexpr CStringView(BasicString const&str) noexcept: BaseStringView(str.data(), str.len()) {} + + template + constexpr CStringView(BString const&str) noexcept: BaseStringView(str.data(), str.len()) {} + + constexpr CStringView(std::nullptr_t) noexcept {} + + constexpr CStringView(const char *str) noexcept: BaseStringView(str) {} + + constexpr CStringView(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {} + + constexpr auto &operator=(CStringView const&other) noexcept { + if (&other != this) { + set(other.data(), other.len()); + } + return *this; + } + + [[nodiscard]] + constexpr const char *c_str() const noexcept { + return data(); + } + +}; + +} + diff --git a/deps/ox/src/ox/std/cstrops.hpp b/deps/ox/src/ox/std/cstrops.hpp new file mode 100644 index 00000000..b754bb46 --- /dev/null +++ b/deps/ox/src/ox/std/cstrops.hpp @@ -0,0 +1,158 @@ +/* + * Copyright 2015 - 2023 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "types.hpp" +#include "typetraits.hpp" + +template +constexpr T1 ox_strcpy(T1 dest, T2 src) noexcept { + using T1Type = typename ox::remove_reference::type; + std::size_t i = 0; + while (src[i]) { + dest[i] = static_cast(src[i]); + ++i; + } + // set null terminator + dest[i] = 0; + return dest; +} + +template +constexpr T1 ox_strncpy(T1 dest, T2 src, std::size_t maxLen) noexcept { + using T1Type = typename ox::remove_reference::type; + std::size_t i = 0; + while (i < maxLen && src[i]) { + dest[i] = static_cast(src[i]); + ++i; + } + // set null terminator + dest[i] = 0; + return dest; +} + +[[nodiscard]] +constexpr auto ox_strnlen(const char *str1, std::size_t maxLen) noexcept { + std::size_t len = 0; + for (; len < maxLen && str1[len]; len++); + return len; +} + +template +[[nodiscard]] +constexpr auto ox_strlen(T str1) noexcept { + std::size_t len = 0; + for (; str1[len]; len++); + return len; +} + +template +[[nodiscard]] +constexpr int ox_strcmp(const T1 &str1, const T2 &str2) noexcept { + auto retval = 0; + auto i = 0u; + while (str1[i] || str2[i]) { + if (str1[i] < str2[i]) { + retval = -1; + break; + } else if (str1[i] > str2[i]) { + retval = 1; + break; + } + i++; + } + return retval; +} + +template +[[nodiscard]] +constexpr int ox_strncmp(T1 str1, T2 str2, const std::size_t maxLen) noexcept { + auto retval = 0; + std::size_t i = 0; + while (i < maxLen && (str1[i] || str2[i])) { + if (str1[i] < str2[i]) { + retval = -1; + break; + } else if (str1[i] > str2[i]) { + retval = 1; + break; + } + i++; + } + return retval; +} + +[[nodiscard]] +constexpr const char *ox_strchr(const char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept { + for (std::size_t i = 0; i <= maxLen; i++) { + if (str[i] == character) { + return &str[i]; + } else if (str[i] == 0) { + return nullptr; + } + } + return nullptr; +} + +[[nodiscard]] +constexpr char *ox_strchr(char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept { + for (std::size_t i = 0; i < maxLen; i++) { + if (str[i] == character) { + return &str[i]; + } else if (str[i] == 0) { + return nullptr; + } + } + return nullptr; +} + +[[nodiscard]] +constexpr int ox_lastIndexOf(const auto &str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept { + int retval = -1; + for (std::size_t i = 0; i < maxLen && str[i]; i++) { + if (str[i] == character) { + retval = static_cast(i); + } + } + return retval; +} + +template +constexpr T ox_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/hashmap.hpp b/deps/ox/src/ox/std/hashmap.hpp index 4cbab67f..6f755db0 100644 --- a/deps/ox/src/ox/std/hashmap.hpp +++ b/deps/ox/src/ox/std/hashmap.hpp @@ -18,25 +18,11 @@ namespace ox { template class HashMap { - using key_t = K; - using value_t = T; + public: + using key_t = K; + using value_t = T; private: - // Maybe StringView. If K (or KK for MaybeSV) is a string type, - // MaybeSV::type/MaybeSV_t is a StringView. - // This avoids creating unnecessary Strings when taking a StringView or C - // string in lookups. - template> - struct MaybeSV { - using type = KK; - }; - template - struct MaybeSV { - using type = ox::StringView; - }; - template - using MaybeSV_t = MaybeSV::type; - struct Pair { K key = {}; T value{}; @@ -85,15 +71,9 @@ class HashMap { constexpr static uint64_t hash(StringView const&) noexcept; - /** - * K is assumed to be a null terminated string. - */ template constexpr Pair *const&access(Vector const&pairs, KK const&key) const; - /** - * K is assumed to be a null terminated string. - */ template constexpr Pair *&access(Vector &pairs, KK const&key); @@ -124,7 +104,7 @@ constexpr bool HashMap::operator==(HashMap const&other) const { if (m_keys != other.m_keys) { return false; } - for (int i = 0; i < m_keys.size(); i++) { + for (int i = 0; i < m_keys.size(); ++i) { auto &k = m_keys[i]; if (at(k) != other.at(k)) { return false; @@ -194,7 +174,7 @@ constexpr void HashMap::erase(MaybeSV_t const&k) { auto h = hash(k) % m_pairs.size(); while (true) { const auto &p = m_pairs[h]; - if (p == nullptr || ox_strcmp(p->key, k) == 0) { + if (p == nullptr || p->key == k) { oxIgnoreError(m_pairs.erase(h)); break; } else { @@ -264,7 +244,7 @@ constexpr typename HashMap::Pair *const&HashMap::access(Vector(hash(k) % pairs.size()); while (true) { const auto &p = pairs[h]; - if (p == nullptr || ox_strcmp(p->key, k) == 0) { + if (p == nullptr || p->key == k) { return p; } else { h = (h + 1) % pairs.size(); @@ -278,14 +258,7 @@ constexpr typename HashMap::Pair *&HashMap::access(Vector &pa auto h = static_cast(hash(k) % pairs.size()); while (true) { auto &p = pairs[h]; - bool matches = [&] { - if constexpr (is_integral_v) { - return p == nullptr || k == p->key; - } else { - return p == nullptr || ox_strcmp(p->key, k) == 0; - } - }(); - if (matches) { + if (p == nullptr || p->key == k) { return p; } else { h = (h + 1) % pairs.size(); diff --git a/deps/ox/src/ox/std/std.hpp b/deps/ox/src/ox/std/std.hpp index 227dfc79..70b110ea 100644 --- a/deps/ox/src/ox/std/std.hpp +++ b/deps/ox/src/ox/std/std.hpp @@ -15,6 +15,8 @@ #include "bstring.hpp" #include "byteswap.hpp" #include "concepts.hpp" +#include "cstringview.hpp" +#include "cstrops.hpp" #include "def.hpp" #include "defer.hpp" #include "defines.hpp" @@ -37,6 +39,7 @@ #include "stacktrace.hpp" #include "stddef.hpp" #include "string.hpp" +#include "stringliteral.hpp" #include "stringview.hpp" #include "strongint.hpp" #include "strops.hpp" diff --git a/deps/ox/src/ox/std/string.hpp b/deps/ox/src/ox/std/string.hpp index 087480d5..1ecc0eab 100644 --- a/deps/ox/src/ox/std/string.hpp +++ b/deps/ox/src/ox/std/string.hpp @@ -581,6 +581,13 @@ extern template class BasicString<8>; using String = BasicString<8>; using CRString = String const&; + +[[nodiscard]] +constexpr ox::String toString(ox::CRStringView sv) noexcept { + return ox::String(sv); +} + + template [[nodiscard]] constexpr auto sizeOf(const ox::BasicString*) noexcept { diff --git a/deps/ox/src/ox/std/stringview.hpp b/deps/ox/src/ox/std/stringview.hpp index 76fc790d..2657ff96 100644 --- a/deps/ox/src/ox/std/stringview.hpp +++ b/deps/ox/src/ox/std/stringview.hpp @@ -12,12 +12,9 @@ #include #endif -#include "bit.hpp" -#include "concepts.hpp" -#include "iterator.hpp" -#include "stringliteral.hpp" -#include "strops.hpp" -#include "vector.hpp" +#include "basestringview.hpp" +#include "cstrops.hpp" +#include "writer.hpp" namespace ox { @@ -89,70 +86,6 @@ constexpr auto operator<=>(CRStringView s1, CRStringView s2) noexcept { } } -[[nodiscard]] -constexpr bool beginsWith(CRStringView base, CRStringView beginning) noexcept { - const auto beginningLen = ox::min(beginning.len(), base.len()); - return base.len() >= beginning.len() && ox_strncmp(base.data(), beginning, beginningLen) == 0; -} - -[[nodiscard]] -constexpr bool endsWith(CRStringView base, CRStringView ending) noexcept { - const auto endingLen = ending.len(); - return base.len() >= endingLen && ox_strcmp(base.data() + (base.len() - endingLen), ending) == 0; -} - -constexpr std::size_t find(CRStringView str, char search) noexcept { - std::size_t i = 0; - for (; i < str.len(); ++i) { - if (str[i] == search) { - break; - } - } - return i; -} - -constexpr std::size_t find(CRStringView str, CRStringView search) noexcept { - std::size_t i = 0; - for (; i < str.len(); ++i) { - if (beginsWith(substr(str, i), search)) { - break; - } - } - return i; -} - -template -constexpr ox::Vector split(CRStringView str, char del) noexcept { - ox::Vector out; - constexpr auto nextSeg = [](CRStringView current, char del) { - return substr(current, find(current, del) + 1); - }; - for (auto current = str; current.len(); current = nextSeg(current, del)) { - const auto next = find(current, del); - if (const auto s = substr(current, 0, next); s.len()) { - out.emplace_back(s); - } - current = substr(current, next); - } - return out; -} - -template -constexpr ox::Vector split(CRStringView str, CRStringView del) noexcept { - ox::Vector out; - constexpr auto nextSeg = [](CRStringView current, CRStringView del) { - return substr(current, find(current, del) + del.len()); - }; - for (auto current = str; current.len(); current = nextSeg(current, del)) { - const auto next = find(current, del); - if (const auto s = substr(current, 0, next); s.len()) { - out.emplace_back(s); - } - current = substr(current, next); - } - return out; -} - constexpr auto write(Writer_c auto &writer, ox::CRStringView sv) noexcept { return writer.write(sv.data(), sv.bytes()); } @@ -163,6 +96,22 @@ constexpr auto toStdStringView(CRStringView sv) noexcept { } #endif + +// Maybe StringView. If T is a string type, MaybeType::type/MaybeSV_t is a +// StringView. This avoids creating unnecessary Strings when taking a +// StringView or C string as a function argument. +template> +struct MaybeSV { + using type = T; +}; +template +struct MaybeSV { + using type = ox::StringView; +}; +template +using MaybeSV_t = MaybeSV::type; + + } constexpr ox::Result ox_atoi(ox::CRStringView str) noexcept { diff --git a/deps/ox/src/ox/std/strops.hpp b/deps/ox/src/ox/std/strops.hpp index 37a9ca1c..33f2d68f 100644 --- a/deps/ox/src/ox/std/strops.hpp +++ b/deps/ox/src/ox/std/strops.hpp @@ -8,125 +8,14 @@ #pragma once -#include "concepts.hpp" +#include "cstrops.hpp" #include "error.hpp" #include "math.hpp" +#include "stringview.hpp" #include "types.hpp" -#include "typetraits.hpp" +#include "vector.hpp" #include "writer.hpp" -template -constexpr T1 ox_strcpy(T1 dest, T2 src) noexcept { - using T1Type = typename ox::remove_reference::type; - std::size_t i = 0; - while (src[i]) { - dest[i] = static_cast(src[i]); - ++i; - } - // set null terminator - dest[i] = 0; - return dest; -} - -template -constexpr T1 ox_strncpy(T1 dest, T2 src, std::size_t maxLen) noexcept { - using T1Type = typename ox::remove_reference::type; - std::size_t i = 0; - while (i < maxLen && src[i]) { - dest[i] = static_cast(src[i]); - ++i; - } - // set null terminator - dest[i] = 0; - return dest; -} - -[[nodiscard]] -constexpr auto ox_strnlen(const char *str1, std::size_t maxLen) noexcept { - std::size_t len = 0; - for (; len < maxLen && str1[len]; len++); - return len; -} - -template -[[nodiscard]] -constexpr auto ox_strlen(T str1) noexcept { - std::size_t len = 0; - for (; str1[len]; len++); - return len; -} - -template -[[nodiscard]] -constexpr int ox_strcmp(const T1 &str1, const T2 &str2) noexcept { - auto retval = 0; - auto i = 0u; - while (str1[i] || str2[i]) { - if (str1[i] < str2[i]) { - retval = -1; - break; - } else if (str1[i] > str2[i]) { - retval = 1; - break; - } - i++; - } - return retval; -} - -template -[[nodiscard]] -constexpr int ox_strncmp(T1 str1, T2 str2, const std::size_t maxLen) noexcept { - auto retval = 0; - std::size_t i = 0; - while (i < maxLen && (str1[i] || str2[i])) { - if (str1[i] < str2[i]) { - retval = -1; - break; - } else if (str1[i] > str2[i]) { - retval = 1; - break; - } - i++; - } - return retval; -} - -[[nodiscard]] -constexpr const char *ox_strchr(const char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept { - for (std::size_t i = 0; i <= maxLen; i++) { - if (str[i] == character) { - return &str[i]; - } else if (str[i] == 0) { - return nullptr; - } - } - return nullptr; -} - -[[nodiscard]] -constexpr char *ox_strchr(char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept { - for (std::size_t i = 0; i < maxLen; i++) { - if (str[i] == character) { - return &str[i]; - } else if (str[i] == 0) { - return nullptr; - } - } - return nullptr; -} - -[[nodiscard]] -constexpr int ox_lastIndexOf(const auto &str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept { - int retval = -1; - for (std::size_t i = 0; i < maxLen && str[i]; i++) { - if (str[i] == character) { - retval = static_cast(i); - } - } - return retval; -} - namespace ox { template @@ -179,38 +68,68 @@ constexpr ox::Error itoa(Integer v, ox::Writer_c auto &writer) noexcept { return {}; } +[[nodiscard]] +constexpr bool beginsWith(CRStringView base, CRStringView beginning) noexcept { + const auto beginningLen = ox::min(beginning.len(), base.len()); + return base.len() >= beginning.len() && ox_strncmp(base.data(), beginning, beginningLen) == 0; +} + +[[nodiscard]] +constexpr bool endsWith(CRStringView base, CRStringView ending) noexcept { + const auto endingLen = ending.len(); + return base.len() >= endingLen && ox_strcmp(base.data() + (base.len() - endingLen), ending) == 0; +} + +constexpr std::size_t find(CRStringView str, char search) noexcept { + std::size_t i = 0; + for (; i < str.len(); ++i) { + if (str[i] == search) { + break; + } + } + return i; +} + +constexpr std::size_t find(CRStringView str, CRStringView search) noexcept { + std::size_t i = 0; + for (; i < str.len(); ++i) { + if (beginsWith(substr(str, i), search)) { + break; + } + } + return i; +} + +template +constexpr ox::Vector split(CRStringView str, char del) noexcept { + ox::Vector out; + constexpr auto nextSeg = [](CRStringView current, char del) { + return substr(current, find(current, del) + 1); + }; + for (auto current = str; current.len(); current = nextSeg(current, del)) { + const auto next = find(current, del); + if (const auto s = substr(current, 0, next); s.len()) { + out.emplace_back(s); + } + current = substr(current, next); + } + return out; +} + +template +constexpr ox::Vector split(CRStringView str, CRStringView del) noexcept { + ox::Vector out; + constexpr auto nextSeg = [](CRStringView current, CRStringView del) { + return substr(current, find(current, del) + del.len()); + }; + for (auto current = str; current.len(); current = nextSeg(current, del)) { + const auto next = find(current, del); + if (const auto s = substr(current, 0, next); s.len()) { + out.emplace_back(s); + } + current = substr(current, next); + } + return out; } -template -constexpr T ox_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; }