Fix compiling on Win32
[lsnes.git] / include / library / string.hpp
blob6d6ed663e00cd0bf69e85b4423af57650a8314e8
1 #ifndef _library__string__hpp__included__
2 #define _library__string__hpp__included__
4 #include <string>
5 #include <sstream>
6 #include <set>
7 #include <list>
8 #include <stdexcept>
9 #include <vector>
10 #include <boost/lexical_cast.hpp>
11 #include "utf8.hpp"
12 #include "int24.hpp"
14 /**
15 * Strip trailing CR if any.
17 std::string strip_CR(const std::string& str);
19 /**
20 * Strip trailing CR if any.
22 void istrip_CR(std::string& str);
24 /**
25 * Return first character or -1 if empty.
27 int firstchar(const std::string& str);
29 /**
30 * String formatter
32 class stringfmt
34 public:
35 stringfmt() {}
36 std::string str() { return x.str(); }
37 std::u32string str32() { return utf8::to32(x.str()); }
38 template<typename T> stringfmt& operator<<(const T& y) { x << y; return *this; }
39 void throwex() { throw std::runtime_error(x.str()); }
40 private:
41 std::ostringstream x;
44 /**
45 * Lambda iterator.
47 template<typename T> class lambda_output_iterator
49 public:
50 template<typename U> class helper
52 public:
53 helper(std::function<void(const U& val)> _fn)
54 : fn(_fn)
57 helper& operator=(const U& v)
59 fn(v);
60 return *this;
62 private:
63 std::function<void(const U& val)> fn;
65 typedef std::output_iterator_tag iterator_category;
66 typedef helper<T> value_type;
67 typedef int difference_type;
68 typedef helper<T>& reference;
69 typedef helper<T>* pointer;
70 /**
71 * Constructor.
73 lambda_output_iterator(std::function<void(const T& val)> _fn)
74 : h(_fn)
77 /**
78 * Dereference.
80 helper<T>& operator*() throw()
82 return h;
84 /**
85 * Increment.
87 lambda_output_iterator<T>& operator++() throw()
90 /**
91 * Increment.
93 lambda_output_iterator<T> operator++(int) throw()
96 private:
97 helper<T> h;
101 * Token iterator.
103 template<typename T> class token_iterator
105 public:
106 typedef std::forward_iterator_tag iterator_category;
107 typedef std::basic_string<T> value_type;
108 typedef int difference_type;
109 typedef const std::basic_string<T>& reference;
110 typedef const std::basic_string<T>* pointer;
112 * Create new end-of-sequence iterator.
114 token_iterator() : str(tmp) { ctor_eos(); }
116 * Create a new start-of-sequence iterator.
118 * Parameter s: The string to iterate. Must remain valid during lifetime of iterator.
119 * Parameter sep: The set of separators.
120 * Parameter whole_sequence: If true, after seeing one separator, throw away separators until none more are found.
122 token_iterator(const std::basic_string<T>& s, std::initializer_list<const T*> sep,
123 bool whole_sequence = false) throw(std::bad_alloc) : str(s) { ctor_itr(sep, whole_sequence); }
125 * Compare.
127 bool operator==(const token_iterator<T>& itr) const throw() { return equals_op(itr); }
129 * Compare.
131 bool operator!=(const token_iterator<T>& itr) const throw() { return !equals_op(itr); }
133 * Dereference.
135 const std::basic_string<T>& operator*() const throw() { return dereference(); }
137 * Increment.
139 token_iterator<T>& operator++() throw(std::bad_alloc) { return preincrement(); }
141 * Increment.
143 token_iterator<T> operator++(int) throw(std::bad_alloc) { return postincrement(); }
145 * Do nothing, pull everything.
147 static void pull_fn();
148 private:
149 void ctor_eos();
150 void ctor_itr(std::initializer_list<const T*> sep, bool whole_sequence = false) throw(std::bad_alloc);
151 token_iterator<T> postincrement() throw(std::bad_alloc);
152 token_iterator<T>& preincrement() throw(std::bad_alloc);
153 const std::basic_string<T>& dereference() const throw();
154 bool equals_op(const token_iterator<T>& itr) const throw();
155 size_t is_sep(size_t pos);
156 void load_helper();
157 const std::basic_string<T>& str;
158 size_t bidx;
159 size_t eidx;
160 std::basic_string<T> tmp;
161 std::set<std::basic_string<T>> spliton;
162 bool is_end_iterator;
163 bool whole_seq;
167 * Foreach helper.
169 template<typename U> class _token_iterator_foreach
171 public:
173 * Create helper.
175 _token_iterator_foreach(const std::basic_string<U>& _s,
176 std::initializer_list<const U*> sep, bool whole_sequence = false)
177 : s(_s, sep, whole_sequence)
181 * Starting iterator.
183 token_iterator<U> begin() throw() { return s; }
185 * Ending iterator.
187 token_iterator<U> end() throw() { return e; }
188 private:
189 token_iterator<U> s;
190 token_iterator<U> e;
193 template<typename T> _token_iterator_foreach<T> token_iterator_foreach(const std::basic_string<T>& _s,
194 std::initializer_list<const T*> sep, bool whole_sequence = false)
196 return _token_iterator_foreach<T>(_s, sep, whole_sequence);
200 class regex_results
202 public:
203 regex_results();
204 regex_results(std::vector<std::string> res, std::vector<std::pair<size_t, size_t>> mch);
205 operator bool() const;
206 bool operator!() const;
207 size_t size() const;
208 const std::string& operator[](size_t i) const;
209 std::pair<size_t, size_t> match(size_t i) const;
210 private:
211 bool matched;
212 std::vector<std::string> results;
213 std::vector<std::pair<size_t, size_t>> matches;
217 * Regexp a string and return matches.
219 * Parameter regex: The regexp to apply.
220 * Parameter str: The string to apply the regexp to.
221 * Parameter ex: If non-null and string does not match, throw this as std::runtime_error.
222 * Returns: The captures.
224 regex_results regex(const std::string& regex, const std::string& str, const char* ex = NULL)
225 throw(std::bad_alloc, std::runtime_error);
228 * Regexp a string and return match result.
230 * Parameter regex: The regexp to apply.
231 * Parameter str: The string to apply the regexp to.
232 * Returns: True if matches, false if not.
234 bool regex_match(const std::string& regex, const std::string& str) throw(std::bad_alloc, std::runtime_error);
237 * Cast string to bool.
239 * The following is true: 'on', 'true', 'yes', '1', 'enable', 'enabled'.
240 * The following is false: 'off', 'false', 'no', '0', 'disable', 'disabled'.
241 * Parameter str: The string to cast.
242 * Returns: -1 if string is bad, 0 if false, 1 if true.
244 int string_to_bool(const std::string& cast_to_bool);
247 * \brief Typeconvert string.
249 template<typename T> inline T parse_value(const std::string& value) throw(std::bad_alloc, std::runtime_error)
251 //Floating-point case.
252 try {
253 if(std::numeric_limits<T>::is_integer) {
254 if(!std::numeric_limits<T>::is_signed && value.length() && value[0] == '-') {
255 throw std::runtime_error("Unsigned values can't be negative");
257 size_t idx = 0;
258 if(value[idx] == '-' || value[idx] == '+')
259 idx++;
260 bool sign = (value[0] == '-');
261 T mult = sign ? -1 : 1;
262 T bound = sign ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
263 T val = 0;
264 if(value.length() > idx + 2 && value[idx] == '0' && value[idx + 1] == 'x') {
265 //Hexadecimal
266 for(size_t i = idx + 2; i < value.length(); i++) {
267 char ch = value[i];
268 T v = 0;
269 if(ch >= '0' && ch <= '9')
270 v = ch - '0';
271 else if(ch >= 'A' && ch <= 'F')
272 v = ch - 'A' + 10;
273 else if(ch >= 'a' && ch <= 'f')
274 v = ch - 'a' + 10;
275 else
276 throw std::runtime_error("Invalid character in number");
277 if((sign && (bound + v) / 16 > val) || (!sign && (bound - v) / 16 < val))
278 throw std::runtime_error("Value exceeds range");
279 val = 16 * val + (sign ? -v : v);
281 } else {
282 //Decimal.
283 for(size_t i = idx; i < value.length(); i++) {
284 char ch = value[i];
285 T v = 0;
286 if(ch >= '0' && ch <= '9')
287 v = ch - '0';
288 else
289 throw std::runtime_error("Invalid character in number");
290 if((sign && (bound + v) / 10 > val) || (!sign && (bound - v) / 10 < val))
291 throw std::runtime_error("Value exceeds range");
292 val = 10 * val + (sign ? -v : v);
295 return val;
297 return boost::lexical_cast<T>(value);
298 } catch(std::exception& e) {
299 throw std::runtime_error("Can't parse value '" + value + "': " + e.what());
303 template<> inline ss_int24_t parse_value(const std::string& value) throw(std::bad_alloc, std::runtime_error)
305 int32_t v = parse_value<int32_t>(value);
306 if(v < -8388608 || v > 8388607)
307 throw std::runtime_error("Can't parse value '" + value + "': Value out of valid range");
308 return v;
311 template<> inline ss_uint24_t parse_value(const std::string& value) throw(std::bad_alloc, std::runtime_error)
313 uint32_t v = parse_value<uint32_t>(value);
314 if(v > 0xFFFFFF)
315 throw std::runtime_error("Can't parse value '" + value + "': Value out of valid range");
316 return v;
319 template<> inline std::string parse_value(const std::string& value) throw(std::bad_alloc, std::runtime_error)
321 return value;
324 template<typename T>
325 class string_list
327 public:
328 string_list();
329 string_list(const std::list<std::basic_string<T>>& list);
330 bool empty();
331 string_list strip_one() const;
332 size_t size() const;
333 const std::basic_string<T>& operator[](size_t idx) const;
334 bool operator<(const string_list<T>& x) const;
335 bool operator==(const string_list<T>& x) const;
336 bool prefix_of(const string_list<T>& x) const;
337 std::basic_string<T> debug_name() const;
338 private:
339 string_list(const std::basic_string<T>* array, size_t arrsize);
340 std::vector<std::basic_string<T>> v;
344 * Split a string into substrings on some unicode codepoint.
346 string_list<char> split_on_codepoint(const std::string& s, char32_t cp);
348 * Split a string into substrings on some unicode codepoint.
350 string_list<char32_t> split_on_codepoint(const std::u32string& s, char32_t cp);
352 #endif