mirror of
https://github.com/hyprwm/hyprutils.git
synced 2025-12-20 03:30:22 +01:00
string: add VarList2 (#84)
reworks how varList works, mixes best of both ConstVarList and regular VarList. Deprecates both.
This commit is contained in:
parent
968f881222
commit
9a9745d7aa
7 changed files with 236 additions and 22 deletions
|
|
@ -4,8 +4,10 @@
|
||||||
namespace Hyprutils {
|
namespace Hyprutils {
|
||||||
namespace String {
|
namespace String {
|
||||||
// trims beginning and end of whitespace characters
|
// trims beginning and end of whitespace characters
|
||||||
std::string trim(const std::string& in);
|
std::string trim(const char* in);
|
||||||
bool isNumber(const std::string& str, bool allowfloat = false);
|
std::string trim(const std::string& in);
|
||||||
void replaceInString(std::string& string, const std::string& what, const std::string& to);
|
std::string_view trim(const std::string_view& in);
|
||||||
|
bool isNumber(const std::string& str, bool allowfloat = false);
|
||||||
|
void replaceInString(std::string& string, const std::string& what, const std::string& to);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
50
include/hyprutils/string/VarList2.hpp
Normal file
50
include/hyprutils/string/VarList2.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Hyprutils {
|
||||||
|
namespace String {
|
||||||
|
class CVarList2 {
|
||||||
|
public:
|
||||||
|
/** Split string into arg list
|
||||||
|
Prefer this over CConstVarList / CVarList, this is better.
|
||||||
|
|
||||||
|
@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
|
||||||
|
@param allowEscape whether to allow escaping the delimiter
|
||||||
|
*/
|
||||||
|
CVarList2(std::string&& in, const size_t lastArgNo = 0, const char delim = ',', const bool removeEmpty = false, const bool allowEscape = true);
|
||||||
|
|
||||||
|
~CVarList2() = 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 append(std::string&& arg);
|
||||||
|
bool contains(const std::string& el);
|
||||||
|
|
||||||
|
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<std::string_view>::const_iterator begin() const {
|
||||||
|
return m_args.begin();
|
||||||
|
}
|
||||||
|
std::vector<std::string_view>::const_iterator end() const {
|
||||||
|
return m_args.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_inString;
|
||||||
|
std::vector<std::string> m_copyStrings;
|
||||||
|
std::vector<std::string_view> m_args;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,26 +1,10 @@
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <hyprutils/string/String.hpp>
|
||||||
#include <hyprutils/string/ConstVarList.hpp>
|
#include <hyprutils/string/ConstVarList.hpp>
|
||||||
|
|
||||||
using namespace Hyprutils::String;
|
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) {
|
CConstVarList::CConstVarList(const std::string& in, const size_t lastArgNo, const char delim, const bool removeEmpty) : m_str(in) {
|
||||||
if (in.empty())
|
if (in.empty())
|
||||||
return;
|
return;
|
||||||
|
|
@ -37,7 +21,7 @@ CConstVarList::CConstVarList(const std::string& in, const size_t lastArgNo, cons
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pos += s.size() + 1;
|
pos += s.size() + 1;
|
||||||
m_args.emplace_back(trim(s.data()));
|
m_args.emplace_back(trim(std::string_view{s.data()}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,27 @@ std::string Hyprutils::String::trim(const std::string& in) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string_view Hyprutils::String::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Hyprutils::String::trim(const char* in) {
|
||||||
|
return trim(std::string{in});
|
||||||
|
}
|
||||||
|
|
||||||
bool Hyprutils::String::isNumber(const std::string& str, bool allowfloat) {
|
bool Hyprutils::String::isNumber(const std::string& str, bool allowfloat) {
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ Hyprutils::String::CVarList::CVarList(const std::string& in, const size_t lastAr
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pos += s.size() + 1;
|
pos += s.size() + 1;
|
||||||
m_vArgs.emplace_back(trim(s.data()));
|
m_vArgs.emplace_back(trim(std::string{s.data()}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
112
src/string/VarList2.cpp
Normal file
112
src/string/VarList2.cpp
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <hyprutils/string/VarList2.hpp>
|
||||||
|
#include <hyprutils/string/String.hpp>
|
||||||
|
|
||||||
|
using namespace Hyprutils::String;
|
||||||
|
|
||||||
|
CVarList2::CVarList2(std::string&& in, const size_t lastArgNo, const char delim, const bool removeEmpty, const bool allowEscape) : m_inString(std::move(in)) {
|
||||||
|
if (!removeEmpty && m_inString.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto isDelimiter = [&delim](const char& c) { return delim == 's' ? std::isspace(c) : delim == c; };
|
||||||
|
|
||||||
|
size_t argBegin = 0;
|
||||||
|
std::vector<size_t> escapedIndices; // local to the current arg
|
||||||
|
for (size_t i = 0; i < m_inString.size(); ++i) {
|
||||||
|
const char& c = m_inString[i];
|
||||||
|
|
||||||
|
if (!isDelimiter(c))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (allowEscape) {
|
||||||
|
// we allow escape, so this might be escaped. Check first
|
||||||
|
if (i - argBegin == 0)
|
||||||
|
continue; // can't be
|
||||||
|
const char& previousC = m_inString[i - 1];
|
||||||
|
if (i - argBegin == 1) {
|
||||||
|
if (previousC == '\\') {
|
||||||
|
escapedIndices.emplace_back(i - argBegin - 1);
|
||||||
|
continue; // escaped
|
||||||
|
}
|
||||||
|
// fall to breaking, not escaped
|
||||||
|
} else {
|
||||||
|
const char& prevPreviousC = m_inString[i - 2];
|
||||||
|
if (previousC == '\\') {
|
||||||
|
// whether or not escaped, pop char
|
||||||
|
escapedIndices.emplace_back(i - argBegin - 1);
|
||||||
|
|
||||||
|
if (prevPreviousC != '\\') {
|
||||||
|
// escaped
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fall to breaking, not escaped, but mark the \\ to be popped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we found a delimiter and need to break up the string (not escaped)
|
||||||
|
|
||||||
|
if (escapedIndices.empty()) {
|
||||||
|
// we didn't escape anything, so we can use inString
|
||||||
|
const auto ARG = trim(std::string_view{m_inString}.substr(argBegin, i - argBegin));
|
||||||
|
|
||||||
|
if (!ARG.empty() || !removeEmpty)
|
||||||
|
m_args.emplace_back(ARG);
|
||||||
|
} else {
|
||||||
|
// we escaped something, fixup the string, add to copies, then emplace
|
||||||
|
std::string cpy = m_inString.substr(argBegin, i - argBegin);
|
||||||
|
for (size_t i = 0; i < escapedIndices.size(); ++i) {
|
||||||
|
cpy = cpy.substr(0, escapedIndices[i] - i) + cpy.substr(escapedIndices[i] - i + 1);
|
||||||
|
}
|
||||||
|
m_copyStrings.emplace_back(std::move(cpy));
|
||||||
|
m_args.emplace_back(trim(std::string_view{m_copyStrings.back()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// update next argBegin
|
||||||
|
argBegin = i + 1;
|
||||||
|
escapedIndices.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// append anything left
|
||||||
|
if (argBegin < m_inString.size()) {
|
||||||
|
if (escapedIndices.empty()) {
|
||||||
|
// we didn't escape anything, so we can use inString
|
||||||
|
const auto ARG = trim(std::string_view{m_inString}.substr(argBegin, m_inString.size() - argBegin));
|
||||||
|
|
||||||
|
if (!ARG.empty() || !removeEmpty)
|
||||||
|
m_args.emplace_back(ARG);
|
||||||
|
} else {
|
||||||
|
// we escaped something, fixup the string, add to copies, then emplace
|
||||||
|
std::string cpy = m_inString.substr(argBegin, m_inString.size() - argBegin);
|
||||||
|
for (size_t i = 0; i < escapedIndices.size(); ++i) {
|
||||||
|
cpy = cpy.substr(0, escapedIndices[i] - i) + cpy.substr(escapedIndices[i] - i + 1);
|
||||||
|
}
|
||||||
|
m_copyStrings.emplace_back(std::move(cpy));
|
||||||
|
m_args.emplace_back(trim(std::string_view{m_copyStrings.back()}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CVarList2::join(const std::string& joiner, size_t from, size_t to) const {
|
||||||
|
if (to == 0 || to <= from)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
std::string roll;
|
||||||
|
for (size_t i = from; i < to; ++i) {
|
||||||
|
roll += m_args[i];
|
||||||
|
if (i + 1 < to)
|
||||||
|
roll += joiner;
|
||||||
|
}
|
||||||
|
return roll;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CVarList2::append(std::string&& arg) {
|
||||||
|
m_copyStrings.emplace_back(std::move(arg));
|
||||||
|
m_args.emplace_back(m_copyStrings.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CVarList2::contains(const std::string& el) {
|
||||||
|
return std::ranges::any_of(m_args, [&el](const auto& e) { return e == el; });
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include <hyprutils/string/String.hpp>
|
#include <hyprutils/string/String.hpp>
|
||||||
#include <hyprutils/string/VarList.hpp>
|
#include <hyprutils/string/VarList.hpp>
|
||||||
|
#include <hyprutils/string/VarList2.hpp>
|
||||||
#include <hyprutils/string/ConstVarList.hpp>
|
#include <hyprutils/string/ConstVarList.hpp>
|
||||||
#include "shared.hpp"
|
#include "shared.hpp"
|
||||||
|
|
||||||
|
|
@ -47,6 +48,50 @@ int main(int argc, char** argv, char** envp) {
|
||||||
EXPECT(listConst2[0], "0");
|
EXPECT(listConst2[0], "0");
|
||||||
EXPECT(listConst2[1], "set");
|
EXPECT(listConst2[1], "set");
|
||||||
|
|
||||||
|
CVarList2 varList2("0 set", 2, ' ');
|
||||||
|
EXPECT(varList2[0], "0");
|
||||||
|
EXPECT(varList2[1], "set");
|
||||||
|
|
||||||
|
varList2.append("Hello");
|
||||||
|
|
||||||
|
EXPECT(varList2[1], "set");
|
||||||
|
EXPECT(varList2[2], "Hello");
|
||||||
|
|
||||||
|
CVarList2 varList2B("hello, world\\, ok?", 0, ',', true, true);
|
||||||
|
EXPECT(varList2B[0], "hello");
|
||||||
|
EXPECT(varList2B[1], "world, ok?");
|
||||||
|
|
||||||
|
CVarList2 varList2C("hello, , ok?", 0, ',', true, true);
|
||||||
|
EXPECT(varList2C[0], "hello");
|
||||||
|
EXPECT(varList2C[1], "ok?");
|
||||||
|
|
||||||
|
CVarList2 varList2D("\\\\, , ok?", 0, ',', true, true);
|
||||||
|
EXPECT(varList2D[0], "\\");
|
||||||
|
EXPECT(varList2D[1], "ok?");
|
||||||
|
|
||||||
|
CVarList2 varList2E("\\, , ok?", 0, ',', true, true);
|
||||||
|
EXPECT(varList2E[0], ",");
|
||||||
|
EXPECT(varList2E[1], "ok?");
|
||||||
|
|
||||||
|
CVarList2 varList2F("Hello, world\\\\, ok?", 0, ',', true, true);
|
||||||
|
EXPECT(varList2F[0], "Hello");
|
||||||
|
EXPECT(varList2F[1], "world\\");
|
||||||
|
EXPECT(varList2F[2], "ok?");
|
||||||
|
|
||||||
|
CVarList2 varList2G("Hello,\\, ok?", 0, ',', true, true);
|
||||||
|
EXPECT(varList2G[0], "Hello");
|
||||||
|
EXPECT(varList2G[1], ", ok?");
|
||||||
|
|
||||||
|
CVarList2 varList2H("Hello,\\\\, ok?", 0, ',', true, true);
|
||||||
|
EXPECT(varList2H[0], "Hello");
|
||||||
|
EXPECT(varList2H[1], "\\");
|
||||||
|
EXPECT(varList2H[2], "ok?");
|
||||||
|
|
||||||
|
CVarList2 varList2I("Hello,\\, ok?", 0, ',', true, false);
|
||||||
|
EXPECT(varList2I[0], "Hello");
|
||||||
|
EXPECT(varList2I[1], "\\");
|
||||||
|
EXPECT(varList2I[2], "ok?");
|
||||||
|
|
||||||
std::string hello = "hello world!";
|
std::string hello = "hello world!";
|
||||||
replaceInString(hello, "hello", "hi");
|
replaceInString(hello, "hello", "hi");
|
||||||
EXPECT(hello, "hi world!");
|
EXPECT(hello, "hi world!");
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue