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  auto pos = str.find_last_not_of(chars);
94  if (pos != string::npos) {
95  str.erase(pos + 1);
96  } else {
97  str.clear();
98  }
99 }
100 void trimRight(string& str, char chars)
101 {
102  auto pos = str.find_last_not_of(chars);
103  if (pos != string::npos) {
104  str.erase(pos + 1);
105  } else {
106  str.clear();
107  }
108 }
109 void trimRight(string_view& str, string_view chars)
110 {
111  while (!str.empty() && (chars.find(str.back()) != string_view::npos)) {
112  str.remove_suffix(1);
113  }
114 }
115 void trimRight(string_view& str, char chars)
116 {
117  while (!str.empty() && (str.back() == chars)) {
118  str.remove_suffix(1);
119  }
120 }
121 
122 void trimLeft(string& str, const char* chars)
123 {
124  str.erase(0, str.find_first_not_of(chars));
125 }
126 void trimLeft(string& str, char chars)
127 {
128  str.erase(0, str.find_first_not_of(chars));
129 }
130 void trimLeft(string_view& str, string_view chars)
131 {
132  while (!str.empty() && (chars.find(str.front()) != string_view::npos)) {
133  str.remove_prefix(1);
134  }
135 }
136 void trimLeft(string_view& str, char chars)
137 {
138  while (!str.empty() && (str.front() == chars)) {
139  str.remove_prefix(1);
140  }
141 }
142 
143 void trim(string_view& str, string_view chars)
144 {
145  trimRight(str, chars);
146  trimLeft (str, chars);
147 }
148 
149 void trim(string_view& str, char chars)
150 {
151  trimRight(str, chars);
152  trimLeft (str, chars);
153 }
154 
155 std::pair<string_view, string_view> splitOnFirst(string_view str, string_view chars)
156 {
157  auto pos = str.find_first_of(chars);
158  if (pos == string_view::npos) {
159  return {str, string_view{}};
160  } else {
161  return {str.substr(0, pos), str.substr(pos + 1)};
162  }
163 }
164 std::pair<string_view, string_view> splitOnFirst(string_view str, char chars)
165 {
166  auto pos = str.find_first_of(chars);
167  if (pos == string_view::npos) {
168  return {str, string_view{}};
169  } else {
170  return {str.substr(0, pos), str.substr(pos + 1)};
171  }
172 }
173 
174 std::pair<string_view, string_view> splitOnLast(string_view str, string_view chars)
175 {
176  auto pos = str.find_last_of(chars);
177  if (pos == string_view::npos) {
178  return {string_view{}, str};
179  } else {
180  return {str.substr(0, pos), str.substr(pos + 1)};
181  }
182 }
183 std::pair<string_view, string_view> splitOnLast(string_view str, char chars)
184 {
185  auto pos = str.find_last_of(chars);
186  if (pos == string_view::npos) {
187  return {string_view{}, str};
188  } else {
189  return {str.substr(0, pos), str.substr(pos + 1)};
190  }
191 }
192 
193 vector<string_view> split(string_view str, char chars)
194 {
195  vector<string_view> result;
196  while (!str.empty()) {
197  auto [first, last] = splitOnFirst(str, chars);
198  result.push_back(first);
199  str = last;
200  }
201  return result;
202 }
203 
204 static unsigned parseNumber(string_view str)
205 {
206  trim(str, " \t");
207  if (!str.empty()) {
208  try {
209  return fast_stou(str);
210  } catch (std::invalid_argument&) {
211  // parse error
212  }
213  }
214  throw openmsx::MSXException("Invalid integer: ", str);
215 }
216 
217 static void insert(unsigned x, vector<unsigned>& result, unsigned min, unsigned max)
218 {
219  if ((x < min) || (x > max)) {
220  throw openmsx::MSXException("Out of range");
221  }
222  auto it = ranges::lower_bound(result, x);
223  if ((it == end(result)) || (*it != x)) {
224  result.insert(it, x);
225  }
226 }
227 
228 static void parseRange2(string_view str, vector<unsigned>& result,
229  unsigned min, unsigned max)
230 {
231  // trimRight only: here we only care about all spaces
232  trimRight(str, " \t");
233  if (str.empty()) return;
234 
235  auto pos = str.find('-');
236  if (pos == string_view::npos) {
237  insert(parseNumber(str), result, min, max);
238  } else {
239  unsigned begin = parseNumber(str.substr(0, pos));
240  unsigned end = parseNumber(str.substr(pos + 1));
241  if (end < begin) {
242  std::swap(begin, end);
243  }
244  for (unsigned i = begin; i <= end; ++i) {
245  insert(i, result, min, max);
246  }
247  }
248 }
249 
250 vector<unsigned> parseRange(string_view str, unsigned min, unsigned max)
251 {
252  vector<unsigned> result;
253  while (true) {
254  auto next = str.find(',');
255  string_view sub = (next == string_view::npos)
256  ? str
257  : str.substr(0, next++);
258  parseRange2(sub, result, min, max);
259  if (next == string_view::npos) break;
260  str = str.substr(next);
261  }
262  return result;
263 }
264 
265 unsigned fast_stou(string_view s)
266 {
267  unsigned result = 0;
268  for (char c : s) {
269  unsigned d = c - '0';
270  if (unlikely(d > 9)) {
271  throw std::invalid_argument("fast_stoi");
272  }
273  result *= 10;
274  result += d;
275  }
276  return result;
277 }
278 
279 #if defined(__APPLE__)
280 
281 std::string fromCFString(CFStringRef str)
282 {
283  // Try the quick route first.
284  const char *cstr = CFStringGetCStringPtr(str, kCFStringEncodingUTF8);
285  if (cstr) {
286  // String was already in UTF8 encoding.
287  return std::string(cstr);
288  }
289 
290  // Convert to UTF8 encoding.
291  CFIndex len = CFStringGetLength(str);
292  CFRange range = CFRangeMake(0, len);
293  CFIndex usedBufLen = 0;
294  CFStringGetBytes(
295  str, range, kCFStringEncodingUTF8, '?', false, nullptr, len, &usedBufLen);
296  UInt8 buffer[usedBufLen];
297  CFStringGetBytes(
298  str, range, kCFStringEncodingUTF8, '?', false, buffer, len, &usedBufLen);
299  return std::string(reinterpret_cast<const char *>(buffer), usedBufLen);
300 }
301 
302 #endif
303 
304 } // namespace StringOp
unsigned fast_stou(string_view s)
Definition: StringOp.cc:265
#define unlikely(x)
Definition: likely.hh:15
vector< string_view > split(string_view str, char chars)
Definition: StringOp.cc:193
vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:274
void trimLeft(string &str, const char *chars)
Definition: StringOp.cc:122
vector< unsigned > parseRange(string_view str, unsigned min, unsigned max)
Definition: StringOp.cc:250
bool startsWith(string_view total, string_view part)
Definition: StringOp.cc:71
vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:292
void trimRight(string &str, const char *chars)
Definition: StringOp.cc:91
std::pair< string_view, string_view > splitOnFirst(string_view str, string_view chars)
Definition: StringOp.cc:155
std::pair< string_view, string_view > splitOnLast(string_view str, string_view chars)
Definition: StringOp.cc:174
auto transform_in_place(ForwardRange &&range, UnaryOperation op)
Definition: stl.hh:239
bool stringToBool(string_view str)
Definition: StringOp.cc:43
int stringToInt(const string &str)
Definition: StringOp.cc:16
double stringToDouble(const string &str)
Definition: StringOp.cc:53
auto lower_bound(ForwardRange &&range, const T &value)
Definition: ranges.hh:71
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1377
string toLower(string_view str)
Definition: StringOp.cc:64
void trim(string_view &str, string_view chars)
Definition: StringOp.cc:143
unsigned stringToUint(const string &str)
Definition: StringOp.cc:27
uint64_t stringToUint64(const string &str)
Definition: StringOp.cc:38
bool endsWith(string_view total, string_view part)
Definition: StringOp.cc:81