mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-17 15:25:35 +00:00
9950adf472
This function had a bug in stable (fixed in dev) when `last` returns npos, but the function also appears to basically be duplicating what the next split version can do, so this just removes it and uses the single more generic split(strview, strview) method.
194 lines
4.5 KiB
C++
194 lines
4.5 KiB
C++
#include "str.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <cstring>
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <set>
|
|
|
|
namespace llarp
|
|
{
|
|
bool
|
|
CaselessLessThan::operator()(std::string_view lhs, std::string_view rhs) const
|
|
{
|
|
const size_t s = std::min(lhs.size(), rhs.size());
|
|
for (size_t i = 0; i < s; ++i)
|
|
{
|
|
auto l = std::tolower(lhs[i]);
|
|
auto r = std::tolower(rhs[i]);
|
|
|
|
if (l < r)
|
|
{
|
|
return true;
|
|
}
|
|
if (l > r)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return lhs.size() < rhs.size();
|
|
}
|
|
|
|
bool
|
|
IsFalseValue(std::string_view str)
|
|
{
|
|
static const std::set<std::string_view, CaselessLessThan> vals{"no", "false", "0", "off"};
|
|
|
|
return vals.count(str) > 0;
|
|
}
|
|
|
|
bool
|
|
IsTrueValue(std::string_view str)
|
|
{
|
|
static const std::set<std::string_view, CaselessLessThan> vals{"yes", "true", "1", "on"};
|
|
|
|
return vals.count(str) > 0;
|
|
}
|
|
|
|
constexpr static char whitespace[] = " \t\n\r\f\v";
|
|
|
|
std::string_view
|
|
TrimWhitespace(std::string_view str)
|
|
{
|
|
size_t begin = str.find_first_not_of(whitespace);
|
|
if (begin == std::string_view::npos)
|
|
{
|
|
str.remove_prefix(str.size());
|
|
return str;
|
|
}
|
|
str.remove_prefix(begin);
|
|
|
|
size_t end = str.find_last_not_of(whitespace);
|
|
if (end != std::string_view::npos)
|
|
str.remove_suffix(str.size() - end - 1);
|
|
|
|
return str;
|
|
}
|
|
|
|
using namespace std::literals;
|
|
|
|
std::vector<std::string_view>
|
|
split(std::string_view str, const std::string_view delim, bool trim)
|
|
{
|
|
std::vector<std::string_view> results;
|
|
// Special case for empty delimiter: splits on each character boundary:
|
|
if (delim.empty())
|
|
{
|
|
results.reserve(str.size());
|
|
for (size_t i = 0; i < str.size(); i++)
|
|
results.emplace_back(str.data() + i, 1);
|
|
return results;
|
|
}
|
|
|
|
for (size_t pos = str.find(delim); pos != std::string_view::npos; pos = str.find(delim))
|
|
{
|
|
if (!trim || !results.empty() || pos > 0)
|
|
results.push_back(str.substr(0, pos));
|
|
str.remove_prefix(pos + delim.size());
|
|
}
|
|
if (!trim || str.size())
|
|
results.push_back(str);
|
|
else
|
|
while (!results.empty() && results.back().empty())
|
|
results.pop_back();
|
|
return results;
|
|
}
|
|
|
|
std::vector<std::string_view>
|
|
split_any(std::string_view str, const std::string_view delims, bool trim)
|
|
{
|
|
if (delims.empty())
|
|
return split(str, delims, trim);
|
|
std::vector<std::string_view> results;
|
|
for (size_t pos = str.find_first_of(delims); pos != std::string_view::npos;
|
|
pos = str.find_first_of(delims))
|
|
{
|
|
if (!trim || !results.empty() || pos > 0)
|
|
results.push_back(str.substr(0, pos));
|
|
size_t until = str.find_first_not_of(delims, pos + 1);
|
|
if (until == std::string_view::npos)
|
|
str.remove_prefix(str.size());
|
|
else
|
|
str.remove_prefix(until);
|
|
}
|
|
if (!trim || str.size())
|
|
results.push_back(str);
|
|
else
|
|
while (!results.empty() && results.back().empty())
|
|
results.pop_back();
|
|
return results;
|
|
}
|
|
|
|
void
|
|
trim(std::string_view& s)
|
|
{
|
|
constexpr auto simple_whitespace = " \t\r\n"sv;
|
|
auto pos = s.find_first_not_of(simple_whitespace);
|
|
if (pos == std::string_view::npos)
|
|
{ // whole string is whitespace
|
|
s.remove_prefix(s.size());
|
|
return;
|
|
}
|
|
s.remove_prefix(pos);
|
|
pos = s.find_last_not_of(simple_whitespace);
|
|
assert(pos != std::string_view::npos);
|
|
s.remove_suffix(s.size() - (pos + 1));
|
|
}
|
|
|
|
std::string
|
|
lowercase_ascii_string(std::string src)
|
|
{
|
|
for (char& ch : src)
|
|
if (ch >= 'A' && ch <= 'Z')
|
|
ch = ch + ('a' - 'A');
|
|
return src;
|
|
}
|
|
|
|
std::string
|
|
friendly_duration(std::chrono::nanoseconds dur)
|
|
{
|
|
std::ostringstream os;
|
|
bool some = false;
|
|
if (dur >= 24h)
|
|
{
|
|
os << dur / 24h << 'd';
|
|
dur %= 24h;
|
|
some = true;
|
|
}
|
|
if (dur >= 1h || some)
|
|
{
|
|
os << dur / 1h << 'h';
|
|
dur %= 1h;
|
|
some = true;
|
|
}
|
|
if (dur >= 1min || some)
|
|
{
|
|
os << dur / 1min << 'm';
|
|
dur %= 1min;
|
|
some = true;
|
|
}
|
|
if (some)
|
|
{
|
|
// If we have >= minutes then don't bother with fractional seconds
|
|
os << dur / 1s << 's';
|
|
}
|
|
else
|
|
{
|
|
double seconds = std::chrono::duration<double>(dur).count();
|
|
os.precision(3);
|
|
if (dur >= 1s)
|
|
os << seconds << "s";
|
|
else if (dur >= 1ms)
|
|
os << seconds * 1000 << "ms";
|
|
else if (dur >= 1us)
|
|
os << seconds * 1'000'000 << u8"µs";
|
|
else
|
|
os << seconds * 1'000'000'000 << "ns";
|
|
}
|
|
return os.str();
|
|
}
|
|
|
|
} // namespace llarp
|