From 7f00411949481317925e6dd6a44bda3672fd1cbb Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 May 2025 17:26:37 +0100 Subject: [PATCH] string: add ConstVarList --- include/hyprutils/string/ConstVarList.hpp | 64 +++++++++++++++++++++++ src/string/ConstVarList.cpp | 54 +++++++++++++++++++ tests/string.cpp | 5 ++ 3 files changed, 123 insertions(+) create mode 100644 include/hyprutils/string/ConstVarList.hpp create mode 100644 src/string/ConstVarList.cpp diff --git a/include/hyprutils/string/ConstVarList.hpp b/include/hyprutils/string/ConstVarList.hpp new file mode 100644 index 0000000..9cc8cf7 --- /dev/null +++ b/include/hyprutils/string/ConstVarList.hpp @@ -0,0 +1,64 @@ +#pragma once +#include +#include +#include + +namespace Hyprutils { + namespace String { + class CConstVarList { + public: + /** Split string into an immutable arg list + @param lastArgNo stop splitting after argv reaches maximum size, last arg will contain rest of unsplit args + @param delim if delimiter is 's', use std::isspace + @param removeEmpty remove empty args from argv + */ + CConstVarList(const std::string& in, const size_t lastArgNo = 0, const char delim = ',', const bool removeEmpty = false); + + ~CConstVarList() = default; + + size_t size() const { + return m_args.size(); + } + + std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const; + + void map(std::function func) { + for (auto& s : m_args) + func(s); + } + + std::string_view operator[](const size_t& idx) const { + if (idx >= m_args.size()) + return ""; + return m_args[idx]; + } + + // for range-based loops + std::vector::iterator begin() { + return m_args.begin(); + } + std::vector::const_iterator begin() const { + return m_args.begin(); + } + std::vector::iterator end() { + return m_args.end(); + } + std::vector::const_iterator end() const { + return m_args.end(); + } + + bool contains(const std::string_view& el) { + for (auto& a : m_args) { + if (a == el) + return true; + } + + return false; + } + + private: + std::string m_str; + std::vector m_args; + }; + } +} diff --git a/src/string/ConstVarList.cpp b/src/string/ConstVarList.cpp new file mode 100644 index 0000000..4d47503 --- /dev/null +++ b/src/string/ConstVarList.cpp @@ -0,0 +1,54 @@ +#include +#include +#include + +using namespace Hyprutils::String; + +static std::string_view trim(const std::string_view& sv) { + if (sv.empty()) + return sv; + + size_t countBefore = 0; + while (countBefore < sv.length() && std::isspace(sv.at(countBefore))) { + countBefore++; + } + + size_t countAfter = 0; + while (countAfter < sv.length() - countBefore && std::isspace(sv.at(sv.length() - countAfter - 1))) { + countAfter++; + } + + return sv.substr(countBefore, sv.length() - countBefore - countAfter); +} + +CConstVarList::CConstVarList(const std::string& in, const size_t lastArgNo, const char delim, const bool removeEmpty) : m_str(in) { + if (in.empty()) + return; + + size_t idx = 0; + size_t pos = 0; + std::ranges::replace_if(m_str, [&](const char& c) { return delim == 's' ? std::isspace(c) : c == delim; }, 0); + + for (const auto& s : m_str | std::views::split(0)) { + if (removeEmpty && s.empty()) + continue; + if (++idx == lastArgNo) { + m_args.emplace_back(trim(in.substr(pos))); + break; + } + pos += s.size() + 1; + m_args.emplace_back(trim(s.data())); + } +} + +std::string CConstVarList::join(const std::string& joiner, size_t from, size_t to) const { + size_t last = to == 0 ? size() : to; + + std::string rolling; + for (size_t i = from; i < last; ++i) { + // cast can be removed once C++26's change to allow this is supported + rolling += std::string{m_args[i]} + (i + 1 < last ? joiner : ""); + } + + return rolling; +} diff --git a/tests/string.cpp b/tests/string.cpp index 51cb3ad..89fcfa3 100644 --- a/tests/string.cpp +++ b/tests/string.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "shared.hpp" using namespace Hyprutils::String; @@ -38,6 +39,10 @@ int main(int argc, char** argv, char** envp) { EXPECT(list[0], "hello"); EXPECT(list[1], "world!"); + CConstVarList listConst("hello world!", 0, 's', true); + EXPECT(listConst[0], "hello"); + EXPECT(listConst[1], "world!"); + std::string hello = "hello world!"; replaceInString(hello, "hello", "hi"); EXPECT(hello, "hi world!");