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