openMSX
StringOp.hh
Go to the documentation of this file.
1 #ifndef STRINGOP_HH
2 #define STRINGOP_HH
3 
4 #include "IterableBitSet.hh"
5 #include "stringsp.hh"
6 #include <algorithm>
7 #include <charconv>
8 #include <concepts>
9 #include <cstdint>
10 #include <iomanip>
11 #include <limits>
12 #include <optional>
13 #include <sstream>
14 #include <string>
15 #include <string_view>
16 #include <type_traits>
17 #include <utility>
18 #if defined(__APPLE__)
19 #include <CoreFoundation/CoreFoundation.h>
20 #endif
21 
22 namespace StringOp
23 {
43  template<std::integral T> [[nodiscard]] std::optional<T> stringTo(std::string_view s);
44 
48  template<int BASE, std::integral T> [[nodiscard]] std::optional<T> stringToBase(std::string_view s);
49 
50  [[nodiscard]] bool stringToBool(std::string_view str);
51 
52  //[[nodiscard]] std::string toLower(std::string_view str);
53 
54  void trimRight(std::string& str, const char* chars);
55  void trimRight(std::string& str, char chars);
56  void trimRight(std::string_view& str, std::string_view chars);
57  void trimRight(std::string_view& str, char chars);
58  void trimLeft (std::string& str, const char* chars);
59  void trimLeft (std::string& str, char chars);
60  void trimLeft (std::string_view& str, std::string_view chars);
61  void trimLeft (std::string_view& str, char chars);
62  void trim (std::string_view& str, std::string_view chars);
63  void trim (std::string_view& str, char chars);
64 
65  [[nodiscard]] std::pair<std::string_view, std::string_view> splitOnFirst(
66  std::string_view str, std::string_view chars);
67  [[nodiscard]] std::pair<std::string_view, std::string_view> splitOnFirst(
68  std::string_view str, char chars);
69  [[nodiscard]] std::pair<std::string_view, std::string_view> splitOnLast(
70  std::string_view str, std::string_view chars);
71  [[nodiscard]] std::pair<std::string_view, std::string_view> splitOnLast(
72  std::string_view str, char chars);
73  [[nodiscard]] IterableBitSet<64> parseRange(std::string_view str,
74  unsigned min, unsigned max);
75 
76  //[[nodiscard]] std::vector<std::string_view> split(std::string_view str, char chars);
77 
78  [[nodiscard]] inline auto split_view(std::string_view str, char c) {
79  struct Sentinel {};
80 
81  struct Iterator {
82  using value_type = std::string_view;
83  using difference_type = ptrdiff_t;
84 
85  Iterator() = default;
86  Iterator(const Iterator&) = default;
87  Iterator& operator=(const Iterator&) = default;
88 
89  Iterator(std::string_view str_, char c_)
90  : str(str_), c(c_) {
91  next_p();
92  }
93 
94  [[nodiscard]] std::string_view operator*() const {
95  return std::string_view(str.data(), p);
96  }
97 
98  Iterator& operator++() {
99  if (p < str.size()) {
100  str.remove_prefix(p + 1);
101  next_p();
102  } else {
103  str = "";
104  }
105  return *this;
106  }
107  Iterator operator++(int) { auto copy = *this; ++(*this); return copy; }
108 
109  [[nodiscard]] bool operator==(const Iterator&) const = default;
110  [[nodiscard]] bool operator==(Sentinel) const { return str.empty(); }
111 
112  void next_p() {
113  p = 0;
114  while ((p < str.size()) && (str[p] != c)) ++p;
115  }
116 
117  private:
118  std::string_view str;
119  std::string_view::size_type p;
120  char c;
121  };
122  static_assert(std::forward_iterator<Iterator>);
123  static_assert(std::sentinel_for<Sentinel, Iterator>);
124 
125  struct Splitter {
126  std::string_view str;
127  char c;
128 
129  [[nodiscard]] auto begin() const { return Iterator{str, c}; }
130  [[nodiscard]] auto end() const { return Sentinel{}; }
131  };
132 
133  return Splitter{str, c};
134  }
135 
136  // case insensitive less-than operator
137  struct caseless {
138  [[nodiscard]] bool operator()(std::string_view s1, std::string_view s2) const {
139  auto m = std::min(s1.size(), s2.size());
140  int r = strncasecmp(s1.data(), s2.data(), m);
141  return (r != 0) ? (r < 0) : (s1.size() < s2.size());
142  }
143  };
144  struct casecmp {
145  [[nodiscard]] bool operator()(std::string_view s1, std::string_view s2) const {
146  if (s1.size() != s2.size()) return false;
147  return strncasecmp(s1.data(), s2.data(), s1.size()) == 0;
148  }
149  };
150 
151 #if defined(__APPLE__)
152  [[nodiscard]] std::string fromCFString(CFStringRef str);
153 #endif
154 
155  template<int BASE, std::integral T>
156  [[nodiscard]] std::optional<T> stringToBase(std::string_view s)
157  {
158  T result;
159  auto b = s.data();
160  auto e = s.data() + s.size();
161  if (auto [p, ec] = std::from_chars(b, e, result, BASE);
162  (ec == std::errc()) && (p == e)) {
163  return result;
164  }
165  return std::nullopt;
166  }
167 
168  template<std::integral T>
169  [[nodiscard]] std::optional<T> stringTo(std::string_view s)
170  {
171  if (s.empty()) [[unlikely]] return {};
172  if constexpr (std::is_signed_v<T>) {
173  bool negate = false;
174  if (s[0] == '-') [[unlikely]] {
175  negate = true;
176  s.remove_prefix(1);
177  }
178 
179  using U = std::make_unsigned_t<T>;
180  auto tmp = stringTo<U>(s);
181  if (!tmp) [[unlikely]] return {};
182 
183  U max = U(std::numeric_limits<T>::max()) + 1; // 0x8000
184  if (negate) [[unlikely]] {
185  if (*tmp > max) [[unlikely]] return {}; // 0x8000
186  return T(~*tmp + 1);
187  } else {
188  if (*tmp >= max) [[unlikely]] return {}; // 0x7fff
189  return T(*tmp);
190  }
191  } else {
192  if (s[0] != '0') [[likely]] {
193  return stringToBase<10, T>(s);
194  } else {
195  if (s.size() == 1) return T(0);
196  if ((s[1] == 'x') || (s[1] == 'X')) [[likely]] {
197  s.remove_prefix(2);
198  return stringToBase<16, T>(s);
199  } else if ((s[1] == 'b') || (s[1] == 'B')) {
200  s.remove_prefix(2);
201  return stringToBase<2, T>(s);
202  } else {
203  return stringToBase<10, T>(s);
204  }
205  }
206  }
207  }
208 }
209 
210 #endif
IterableBitSet.
constexpr double e
Definition: Math.hh:18
void trim(string_view &str, string_view chars)
Definition: StringOp.cc:79
IterableBitSet< 64 > parseRange(string_view str, unsigned min, unsigned max)
Definition: StringOp.cc:177
bool stringToBool(string_view str)
Definition: StringOp.cc:12
std::optional< T > stringToBase(std::string_view s)
As above, but without dynamic base detection.
Definition: StringOp.hh:156
std::pair< string_view, string_view > splitOnLast(string_view str, string_view chars)
Definition: StringOp.cc:108
void trimRight(string &str, const char *chars)
Definition: StringOp.cc:29
std::optional< T > stringTo(std::string_view s)
Convert a string to an integral type 'T' (int, uint64_t, ...).
Definition: StringOp.hh:169
std::pair< string_view, string_view > splitOnFirst(string_view str, string_view chars)
Definition: StringOp.cc:91
void trimLeft(string &str, const char *chars)
Definition: StringOp.cc:58
auto split_view(std::string_view str, char c)
Definition: StringOp.hh:78
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:265
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:283
bool operator==(const Event &x, const Event &y)
Definition: Event.cc:11
auto copy(InputRange &&range, OutputIter out)
Definition: ranges.hh:208
bool operator()(std::string_view s1, std::string_view s2) const
Definition: StringOp.hh:145
bool operator()(std::string_view s1, std::string_view s2) const
Definition: StringOp.hh:138
constexpr uint128 operator*(const uint128 &a, const uint128 &b)
Definition: uint128.hh:189
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)