openMSX
StringOp.cc
Go to the documentation of this file.
1 #include "StringOp.hh"
2 #include "MSXException.hh"
3 #include "likely.hh"
4 #include "ranges.hh"
5 #include "stl.hh"
6 #include "view.hh"
7 #include <cstdlib>
8 #include <stdexcept>
9 
10 using std::string;
11 using std::string_view;
12 using std::vector;
13 
14 namespace StringOp {
15 
16 int stringToInt(const string& str)
17 {
18  return strtol(str.c_str(), nullptr, 0);
19 }
20 bool stringToInt(const string& str, int& result)
21 {
22  char* endptr;
23  result = strtol(str.c_str(), &endptr, 0);
24  return *endptr == '\0';
25 }
26 
27 unsigned stringToUint(const string& str)
28 {
29  return strtoul(str.c_str(), nullptr, 0);
30 }
31 bool stringToUint(const string& str, unsigned& result)
32 {
33  char* endptr;
34  result = strtoul(str.c_str(), &endptr, 0);
35  return *endptr == '\0';
36 }
37 
38 uint64_t stringToUint64(const string& str)
39 {
40  return strtoull(str.c_str(), nullptr, 0);
41 }
42 
43 bool stringToBool(string_view str)
44 {
45  if (str == "1") return true;
46  if ((str.size() == 4) && (strncasecmp(str.data(), "true", 4) == 0))
47  return true;
48  if ((str.size() == 3) && (strncasecmp(str.data(), "yes", 3) == 0))
49  return true;
50  return false;
51 }
52 
53 double stringToDouble(const string& str)
54 {
55  return strtod(str.c_str(), nullptr);
56 }
57 bool stringToDouble(const string& str, double& result)
58 {
59  char* endptr;
60  result = strtod(str.c_str(), &endptr);
61  return *endptr == '\0';
62 }
63 
64 string toLower(string_view str)
65 {
66  string result(str);
67  transform_in_place(result, ::tolower);
68  return result;
69 }
70 
71 bool startsWith(string_view total, string_view part)
72 {
73  return (total.size() >= part.size()) &&
74  (memcmp(total.data(), part.data(), part.size()) == 0);
75 }
76 bool startsWith(string_view total, char part)
77 {
78  return !total.empty() && (total.front() == part);
79 }
80 
81 bool endsWith(string_view total, string_view part)
82 {
83  return (total.size() >= part.size()) &&
84  (memcmp(total.data() + total.size() - part.size(), part.data(), part.size()) == 0);
85 }
86 bool endsWith(string_view total, char part)
87 {
88  return !total.empty() && (total.back() == part);
89 }
90 
91 void trimRight(string& str, const char* chars)
92 {
93  if (auto pos = str.find_last_not_of(chars); pos != string::npos) {
94  str.erase(pos + 1);
95  } else {
96  str.clear();
97  }
98 }
99 void trimRight(string& str, char chars)
100 {
101  if (auto pos = str.find_last_not_of(chars); pos != string::npos) {
102  str.erase(pos + 1);
103  } else {
104  str.clear();
105  }
106 }
107 void trimRight(string_view& str, string_view chars)
108 {
109  while (!str.empty() && (chars.find(str.back()) != string_view::npos)) {
110  str.remove_suffix(1);
111  }
112 }
113 void trimRight(string_view& str, char chars)
114 {
115  while (!str.empty() && (str.back() == chars)) {
116  str.remove_suffix(1);
117  }
118 }
119 
120 void trimLeft(string& str, const char* chars)
121 {
122  str.erase(0, str.find_first_not_of(chars));
123 }
124 void trimLeft(string& str, char chars)
125 {
126  str.erase(0, str.find_first_not_of(chars));
127 }
128 void trimLeft(string_view& str, string_view chars)
129 {
130  while (!str.empty() && (chars.find(str.front()) != string_view::npos)) {
131  str.remove_prefix(1);
132  }
133 }
134 void trimLeft(string_view& str, char chars)
135 {
136  while (!str.empty() && (str.front() == chars)) {
137  str.remove_prefix(1);
138  }
139 }
140 
141 void trim(string_view& str, string_view chars)
142 {
143  trimRight(str, chars);
144  trimLeft (str, chars);
145 }
146 
147 void trim(string_view& str, char chars)
148 {
149  trimRight(str, chars);
150  trimLeft (str, chars);
151 }
152 
153 std::pair<string_view, string_view> splitOnFirst(string_view str, string_view chars)
154 {
155  if (auto pos = str.find_first_of(chars); pos == string_view::npos) {
156  return {str, string_view{}};
157  } else {
158  return {str.substr(0, pos), str.substr(pos + 1)};
159  }
160 }
161 std::pair<string_view, string_view> splitOnFirst(string_view str, char chars)
162 {
163  if (auto pos = str.find_first_of(chars); pos == string_view::npos) {
164  return {str, string_view{}};
165  } else {
166  return {str.substr(0, pos), str.substr(pos + 1)};
167  }
168 }
169 
170 std::pair<string_view, string_view> splitOnLast(string_view str, string_view chars)
171 {
172  if (auto pos = str.find_last_of(chars); pos == string_view::npos) {
173  return {string_view{}, str};
174  } else {
175  return {str.substr(0, pos), str.substr(pos + 1)};
176  }
177 }
178 std::pair<string_view, string_view> splitOnLast(string_view str, char chars)
179 {
180  if (auto pos = str.find_last_of(chars); pos == string_view::npos) {
181  return {string_view{}, str};
182  } else {
183  return {str.substr(0, pos), str.substr(pos + 1)};
184  }
185 }
186 
187 vector<string_view> split(string_view str, char chars)
188 {
189  vector<string_view> result;
190  while (!str.empty()) {
191  auto [first, last] = splitOnFirst(str, chars);
192  result.push_back(first);
193  str = last;
194  }
195  return result;
196 }
197 
198 static unsigned parseNumber(string_view str)
199 {
200  trim(str, " \t");
201  if (!str.empty()) {
202  try {
203  return fast_stou(str);
204  } catch (std::invalid_argument&) {
205  // parse error
206  }
207  }
208  throw openmsx::MSXException("Invalid integer: ", str);
209 }
210 
211 static void insert(unsigned x, vector<unsigned>& result, unsigned min, unsigned max)
212 {
213  if ((x < min) || (x > max)) {
214  throw openmsx::MSXException("Out of range");
215  }
216  if (auto it = ranges::lower_bound(result, x);
217  (it == end(result)) || (*it != x)) {
218  result.insert(it, x);
219  }
220 }
221 
222 static void parseRange2(string_view str, vector<unsigned>& result,
223  unsigned min, unsigned max)
224 {
225  // trimRight only: here we only care about all spaces
226  trimRight(str, " \t");
227  if (str.empty()) return;
228 
229  if (auto pos = str.find('-'); pos == string_view::npos) {
230  insert(parseNumber(str), result, min, max);
231  } else {
232  unsigned begin = parseNumber(str.substr(0, pos));
233  unsigned end = parseNumber(str.substr(pos + 1));
234  if (end < begin) {
235  std::swap(begin, end);
236  }
237  for (unsigned i = begin; i <= end; ++i) {
238  insert(i, result, min, max);
239  }
240  }
241 }
242 
243 vector<unsigned> parseRange(string_view str, unsigned min, unsigned max)
244 {
245  vector<unsigned> result;
246  while (true) {
247  auto next = str.find(',');
248  string_view sub = (next == string_view::npos)
249  ? str
250  : str.substr(0, next++);
251  parseRange2(sub, result, min, max);
252  if (next == string_view::npos) break;
253  str = str.substr(next);
254  }
255  return result;
256 }
257 
258 unsigned fast_stou(string_view s)
259 {
260  unsigned result = 0;
261  for (char c : s) {
262  unsigned d = c - '0';
263  if (unlikely(d > 9)) {
264  throw std::invalid_argument("fast_stoi");
265  }
266  result *= 10;
267  result += d;
268  }
269  return result;
270 }
271 
272 #if defined(__APPLE__)
273 
274 std::string fromCFString(CFStringRef str)
275 {
276  // Try the quick route first.
277  const char *cstr = CFStringGetCStringPtr(str, kCFStringEncodingUTF8);
278  if (cstr) {
279  // String was already in UTF8 encoding.
280  return std::string(cstr);
281  }
282 
283  // Convert to UTF8 encoding.
284  CFIndex len = CFStringGetLength(str);
285  CFRange range = CFRangeMake(0, len);
286  CFIndex usedBufLen = 0;
287  CFStringGetBytes(
288  str, range, kCFStringEncodingUTF8, '?', false, nullptr, len, &usedBufLen);
289  UInt8 buffer[usedBufLen];
290  CFStringGetBytes(
291  str, range, kCFStringEncodingUTF8, '?', false, buffer, len, &usedBufLen);
292  return std::string(reinterpret_cast<const char *>(buffer), usedBufLen);
293 }
294 
295 #endif
296 
297 } // namespace StringOp
StringOp::stringToDouble
double stringToDouble(const string &str)
Definition: StringOp.cc:53
StringOp::stringToUint64
uint64_t stringToUint64(const string &str)
Definition: StringOp.cc:38
StringOp::startsWith
bool startsWith(string_view total, string_view part)
Definition: StringOp.cc:71
gl::min
vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:274
unlikely
#define unlikely(x)
Definition: likely.hh:15
StringOp::trimLeft
void trimLeft(string &str, const char *chars)
Definition: StringOp.cc:120
StringOp::trim
void trim(string_view &str, string_view chars)
Definition: StringOp.cc:141
StringOp::split
vector< string_view > split(string_view str, char chars)
Definition: StringOp.cc:187
ranges::lower_bound
auto lower_bound(ForwardRange &&range, const T &value)
Definition: ranges.hh:71
StringOp
Definition: StringOp.cc:14
StringOp::splitOnFirst
std::pair< string_view, string_view > splitOnFirst(string_view str, string_view chars)
Definition: StringOp.cc:153
StringOp::fast_stou
unsigned fast_stou(string_view s)
Definition: StringOp.cc:258
StringOp::parseRange
vector< unsigned > parseRange(string_view str, unsigned min, unsigned max)
Definition: StringOp.cc:243
ranges.hh
MSXException.hh
openmsx::MSXException
Definition: MSXException.hh:10
StringOp::toLower
string toLower(string_view str)
Definition: StringOp.cc:64
StringOp::stringToUint
unsigned stringToUint(const string &str)
Definition: StringOp.cc:27
likely.hh
StringOp::endsWith
bool endsWith(string_view total, string_view part)
Definition: StringOp.cc:81
StringOp::stringToBool
bool stringToBool(string_view str)
Definition: StringOp.cc:43
view.hh
StringOp::trimRight
void trimRight(string &str, const char *chars)
Definition: StringOp.cc:91
StringOp::splitOnLast
std::pair< string_view, string_view > splitOnLast(string_view str, string_view chars)
Definition: StringOp.cc:170
StringOp::stringToInt
int stringToInt(const string &str)
Definition: StringOp.cc:16
openmsx::x
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1419
StringOp.hh
std::swap
void swap(openmsx::MemBuffer< T > &l, openmsx::MemBuffer< T > &r) noexcept
Definition: MemBuffer.hh:202
transform_in_place
auto transform_in_place(ForwardRange &&range, UnaryOperation op)
Definition: stl.hh:239
gl::max
vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:292
stl.hh