SlHelpers
String.h
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #pragma once
4 
5 #include <algorithm>
6 #include <charconv>
7 #include <cstring>
8 #include <cctype>
9 #include <functional>
10 #include <optional>
11 #include <string>
12 #include <vector>
13 
14 namespace SlHelpers {
15 
25 class GetLine {
26 public:
31  GetLine(std::string_view str) noexcept : m_str(str) {}
32 
37  std::optional<std::string_view> get() noexcept {
38  if (m_str.empty())
39  return std::nullopt;
40 
41  const auto eol = m_str.find('\n');
42  const auto last = eol == std::string_view::npos;
43  auto line = last ? m_str : m_str.substr(0, eol);
44 
45  m_str.remove_prefix(last ? m_str.size() : eol + 1);
46 
47  return line;
48  }
49 private:
50  std::string_view m_str;
51 };
52 
56 class String {
57 public:
59  inline static constinit const auto npos = std::string_view::npos;
60  static_assert(std::string_view::npos == std::string::npos);
61 
62  String() = delete;
63 
65  template <typename I = unsigned>
66  requires std::is_integral_v<I>
67  static std::optional<I> toNum(std::string_view str, int base = 10) noexcept
68  {
69  I num;
70  if (std::from_chars(str.data(), str.data() + str.size(), num, base).ec != std::errc())
71  return std::nullopt;
72  return num;
73  }
74 
81  static constexpr std::string_view::size_type
82  iFind(std::string_view str, std::string_view sub) noexcept {
83  if (str.empty() && sub.empty())
84  return 0;
85  const auto it = std::search(str.begin(), str.end(), sub.begin(), sub.end(),
86  [](char ch1, char ch2) {
87  return std::tolower(static_cast<unsigned char>(ch1)) ==
88  std::tolower(static_cast<unsigned char>(ch2));
89  });
90  if (it == str.end())
91  return npos;
92  return it - str.begin();
93  }
94 
102  [[deprecated]] static std::vector<std::string>
103  split(std::string str, const std::string &delim,
104  const std::optional<char> &comment = std::nullopt) noexcept {
105  std::vector<std::string> res;
106 
107  auto tok = ::strtok(str.data(), delim.c_str());
108  while (tok) {
109  if (comment && tok[0] == *comment)
110  break;
111  res.push_back(tok);
112  tok = ::strtok(nullptr, delim.c_str());
113  }
114 
115  return res;
116  }
117 
127  static std::vector<std::string_view>
128  splitSV(std::string_view str,
129  std::string_view delim,
130  std::optional<char> comment = std::nullopt) noexcept
131  {
132  std::vector<std::string_view> res;
133  std::size_t end = 0;
134 
135  do {
136  const auto start = str.find_first_not_of(delim, end);
137  if (start == npos)
138  break;
139 
140  end = str.find_first_of(delim, start);
141  const auto len = (end == npos) ? (str.length() - start) : (end - start);
142  auto token = str.substr(start, len);
143  if (comment && !token.empty() && token[0] == *comment)
144  break;
145 
146  res.push_back(token);
147  } while (end != npos);
148 
149  return res;
150  }
151 
157  template <typename T>
158  static constexpr T trim(const T &line) noexcept
159  {
160  constexpr const std::string_view spaces{" \n\t\r"};
161  const auto pos1 = line.find_first_not_of(spaces);
162  const auto pos2 = line.find_last_not_of(spaces);
163 
164  if (pos1 == npos)
165  return {};
166 
167  return line.substr(pos1, pos2 - pos1 + 1);
168  }
169 
175  static constexpr bool isHex(std::string_view s) noexcept {
176  return std::all_of(s.cbegin(), s.cend(), ::isxdigit);
177  }
178 
186  template <std::ranges::input_range Range, typename Output>
187  requires requires(std::ostream &out, Output output,
188  std::ranges::range_reference_t<Range> e) {
189  std::invoke(output, out, e);
190  }
191  static void join(std::ostream &out, Range &&iterable, Output output,
192  std::string_view sep = ", ") {
193  bool first = true;
194  for (auto &&e: iterable) {
195  if (!first)
196  out << sep;
197  first = false;
198 
199  std::invoke(output, out, e);
200  }
201  }
202 
210  template <std::ranges::input_range Range>
211  static void join(std::ostream &out, Range &&iterable, std::string_view sep = ", ",
212  std::string_view quote = "") {
213  join(out, std::forward<Range>(iterable),
214  [quote](auto &out, const auto &x) { out << quote << x << quote; },
215  sep);
216  }
217 
223  struct Hash {
225  using is_transparent = void;
226 
231  auto hash(std::string_view sv) const noexcept {
232  return std::hash<std::string_view>{}(sv);
233  }
234 
236  size_t operator()(const char *charp) const noexcept { return hash(charp); }
237 
239  size_t operator()(std::string_view sv) const noexcept { return hash(sv); }
240 
242  size_t operator()(const std::string &s) const noexcept { return hash(s); }
243  };
244 
250  struct Eq {
252  using is_transparent = void;
253 
260  bool operator()(std::string_view a, std::string_view b) const noexcept {
261  return a == b;
262  }
263  };
264 };
265 
266 }
static constexpr T trim(const T &line) noexcept
Trim string (remove surrounding whitespace)
Definition: String.h:158
static std::vector< std::string_view > splitSV(std::string_view str, std::string_view delim, std::optional< char > comment=std::nullopt) noexcept
Split str by delim into a vector, ignoring everything after comment.
Definition: String.h:128
Equality test for string and string_view to be used in containers.
Definition: String.h:250
requires requires(std::ostream &out, Output output, std::ranges::range_reference_t< Range > e)
Join iterable into out using separator sep, calling output.
Definition: String.h:187
Hash for string and string_view to be used in hashing containers.
Definition: String.h:223
static void join(std::ostream &out, Range &&iterable, std::string_view sep=", ", std::string_view quote="")
Join iterable into out using separator sep and quoting quote.
Definition: String.h:211
requires static std::is_integral_v< I > std::optional< I > toNum(std::string_view str, int base=10) noexcept
Convert str to a number.
Definition: String.h:67
static constexpr bool isHex(std::string_view s) noexcept
Is the string consisting of hex number?
Definition: String.h:175
size_t operator()(const std::string &s) const noexcept
Hash string s.
Definition: String.h:242
static std::vector< std::string > split(std::string str, const std::string &delim, const std::optional< char > &comment=std::nullopt) noexcept
Split a string into vector of strings, DO NOT USE THIS.
Definition: String.h:103
GetLine(std::string_view str) noexcept
Construct GetLine to parse str.
Definition: String.h:31
Various helpers on strings.
Definition: String.h:56
static constexpr std::string_view::size_type iFind(std::string_view str, std::string_view sub) noexcept
Like string::find() but ignoring case.
Definition: String.h:82
auto hash(std::string_view sv) const noexcept
Hash any kind of string using std::hash.
Definition: String.h:231
void is_transparent
For containers to know this is a transparent hash.
Definition: String.h:225
Parses a string view into lines.
Definition: String.h:25
static constinit const auto npos
A local alias for std::string_view::npos.
Definition: String.h:59
void is_transparent
For containers to know this is a transparent eq test.
Definition: String.h:252
bool operator()(std::string_view a, std::string_view b) const noexcept
Compare any kinds of two strings a and b.
Definition: String.h:260
size_t operator()(const char *charp) const noexcept
Hash charp.
Definition: String.h:236
size_t operator()(std::string_view sv) const noexcept
Hash string_view sv.
Definition: String.h:239
Definition: Color.h:8