From 3a62650d62ca7959d8434c4d5f5e6724ae3b1609 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Tue, 28 Nov 2023 23:31:11 -0600 Subject: [PATCH] [ox/std] Make String(StringView) constructor explicit, add StringLiteral --- deps/ox/src/ox/std/CMakeLists.txt | 1 + deps/ox/src/ox/std/memory.hpp | 4 +- deps/ox/src/ox/std/new.hpp | 4 +- deps/ox/src/ox/std/string.hpp | 12 +- deps/ox/src/ox/std/stringliteral.hpp | 47 +++++ deps/ox/src/ox/std/stringview.hpp | 285 +++++---------------------- deps/ox/src/ox/std/strops.hpp | 19 ++ deps/ox/src/ox/std/test/tests.cpp | 4 + deps/ox/src/ox/std/uuid.hpp | 2 +- deps/ox/src/ox/std/vector.hpp | 2 +- 10 files changed, 137 insertions(+), 243 deletions(-) create mode 100644 deps/ox/src/ox/std/stringliteral.hpp diff --git a/deps/ox/src/ox/std/CMakeLists.txt b/deps/ox/src/ox/std/CMakeLists.txt index dcb947d7..07b965bc 100644 --- a/deps/ox/src/ox/std/CMakeLists.txt +++ b/deps/ox/src/ox/std/CMakeLists.txt @@ -118,6 +118,7 @@ install( std.hpp stddef.hpp string.hpp + stringliteral.hpp stringview.hpp strongint.hpp strops.hpp diff --git a/deps/ox/src/ox/std/memory.hpp b/deps/ox/src/ox/std/memory.hpp index 8457fbd2..94af0371 100644 --- a/deps/ox/src/ox/std/memory.hpp +++ b/deps/ox/src/ox/std/memory.hpp @@ -282,10 +282,10 @@ constexpr bool operator!=(std::nullptr_t, const UniquePtr &p2) noexcept { } -template +template [[nodiscard]] constexpr auto make_unique(Args&&... args) { - return UniquePtr(new T(ox::forward(args)...)); + return UniquePtr(new T(ox::forward(args)...)); } } diff --git a/deps/ox/src/ox/std/new.hpp b/deps/ox/src/ox/std/new.hpp index ac3ed318..228fa8cc 100644 --- a/deps/ox/src/ox/std/new.hpp +++ b/deps/ox/src/ox/std/new.hpp @@ -35,9 +35,9 @@ constexpr void *operator new[](std::size_t, void *addr) noexcept { namespace ox { -template +template [[nodiscard]] -constexpr T *make(Args &&...args) noexcept { +constexpr U *make(Args &&...args) noexcept { #ifdef __cpp_exceptions try { return new T(ox::forward(args)...); diff --git a/deps/ox/src/ox/std/string.hpp b/deps/ox/src/ox/std/string.hpp index de1f0b1d..087480d5 100644 --- a/deps/ox/src/ox/std/string.hpp +++ b/deps/ox/src/ox/std/string.hpp @@ -118,6 +118,8 @@ class BasicString { constexpr BasicString &operator=(BasicString &&src) noexcept; + constexpr BasicString &operator=(CRStringView src) noexcept; + constexpr BasicString &operator+=(const char *str) noexcept; constexpr BasicString &operator+=(char *str) noexcept; @@ -341,7 +343,15 @@ constexpr BasicString &BasicString::operat template constexpr BasicString &BasicString::operator=(BasicString &&src) noexcept { - m_buff = std::move(src.m_buff); + if (this != &src) { + m_buff = std::move(src.m_buff); + } + return *this; +} + +template +constexpr BasicString &BasicString::operator=(CRStringView src) noexcept { + set(src); return *this; } diff --git a/deps/ox/src/ox/std/stringliteral.hpp b/deps/ox/src/ox/std/stringliteral.hpp new file mode 100644 index 00000000..f6566221 --- /dev/null +++ b/deps/ox/src/ox/std/stringliteral.hpp @@ -0,0 +1,47 @@ +/* + * Copyright 2015 - 2022 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 "basestringview.hpp" + +namespace ox { + +/** + * StringLiteral is used for functions that want to ensure that they are taking + * string literals, and not strings outside of the data section of the program + * that might get deleted. + * This type cannot force you to use it correctly, so don't give it something + * that is not a literal. + * If you do this: + * StringLiteral(str.c_str()) + * the resulting segfault is on you. + */ +class StringLiteral: public detail::BaseStringView { + public: + constexpr StringLiteral() noexcept = default; + + constexpr StringLiteral(StringLiteral const&sv) noexcept = default; + + constexpr explicit StringLiteral(std::nullptr_t) noexcept {} + + constexpr explicit StringLiteral(const char *str) noexcept: BaseStringView(str) {} + + constexpr explicit StringLiteral(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {} + + constexpr auto &operator=(StringLiteral const&other) noexcept { + if (&other != this) { + set(other.data(), other.len()); + } + return *this; + } + + +}; + +} diff --git a/deps/ox/src/ox/std/stringview.hpp b/deps/ox/src/ox/std/stringview.hpp index 69f5cc16..e6307968 100644 --- a/deps/ox/src/ox/std/stringview.hpp +++ b/deps/ox/src/ox/std/stringview.hpp @@ -13,11 +13,11 @@ #endif #include "bit.hpp" +#include "concepts.hpp" #include "iterator.hpp" +#include "stringliteral.hpp" #include "strops.hpp" -#include "types.hpp" #include "vector.hpp" -#include "writer.hpp" namespace ox { @@ -27,256 +27,69 @@ class BString; template class BasicString; -class StringView { - 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; +class StringView: public detail::BaseStringView { public: constexpr StringView() noexcept = default; constexpr StringView(const StringView &sv) noexcept = default; #ifdef OX_USE_STDLIB - constexpr StringView(const std::string_view &sv) noexcept: m_str(sv.data()), m_len(sv.size()) {} + constexpr StringView(const std::string_view &sv) noexcept: BaseStringView(sv.data(), sv.size()) {} #endif template - constexpr StringView(const BasicString &str) noexcept: m_str(str.c_str()), m_len(str.len()) {} + constexpr StringView(BaseStringView const&str) noexcept: BaseStringView(str.data(), str.bytes()) {} template - constexpr StringView(const BString &str) noexcept: m_str(str.c_str()), m_len(str.len()) {} + constexpr StringView(const BasicString &str) noexcept: BaseStringView(str.data(), str.len()) {} + + template + constexpr StringView(const BString &str) noexcept: BaseStringView(str.data(), str.len()) {} constexpr StringView(std::nullptr_t) noexcept {} - constexpr StringView(const char *str) noexcept: m_str(str), m_len(str ? ox_strlen(str) : 0) {} + constexpr StringView(const char *str) noexcept: BaseStringView(str) {} - constexpr StringView(const char *str, std::size_t len) noexcept: m_str(str), m_len(len) {} + constexpr StringView(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {} - [[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 substr(std::size_t pos) const noexcept { - if (m_len >= pos) { - return StringView(m_str + pos, m_len - pos); - } - return StringView(); - } - - [[nodiscard]] - constexpr auto substr(std::size_t start, std::size_t end) const noexcept { - if (m_len >= start && end >= start) { - return StringView(m_str + start, end - start); - } - return StringView(); - } - - constexpr auto operator[](std::size_t i) const noexcept { - return m_str[i]; - } - - constexpr ox::StringView &operator=(const StringView &other) noexcept = default; - - constexpr auto operator==(const StringView &other) const noexcept { - if (other.len() != len()) { - return false; - } - return ox_strncmp(m_str, other.m_str, len()) == 0; - } - - constexpr auto operator<=>(const StringView &str2) const noexcept { - const StringView &str1 = *this; - const auto maxLen = ox::min(str1.len(), str2.len()); - const auto a = &str1.front(); - const auto b = &str2.front(); - for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) { - if (a[i] < b[i]) { - return -1; - } else if (a[i] > b[i]) { - return 1; - } - } - if (str1.len() > str2.len()) { - return 1; - } else if (str1.len() < str2.len()) { - return -1; - } else { - return 0; + constexpr auto &operator=(StringView const&other) noexcept { + if (&other != this) { + set(other.data(), other.len()); } + return *this; } }; using CRStringView = const StringView&; +constexpr auto operator==(CRStringView s1, CRStringView s2) noexcept { + if (s2.len() != s1.len()) { + return false; + } + return ox_strncmp(s1.data(), s2.data(), s1.len()) == 0; +} + +constexpr auto operator<=>(CRStringView s1, CRStringView s2) noexcept { + const auto maxLen = ox::min(s1.len(), s2.len()); + const auto a = &s1.front(); + const auto b = &s2.front(); + for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) { + if (a[i] < b[i]) { + return -1; + } else if (a[i] > b[i]) { + return 1; + } + } + if (s1.len() > s2.len()) { + return 1; + } else if (s1.len() < s2.len()) { + return -1; + } else { + return 0; + } +} + [[nodiscard]] constexpr bool beginsWith(CRStringView base, CRStringView beginning) noexcept { const auto beginningLen = ox::min(beginning.len(), base.len()); @@ -302,7 +115,7 @@ constexpr std::size_t find(CRStringView str, char search) noexcept { constexpr std::size_t find(CRStringView str, CRStringView search) noexcept { std::size_t i = 0; for (; i < str.len(); ++i) { - if (beginsWith(str.substr(i), search)) { + if (beginsWith(substr(str, i), search)) { break; } } @@ -313,14 +126,14 @@ template constexpr ox::Vector split(CRStringView str, char del) noexcept { ox::Vector out; constexpr auto nextSeg = [](CRStringView current, char del) { - return current.substr(find(current, del) + 1); + 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 = current.substr(0, next); s.len()) { + if (const auto s = substr(current, 0, next); s.len()) { out.emplace_back(s); } - current = current.substr(next); + current = substr(current, next); } return out; } @@ -329,14 +142,14 @@ template constexpr ox::Vector split(CRStringView str, CRStringView del) noexcept { ox::Vector out; constexpr auto nextSeg = [](CRStringView current, CRStringView del) { - return current.substr(find(current, del) + del.len()); + 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 = current.substr(0, next); s.len()) { + if (const auto s = substr(current, 0, next); s.len()) { out.emplace_back(s); } - current = current.substr(next); + current = substr(current, next); } return out; } diff --git a/deps/ox/src/ox/std/strops.hpp b/deps/ox/src/ox/std/strops.hpp index cf01354c..37a9ca1c 100644 --- a/deps/ox/src/ox/std/strops.hpp +++ b/deps/ox/src/ox/std/strops.hpp @@ -8,6 +8,7 @@ #pragma once +#include "concepts.hpp" #include "error.hpp" #include "math.hpp" #include "types.hpp" @@ -128,6 +129,24 @@ constexpr int ox_lastIndexOf(const auto &str, int character, std::size_t maxLen namespace ox { +template +[[nodiscard]] +constexpr Str substr(Str const&str, std::size_t pos) noexcept { + if (str.len() >= pos) { + return Str(str.data() + pos, str.len() - pos); + } + return Str(); +} + +template +[[nodiscard]] +constexpr Str substr(Str const&str, std::size_t start, std::size_t end) noexcept { + if (str.len() >= start && end >= start) { + return Str(str.data() + start, end - start); + } + return Str(); +} + template constexpr ox::Error itoa(Integer v, ox::Writer_c auto &writer) noexcept { if (v) { diff --git a/deps/ox/src/ox/std/test/tests.cpp b/deps/ox/src/ox/std/test/tests.cpp index 815d66cc..3703639d 100644 --- a/deps/ox/src/ox/std/test/tests.cpp +++ b/deps/ox/src/ox/std/test/tests.cpp @@ -105,6 +105,10 @@ static std::map tests = { oxAssert(endsWith(str, "df"), "String endsWith is broken"); oxAssert(!endsWith(str, "awefawe"), "String endsWith is broken"); oxAssert(!endsWith(str, "eu"), "String endsWith is broken"); + oxAssert(ox::StringView("Write") != ox::String(""), "String / StringView comparison broken"); + oxAssert(ox::String("Write") != ox::StringView(""), "String / StringView comparison broken"); + oxAssert(ox::String("Write") == ox::StringView("Write"), "String / StringView comparison broken"); + oxAssert(ox::String(ox::StringView("Write")) == ox::StringView("Write"), "String / StringView comparison broken"); return OxError(0); } }, diff --git a/deps/ox/src/ox/std/uuid.hpp b/deps/ox/src/ox/std/uuid.hpp index 96c74c94..5374588c 100644 --- a/deps/ox/src/ox/std/uuid.hpp +++ b/deps/ox/src/ox/std/uuid.hpp @@ -132,7 +132,7 @@ class UUID { ++i; continue; } - const auto seg = s.substr(i, i + 2); + const auto seg = substr(s, i, i + 2); if (seg.len() != 2) { return OxError(1, "Invalid UUID"); } diff --git a/deps/ox/src/ox/std/vector.hpp b/deps/ox/src/ox/std/vector.hpp index 69bfbc49..0b588a6b 100644 --- a/deps/ox/src/ox/std/vector.hpp +++ b/deps/ox/src/ox/std/vector.hpp @@ -324,7 +324,7 @@ constexpr Vector::Vector(std::size_t size) noexce template constexpr Vector::Vector(std::initializer_list list) noexcept { for (auto &item : list) { - emplace_back(item); + emplace_back(std::move(item)); } }