lokinet/llarp/util/str.cpp
Jason Rhinelander 9950adf472 Remove unneeded split(str, char) method
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.
2021-08-11 00:26:52 -03:00

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