From 3c9e6d10eac68f824c56b13b0ad5fe683dab779f Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sat, 4 Feb 2023 22:59:44 -0600 Subject: [PATCH] [ox/std] Add StringView split and find functions --- deps/ox/src/ox/std/stringview.hpp | 70 ++++++++++++++++++++++++-- deps/ox/src/ox/std/test/CMakeLists.txt | 1 + deps/ox/src/ox/std/test/tests.cpp | 69 ++++++++++++++++++++++++- 3 files changed, 136 insertions(+), 4 deletions(-) diff --git a/deps/ox/src/ox/std/stringview.hpp b/deps/ox/src/ox/std/stringview.hpp index e1a65559..652a4a86 100644 --- a/deps/ox/src/ox/std/stringview.hpp +++ b/deps/ox/src/ox/std/stringview.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 gary@drinkingtea.net + * 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 @@ -12,10 +12,11 @@ #include #endif +#include "bit.hpp" #include "iterator.hpp" #include "strops.hpp" #include "types.hpp" -#include "bit.hpp" +#include "vector.hpp" namespace ox { @@ -223,7 +224,18 @@ class StringView { [[nodiscard]] constexpr auto substr(std::size_t pos) const noexcept { - return StringView(m_str + pos, m_len - pos); + 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 { @@ -276,6 +288,58 @@ constexpr bool endsWith(CRStringView base, CRStringView ending) noexcept { 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(str.substr(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 current.substr(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()) { + out.emplace_back(s); + } + current = current.substr(next); + } + return out; +} + +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()); + }; + 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()) { + out.emplace_back(s); + } + current = current.substr(next); + } + return out; +} + #ifdef OX_USE_STDLIB constexpr auto toStdStringView(CRStringView sv) noexcept { return std::string_view(sv.data(), sv.bytes()); diff --git a/deps/ox/src/ox/std/test/CMakeLists.txt b/deps/ox/src/ox/std/test/CMakeLists.txt index d77197eb..140a7c1d 100644 --- a/deps/ox/src/ox/std/test/CMakeLists.txt +++ b/deps/ox/src/ox/std/test/CMakeLists.txt @@ -18,3 +18,4 @@ add_test("[ox/std] HashMap" StdTest "HashMap") 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") diff --git a/deps/ox/src/ox/std/test/tests.cpp b/deps/ox/src/ox/std/test/tests.cpp index 5ffbf490..7f5b7c91 100644 --- a/deps/ox/src/ox/std/test/tests.cpp +++ b/deps/ox/src/ox/std/test/tests.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 gary@drinkingtea.net + * 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 @@ -155,6 +155,73 @@ static std::map tests = { return OxError(0); } }, + { + "StringSplit", + [] { + ox::StringView sv = "ab.cd"; + auto list = ox::split(sv, "."); + oxExpect(list.size(), 2u); + oxExpect(list[0], "ab"); + oxExpect(list[1], "cd"); + sv = "ab.cd.fg"; + list = ox::split(sv, "."); + oxExpect(list.size(), 3u); + oxExpect(list[0], "ab"); + oxExpect(list[1], "cd"); + oxExpect(list[2], "fg"); + sv = "ab.cd."; + list = ox::split(sv, "."); + oxExpect(list.size(), 2u); + oxExpect(list[0], "ab"); + oxExpect(list[1], "cd"); + sv = ".ab.cd."; + list = ox::split(sv, "."); + oxExpect(list.size(), 2u); + oxExpect(list[0], "ab"); + oxExpect(list[1], "cd"); + sv = "."; + list = ox::split(sv, "."); + oxExpect(list.size(), 0u); + sv = "."; + list = ox::split(sv, "."); + oxExpect(list.size(), 0u); + sv = ""; + list = ox::split(sv, "."); + oxExpect(list.size(), 0u); + // split by single char + sv = "ab.cd"; + list = ox::split(sv, '.'); + oxExpect(list.size(), 2u); + oxExpect(list[0], "ab"); + oxExpect(list[1], "cd"); + sv = "ab.cd.fg"; + list = ox::split(sv, '.'); + oxExpect(list.size(), 3u); + oxExpect(list[0], "ab"); + oxExpect(list[1], "cd"); + oxExpect(list[2], "fg"); + sv = "ab.cd."; + list = ox::split(sv, '.'); + oxExpect(list.size(), 2u); + oxExpect(list[0], "ab"); + oxExpect(list[1], "cd"); + sv = ".ab.cd."; + list = ox::split(sv, '.'); + oxExpect(list.size(), 2u); + oxExpect(list[0], "ab"); + oxExpect(list[1], "cd"); + sv = "."; + list = ox::split(sv, '.'); + oxExpect(list.size(), 0u); + sv = "."; + list = ox::split(sv, '.'); + oxExpect(list.size(), 0u); + sv = ""; + list = ox::split(sv, '.'); + oxExpect(list.size(), 0u); + return OxError(0); + } + }, }; int main(int argc, const char **args) {