mirror of
https://github.com/hyprwm/hyprutils.git
synced 2025-12-20 08:10:10 +01:00
string: add VarList2
reworks how varList works, mixes best of both ConstVarList and regular VarList. Deprecates both.
This commit is contained in:
parent
968f881222
commit
b5ed73ace1
7 changed files with 231 additions and 22 deletions
|
|
@ -4,8 +4,10 @@
|
|||
namespace Hyprutils {
|
||||
namespace String {
|
||||
// trims beginning and end of whitespace characters
|
||||
std::string trim(const std::string& in);
|
||||
bool isNumber(const std::string& str, bool allowfloat = false);
|
||||
void replaceInString(std::string& string, const std::string& what, const std::string& to);
|
||||
std::string trim(const char* in);
|
||||
std::string trim(const std::string& in);
|
||||
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 = false);
|
||||
|
||||
~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 <algorithm>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/string/ConstVarList.hpp>
|
||||
|
||||
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;
|
||||
|
|
@ -37,7 +21,7 @@ CConstVarList::CConstVarList(const std::string& in, const size_t lastArgNo, cons
|
|||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (str.empty())
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ Hyprutils::String::CVarList::CVarList(const std::string& in, const size_t lastAr
|
|||
break;
|
||||
}
|
||||
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/VarList.hpp>
|
||||
#include <hyprutils/string/VarList2.hpp>
|
||||
#include <hyprutils/string/ConstVarList.hpp>
|
||||
#include "shared.hpp"
|
||||
|
||||
|
|
@ -47,6 +48,45 @@ int main(int argc, char** argv, char** envp) {
|
|||
EXPECT(listConst2[0], "0");
|
||||
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?");
|
||||
|
||||
std::string hello = "hello world!";
|
||||
replaceInString(hello, "hello", "hi");
|
||||
EXPECT(hello, "hi world!");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue