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 <ranges>
12 #include <string>
13 #include <vector>
14 
15 namespace SlHelpers {
16 
26 class GetLine {
27 public:
32  GetLine(std::string_view str) noexcept : m_str(str) {}
33 
38  std::optional<std::string_view> get() noexcept {
39  if (m_str.empty())
40  return std::nullopt;
41 
42  const auto eol = m_str.find('\n');
43  const auto last = eol == std::string_view::npos;
44  auto line = last ? m_str : m_str.substr(0, eol);
45 
46  m_str.remove_prefix(last ? m_str.size() : eol + 1);
47 
48  return line;
49  }
50 private:
51  std::string_view m_str;
52 };
53 
57 class String {
58 public:
60  inline static constinit const auto npos = std::string_view::npos;
61  static_assert(std::string_view::npos == std::string::npos);
62 
63  String() = delete;
64 
66  template <typename I = unsigned>
67  requires std::is_integral_v<I>
68  static std::optional<I> toNum(std::string_view str, int base = 10) noexcept
69  {
70  I num;
71  if (std::from_chars(str.data(), str.data() + str.size(), num, base).ec != std::errc())
72  return std::nullopt;
73  return num;
74  }
75 
77  static bool constexpr iEqual(unsigned char a, unsigned char b) noexcept {
78  return std::tolower(a) == std::tolower(b);
79  }
80 
87  static constexpr std::string_view::size_type
88  iFind(std::string_view str, std::string_view sub) noexcept {
89  if (str.empty() && sub.empty())
90  return 0;
91  const auto it = std::search(str.begin(), str.end(), sub.begin(), sub.end(), iEqual);
92  if (it == str.end())
93  return npos;
94  return it - str.begin();
95  }
96 
103  static constexpr bool
104  iStartsWith(std::string_view str, std::string_view prefix) noexcept {
105  if (str.size() < prefix.size())
106  return false;
107 
108  return std::ranges::equal(str | std::views::take(prefix.size()), prefix, iEqual);
109  }
110 
117  static constexpr bool
118  iEndsWith(std::string_view str, std::string_view suffix) noexcept {
119  if (str.size() < suffix.size())
120  return false;
121 
122  return std::ranges::equal(str | std::views::drop(str.size() - suffix.size()),
123  suffix, iEqual);
124  }
125 
135  static std::vector<std::string_view>
136  splitSV(std::string_view str,
137  std::string_view delim,
138  std::optional<char> comment = std::nullopt) noexcept
139  {
140  std::vector<std::string_view> res;
141  std::size_t end = 0;
142 
143  do {
144  const auto start = str.find_first_not_of(delim, end);
145  if (start == npos)
146  break;
147 
148  end = str.find_first_of(delim, start);
149  const auto len = (end == npos) ? (str.length() - start) : (end - start);
150  auto token = str.substr(start, len);
151  if (comment && token.starts_with(*comment))
152  break;
153 
154  res.push_back(token);
155  } while (end != npos);
156 
157  return res;
158  }
159 
165  template <typename T>
166  static constexpr T trim(const T &line) noexcept
167  {
168  constexpr const std::string_view spaces{" \n\t\r"};
169  const auto pos1 = line.find_first_not_of(spaces);
170  const auto pos2 = line.find_last_not_of(spaces);
171 
172  if (pos1 == npos)
173  return {};
174 
175  return line.substr(pos1, pos2 - pos1 + 1);
176  }
177 
183  static constexpr bool isHex(std::string_view s) noexcept {
184  return std::all_of(s.cbegin(), s.cend(), ::isxdigit);
185  }
186 
194  template <std::ranges::input_range Range, typename Output>
195  requires requires(std::ostream &out, Output output,
196  std::ranges::range_reference_t<Range> e) {
197  std::invoke(output, out, e);
198  }
199  static void join(std::ostream &out, Range &&iterable, Output output,
200  std::string_view sep = ", ") {
201  bool first = true;
202  for (auto &&e: iterable) {
203  if (!first)
204  out << sep;
205  first = false;
206 
207  std::invoke(output, out, e);
208  }
209  }
210 
218  template <std::ranges::input_range Range>
219  static void join(std::ostream &out, Range &&iterable, std::string_view sep = ", ",
220  std::string_view quote = "") {
221  join(out, std::forward<Range>(iterable),
222  [quote](auto &out, const auto &x) { out << quote << x << quote; },
223  sep);
224  }
225 
231  struct Hash {
233  using is_transparent = void;
234 
239  auto hash(std::string_view sv) const noexcept {
240  return std::hash<std::string_view>{}(sv);
241  }
242 
244  size_t operator()(const char *charp) const noexcept { return hash(charp); }
245 
247  size_t operator()(std::string_view sv) const noexcept { return hash(sv); }
248 
250  size_t operator()(const std::string &s) const noexcept { return hash(s); }
251  };
252 
258  struct Eq {
260  using is_transparent = void;
261 
268  bool operator()(std::string_view a, std::string_view b) const noexcept {
269  return a == b;
270  }
271  };
272 };
273 
274 }
static constexpr T trim(const T &line) noexcept
Trim string (remove surrounding whitespace)
Definition: String.h:166
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:136
Equality test for string and string_view to be used in containers.
Definition: String.h:258
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:195
Hash for string and string_view to be used in hashing containers.
Definition: String.h:231
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:219
static constexpr bool iStartsWith(std::string_view str, std::string_view prefix) noexcept
Like string::starts_with() but ignoring case.
Definition: String.h:104
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:68
static constexpr bool isHex(std::string_view s) noexcept
Is the string consisting of hex number?
Definition: String.h:183
size_t operator()(const std::string &s) const noexcept
Hash string s.
Definition: String.h:250
GetLine(std::string_view str) noexcept
Construct GetLine to parse str.
Definition: String.h:32
Various helpers on strings.
Definition: String.h:57
static bool constexpr iEqual(unsigned char a, unsigned char b) noexcept
Compare two characters ignoring case.
Definition: String.h:77
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:88
auto hash(std::string_view sv) const noexcept
Hash any kind of string using std::hash.
Definition: String.h:239
void is_transparent
For containers to know this is a transparent hash.
Definition: String.h:233
Parses a string view into lines.
Definition: String.h:26
static constinit const auto npos
A local alias for std::string_view::npos.
Definition: String.h:60
void is_transparent
For containers to know this is a transparent eq test.
Definition: String.h:260
bool operator()(std::string_view a, std::string_view b) const noexcept
Compare any kinds of two strings a and b.
Definition: String.h:268
static constexpr bool iEndsWith(std::string_view str, std::string_view suffix) noexcept
Like string::ends_with() but ignoring case.
Definition: String.h:118
size_t operator()(const char *charp) const noexcept
Hash charp.
Definition: String.h:244
size_t operator()(std::string_view sv) const noexcept
Hash string_view sv.
Definition: String.h:247
Definition: Color.h:8