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 "likely.hh"
6 #include "stringsp.hh"
7 #include <algorithm>
8 #include <charconv>
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<typename T> [[nodiscard]] std::optional<T> stringTo(std::string_view s);
44 
48  template<int BASE, typename 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  [[nodiscard]] bool startsWith(std::string_view total, std::string_view part);
55  [[nodiscard]] bool startsWith(std::string_view total, char part);
56  [[nodiscard]] bool endsWith (std::string_view total, std::string_view part);
57  [[nodiscard]] bool endsWith (std::string_view total, char part);
58 
59  void trimRight(std::string& str, const char* chars);
60  void trimRight(std::string& str, char chars);
61  void trimRight(std::string_view& str, std::string_view chars);
62  void trimRight(std::string_view& str, char chars);
63  void trimLeft (std::string& str, const char* chars);
64  void trimLeft (std::string& str, char chars);
65  void trimLeft (std::string_view& str, std::string_view chars);
66  void trimLeft (std::string_view& str, char chars);
67  void trim (std::string_view& str, std::string_view chars);
68  void trim (std::string_view& str, char chars);
69 
70  [[nodiscard]] std::pair<std::string_view, std::string_view> splitOnFirst(
71  std::string_view str, std::string_view chars);
72  [[nodiscard]] std::pair<std::string_view, std::string_view> splitOnFirst(
73  std::string_view str, char chars);
74  [[nodiscard]] std::pair<std::string_view, std::string_view> splitOnLast(
75  std::string_view str, std::string_view chars);
76  [[nodiscard]] std::pair<std::string_view, std::string_view> splitOnLast(
77  std::string_view str, char chars);
78  [[nodiscard]] IterableBitSet<64> parseRange(std::string_view str,
79  unsigned min, unsigned max);
80 
81  //[[nodiscard]] std::vector<std::string_view> split(std::string_view str, char chars);
82 
83  [[nodiscard]] inline auto split_view(std::string_view str, char c) {
84  struct Sentinel {};
85 
86  struct Iterator {
87  std::string_view str;
88  std::string_view::size_type p;
89  const char c;
90 
91  Iterator(std::string_view str_, char c_)
92  : str(str_), c(c_) {
93  next_p();
94  }
95 
96  [[nodiscard]] std::string_view operator*() const {
97  return std::string_view(str.data(), p);
98  }
99 
100  Iterator& operator++() {
101  if (p < str.size()) {
102  str.remove_prefix(p + 1);
103  next_p();
104  } else {
105  str = "";
106  }
107  return *this;
108  }
109 
110  [[nodiscard]] bool operator==(Sentinel) const { return str.empty(); }
111  [[nodiscard]] bool operator!=(Sentinel) const { return !str.empty(); }
112 
113  void next_p() {
114  p = 0;
115  while ((p < str.size()) && (str[p] != c)) ++p;
116  }
117  };
118 
119  struct Splitter {
120  std::string_view str;
121  char c;
122 
123  [[nodiscard]] auto begin() const { return Iterator{str, c}; }
124  [[nodiscard]] auto end() const { return Sentinel{}; }
125  };
126 
127  return Splitter{str, c};
128  }
129 
130  // case insensitive less-than operator
131  struct caseless {
132  [[nodiscard]] bool operator()(std::string_view s1, std::string_view s2) const {
133  auto m = std::min(s1.size(), s2.size());
134  int r = strncasecmp(s1.data(), s2.data(), m);
135  return (r != 0) ? (r < 0) : (s1.size() < s2.size());
136  }
137  };
138  struct casecmp {
139  [[nodiscard]] bool operator()(std::string_view s1, std::string_view s2) const {
140  if (s1.size() != s2.size()) return false;
141  return strncasecmp(s1.data(), s2.data(), s1.size()) == 0;
142  }
143  };
144 
145 #if defined(__APPLE__)
146  [[nodiscard]] std::string fromCFString(CFStringRef str);
147 #endif
148 
149  template<int BASE, typename T>
150  [[nodiscard]] std::optional<T> stringToBase(std::string_view s)
151  {
152  T result;
153  auto b = s.data();
154  auto e = s.data() + s.size();
155  if (auto [p, ec] = std::from_chars(b, e, result, BASE);
156  (ec == std::errc()) && (p == e)) {
157  return result;
158  }
159  return std::nullopt;
160  }
161 
162  template<typename T>
163  [[nodiscard]] std::optional<T> stringTo(std::string_view s)
164  {
165  if (unlikely(s.empty())) return {};
166  if constexpr (std::is_signed_v<T>) {
167  bool negate = false;
168  if (unlikely(s[0] == '-')) {
169  negate = true;
170  s.remove_prefix(1);
171  }
172 
173  using U = std::make_unsigned_t<T>;
174  auto tmp = stringTo<U>(s);
175  if (unlikely(!tmp)) return {};
176 
177  U max = U(std::numeric_limits<T>::max()) + 1; // 0x8000
178  if (unlikely(negate)) {
179  if (unlikely(*tmp > max)) return {}; // 0x8000
180  return T(~*tmp + 1);
181  } else {
182  if (unlikely(*tmp >= max)) return {}; // 0x7fff
183  return T(*tmp);
184  }
185  } else {
186  if (likely(s[0] != '0')) {
187  return stringToBase<10, T>(s);
188  } else {
189  if (s.size() == 1) return T(0);
190  if (likely((s[1] == 'x') || (s[1] == 'X'))) {
191  s.remove_prefix(2);
192  return stringToBase<16, T>(s);
193  } else if ((s[1] == 'b') || (s[1] == 'B')) {
194  s.remove_prefix(2);
195  return stringToBase<2, T>(s);
196  } else {
197  return stringToBase<10, T>(s);
198  }
199  }
200  }
201  }
202 }
203 
204 #endif
IterableBitSet.
#define likely(x)
Definition: likely.hh:14
#define unlikely(x)
Definition: likely.hh:15
void trim(string_view &str, string_view chars)
Definition: StringOp.cc:99
IterableBitSet< 64 > parseRange(string_view str, unsigned min, unsigned max)
Definition: StringOp.cc:197
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:150
std::pair< string_view, string_view > splitOnLast(string_view str, string_view chars)
Definition: StringOp.cc:128
void trimRight(string &str, const char *chars)
Definition: StringOp.cc:49
std::optional< T > stringTo(std::string_view s)
Convert a string to an integral type 'T' (int, uint64_t, ...).
Definition: StringOp.hh:163
std::pair< string_view, string_view > splitOnFirst(string_view str, string_view chars)
Definition: StringOp.cc:111
bool endsWith(string_view total, string_view part)
Definition: StringOp.cc:39
void trimLeft(string &str, const char *chars)
Definition: StringOp.cc:78
auto split_view(std::string_view str, char c)
Definition: StringOp.hh:83
bool startsWith(string_view total, string_view part)
Definition: StringOp.cc:29
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:269
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:287
bool operator!=(const Event &x, const Event &y)
Definition: Event.hh:64
bool operator==(const Event &x, const Event &y)
Definition: Event.cc:11
bool operator()(std::string_view s1, std::string_view s2) const
Definition: StringOp.hh:139
bool operator()(std::string_view s1, std::string_view s2) const
Definition: StringOp.hh:132
constexpr uint128 operator*(const uint128 &a, const uint128 &b)
Definition: uint128.hh:187
constexpr auto begin(const zstring_view &x)
Definition: zstring_view.hh:83
constexpr auto end(const zstring_view &x)
Definition: zstring_view.hh:84