diff --git a/deps/ox/src/ox/std/optional.hpp b/deps/ox/src/ox/std/optional.hpp index de302910..ab0cfc02 100644 --- a/deps/ox/src/ox/std/optional.hpp +++ b/deps/ox/src/ox/std/optional.hpp @@ -28,7 +28,7 @@ class Optional { constexpr Optional() noexcept = default; template - constexpr Optional(Args &&... args); + explicit constexpr Optional(Args &&... args); constexpr Optional(const Optional &other) { if (other.m_ptr) { @@ -131,7 +131,7 @@ class Optional { if (std::is_constant_evaluated()) { m_ptr = new U(ox::forward(args)...); } else { - m_ptr = std::construct_at(reinterpret_cast(m_data.data()), ox::forward(args)...); + m_ptr = std::construct_at(reinterpret_cast(m_data.data()), ox::forward(args)...); } return *m_ptr; } diff --git a/deps/ox/src/ox/std/test/CMakeLists.txt b/deps/ox/src/ox/std/test/CMakeLists.txt index a16dd009..05add638 100644 --- a/deps/ox/src/ox/std/test/CMakeLists.txt +++ b/deps/ox/src/ox/std/test/CMakeLists.txt @@ -19,4 +19,5 @@ add_test("[ox/std] HeapMgr" StdTest malloc) add_test("[ox/std] Serialize-Int" StdTest "Serialize-Int") add_test("[ox/std] BufferWriter" StdTest "BufferWriter") add_test("[ox/std] StringSplit" StdTest "StringSplit") +add_test("[ox/std] FromHex" StdTest "FromHex") add_test("[ox/std] ToHex" StdTest "ToHex") diff --git a/deps/ox/src/ox/std/test/tests.cpp b/deps/ox/src/ox/std/test/tests.cpp index d5916dbf..9d96c9de 100644 --- a/deps/ox/src/ox/std/test/tests.cpp +++ b/deps/ox/src/ox/std/test/tests.cpp @@ -60,6 +60,8 @@ static std::map tests = { oxAssert(s == "AB9C", "BString append broken"); s = "asdf"; oxAssert(s == "asdf", "String assign broken"); + oxAssert(s != "aoeu", "String assign broken"); + oxAssert(s.len() == 4, "String assign broken"); return OxError(0); } }, @@ -156,6 +158,29 @@ static std::map tests = { return OxError(0); } }, + { + "FromHex", + [] { + oxExpect(ox::detail::fromHex("01").unwrap(), 0x01); + oxExpect(ox::detail::fromHex("02").unwrap(), 0x02); + oxExpect(ox::detail::fromHex("03").unwrap(), 0x03); + oxExpect(ox::detail::fromHex("04").unwrap(), 0x04); + oxExpect(ox::detail::fromHex("05").unwrap(), 0x05); + oxExpect(ox::detail::fromHex("06").unwrap(), 0x06); + oxExpect(ox::detail::fromHex("07").unwrap(), 0x07); + oxExpect(ox::detail::fromHex("08").unwrap(), 0x08); + oxExpect(ox::detail::fromHex("0d").unwrap(), 0x0d); + oxExpect(ox::detail::fromHex("0e").unwrap(), 0x0e); + oxExpect(ox::detail::fromHex("0f").unwrap(), 0x0f); + oxExpect(ox::detail::fromHex("0F").unwrap(), 0x0f); + oxExpect(ox::detail::fromHex("fF").unwrap(), 0xff); + oxExpect(ox::detail::fromHex("ff").unwrap(), 0xff); + oxExpect(ox::detail::fromHex("a0").unwrap(), 0xa0); + oxExpect(ox::detail::fromHex("93").unwrap(), 0x93); + oxExpect(ox::detail::fromHex("40").unwrap(), 0x40); + return OxError(0); + } + }, { "ToHex", [] { @@ -168,7 +193,7 @@ static std::map tests = { oxExpect(ox::detail::toHex(0x07), "07"); oxExpect(ox::detail::toHex(0x08), "08"); oxExpect(ox::detail::toHex(0x0d), "0d"); - oxExpect(ox::detail::toHex(0x0e), "03"); + oxExpect(ox::detail::toHex(0x0e), "0e"); oxExpect(ox::detail::toHex(0x0f), "0f"); oxExpect(ox::detail::toHex(0x93), "93"); oxExpect(ox::detail::toHex(0x40), "40"); diff --git a/deps/ox/src/ox/std/uuid.cpp b/deps/ox/src/ox/std/uuid.cpp index a82286d7..4e9c833f 100644 --- a/deps/ox/src/ox/std/uuid.cpp +++ b/deps/ox/src/ox/std/uuid.cpp @@ -13,7 +13,7 @@ namespace ox { bool UUID::s_seeded = false; Random UUID::s_rand; -void UUID::seed(const RandomSeed &seed) noexcept { +void UUID::seedGenerator(const RandomSeed &seed) noexcept { s_seeded = true; s_rand.seed(seed); } diff --git a/deps/ox/src/ox/std/uuid.hpp b/deps/ox/src/ox/std/uuid.hpp index 079dccb5..34f42d7b 100644 --- a/deps/ox/src/ox/std/uuid.hpp +++ b/deps/ox/src/ox/std/uuid.hpp @@ -11,12 +11,56 @@ #include "array.hpp" #include "bstring.hpp" #include "random.hpp" +#include "stringview.hpp" #include "strops.hpp" #include "trace.hpp" namespace ox { +using UUIDStr = ox::BString<36>; + namespace detail { + +[[nodiscard]] +constexpr auto isHexChar(char c) noexcept { + return (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F'); +} + +constexpr ox::Result fromHex(ox::CRStringView v) noexcept { + constexpr auto valMap = [] { + ox::Array out; + out['A'] = out['a'] = 10; + out['B'] = out['b'] = 11; + out['C'] = out['c'] = 12; + out['D'] = out['d'] = 13; + out['E'] = out['e'] = 14; + out['F'] = out['f'] = 15; + out['0'] = 0; + out['1'] = 1; + out['2'] = 2; + out['3'] = 3; + out['4'] = 4; + out['5'] = 5; + out['6'] = 6; + out['7'] = 7; + out['8'] = 8; + out['9'] = 9; + return out; + }(); + if (!detail::isHexChar(v[0]) || !detail::isHexChar(v[1])) { + return OxError(1, "Invalid UUID"); + } + if (v.len() != 2) { + return OxError(2); + } + uint8_t out = 0; + out += valMap[static_cast(v[0])] * 16u; + out += valMap[static_cast(v[1])]; + return out; +} + constexpr ox::BString<2> toHex(uint8_t v) noexcept { constexpr ox::Array valMap { '0', @@ -42,6 +86,7 @@ constexpr ox::BString<2> toHex(uint8_t v) noexcept { out[2] = 0; return out.data(); } + } class UUID { @@ -51,13 +96,35 @@ class UUID { ox::Array m_value; public: - static void seed(const RandomSeed &seed) noexcept; + static void seedGenerator(const RandomSeed &seed) noexcept; static ox::Result generate() noexcept; + constexpr ox::Error fromString(ox::CRStringView s) noexcept { + if (s.len() < 36) { + return OxError(1, "Insufficient data contain complete UUID"); + } + auto valueI = 0u; + for (auto i = 0u; i < s.len();) { + if (s[i] == '-') { + ++i; + continue; + } + const auto seg = s.substr(i, i + 2); + if (seg.len() != 2) { + return OxError(1, "Invalid UUID"); + } + oxRequire(val, detail::fromHex(seg)); + m_value[valueI] = val; + i += 2; + ++valueI; + } + return {}; + } + [[nodiscard]] - constexpr ox::BString<36> toString() const noexcept { - ox::BString<36> out; + constexpr UUIDStr toString() const noexcept { + UUIDStr out; auto i = 0u; constexpr auto printChars = []( ox::BString<36> *out, const Array &value, std::size_t cnt, unsigned i) {