rcolyer.net
RC Lib  Version 202403231100
RStr.h
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////
2 //
3 // RC Library, (c) 2011-2016, Ryan A. Colyer
4 // Distributed under the Boost Software License, v1.0. (LICENSE.txt)
5 //
6 /// \file RStr.h
7 /// Provides a robust value-added wrapper for std::string.
8 /////////////////////////////////////////////////////////////////////
9 
10 #ifndef RC_RSTR_H
11 #define RC_RSTR_H
12 
13 #include "RCconfig.h"
14 #include "Macros.h"
15 #include "Types.h"
16 #include "Errors.h"
17 #include "RCBits.h"
18 #include "Data1D.h"
19 #include "Data2D.h"
20 #include "Data3D.h"
21 #include "Iter.h"
22 
23 #ifdef WIN32
24 #include <tchar.h>
25 #endif
26 
27 #include <algorithm>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <iostream>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #ifndef CPP11324324
35 #include <sstream>
36 #endif
37 
38 /// @cond PROTECTED
39 // Use C++11 regex by default, otherwise try Boost.
40 #ifdef CPP11
41 #define RC_RSTR_REGEX
42 #include <regex>
43 #define RC_REGEX_NS std
44 #else
45 #ifdef RC_HAVE_BOOST
46 #define RC_RSTR_REGEX
47 #include <boost/regex.hpp>
48 #define RC_REGEX_NS boost
49 #endif
50 #endif
51 /// @endcond
52 
53 #ifdef RC_HAVE_QT
54 #include <QString>
55 #endif
56 
57 
58 namespace RC {
59  /// The styles in which an integral number can be formatted.
60  /** DEC == decimal, HEX == hexadecimal, HEX0x == hexadecimal with "0x"
61  * prepended, OCT == octal, OCT0 == octal with "0" prepended,
62  * BIN == binary, CHAR == treated as a character.
63  */
64  enum RStr_IntStyle { DEC=100000, HEX, HEX0x, OCT, OCT0, BIN, CHAR };
65  /// The styles in which a floating point number can be formatted.
66  /** AUTO == determine the format automatically, FIXED == as 0.0000123,
67  * SCI == as 1.23e-5
68  * SCI treats the precision parameter as a count of significant digits.
69  * FIXED treats the precision parameter as digits right of the decimal
70  * point.
71  * AUTO treats the precision parameter as the most significant digits
72  * to show, but trims trailing zeros.
73  */
74  enum RStr_FloatStyle { AUTO=100000, FIXED, SCI };
75 
76 
77  class RStr;
78  /// The random-access iterator for RStr begin() and end()
80 
81  /// A bounds-safe string class which provides an identical interface to
82  /// std::string plus many convenience functions for string manipulation.
83  /** This class checks boundaries on access and sanitizes inputs whenever
84  * possible, throwing ErrorMsgBounds or ErrorMsgNull when a usage problem
85  * arises. Functions are provided for converting to and from numerical
86  * types with formatting control, as well as high-level functions for
87  * splitting, joining, regular expressions, word-wrapping and alignment,
88  * and working with base64, UTF-8, and CSV.
89  *
90  * Usage example:
91  * \code{.cpp}
92  * u64 val = 0x12ab34cd5;
93  *
94  * // 5011360981 in hex is 0x000000012ab34cd5, or 12ab34cd5
95  * cout << val << " in hex is " << RStr(val, HEX0x)
96  * << ", or " << RStr(val, HEX, 1) << endl;
97  *
98  * // Its reciprocal is 1.9955e-10
99  * RStr message = "Its reciprocal is " + RStr(1.0/val, SCI, 5) + "\n";
100  * cout << message;
101  *
102  * // Pi dollars would be $3.14
103  * cout << "Pi dollars would be $" << RStr(3.14159, FIXED, 2) << endl;
104  *
105  * // foo, bar, baz
106  * cout << RStr::Join(RStr("foo:bar:baz").Split(':'), ", ") << endl;
107  * \endcode
108  * \nosubgrouping
109  */
110  class RStr {
111  protected:
112  /// @cond PROTECTED
113 
114  #ifdef WIN32
115  static inline size_t strnlen(const char *s, size_t n) {
116  size_t i;
117  for (i=0; i<n; i++) {
118  if (s[i] == 0) {
119  return i;
120  }
121  }
122  return n;
123  }
124  #endif
125 
126  template<class InputIterator>
127  inline void FindNullTerm(InputIterator& first, InputIterator& last) {
128  for(InputIterator iter = first; iter != last; ++iter) {
129  if (0 == char(*iter)) {
130  last = iter;
131  break;
132  }
133  }
134  }
135  /// @endcond
136  public:
137 
138  /// \name Wrapper methods for std::string
139  /// @{
140 
141 
142  /// Default constructor, initializes to blank string.
143  inline RStr() {
144  }
145 
146  /// Copy constructor.
147  inline RStr(const RStr& other)
148  : str (other.str) {
149  }
150 
151  /// Initializes to str.
152  inline RStr(const std::string& str)
153  : str (str) {
154  }
155 
156  /// Creates a new RStr from a segment of s starting at index pos with
157  /// length n or until the end.
158  /** Throws RC::ErrorMsgBounds if pos is out of bounds. */
159  inline RStr(const RStr& s, size_t pos, size_t n = npos) {
160  s.AssertPlus(pos);
161  str = std::string(s.str, pos, n);
162  }
163 
164  /// Creates a new RStr from n characters at s, or until null-termination.
165  /** Creates an empty string if s is NULL. */
166  inline RStr(const char *s, size_t n) {
167  if (s != NULL) {
168  size_t len = strnlen(s, n);
169  if (len < n) { n = len; }
170  str = std::string(s, n);
171  }
172  }
173 
174  /// Creates a new RStr from s until null-termination, or empty string if s
175  /// is NULL.
176  inline RStr(const char *s) {
177  if (s != NULL) {
178  str = std::string(s);
179  }
180  }
181 
182  /// Initializes to n copies of character c.
183  inline RStr(size_t n, char c)
184  : str (std::string(n, c)) {
185  }
186 
187  /// Initializes the string from the values in the iterator range.
188  template <class InputIterator>
189  inline RStr(InputIterator begin, InputIterator end)
190  : str (std::string(begin, end)) {
191  }
192 
193 #ifdef CPP11
194  /// Initializes the string with the list of characters.
195  inline RStr(const std::initializer_list<char> characters)
196  : str (characters) {
197  }
198 
199  /// Moves other to this RStr.
200  inline RStr(RStr&& other) noexcept
201  : str (other.str) {
202  }
203 #endif
204 
205  /// Copies the contents of s to this RStr.
206  inline RStr& operator= (const RStr& s) {
207  str = s.str;
208  return *this;
209  }
210 
211  /// Copies the null-terminated characters at s to this RStr, or empties
212  /// if s is NULL.
213  inline RStr& operator= (const char *s) {
214  if (s != NULL) {
215  str = s;
216  }
217  else {
218  str.clear();
219  }
220  return *this;
221  }
222 
223  /// Sets the RStr to char c.
224  inline RStr& operator= (char c) {
225  str = c;
226  return *this;
227  }
228 
229 #ifdef CPP11
230  /// Sets the contents of the RStr to the initializer list.
231  inline RStr& operator= (std::initializer_list<char> characters) {
232  str = characters;
233  return *this;
234  }
235 
236  /// Moves the contests of other to this RStr.
237  inline RStr& operator= (RStr&& other) {
238  str = std::move(other.str);
239  return *this;
240  }
241 #endif
242 
243  /// Returns a bounds-safe iterator to the first element.
244  /** The iterator throws ErrorMsgNull if it is accessed after this RStr
245  * is destructed. The element pointed to by this respects the offset
246  * with SetOffset.
247  */
248  inline RStrIter begin() {
249  return RStrIter(this, 0);
250  }
251 
252  /// Returns a bounds-safe iterator which points past the last element.
253  /** Accessing this iterator before decrementing it will trigger an
254  * ErrorMsgBounds. Accessing a decremented iterator after this RStr is
255  * destructed will throw ErrorMsgNull.
256  */
257  inline RStrIter end() {
258  return RStrIter(this, str.length());
259  }
260 
261 
262  /// Returns the length of the string.
263  inline size_t size() const { return str.size(); }
264  /// Returns the length of the string.
265  inline size_t length() const { return str.length(); }
266  /// Returns the maximum size of the string.
267  inline size_t max_size() const { return str.max_size(); }
268  /// Resizes the string, filling with character c if enlarging.
269  inline void resize(size_t n, char c) { str.resize(n, c); }
270  /// Resizes the string, filling with null characters if enlarging.
271  inline void resize(size_t n) { str.resize(n); }
272  /// Returns the allocated storage space
273  inline size_t capacity() const {
274  return str.capacity();
275  }
276  /// Request a storage capacity increase to capsize.
277  inline void reserve( size_t capsize=0 ) { str.reserve(capsize); }
278  /// Make the string empty.
279  inline void clear() { str.clear(); }
280  /// True of the string is empty.
281  inline bool empty() const { return str.empty(); }
282 
283  /// Returns the char at index pos, or throws ErrorMsgBounds if out of
284  /// bounds.
285  inline char& operator[] (size_t pos) {
286  AssertPlus(pos);
287  return str[pos];
288  }
289 
290  /// Const version of operator[]
291  inline const char& operator[] (size_t pos) const {
292  AssertPlus(pos);
293  return str[pos];
294  }
295 
296  /// Identical to operator[]
297  inline char& at(size_t pos) {
298  Assert(pos);
299  return str[pos];
300  }
301 
302  /// Const version of at
303  inline const char& at(size_t pos) const {
304  Assert(pos);
305  return str[pos];
306  }
307 
308  /// Appends s to this RStr.
309  inline RStr& operator+= (const RStr& s) {
310  str += s.str;
311  return *this;
312  }
313 
314  /// Appends s to this RStr if s is non-NULL.
315  inline RStr& operator+= (const char* s) {
316  if (s != NULL) {
317  str += s;
318  }
319  return *this;
320  }
321 
322  /// Appends the char c to this RStr.
323  inline RStr& operator+= (char c) {
324  str += c;
325  return *this;
326  }
327 
328  /// Appends s to this RStr.
329  inline RStr& append(const RStr& s) {
330  str.append(s.str);
331  return *this;
332  }
333 
334  /// Appends n characters in s starting at pos to this RStr, or fewer
335  /// characters if s is too short.
336  inline RStr& append(const RStr& s, size_t pos, size_t n) {
337  str.append(s.str, pos, n);
338  return *this;
339  }
340 
341  /// Appends n characters starting at s to this RStr, or fewer if
342  /// null-termination is reached in s.
343  /** Appends nothing if s is NULL. */
344  inline RStr& append(const char* s, size_t n) {
345  if (s != NULL) {
346  size_t len = strnlen(s, n);
347  if (len < n) { n = len; }
348  str.append(s, n);
349  }
350  return *this;
351  }
352 
353  /// Append s to this RStr if s is non-NULL.
354  inline RStr& append(const char* s) {
355  if (s != NULL) {
356  str.append(s);
357  }
358  return *this;
359  }
360 
361  /// Appends n copies of char c.
362  inline RStr& append(size_t n, char c) {
363  str.append(n, c);
364  return *this;
365  }
366 
367  /// Appends from first to one before last, or until a null character.
368  template <class InputIterator>
369  inline RStr& append(InputIterator first, InputIterator last) {
370  FindNullTerm(first, last);
371  str.append(first, last);
372  return *this;
373  }
374 
375 #ifdef CPP11
376  /// Append the initializer list of characters.
377  inline RStr& append (std::initializer_list<char> characters) {
378  str.append(characters);
379  return *this;
380  }
381 #endif
382 
383  /// Appends character c.
384  inline void push_back(char c) { str.push_back(c); }
385 
386  /// Copies s to this RStr.
387  inline RStr& assign(const RStr& s) {
388  str.assign(s.str);
389  return *this;
390  }
391 
392  /// Sets this RStr to n characters in s at index pos, or until the end.
393  inline RStr& assign(const RStr& s, size_t pos, size_t n) {
394  str.assign(s.str, pos, n);
395  return *this;
396  }
397 
398  /// Sets this RStr to n characters starting at s or until null-termination.
399  /** The string is cleared if s is NULL. */
400  inline RStr& assign(const char* s, size_t n) {
401  if (s != NULL) {
402  size_t len = strnlen(s, n);
403  if (len < n) { n = len; }
404  str.assign(s, n);
405  }
406  else { str.clear(); }
407  return *this;
408  }
409 
410  /// Sets this RStr to the characters at s until null-termination.
411  /** The string is cleared if s is NULL. */
412  inline RStr& assign(const char* s) {
413  if (s != NULL) {
414  str.assign(s);
415  }
416  else { str.clear(); }
417  return *this;
418  }
419 
420  /// Sets this RStr to n copies of character c.
421  inline RStr& assign(size_t n, char c) {
422  str.assign(n, c);
423  return *this;
424  }
425 
426  /// Sets the RStr to characters from first to one before last, or until
427  /// a null character.
428  template <class InputIterator>
429  inline RStr& assign(InputIterator first, InputIterator last) {
430  FindNullTerm(first, last);
431  str.assign(first, last);
432  return *this;
433  }
434 
435  /// Inserts s starting at index pos_this of this RStr, or throws
436  /// ErrorMsgBounds.
437  // Bounds check does not throw out_of_range. Throws RC::ErrorMsgBounds.
438  inline RStr& insert(size_t pos_this, const RStr& s) {
439  AssertPlus(pos_this);
440  str.insert(pos_this, s.str);
441  return *this;
442  }
443 
444  /// Inserts at index pos_this, n characters from s starting at pos_s.
445  /** Throws ErrorMsgBounds if pos_this or pos_s are out of their respective
446  * bounds. Inserts fewer characters if n is greater than the remaining
447  * characters.
448  */
449  inline RStr& insert(size_t pos_this, const RStr& s,
450  size_t pos_s, size_t n) {
451  AssertPlus(pos_this);
452  s.AssertPlus(pos_s);
453  str.insert(pos_this, s.str, pos_s, n);
454  return *this;
455  }
456 
457  /// Inserts at index pos_this, n characters from s or until
458  /// NULL-termination
459  /** If s is NULL, nothing is inserted. */
460  inline RStr& insert(size_t pos_this, const char* s, size_t n) {
461  if (s != NULL) {
462  AssertPlus(pos_this);
463  n = strnlen(s, n);
464  str.insert(pos_this, s, n);
465  }
466  return *this;
467  }
468 
469  /// Inserts s at index pos_this until null-termination, or nothing if s
470  /// is NULL.
471  inline RStr& insert(size_t pos_this, const char* s) {
472  if (s != NULL) {
473  AssertPlus(pos_this);
474  str.insert(pos_this, s);
475  }
476  return *this;
477  }
478 
479  /// Inserts n copies of char c at pos_this.
480  inline RStr& insert(size_t pos_this, size_t n, char c) {
481  AssertPlus(pos_this);
482  str.insert(pos_this, n, c);
483  return *this;
484  }
485 
486  /// Inserts char c at iterator position p.
487  inline RStrIter insert(RStrIter p, char c) {
488  str.insert(p.GetIndex(), 1, c);
489  return p;
490  }
491 
492  /// Inserts n copies of char c at iterator position p.
493  inline void insert(RStrIter p, size_t n, char c) {
494  str.insert(p.GetIndex(), n, c);
495  }
496 
497  /// At iterator position p, inserts characters from first through one
498  /// before last or until null-termination.
499  template <class InputIterator>
500  inline void insert(RStrIter p, InputIterator first, InputIterator last) {
501  FindNullTerm(first, last);
502  AssertPlus(p.GetIndex());
503  str.insert(str.begin()+p.GetIndex(), first, last);
504  }
505 
506 #ifdef CPP11
507  /// At iterator position p, inserts list of characters.
508  inline RStr& insert(const RStrIter p,
509  std::initializer_list<char> characters) {
510  str.insert(p.GetIndex(), characters);
511  return *this;
512  }
513 #endif
514 
515  /// Erases n characters at index pos, or until the end.
516  inline RStr& erase (size_t pos=0, size_t n=npos) {
517  AssertPlus(pos);
518  str.erase(pos, n);
519  return *this;
520  }
521 
522  /// Erases one character at index pos.
523  inline RStrIter erase(const RStrIter pos) {
524  erase(pos.GetIndex(), 1);
525  return pos;
526  }
527 
528  /// Erases from index first through one before index last.
529  inline RStrIter erase(const RStrIter first, const RStrIter last) {
530  size_t first_i = first.GetIndex();
531  size_t last_i = last.GetIndex();
532 
533  if (last_i > first_i) {
534  erase(first_i, last_i - first_i);
535  }
536 
537  return first;
538  }
539 
540 
541  /// Replace n_this characters at pos_this with all of s.
542  inline RStr& replace(size_t pos_this, size_t n_this, const RStr& s) {
543  erase(pos_this, n_this);
544  insert(pos_this, s);
545  return *this;
546  }
547 
548  /// Replace from first to one before last with all of s.
549  inline RStr& replace(RStrIter first, RStrIter last, const RStr& s) {
550  return replace(first.GetIndex(), last-first, s);
551  }
552 
553  /// Replace n_this characters at pos_this with n_s characters from s
554  /// starting at pos_s.
555  inline RStr& replace(size_t pos_this, size_t n_this,
556  const RStr& s, size_t pos_s, size_t n_s) {
557  erase(pos_this, n_this);
558  insert(pos_this, s, pos_s, n_s);
559  return *this;
560  }
561 
562  /// Replace n_this characters at pos_this with n_s characters from s, or
563  /// until s's null-termination.
564  inline RStr& replace(size_t pos_this, size_t n_this, const char* s,
565  size_t n_s) {
566  erase(pos_this, n_this);
567  insert(pos_this, s, n_s);
568  return *this;
569  }
570 
571  /// Replace from first through one before last with n_s characters from s,
572  /// or until s's null-termination.
573  inline RStr& replace(RStrIter first, RStrIter last,
574  const char* s, size_t n_s) {
575  return replace(first.GetIndex(), last-first, s, n_s);
576  }
577 
578  /// Replace n_this characters at pos_this with all of s, or nothing if s
579  /// is NULL.
580  inline RStr& replace(size_t pos_this, size_t n_this, const char* s) {
581  erase(pos_this, n_this);
582  insert(pos_this, s);
583  return *this;
584  }
585 
586  /// Replace from first to one before last with all of s, or nothing if s
587  /// is NULL.
588  inline RStr& replace(RStrIter first, RStrIter last, const char* s) {
589  return replace(first.GetIndex(), last-first, s);
590  }
591 
592  /// Replace n_this characters at pos_this with n_c copies of c.
593  inline RStr& replace(size_t pos_this, size_t n_this, size_t n_c, char c) {
594  erase(pos_this, n_this);
595  insert(pos_this, n_c, c);
596  return *this;
597  }
598 
599  /// Replace from first through one before last with n_c copies of c.
600  // Bounds checked.
601  inline RStr& replace(RStrIter first, RStrIter last, size_t n_c, char c) {
602  return replace(first.GetIndex(), last-first, n_c, c);
603  }
604 
605  /// Replace from first through one before lsat with in1 through one before
606  /// in2, or until null-termination.
607  template <class InputIterator>
608  inline RStr& replace(RStrIter first, RStrIter last,
609  InputIterator in_first, InputIterator in_last) {
610  erase(first, last);
611  insert(first, in_first, in_last);
612  return *this;
613  }
614 
615 
616  /// Swap contents with s.
617  inline void swap(RStr& s) {
618  str.swap(s.str);
619  }
620 
621  /// Provides a null-terminated C style string corresponding to RStr.
622  inline const char* c_str() const {
623  return str.c_str();
624  }
625 
626  /// Identical to c_str.
627  inline const char* data() const {
628  return str.c_str();
629  }
630 
631 
632  /// Get the allocator used for string storage.
633  inline std::allocator<char> get_allocator() const {
634  return str.get_allocator();
635  }
636 
637 
638  /// Copies n characters to s, starting from pos_this.
639  /** Warning: If n is greater than the length of s, this routine can
640  * write past the end of s. Consider instead obtaining a managed
641  * Data1D<char> via ToData(), using Data1D::CopyAt, and accessing the
642  * char* with Data1D::Raw for interfacing with C routines.
643  */
644  inline size_t copy(char *s, size_t n, size_t pos=0) const {
645  Assert(s);
646  AssertPlus(pos);
647  return str.copy(s, n, pos);
648  }
649 
650 
651  /// Returns the index at pos or later which matches string s, or npos if
652  /// no match.
653  inline size_t find(const RStr& s, size_t pos=0) const {
654  return str.find(s.str, pos);
655  }
656 
657  /// Returns the index at pos or later which matches n characters of s, or
658  /// npos if no match.
659  inline size_t find(const char* s, size_t pos, size_t n) const {
660  Assert(s);
661  if (strnlen(s, n) < n) {
662  return npos;
663  }
664  return str.find(s, pos, n);
665  }
666 
667  /// Returns the index at pos or later which matches s until
668  /// null-termination, or npos if no match.
669  inline size_t find(const char* s, size_t pos=0) const {
670  Assert(s);
671  return str.find(s, pos);
672  }
673 
674  /// Returns the index at pos or later which matches character c.
675  inline size_t find(char c, size_t pos=0) const {
676  return str.find(c, pos);
677  }
678 
679 
680  /// Returns the index at pos or before which starts a match of string s,
681  /// or npos if no match.
682  inline size_t rfind(const RStr& s, size_t pos=npos) const {
683  return str.rfind(s.str, pos);
684  }
685 
686  /// Returns the index at pos or before which matches n characters of s, or
687  /// npos if no match.
688  inline size_t rfind(const char* s, size_t pos, size_t n) const {
689  Assert(s);
690  if (strnlen(s, n) < n) {
691  return npos;
692  }
693  return str.rfind(s, pos, n);
694  }
695 
696  /// Returns the index at pos or before which matches s until
697  /// null-termination, or npos if no match.
698  inline size_t rfind(const char* s, size_t pos=npos) const {
699  Assert(s);
700  return str.rfind(s, pos);
701  }
702 
703  /// Returns the index at pos or before which matches character c.
704  inline size_t rfind(char c, size_t pos=npos) const {
705  return str.rfind(c, pos);
706  }
707 
708 
709  /// Returns the first index at pos or later which matches a character
710  /// in s, or npos if none match.
711  inline size_t find_first_of(const RStr& s, size_t pos=0) const {
712  return str.find_first_of(s.str, pos);
713  }
714 
715  /// Returns the first index at pos or later which matches one of the first
716  /// n characters in s, or npos if none match.
717  inline size_t find_first_of(const char* s, size_t pos, size_t n) const {
718  Assert(s);
719  size_t len = strnlen(s, n);
720  if (len < n) { n = len; }
721  return str.find_first_of(s, pos, n);
722  }
723 
724  /// Returns the first index at pos or later which matches a character
725  /// in s, or npos if none match.
726  inline size_t find_first_of(const char* s, size_t pos=0) const {
727  Assert(s);
728  return str.find_first_of(s, pos);
729  }
730 
731  /// Returns the index at pos or later which matches character c.
732  inline size_t find_first_of(char c, size_t pos=0) const {
733  return str.find_first_of(c, pos);
734  }
735 
736 
737  /// Returns the highest index at pos or before which matches a character
738  /// in s, or npos if none match.
739  inline size_t find_last_of(const RStr& s, size_t pos=npos) const {
740  return str.find_last_of(s.str, pos);
741  }
742 
743  /// Returns the highest index at pos or before which matches the first n
744  /// characters in s, or npos if none match.
745  inline size_t find_last_of(const char* s, size_t pos, size_t n) const {
746  Assert(s);
747  size_t len = strnlen(s, n);
748  if (len < n) { n = len; }
749  return str.find_last_of(s, pos, n);
750  }
751 
752  /// Returns the highest index at pos or before which matches a character
753  /// in s, or npos if none match.
754  inline size_t find_last_of(const char* s, size_t pos=npos) const {
755  Assert(s);
756  return str.find_last_of(s, pos);
757  }
758 
759  /// Returns the highest index at pos or before which matches character c,
760  /// or npos if none match.
761  inline size_t find_last_of(char c, size_t pos=npos) const {
762  return str.find_last_of(c, pos);
763  }
764 
765 
766  /// Returns the first index at pos or later which does not match a
767  /// character in s, or npos if all match.
768  inline size_t find_first_not_of(const RStr& s, size_t pos=0) const {
769  return str.find_first_not_of(s.str, pos);
770  }
771 
772  /// Returns the first index at pos or later which does not match the first
773  /// n characters in s, or npos if all match.
774  inline size_t find_first_not_of(const char* s, size_t pos, size_t n) const {
775  Assert(s);
776  size_t len = strnlen(s, n);
777  if (len < n) { n = len; }
778  return str.find_first_not_of(s, pos, n);
779  }
780 
781  /// Returns the first index at pos or later which does not match a
782  /// character in s, or npos if all match.
783  inline size_t find_first_not_of(const char* s, size_t pos=0) const {
784  Assert(s);
785  return str.find_first_not_of(s, pos);
786  }
787 
788  /// Returns the first index at pos or later which does not match character
789  /// c, or npos if all match.
790  inline size_t find_first_not_of(char c, size_t pos=0) const {
791  return str.find_first_not_of(c, pos);
792  }
793 
794 
795  /// Returns the highest index at pos or before which does not match a
796  /// character in s, or npos if all match.
797  inline size_t find_last_not_of(const RStr& s, size_t pos=npos) const {
798  return str.find_last_not_of(s.str, pos);
799  }
800 
801  /// Returns the highest index at pos or before which does not match the
802  /// first n characters in s, or npos if all match.
803  inline size_t find_last_not_of(const char* s, size_t pos, size_t n) const {
804  Assert(s);
805  size_t len = strnlen(s, n);
806  if (len < n) { n = len; }
807  return str.find_last_not_of(s, pos, n);
808  }
809 
810  /// Returns the highest index at pos or before which does not match a
811  /// character in s, or npos if all match.
812  inline size_t find_last_not_of(const char* s, size_t pos=npos) const {
813  Assert(s);
814  return str.find_last_not_of(s, pos);
815  }
816 
817  /// Returns the highest index at pos or before which does not match
818  /// character c, or npos if all match.
819  inline size_t find_last_not_of(char c, size_t pos=npos) const {
820  return str.find_last_not_of(c, pos);
821  }
822 
823 
824  /// Creates a substring from n characters starting at position pos, or
825  /// until the end of the string.
826  inline RStr substr(size_t pos=0, size_t n=npos) const {
827  AssertPlus(pos);
828  return RStr(str.substr(pos, n));
829  }
830 
831 
832  /// Returns negative, 0, or positive if this string is lesser,
833  /// equal, or greater than s.
834  inline int compare(const RStr& s) const {
835  return str.compare(s.str);
836  }
837 
838  /// Returns negative, 0, or positive if this string is lesser,
839  /// equal, or greater than s.
840  inline int compare(const char* s) const {
841  Assert(s);
842  return str.compare(s);
843  }
844 
845  /// Returns negative, 0, or positive if the n_this characters at pos_this
846  /// are lesser, equal, or greater than s.
847  inline int compare(size_t pos_this, size_t n_this, const RStr& s) const {
848  AssertPlus(pos_this);
849  return str.compare(pos_this, n_this, s.str);
850  }
851 
852  /// Returns negative, 0, or positive if the n_this characters at pos_this
853  /// are lesser, equal, or greater than s.
854  inline int compare(size_t pos_this, size_t n_this, const char* s) const {
855  Assert(s);
856  AssertPlus(pos_this);
857  return str.compare(pos_this, n_this, s);
858  }
859 
860  /// Returns negative, 0, or positive if the n_this characters at pos_this
861  /// are lesser, equal, or greater than the n_s characters at pos_s in s.
862  inline int compare(size_t pos_this, size_t n_this,
863  const RStr& s, size_t pos_s, size_t n_s) const {
864  AssertPlus(pos_this);
865  s.AssertPlus(pos_s);
866  return str.compare(pos_this, n_this, s.str, pos_s, n_s);
867  }
868 
869  /// Returns negative, 0, or positive if the n_this characters at pos_this
870  /// are lesser, equal, or greater than the n_s characters in s.
871  inline int compare(size_t pos_this, size_t n_this,
872  const char* s, size_t n_s) const {
873  Assert(s);
874  AssertPlus(pos_this);
875  size_t len = strnlen(s, n_s);
876  if (len < n_s) { n_s = len; }
877  return str.compare(pos_this, n_this, s, n_s);
878  }
879 
880 
881  /// @}
882  // End wrapper methods for std::string.
883 
884 
885  protected:
886  /// @cond PROTECTED
887  template<class T>
888  void ParseInt(T x, RStr_IntStyle style=DEC, i32 pad_to=-1,
889  char pad_with='0') {
890  Data1D<char> arr;
891  arr.Reserve(64);
892  char basetable[37] = "0123456789abcdefghijklmnopqrstuvwxyz";
893  i32 base = 10;
894  switch(style) {
895  case BIN: base = 2; break;
896  case OCT0:
897  case OCT: base = 8; break;
898  case DEC: base = 10; break;
899  case HEX0x:
900  case HEX: base = 16; break;
901  case CHAR: str = char(x); return;
902  default: Throw_RC_Error("Unknown style");
903  }
904  if (base < 1 || base > 36) {
905  Throw_RC_Error("Base out of range");
906  }
907  // Auto hex precision for type size.
908  if (pad_to < 0 && base == 16) {
909  pad_to = i32(sizeof(x) << 1);
910  }
911 
912  bool neg = false;
913  if (x<0) {
914  neg = true;
915  do {
916  arr += basetable[-(x%base)];
917  x /= base;
918  } while (x);
919  }
920  else {
921  do {
922  arr += basetable[x%base];
923  x /= base;
924  } while (x);
925  }
926 
927  size_t pad_by = 0;
928  if (pad_to > 0 && arr.size() < size_t(pad_to)) {
929  pad_by = pad_to - arr.size();
930  }
931 
932  if (neg) {
933  str.reserve(str.size() + pad_to + arr.size() + 1);
934  str += '-';
935  }
936  else {
937  str.reserve(str.size() + pad_to + arr.size());
938  }
939 
940  if (style == OCT0) {
941  str += "0";
942  }
943  else if (style == HEX0x) {
944  str += "0x";
945  }
946 
947  for (size_t i=0; i<pad_by; i++) {
948  str += pad_with;
949  }
950 
951  for (size_t i=0; i<arr.size(); i++) {
952  str += arr[arr.size()-1-i];
953  }
954  }
955 
956  template<class T>
957  void ParseFloat(T x, RC::RStr_FloatStyle style=AUTO,
958  u32 precision=std::numeric_limits<T>::digits10) {
959 #ifdef WIN32
960  unsigned int previous_output_format;
961  previous_output_format = _set_output_format(_TWO_DIGIT_EXPONENT);
962 #endif
963 
964  std::stringstream ss;
965  if (style == SCI) {
966  ss.setf(std::ios::scientific, std::ios::floatfield);
967  precision--;
968  }
969  else if (style == FIXED) {
970  ss.setf(std::ios::fixed, std::ios::floatfield);
971  }
972  ss.precision(precision);
973  ss << x;
974  ss >> str;
975 
976 #ifdef WIN32
977  _set_output_format(previous_output_format);
978 #endif
979  }
980 
981  /// @endcond
982  public:
983 
984  /// \name Convert to and from other supported types
985  /// @{
986 
987  /// The default constructor for a char, treating it as a character.
988  /** To override, cast to another type or add an RStr_IntStyle parameter.
989  */
990  inline RStr(char x) {
991  str = x;
992  }
993 
994  /// Formats x as a string in the given style, and with at least
995  /// precision 0-padded digits.
996  /** Note, the default style for a char is as a character. */
997  inline RStr(char x, RStr_IntStyle style, i32 precision=-1) { \
998  ParseInt(x, style, precision); \
999  }
1000 
1001  /// Internal.
1002 #define RC_RSTR_Int_Input(TYPE) \
1003  /** \brief Formats x as a string in the given style, and with at least \
1004  precision 0-padded digits. */ \
1005  inline RStr(TYPE x, RStr_IntStyle style=DEC, i32 precision=-1) { \
1006  ParseInt(x, style, precision); \
1007  }
1017 #ifdef MACOS
1018  RC_RSTR_Int_Input(size_t)
1019 #endif
1020 
1021  /// Internal.
1022 #define RC_RSTR_Float_Input(TYPE) \
1023  /** \brief Formats x as a string in the given style, and with it rounded
1024  to precision digits.
1025  \details For SCI precision is the significant digits to show, for
1026  AUTO it is the most signicant digits to show before removing trailing
1027  zeroes, and for FIXED, precision is digits after the decimal. AUTO
1028  has no exponent for numbers in the range (1e-5, 10^Precision). */ \
1029  inline RStr(TYPE x, RStr_FloatStyle style=AUTO, \
1030  u32 precision=std::numeric_limits<TYPE>::digits10) { \
1031  ParseFloat(x, style, precision); \
1032  }
1035 #ifdef RC_HAVE_F80
1037 #endif
1038 
1039 
1040  /// "true" if b is true, or "false" if b is false.
1041  inline RStr(bool b) {
1042  str = b ? "true" : "false";
1043  }
1044 
1045 
1046  /// Constructor for displaying a pointer, with 0's prepended if pad0s is
1047  /// true, and 0x prepended if use0x is true.
1048  inline RStr(bool pad0s, void *ptr, bool use0x=true) {
1049  u32 precision = pad0s ? (2*sizeof(ptr)) : 1;
1050 
1051  if (use0x) {
1052  ParseInt(size_t(ptr), HEX0x, precision);
1053  }
1054  else {
1055  ParseInt(size_t(ptr), HEX, precision);
1056  }
1057  }
1058 
1059 
1060  /// Initialize the string with the bytes stored in Data1D treated as
1061  /// raw character data.
1062  template <class T>
1063  explicit inline RStr(const Data1D<T>& arr) {
1064  char *s = reinterpret_cast<char*>(arr.Raw());
1065  size_t n = arr.size() * arr.TypeSize();
1066  if (s != NULL) {
1067  n = strnlen(s, n);
1068  str = std::string(s, n);
1069  }
1070  }
1071 
1072 
1073  /// Convert a std::wstring to RStr, discarding the high bits.
1074  inline RStr(const std::wstring& wstr) {
1075  str.assign(wstr.begin(), wstr.end());
1076  }
1077 
1078 
1079 #ifdef RC_HAVE_QT
1080  /// Convert a QString to RStr, discarding the high bits.
1081  inline RStr(const QString &qstr) {
1082  str = qstr.toStdString();
1083  }
1084 #endif
1086 
1087  /// Convert the beginning characters of this string to a float.
1088  /** Note, these detect hexadecimal float numbers formatted like like
1089  * 0xF.8 = 15.5, but they do not process octal.
1090  */
1091  inline f32 Get_f32() const { return strtof(str.c_str(), NULL); }
1092  /// Convert the beginning characters of this string to a float.
1093  inline f64 Get_f64() const { return strtod(str.c_str(), NULL); }
1094 #ifdef RC_HAVE_F80
1095  /// Convert the beginning characters of this string to a float.
1096  inline f80 Get_f80() const { return strtold(str.c_str(), NULL); }
1097 #endif
1099  /// Convert the beginning characters of this string to this integer type.
1100  /** Note, the default parameter for base autodetects according
1101  * to decimal, unless 0-leading octal as 013 = 11, or 0x-leading
1102  * hexadecimal as 0xF = 15.
1103  */
1104  inline u32 Get_u32(int base=0) const
1105  { return strtoul(str.c_str(), NULL, base); }
1106  /// Convert the beginning characters of this string to this integer type.
1107  inline u64 Get_u64(int base=0) const
1108  { return strtoull(str.c_str(), NULL, base); }
1109  /// Convert the beginning characters of this string to this integer type.
1110  inline i32 Get_i32(int base=0) const
1111  { return strtol(str.c_str(), NULL, base); }
1112  /// Convert the beginning characters of this string to this integer type.
1113  inline i64 Get_i64(int base=0) const
1114  { return strtoll(str.c_str(), NULL, base); }
1116  /// Convert the beginning characters of this string as a hexadecimal
1117  /// to this integer type.
1118  inline u32 Get_hex32() const { return Get_u32(16); }
1119  /// Convert the beginning characters of this string as a hexadecimal
1120  /// to this integer type.
1121  inline u64 Get_hex64() const { return Get_u64(16); }
1122 
1123  /// Returns true if case-insensitive "true", "T", or non-zero.
1124  inline bool Get_bool() const {
1125  if (Is_f64() && (Get_f64() != 0)) {
1126  return true;
1127  }
1128  RStr tmp = *this;
1129  tmp.ToLower();
1130  if (tmp.str == "true" || tmp.str == "t") {
1131  return true;
1132  }
1133  return false;
1134  }
1135 
1136  // Provides Get(x) for all the types above.
1139 #ifdef RC_HAVE_F80
1141 #endif
1142  RC_GetTc(u32)
1143  RC_GetTc(u64)
1144  RC_GetTc(i32)
1146  RC_GetTc(bool)
1147 
1148 
1149  /// True if the start of the string can be converted to an f32.
1150  /** @param strict Return true only if the full string converts. */
1151  inline bool Is_f32(bool strict=false) const {
1152  char *test;
1153  errno = 0;
1154  f32 x = strtof(str.c_str(), &test);
1155  UnusedVar(x);
1156  bool retval = (errno == 0);
1157  if (strict) { retval = retval && (test == str.c_str()+str.length()); }
1158  else { retval = retval && (test != str.c_str()); }
1159  return retval;
1160  }
1161 
1162  /// True if the start of the string can be converted to an f64.
1163  /** @param strict Return true only if the full string converts. */
1164  inline bool Is_f64(bool strict=false) const {
1165  char *test;
1166  errno = 0;
1167  f64 x = strtod(str.c_str(), &test);
1168  UnusedVar(x);
1169  bool retval = (errno == 0);
1170  if (strict) { retval = retval && (test == str.c_str()+str.length()); }
1171  else { retval = retval && (test != str.c_str()); }
1172  return retval;
1173  }
1174 
1175 #ifdef RC_HAVE_F80
1176  /// True if the start of the string can be converted to an f80.
1177  /** @param strict Return true only if the full string converts. */
1178  inline bool Is_f80(bool strict=false) const {
1179  char *test;
1180  errno = 0;
1181  f80 x = strtold(str.c_str(), &test);
1182  UnusedVar(x);
1183  bool retval = (errno == 0);
1184  if (strict) { retval = retval && (test == str.c_str()+str.length()); }
1185  else { retval = retval && (test != str.c_str()); }
1186  return retval;
1187  }
1188 #endif
1189 
1190  /// True if the start of the string can be converted to an u32.
1191  /** @param base The conversion base to test (0 is automatic).
1192  * @param strict Return true only if the full string converts.
1193  */
1194  inline bool Is_u32(int base=0, bool strict=false) const {
1195  char *test;
1196  errno = 0;
1197  u32 x = strtoul(str.c_str(), &test, base);
1198  UnusedVar(x);
1199  bool retval = (errno == 0);
1200  if (strict) {
1201  retval = retval && (test == str.c_str()+str.length())
1202  && (Get_f32() >= 0);
1203  }
1204  else { retval = retval && (test != str.c_str()); }
1205  return retval;
1206  }
1207 
1208  /// True if the start of the can be converted to an u64.
1209  /** @param base The conversion base to test (0 is automatic).
1210  * @param strict Return true only if the full string converts.
1211  */
1212  inline bool Is_u64(int base=0, bool strict=false) const {
1213  char *test;
1214  errno = 0;
1215  u64 x = strtoull(str.c_str(), &test, base);
1216  UnusedVar(x);
1217  bool retval = (errno == 0);
1218  if (strict) {
1219  retval = retval && (test == str.c_str()+str.length())
1220  && (Get_f32() >= 0);
1221  }
1222  else { retval = retval && (test != str.c_str()); }
1223  return retval;
1224  }
1225 
1226  /// True if the start of the string can be converted to an i32.
1227  /** @param base The conversion base to test (0 is automatic).
1228  * @param strict Return true only if the full string converts.
1229  */
1230  inline bool Is_i32(int base=0, bool strict=false) const {
1231  char *test;
1232  errno = 0;
1233  i32 x = strtol(str.c_str(), &test, base);
1234  UnusedVar(x);
1235  bool retval = (errno == 0);
1236  if (strict) { retval = retval && (test == str.c_str()+str.length()); }
1237  else { retval = retval && (test != str.c_str()); }
1238  return retval;
1239  }
1240 
1241  /// True if the start of the string can be converted to an i64.
1242  /** @param base The conversion base to test (0 is automatic).
1243  * @param strict Return true only if the full string converts.
1244  */
1245  inline bool Is_i64(int base=0, bool strict=false) const {
1246  char *test;
1247  errno = 0;
1248  i64 x = strtoll(str.c_str(), &test, base);
1249  UnusedVar(x);
1250  bool retval = (errno == 0);
1251  if (strict) { retval = retval && (test == str.c_str()+str.length()); }
1252  else { retval = retval && (test != str.c_str()); }
1253  return retval;
1254  }
1255 
1256 
1257  /// True if the start of the string can be converted as hexadecimal to
1258  /// a u32.
1259  /** @param strict Return true only if the full string converts. */
1260  inline bool Is_hex32(bool strict=false) const {
1261  return Is_u32(16, strict);
1262  }
1263  /// True if the start of the string can be converted as hexadecimal to
1264  /// a u64.
1265  /** @param strict Return true only if the full string converts. */
1266  inline bool Is_hex64(bool strict=false) const {
1267  return Is_u64(16, strict);
1268  }
1269 
1270  /// True if the string is a "0", "1", or case insensitive "true",
1271  /// "false", "T", or "F".
1272  inline bool Is_bool() const {
1273  if (str == "0" || str == "1") {
1274  return true;
1275  }
1276  if (size() <= 4) {
1277  RStr tmp = *this;
1278  tmp.ToLower();
1279  if (tmp.str == "true" || tmp.str == "false" ||
1280  tmp.str == "t" || tmp.str == "f") {
1281  return true;
1282  }
1283  }
1284  return false;
1285  }
1286 
1287 #ifdef RC_HAVE_QT
1288  /// Convert the RStr to a QString.
1289  inline QString ToQString() const {
1290  return QString::fromStdString(str);
1291  }
1292 #endif
1293 
1294  /// Convert the RStr to a std::wstring.
1295  inline std::wstring wstring() {
1296  std::wstring wstr;
1297  wstr.assign(str.begin(), str.end());
1298  return wstr;
1299  }
1300 
1301 #ifdef WIN32
1302  /// For Win32, provides an LPCSTR to the string
1303  inline const char* ToLPCSTR() const {
1304  return c_str();
1305  }
1306 
1307  /// For Win32, provides an LPCWSTR to the string
1308  /** Return type implicitly casts to const whcar_t*, or with Get().
1309  */
1312  hr.Set(hr.Held().c_str());
1313  return hr;
1314  }
1315 #ifdef UNICODE
1316  inline HoldRelated<std::wstring, const wchar_t*> ToLPCTSTR() {
1317  return ToLPCWSTR();
1318  }
1319 #else
1320  /// For Win32, provides an LPCTSTR to the string.
1321  /** See ToLPCWSTR() for the return type if UNICODE is defined.
1322  */
1323  inline const char* ToLPCTSTR() {
1324  return ToLPCSTR();
1325  }
1326 #endif
1327 #endif
1329 
1330  /// Provides raw access to the std::string this RStr wraps.
1331  inline std::string& Raw() { return str; }
1333  /// Provides const raw access to the std::string this RStr wraps.
1334  inline const std::string& Raw() const { return str; }
1335 
1336  /// Returns a Data1D<char> corresponding to the character data in the
1337  /// string.
1338  inline Data1D<char> ToData() const {
1339  char *copy = new char[size()];
1340  UnusedVar(strncpy(copy, c_str(), size()));
1341  return Data1D<char>(size(), copy, true);
1342  }
1343 
1344  /// @} Basic types
1346 
1347  /// \name Bounds-checking
1348  /// @{
1349 
1350  /// True if the index pos is in bounds.
1351  inline bool Check(size_t pos) const {
1352  return (pos < str.length());
1353  }
1354 
1355  /// True if the index pos is in bounds, permitting the null.
1356  inline bool CheckPlus(size_t pos) const {
1357  return (pos <= str.length());
1358  }
1359 
1360  /// Throws ErrorMsgBounds if the index pos is out of bounds.
1361  inline void Assert(size_t pos) const {
1362  if ( ! Check(pos) ) {
1363  Throw_RC_Type(Bounds, "Out of bounds");
1364  }
1365  }
1366 
1367  /// Throws ErrorMsgBounds if the index pos is out of bounds, permitting
1368  /// the null.
1369  inline void AssertPlus(size_t pos) const {
1370  if ( ! CheckPlus(pos) ) {
1371  Throw_RC_Type(Bounds, "Out of bounds");
1372  }
1373  }
1374 
1375 
1376  /// Throws ErrorMsgNull if ptr is null.
1377  inline void Assert(const char* ptr) const {
1378  if (ptr == NULL) {
1379  Throw_RC_Type(Null, "NULL pointer");
1380  }
1381  }
1382 
1383  /// @} Bounds-checking
1384 
1386  /// \name Text alignment and arrangement functions
1387  /// @{
1388 
1389  /// If the length is less than pad_to, add pad_width to the left until it
1390  /// reaches that size.
1391  inline RStr& PadLeft(const size_t pad_to, const char pad_with=' ') {
1392  if (pad_to > length()) {
1393  RStr padded;
1394  padded = RStr(pad_to-length(), pad_with);
1395  padded += *this;
1396  *this = padded;
1397  }
1398  return *this;
1399  }
1400 
1401 
1402  /// If the length is less than pad_to, add pad_width to the right until it
1403  /// reaches that size.
1404  inline RStr& PadRight(const size_t pad_to, const char pad_with=' ') {
1405  if (pad_to > length()) {
1406  *this += RStr(pad_to-length(), pad_with);
1407  }
1408  return *this;
1409  }
1410 
1411 
1412  /// If the length is less than pad_to, add pad_width evenly to the right
1413  /// and left until it reaches that size.
1414  inline RStr& PadCenter(const size_t pad_to, const char pad_with=' ') {
1415  if (pad_to > length()) {
1416  size_t diff = pad_to - length();
1417  size_t half = diff/2;
1418  PadLeft(pad_to - diff + half, pad_with);
1419  PadRight(pad_to, pad_with);
1420  }
1421  return *this;
1422  }
1423 
1424 
1425  /// Wraps each line in this RStr to be no longer than width.
1426  inline Data1D<RStr> Wrap(const size_t width) {
1427  Data1D<RStr> wrapped;
1428  size_t pos = 0;
1429 
1430  do {
1431  size_t this_width, end_pos;
1432  size_t search_end = pos + width;
1433  if (search_end > length()) { search_end = length(); }
1434  for(end_pos=pos; end_pos < search_end; end_pos++) {
1435  if (str[end_pos] == '\n') { break; }
1436  }
1437  if (end_pos < search_end) {
1438  // newline found
1439  this_width = end_pos - pos;
1440  if (end_pos > 0 && str[end_pos-1] == '\r') {
1441  this_width--;
1442  }
1443  wrapped += substr(pos, this_width);
1444  pos = end_pos+1;
1445  }
1446  else {
1447  wrapped += substr(pos, width);
1448  pos += width;
1449  }
1450  } while(pos < length());
1451 
1452  return wrapped;
1453  }
1454 
1455 
1456  /// Wraps each line in this RStr to be no longer than width, but tries
1457  /// to keep whole words together.
1458  inline Data1D<RStr> WordWrap(const size_t width) {
1459  Data1D<RStr> wrapped;
1460  size_t pos = 0;
1461  size_t this_width;
1462 
1463  do {
1464  size_t end_pos;
1465  size_t search_end = pos + width;
1466  if (search_end > length()) {
1467  wrapped += substr(pos);
1468  break;
1469  }
1470  for(end_pos=pos; end_pos < search_end; end_pos++) {
1471  if (str[end_pos] == '\n') { break; }
1472  }
1473  if (end_pos < search_end) {
1474  // newline found
1475  this_width = end_pos - pos;
1476  if (end_pos > 0 && str[end_pos-1] == '\r') {
1477  this_width--;
1478  }
1479  wrapped += substr(pos, this_width);
1480  pos = end_pos+1;
1481  }
1482  else {
1483  // No newline found. Check for space.
1484  size_t try_pos = pos+width;
1485  try_pos = (try_pos < length()) ? try_pos : length()-1;
1486  end_pos = find_last_of(" ", try_pos);
1487  if (end_pos == npos || end_pos < pos) {
1488  this_width = width;
1489  end_pos = pos+width;
1490  }
1491  else {
1492  this_width = end_pos - pos;
1493  end_pos = find_first_not_of(" ", end_pos);
1494  }
1495  wrapped += substr(pos, this_width);
1496  pos = end_pos;
1497  }
1498  } while(pos < length());
1499 
1500  return wrapped;
1501  }
1502 
1503  /// @} alignment/arrangement
1504 
1505 
1506 #ifdef RC_RSTR_REGEX
1507  /// \name Regular expression support
1508  /// These use C++11 regex by default, but can fall back on boost regex if
1509  /// C++11 is missing and RC_HAVE_BOOST is defined in RCconfig.h.
1510  /// @{
1512  /// True if the regular expression reg matches this string.
1513  inline bool Match(const RC_REGEX_NS::regex& reg) {
1514  return RC_REGEX_NS::regex_search(str, reg);
1515  }
1516  /// True if the regular expression regstr matches this string.
1517  inline bool Match(const RStr& regstr) {
1518  RC_REGEX_NS::regex reg(regstr.c_str());
1519  return Match(reg);
1520  }
1521 
1522 
1523  /// True if the regular expression reg matches this string, and returns
1524  /// the matches in matches.
1525  inline bool Match(const RC_REGEX_NS::regex& reg, Data1D<RStr>& matches) {
1526  bool result;
1527  RStr tmp;
1528 
1529  RC_REGEX_NS::cmatch matcharr;
1530 
1531  result = RC_REGEX_NS::regex_search(str.c_str(), matcharr, reg);
1532 
1533  matches.Resize(0);
1534 
1535  if (result) {
1536  for (size_t i=1; i<matcharr.size(); i++) {
1537  tmp.assign(matcharr[i].first, matcharr[i].second);
1538  matches.Append(tmp);
1539  }
1540  }
1541 
1542  return result;
1543  }
1544  /// True if the regular expression regstr matches this string, and returns
1545  /// the matches in matches.
1546  inline bool Match(const RStr& regstr, Data1D<RStr>& matches) {
1547  RC_REGEX_NS::regex reg(regstr.c_str());
1548  return Match(reg, matches);
1549  }
1550 
1552  /// Substitutes regular expression reg with subst in this string.
1553  inline void Subst(const RC_REGEX_NS::regex& reg, const RStr& subst) {
1554  str = RC_REGEX_NS::regex_replace(str, reg, subst.str);
1555  }
1556  /// Substitutes regular expression regstr with subst in this string.
1557  inline void Subst(const RStr& regstr, const RStr& subst) {
1558  RC_REGEX_NS::regex reg(regstr.c_str());
1559  Subst(reg, subst);
1560  }
1561  /// @} regex
1562 #endif // RC_RSTR_REGEX
1564 
1565  /// \name Text manipulation routines
1566  /// @{
1567 
1568  /// Returns true if pos or later which matches string s.
1569  inline bool Contains(const RStr& s, size_t pos=0) const {
1570  return npos != find(s, pos);
1571  }
1572 
1573  /// Returns the index after the first instance of string s at pos or
1574  /// later, or npos if no match.
1575  inline size_t After(const RStr& s, size_t pos=0) const {
1576  size_t res = find(s, pos);
1577  return (res == npos ? npos : res + s.size());
1578  }
1579 
1580  /// Remove all trailing newline characters, or provided char set.
1581  inline RStr& Chomp(const RStr& chomp_chars = "\r\n") {
1582  size_t end;
1583 
1584  if (length() > 0) {
1585  end = str.find_last_not_of(chomp_chars.str);
1586  if (end == npos) {
1587  str.clear();
1588  }
1589  else {
1590  str.resize(end+1);
1591  }
1592  }
1593  return *this;
1594  }
1595 
1596 
1597  /// Remove all leading and trailing whitespace, or provided char set.
1598  inline RStr& Trim(const RStr& trim_chars = " \t\r\n") {
1599  size_t start, end;
1600 
1601  if (length() > 0) {
1602  end = str.find_last_not_of(trim_chars.str);
1603  if (end == npos) {
1604  str = "";
1605  }
1606  else {
1607  start = str.find_first_not_of(trim_chars.str);
1608  str = str.substr(start, end-start+1);
1609  }
1610  }
1611  return *this;
1612  }
1613 
1614 
1615  /// Make sure the string is no longer than max_size.
1616  inline RStr& Truncate(const size_t max_size) {
1617  if (max_size < length()) {
1618  resize(max_size);
1619  }
1620  return *this;
1621  }
1622 
1623 
1624 
1625  /// Make this RStr lowercase.
1626  inline RStr& ToLower() {
1627  size_t i;
1628  for (i=0; i<str.length(); i++) {
1629  str[i] = tolower(str[i]);
1630  }
1631  return *this;
1632  }
1633 
1634 
1635  /// Make this RStr uppercase.
1636  inline RStr& ToUpper() {
1637  size_t i;
1638  for (i=0; i<str.length(); i++) {
1639  str[i] = toupper(str[i]);
1640  }
1641  return *this;
1642  }
1643 
1644 
1645  /// Return an array of strings split at each instance of c.
1646  inline Data1D<RStr> Split(char c) const {
1647  Data1D<RStr> retval;
1648  size_t start, end;
1649 
1650  start = 0;
1651 
1652  while (start <= str.length()) {
1653  end = str.find_first_of(c, start);
1654  if (end == npos) {
1655  retval.Append(str.substr(start, npos));
1656  break;
1657  }
1658  else {
1659  retval.Append(str.substr(start, end-start));
1660  }
1661  start = end+1;
1662  }
1663 
1664  return retval;
1665  }
1666 
1667 
1668  /// Return an array of 2 strings split at the first character from
1669  /// dividers.
1670  inline Data1D<RStr> SplitFirst(const RStr& dividers) const {
1671  Data1D<RStr> retval(2);
1672  size_t mid;
1673 
1674  mid = str.find_first_of(dividers.str, 0);
1675  if (mid == npos) {
1676  retval[0] = str.substr(0, npos);
1677  }
1678  else {
1679  retval[0] = str.substr(0, mid);
1680  if ((mid+1) < str.length()) {
1681  retval[1] = str.substr(mid+1, npos);
1682  }
1683  }
1685  return retval;
1686  }
1687 
1688 
1689  /// Return an array of 2 strings split at the last character from dividers.
1690  inline Data1D<RStr> SplitLast(const RStr& dividers) const {
1691  Data1D<RStr> retval(2);
1692  size_t mid;
1693 
1694  mid = str.find_last_of(dividers.str, npos);
1695  if (mid == npos) {
1696  retval[0] = str.substr(0, npos);
1697  }
1698  else {
1699  retval[0] = str.substr(0, mid);
1700  if ((mid+1) < str.length()) {
1701  retval[1] = str.substr(mid+1, npos);
1702  }
1703  }
1704 
1705  return retval;
1706  }
1707 
1708 
1709  /// Return an array of strings split by any characters in dividers.
1710  /** Always returns at least one element.
1711  */
1712  inline Data1D<RStr> SplitAny(const RStr& dividers) const {
1713  Data1D<RStr> retval;
1714  size_t start, end;
1715 
1716  end = 0;
1717 
1718  while (end < str.length()) {
1719  start = str.find_first_not_of(dividers.str, end);
1720  if (start == npos) {
1721  break;
1722  }
1723  end = str.find_first_of(dividers.str, start);
1724  if (end == npos) {
1725  end = str.length();
1726  }
1727  retval.Append(str.substr(start, end-start));
1728  }
1729 
1730  if (retval.size() == 0) { retval += ""; }
1731  return retval;
1732  }
1733 
1734 
1735  /// Return an array of one or more whitespace separated words.
1736  inline Data1D<RStr> SplitWords() const {
1737  return SplitAny(" \t\r\n");
1738  }
1739 
1740 
1741  /// Takes a Data1D<T> array and joins them as one string with spacer
1742  /// between each element while applying the function to each element.
1743  /** Note: The default func converts each element to a string with its
1744  * RStr(T) constructor, and thus only works on types for which a
1745  * constructor exists.
1746  */
1747  template <class T>
1748  static inline RStr Join(const Data1D<T>& str_arr,
1749  const RStr& spacer="",
1750  RStr(*func)(const T&)=nullptr) {
1751  RStr retval;
1752  size_t i;
1753 
1754  if (str_arr.size() == 0) {
1755  retval.str = "";
1756  return retval;
1757  }
1758 
1759  if (func == nullptr) {
1760  func = [](const T& in) { return RStr(in); };
1761  }
1762 
1763  retval = func(str_arr[0]);
1764 
1765  for (i=1; i<str_arr.size(); i++) {
1766  retval += spacer;
1767  retval += func(str_arr[i]);
1768  }
1769 
1770  return retval;
1771  }
1772 
1773  /// @} Text manipulation
1775 
1776  /// \name Metrics
1777  /// @{
1778 
1779  /// Compute the Levenshtein distance to other.
1780  inline size_t Distance(const RStr& other) const {
1781  size_t thislen = length();
1782  size_t otherlen = other.length();
1783 
1784  Data2D<size_t> count(thislen+1, 2);
1785 
1786  u32 prev_ind = 0;
1787  u32 curr_ind = 1;
1788  size_t i, j;
1789  size_t subst_cnt, insert_cnt;
1790  for (i=0; i<count.size1(); i++) {
1791  count[0][i] = i;
1792  }
1793 
1794  for (i=0; i<otherlen; i++) {
1795  count[curr_ind][0] = i+1;
1796  char ch = other[i];
1797  for (j=0; j<thislen; j++) {
1798  insert_cnt = std::min(1+count[curr_ind][j], 1+count[prev_ind][1+j]);
1799  subst_cnt = count[prev_ind][j] + ((str[j] == ch) ? 0 : 1);
1800  count[curr_ind][j+1] = std::min(insert_cnt, subst_cnt);
1801  }
1802 
1803  prev_ind ^= 1;
1804  curr_ind ^= 1;
1805  }
1806 
1807  return count[prev_ind][thislen];
1808  }
1809 
1810  /// Determine the length of the contents treated as a UTF-8 string.
1811  /** Throws ErrorMsg "Invalid UTF-8" if the string cannot be parsed as a
1812  * UTF-8 string.
1813  */
1814  inline size_t Length8() const {
1815  size_t len = 0;
1816  for (size_t i=0; i<str.length(); i++) {
1817  u32 cnt = 0;
1818  u8 ch = str[i];
1819  while (0x80 & ch) {
1820  cnt++;
1821  ch = ch << 1;
1822  }
1823  if (cnt == 1) {
1824  Throw_RC_Error("Invalid UTF-8");
1825  }
1826  for (u32 parts=1; (parts<cnt); parts++) {
1827  i++;
1828  if (i >= str.length() || (((u8(str[i])) & 0xC0)!=0x80)) {
1829  Throw_RC_Error("Invalid UTF-8");
1830  }
1831  }
1832  len++;
1833  }
1834  return len;
1835  }
1836 
1837  /// @} Metrics
1838 
1840  /// \name Interacting with standard formats
1841  /// @{
1842 
1843 
1844  /// Return comma-separated values with whitespace trimmed.
1845  inline Data1D<RStr> SplitCSV(char divider=',') const {
1846  Data1D<RStr> retval;
1847  size_t i;
1848 
1849  retval = Split(divider);
1850 
1851  for (i=0; i<retval.size(); i++) {
1852  retval[i].Trim();
1853  }
1854 
1855  return retval;
1856  }
1857 
1859  /// Makes a comma-separated values string out of a Data1D<T> arr.
1860  /** The type must have an RStr(T) constructor. The elements are
1861  * separated by ", ".
1862  */
1863  template <class T>
1864  static inline RStr MakeCSV(const Data1D<T>& arr,
1865  const RStr& divider=", ") {
1866  RStr retval;
1867  size_t i;
1868 
1869  if (arr.size() == 0) {
1870  retval.str = "";
1871  return retval;
1872  }
1873 
1874  retval = RStr(arr[0]);
1875 
1876  for (i=1; i<arr.size(); i++) {
1877  retval += divider;
1878  retval += RStr(arr[i]);
1879  }
1880 
1881  return retval;
1882  }
1883 
1884  /// Makes a comma-separated values string out of a Data2D<T> arr.
1885  /** The elements are separated by ", " in the first dimension, and
1886  * followed by "\n" in the second dimension.
1887  * @see MakeCSV
1888  */
1889  template <class T>
1890  static inline RStr MakeCSV(const Data2D<T>& arr,
1891  const RStr& divider1=", ", const RStr& divider2="\n") {
1892  RStr retval;
1893  size_t i;
1894 
1895  for (i=0; i<arr.size2(); i++) {
1896  retval += MakeCSV(arr[i], divider1);
1897  retval += divider2;
1898  }
1899 
1900  return retval;
1901  }
1902 
1903  /// Makes a comma-separated values string out of a Data3D<T> arr.
1904  /** The elements are separated by ", " in the first dimension,
1905  * followed by "\n" in the second dimension, and separated by an
1906  * additional "\n" in the third dimension.
1907  * @see MakeCSV
1908  */
1909  template <class T>
1910  static inline RStr MakeCSV(const Data3D<T>& arr,
1911  const RStr& divider1=", ", const RStr& divider2="\n",
1912  const RStr& divider3="\n") {
1913  RStr retval;
1914  size_t i;
1915 
1916  if (arr.size3() == 0) {
1917  retval.str = "";
1918  return retval;
1919  }
1920 
1921  retval = MakeCSV(arr[0], divider1, divider2);
1922 
1923  for (i=1; i<arr.size3(); i++) {
1924  retval += divider3;
1925  retval += MakeCSV(arr[i], divider1, divider2);
1926  }
1927 
1928  return retval;
1929  }
1930 
1931 
1932  /// Treat this string as ISO-8859-1 and return a UTF8 string.
1933  /** This supports the windows-1252 extension as required by HTML5. */
1934  inline RStr ISOtoUTF8() const {
1935  RStr utf8;
1936  for (size_t i=0; i<str.length(); i++) {
1937  if ((u8(str[i])) < 0x80) {
1938  utf8 += str[i];
1939  }
1940  else {
1941  if ((u8(str[i])) < 0xA0) {
1942  // Windows-1252 extension
1943  u8 win1252[4*0x20] = {0xe2,0x82,0xac,0,0x81,0,0,0,
1944  0xe2,0x80,0x9a,0,0xc6,0x92,0,0,0xe2,0x80,0x9e,0,
1945  0xe2,0x80,0xa6,0,0xe2,0x80,0xa0,0,0xe2,0x80,0xa1,0,
1946  0xcb,0x86,0,0,0xe2,0x80,0xb0,0,0xc5,0xa0,0,0,
1947  0xe2,0x80,0xb9,0,0xc5,0x92,0,0,0x8d,0,0,0,0xc5,0xbd,0,0,
1948  0x8f,0,0,0,0x90,0,0,0,0xe2,0x80,0x98,0,0xe2,0x80,0x99,0,
1949  0xe2,0x80,0x9c,0,0xe2,0x80,0x9d,0,0xe2,0x80,0xa2,0,
1950  0xe2,0x80,0x93,0,0xe2,0x80,0x94,0,0xcb,0x9c,0,0,
1951  0xe2,0x84,0xa2,0,0xc5,0xa1,0,0,0xe2,0x80,0xba,0,
1952  0xc5,0x93,0,0,0x9d,0,0,0,0xc5,0xbe,0,0,0xc5,0xb8,0,0};
1953  utf8 += RStr(reinterpret_cast<char*>(
1954  &win1252[4*(u8(str[i])-0x80)]));
1955  }
1956  else {
1957  // Standard ISO-8859-1 extension
1958  utf8 += (str[i] & 0x40) ? 0xc3 : 0xc2;
1959  utf8 += str[i] & 0xbf;
1960  }
1961  }
1962  }
1963  return utf8;
1964  }
1965 
1967  /// Treat the contents as a UTF-8 string, and return corresponding
1968  /// UTF-32 data.
1969  /** Throws ErrorMsg "Invalid UTF-8" if the string cannot be parsed as a
1970  * UTF-8 string.
1971  */
1972  inline Data1D<u32> UTF8toUTF32() const {
1973  Data1D<u32> utf32; utf32.Reserve(Length8()); // Validates
1974  for (size_t i=0; i<str.length(); i++) {
1975  u32 cnt = 0;
1976  u8 ch = str[i];
1977  while (0x80 & ch) {
1978  cnt++;
1979  ch = ch << 1;
1980  }
1981  u32 val = (u8(str[i])) & (0x7F >> cnt);
1982  for (u32 parts=1; (parts<cnt) && ((i+1)<str.length()); parts++) {
1983  i++;
1984  val = (val << 6) + ((u8(str[i])) & 0x3F);
1985  }
1986  utf32 += val;
1987  }
1988  return utf32;
1989  }
1990 
1991 
1992  protected:
1993  /// @cond PROTECTED
1994  enum B64Type { B64STANDARD, B64URL };
1995  static inline void B64DoWrap(size_t wrap, RStr& encoded, size_t& s_cnt) {
1996  if (wrap && s_cnt && (s_cnt % wrap == 0)) {
1997  encoded += NewLine();
1998  }
1999  s_cnt++;
2000  }
2001  static inline void B64Error() { Throw_RC_Error("Invalid Base64 Data"); }
2002  static inline void B64DoEnc(u32& val, RStr& encoded, B64Type type) {
2003  const char b64enc[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2004  "abcdefghijklmnopqrstuvwxyz"
2005  "0123456789+/";
2006  const char b64encurl[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2007  "abcdefghijklmnopqrstuvwxyz"
2008  "0123456789-_";
2009  if (type == B64STANDARD) {
2010  encoded += b64enc[val >> 18];
2011  }
2012  else {
2013  encoded += b64encurl[val >> 18];
2014  }
2015  val = (val << 6) & 0x00FFFFFF;
2016  }
2017  static inline void B64DoDec(u8 inp, u32& val) {
2018  const char b64dec[257] =
2019  "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!n!n!odefghijklm!!!!!!"
2020  "!0123456789:;<=>?@ABCDEFGHI!!!!o!JKLMNOPQRSTUVWXYZ[\\]^_`abc!!!!!"
2021  "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
2022  "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
2023  u32 x = b64dec[inp];
2024  if (x == '!') { B64Error(); }
2025  val = (val << 6) + (x - '0');
2026  }
2027  static inline void B64DoPack(u32& val, Data1D<u8>& decoded) {
2028  decoded += val >> 16;
2029  val = (val << 8) & 0x00FFFFFF;
2030  }
2031 
2032  static inline RStr ToBase64Type(const Data1D<u8>& input, size_t wrap,
2033  B64Type type) {
2034  RStr encoded;
2035 
2036  size_t i;
2037  size_t s_cnt = 0;
2038  u32 val = 0;
2039  for(i=0; i<input.size(); i++) {
2040  val = (val << 8) + input[i];
2041  if ((i % 3) == 2) {
2042  for (u32 s=0; s<4; s++) {
2043  B64DoWrap(wrap, encoded, s_cnt);
2044  B64DoEnc(val, encoded, type);
2045  }
2046  }
2047  }
2048 
2049  u32 resid = i%3;
2050  if (resid > 0) { resid++; }
2051  u32 pad = (4-resid) & 3;
2052  val <<= 8*pad;
2053 
2054  for (u32 s=0; s<resid; s++) {
2055  B64DoWrap(wrap, encoded, s_cnt);
2056  B64DoEnc(val, encoded, type);
2057  }
2058  if (type == B64STANDARD) {
2059  for (u32 s=0; s<pad; s++) {
2060  B64DoWrap(wrap, encoded, s_cnt);
2061  encoded += "=";
2062  }
2063  }
2064 
2065  return encoded;
2066  }
2067 
2068  /// @endcond
2069  public:
2070 
2071  /// Encodes input to standard base64 in compliance with RFC 4648.
2072  static inline RStr ToBase64(const Data1D<u8>& input, size_t wrap=0) {
2073  return ToBase64Type(input, wrap, B64STANDARD);
2074  }
2075 
2076  /// Encodes input to base64url in compliance with RFC 4648, safe for url
2077  /// and filename use.
2078  static inline RStr ToBase64URL(const Data1D<u8>& input, size_t wrap=0) {
2079  return ToBase64Type(input, wrap, B64URL);
2080  }
2081 
2082  /// Decodes input from base64 in compliance with RFC 4648, standard or
2083  /// URL encoding.
2084  static inline Data1D<u8> FromBase64(const RStr& input) {
2085  Data1D<u8> decoded;
2086  size_t icnt = 0;
2087  u32 val = 0;
2088  for (size_t i=0; i<input.size(); i++) {
2089  if (input[i] == '\n' || input[i] == '\r') { continue; }
2090  if (input[i] == '=') { break; }
2091  B64DoDec(input[i], val);
2092  if ((icnt&3) == 3) {
2093  for (size_t d=0; d<3; d++) {
2094  B64DoPack(val, decoded);
2095  }
2096  }
2097  icnt++;
2098  }
2099  u32 resid = 0;
2100  switch(icnt&3) {
2101  case 0: return decoded;
2102  case 2: resid = 1; break;
2103  case 3: resid = 2; break;
2104  default: B64Error();
2105  }
2106  val <<= (4-(icnt&3))*6;
2107  for (u32 d=0; d<resid; d++) {
2108  B64DoPack(val, decoded);
2109  }
2110  return decoded;
2111  }
2112 
2113 
2114  /// Converts hexstr to a byte array, like "a4c208" -> { 0xa4, 0xc2, 0x08 }
2115  static inline Data1D<u8> FromHexStr(const RStr& hexstr) {
2116  Data1D<u8> bytes;
2117  RStr parse;
2118  for (size_t i=0; i<hexstr.size(); i++) {
2119  parse += hexstr[i];
2120  if (i&1) {
2121  if (!parse.Is_hex32()) { Throw_RC_Error("Invalid hex string"); }
2122  bytes += parse.Get_hex32();
2123  parse.clear();
2124  }
2125  }
2126  return bytes;
2127  }
2128 
2129 
2130  /// Converts rawdata to a hex string, like { 0xa4, 0xc2, 0x08 } -> "a4c208"
2131  template<class T>
2132  static inline RStr ToHexStr(const Data1D<T>& rawdata) {
2133  RStr hexstr;
2134  u8 *ptr = reinterpret_cast<u8*>(rawdata.Raw());
2135  size_t len = rawdata.size() * sizeof(T);
2136  for (size_t i=0; i<len; i++) {
2137  hexstr += RStr(ptr[i], HEX);
2138  }
2139  return hexstr;
2140  }
2141 
2142 
2143  /// Converts standard arguments to "int main" into a Data1D<RStr>.
2144  /** Index 0 contains the program name, corresponding to argv[0],
2145  * and index 1 on up are the parameters. Thus size()-1 of the returned
2146  * value is the number of command-line parameters received.
2147  * If called with no arguments, the previous arglist is returned.
2148  */
2149  static inline Data1D<RStr> Args(int argc=0, char *argv[]=NULL) {
2150  static Data1D<RStr> arglist;
2151 
2152  if (argc==0) {
2153  return arglist;
2154  }
2155 
2156  if (argv == NULL) {
2157  Throw_RC_Type(Null, "NULL pointer");
2158  }
2159 
2160  arglist.Resize(argc);
2161 
2162  int i;
2163  for (i=0; i<argc; i++) {
2164  arglist[i] = argv[i];
2165  }
2167  return arglist;
2168  }
2169 
2170 
2171  /// Returns a thread-safe error string corresponding to err_num.
2172  static inline RStr Errno(int err_num) {
2173  const size_t bufsize = 1024;
2174  char buf[bufsize]; buf[0] = '\0';
2175 #ifdef WIN32
2176  UnusedVar(strerror_s(buf, bufsize, err_num));
2177 #else
2178  UnusedVar(strerror_r(err_num, buf, bufsize));
2179 #endif
2180  return RStr(buf);
2181  }
2182  /// Returns a thread-safe error string corresponding to errno.
2183  static inline RStr Errno() { return Errno(errno); }
2184 
2185  /// @} Standard formats.
2186 
2187 
2188  /// \name Stream interfacing
2189  /// @{
2190 
2191  /// Set the string equal to the next line from istream in, up to
2192  /// character delim.
2193  /** Usage example: RStr line; while(line.GetLine()) {
2194  * cout << line << endl; }
2195  * Note: Due to buffering, it can be more efficient to use:
2196  * FileRead fr(stdin); while(fr.Get(line)) { ... } But GetLine is
2197  * the better choice to avoid reading ahead, or for interactive input.
2198  * @return True if input was received.
2199  */
2200  inline bool GetLine(std::istream& in = std::cin, char delim='\n') {
2201  if (in.eof() || (!in.good())) { return false; }
2202  std::getline(in, str, delim);
2203 
2204  // Transparently handle windows style newlines.
2205  size_t lastch = str.size()-1;
2206  if (delim=='\n' && str.size()>0 && str[lastch]=='\r') {
2207  str.erase(lastch);
2208  }
2209 
2210  return !in.fail() && (in.good() || in.eof());
2211  }
2212 
2213  friend std::istream& operator>> (std::istream &in, RStr &rstr);
2214  friend std::ostream& operator<< (std::ostream &out, const RStr &rstr);
2215  /// @}
2216 
2217  /// \name Constants
2218  /// @{
2220  /// The largest possible value of size_t.
2221  static const size_t npos = -1;
2222  /// Provides all the standard whitespace characters.
2223  static inline const RStr Whitespace() { return " \t\r\n"; }
2224  /// Provides the OS-specific newline string.
2225  static inline const RStr NewLine() {
2226 #ifdef WIN32
2227  return "\r\n";
2228 #else
2229  return "\n";
2230 #endif
2231  }
2232 
2233  /// @}
2234 
2235 
2236  protected:
2237  /// @cond PROTECTED
2238 
2239  std::string str;
2240  /// @endcond
2241  };
2242 
2243 
2244  /// Concatenates two RStr'ings.
2245  inline RStr operator+ (const RStr &lhs, const RStr &rhs) {
2246  RStr retval = lhs;
2247  retval += rhs;
2248  return retval;
2249  }
2250 
2251 
2252  /// Input text from a std::istream (e.g., std::cin) into an RStr.
2253  inline std::istream& operator>> (std::istream &in, RStr &rstr) {
2254  return (in >> rstr.str);
2255  }
2256 
2257  /// Output text from an RStr to a std::ostream (e.g., std::cout).
2258  inline std::ostream& operator<< (std::ostream &out, const RStr &rstr) {
2259  return (out << rstr.str);
2260  }
2261 
2262 
2263  /// Swaps two RStr'ings.
2264  inline void swap(RStr& lhs, RStr& rhs) {
2265  lhs.swap(rhs);
2266  }
2267 
2268 
2269  /// Sets str equal to one line from the input stream, up to end of file or
2270  /// the delim, which is discarded.
2271  inline std::istream& getline(std::istream& is, RStr& str, char delim='\n') {
2272  return getline(is, str.Raw(), delim);
2273  }
2274 
2275 
2276  /// True if lhs equals rhs.
2277  inline bool operator== (const RStr& lhs, const RStr& rhs) {
2278  return (lhs.compare(rhs) == 0);
2279  }
2280 
2281  /// True if lhs does not equal rhs.
2282  inline bool operator!= (const RStr& lhs, const RStr& rhs) {
2283  return (lhs.compare(rhs) != 0);
2284  }
2285 
2286  /// True if lhs is less than rhs.
2287  inline bool operator< (const RStr& lhs, const RStr& rhs) {
2288  return (lhs.compare(rhs) < 0);
2289  }
2290 
2291  /// True if lhs is greater than rhs.
2292  inline bool operator> (const RStr& lhs, const RStr& rhs) {
2293  return (lhs.compare(rhs) > 0);
2294  }
2295 
2296  /// True if lhs is less than or equal to rhs.
2297  inline bool operator<= (const RStr& lhs, const RStr& rhs) {
2298  return (lhs.compare(rhs) <= 0);
2299  }
2300 
2301  /// True if lhs is greater than or equal to rhs.
2302  inline bool operator>= (const RStr& lhs, const RStr& rhs) {
2303  return (lhs.compare(rhs) >= 0);
2304  }
2306 #ifdef RC_RSTR_REGEX
2307  /// A regular expression component to match a floating point number.
2308  const RStr REG_FLT("[-+]?[0-9]*\\.?[0-9]+[eE][-+]?[0-9]+|[-+]?[0-9]*\\.?[0-9]+");
2309  /// A regular expression component to match and return a floating point
2310  /// number.
2311  const RStr REG_FLTP("([-+]?[0-9]*\\.?[0-9]+[eE][-+]?[0-9]+|[-+]?[0-9]*\\.?[0-9]+)");
2312 #endif
2314  /// Provides number-based singular/plural string management.
2315  /** Example usage: PluralStr cat("cat", "cats"); cout << cat.Count(5)
2316  * << " plus one " << cat.For(1) << " is 6 " << cat.For(6); Produces:
2317  * "5 cats plus one cat is 6 cats"
2318  */
2319  class PluralStr {
2320  public:
2321  /// Initialize with the singular and plural version of a string.
2322  inline PluralStr(const RStr& singular, const RStr& plural)
2323  : singular(singular), plural(plural) { }
2324  /// Provides the singular form if arg is 1, or the plural version
2325  /// otherwise.
2326  template<class T>
2327  inline RStr For(T arg) const {
2328  return (arg==1) ? singular : plural;
2329  }
2330  /// For any number arg, provides the number, followed by a space,
2331  /// followed by the correct singular or plural form.
2332  template<class T>
2333  inline RStr Count(T arg) const {
2334  return RStr(arg) + " " + For(arg);
2335  }
2336  protected:
2337  /// @cond PROTECTED
2338  RStr singular, plural;
2339  /// @endcond
2340  };
2341 }
2342 
2343 /// @cond PROTECTED
2344 #ifdef CPP11
2345 #include <functional>
2346 namespace std {
2347  template<> struct hash<RC::RStr> {
2348  std::size_t operator()(const RC::RStr& s) const {
2349  return h(s.Raw());
2350  }
2351  private:
2352  std::hash<std::string> h;
2353  };
2354 }
2355 #endif
2356 /// @endcond
2357 
2358 #endif // RC_RSTR_H
2359 
Provides a one-dimensional vector-like structure.
Provides a bounds-safe two-dimensional resizeable structure.
Provides a bounds-safe three-dimensional resizeable structure.
Provides informative exception handling.
#define Throw_RC_Type(Type, err)
Use this to throw an RC:ErrorMsg subtype exception.
Definition: Errors.h:282
#define Throw_RC_Error(err)
Use this to throw an RC:ErrorMsg exception.
Definition: Errors.h:274
Provides a bounds-checked iterator that knows when its target was deleted.
Provides a set of convenience macros for metaprogramming and debugging.
#define RC_GetTc(T)
Generates wrappers for const Get_T functions.
Definition: Macros.h:234
Provides short convenience classes and functions.
The version information and configuration settings for RC Lib.
#define RC_RSTR_Int_Input(TYPE)
Internal.
Definition: RStr.h:1002
#define RC_RSTR_Float_Input(TYPE)
Internal.
Definition: RStr.h:1021
Provides typedefs and routines for working with primitives.
uint64_t u64
64-bit unsigned integer.
Definition: Types.h:31
int32_t i32
32-bit signed integer.
Definition: Types.h:28
float f32
32-bit float.
Definition: Types.h:33
int64_t i64
64-bit signed integer.
Definition: Types.h:30
uint8_t u8
8-bit unsigned integer.
Definition: Types.h:25
double f64
64-bit float.
Definition: Types.h:34
long double f80
80-bit float. (Note: Usually takes 16 bytes.)
Definition: Types.h:39
uint16_t u16
16-bit unsigned integer.
Definition: Types.h:27
int16_t i16
16-bit signed integer.
Definition: Types.h:26
int8_t i8
8-bit signed integer.
Definition: Types.h:24
uint32_t u32
32-bit unsigned integer.
Definition: Types.h:29
A bounds-safe one-dimensional vector-like structure.
Definition: Data1D.h:49
void Append(const T &newT)
Add an element to the end, expanding if necessary.
Definition: Data1D.h:811
size_t TypeSize() const
Returns the size of this Data1D's type.
Definition: Data1D.h:361
T * Raw() const
Access a raw unprotected C-pointer to the enclosed data.
Definition: Data1D.h:356
void Reserve(const size_t reserve_size)
Reserve storage without resizing the array.
Definition: Data1D.h:271
size_t size() const
Returns the current number of elements.
Definition: Data1D.h:359
void Resize(const size_t resize_size)
Resize the array, reallocating if necessary.
Definition: Data1D.h:302
A bounds-safe two-dimensional resizeable structure.
Definition: Data2D.h:32
size_t size1() const
Get the size of dimension 1.
Definition: Data2D.h:214
size_t size2() const
Get the size of dimension 2.
Definition: Data2D.h:216
A bounds-safe three-dimensional resizeable structure.
Definition: Data3D.h:31
size_t size3() const
Get the size of dimension 3.
Definition: Data3D.h:201
Stores the value of type Hold while providing access via type Provide.
Definition: RCBits.h:264
Provides number-based singular/plural string management.
Definition: RStr.h:2313
RStr For(T arg) const
Provides the singular form if arg is 1, or the plural version otherwise.
Definition: RStr.h:2321
PluralStr(const RStr &singular, const RStr &plural)
Initialize with the singular and plural version of a string.
Definition: RStr.h:2316
RStr Count(T arg) const
For any number arg, provides the number, followed by a space, followed by the correct singular or plu...
Definition: RStr.h:2327
A bounds-checked iterator for random-access containers that knows when its target was deleted.
Definition: Iter.h:27
size_t GetIndex() const
Return the index of the container which this iterator corresponds to.
Definition: Iter.h:62
A bounds-safe string class which provides an identical interface to std::string plus many convenience...
Definition: RStr.h:110
const char * data() const
Identical to c_str.
Definition: RStr.h:627
friend std::ostream & operator<<(std::ostream &out, const RStr &rstr)
Output text from an RStr to a std::ostream (e.g., std::cout).
Definition: RStr.h:2252
bool Is_hex32(bool strict=false) const
True if the start of the string can be converted as hexadecimal to a u32.
Definition: RStr.h:1254
RStr & operator+=(const RStr &s)
Appends s to this RStr.
Definition: RStr.h:309
bool Is_f32(bool strict=false) const
True if the start of the string can be converted to an f32.
Definition: RStr.h:1145
bool Is_hex64(bool strict=false) const
True if the start of the string can be converted as hexadecimal to a u64.
Definition: RStr.h:1260
static RStr ToHexStr(const Data1D< T > &rawdata)
Converts rawdata to a hex string, like { 0xa4, 0xc2, 0x08 } -> "a4c208".
Definition: RStr.h:2126
RStr & assign(const RStr &s)
Copies s to this RStr.
Definition: RStr.h:387
i32 Get_i32(int base=0) const
Convert the beginning characters of this string to this integer type.
Definition: RStr.h:1104
i64 Get_i64(int base=0) const
Convert the beginning characters of this string to this integer type.
Definition: RStr.h:1107
RStr(const char *s)
Creates a new RStr from s until null-termination, or empty string if s is NULL.
Definition: RStr.h:176
bool Is_i64(int base=0, bool strict=false) const
True if the start of the string can be converted to an i64.
Definition: RStr.h:1239
std::wstring wstring()
Convert the RStr to a std::wstring.
Definition: RStr.h:1289
void Subst(const RC_REGEX_NS::regex &reg, const RStr &subst)
Substitutes regular expression reg with subst in this string.
Definition: RStr.h:1547
RStr & insert(size_t pos_this, const RStr &s, size_t pos_s, size_t n)
Inserts at index pos_this, n characters from s starting at pos_s.
Definition: RStr.h:449
size_t find_last_not_of(const char *s, size_t pos=npos) const
Returns the highest index at pos or before which does not match a character in s, or npos if all matc...
Definition: RStr.h:812
RStr & assign(const char *s, size_t n)
Sets this RStr to n characters starting at s or until null-termination.
Definition: RStr.h:400
const char * ToLPCSTR() const
For Win32, provides an LPCSTR to the string.
Definition: RStr.h:1297
static RStr ToBase64(const Data1D< u8 > &input, size_t wrap=0)
Encodes input to standard base64 in compliance with RFC 4648.
Definition: RStr.h:2066
RStr & replace(RStrIter first, RStrIter last, const RStr &s)
Replace from first to one before last with all of s.
Definition: RStr.h:549
static Data1D< RStr > Args(int argc=0, char *argv[]=NULL)
Converts standard arguments to "int main" into a Data1D<RStr>.
Definition: RStr.h:2143
size_t capacity() const
Returns the allocated storage space.
Definition: RStr.h:273
static RStr Errno()
Returns a thread-safe error string corresponding to errno.
Definition: RStr.h:2177
bool Is_f64(bool strict=false) const
True if the start of the string can be converted to an f64.
Definition: RStr.h:1158
RStr & Chomp(const RStr &chomp_chars="\r\n")
Remove all trailing newline characters, or provided char set.
Definition: RStr.h:1575
size_t rfind(const char *s, size_t pos=npos) const
Returns the index at pos or before which matches s until null-termination, or npos if no match.
Definition: RStr.h:698
size_t find_first_of(char c, size_t pos=0) const
Returns the index at pos or later which matches character c.
Definition: RStr.h:732
RStr & Truncate(const size_t max_size)
Make sure the string is no longer than max_size.
Definition: RStr.h:1610
RStr & PadLeft(const size_t pad_to, const char pad_with=' ')
If the length is less than pad_to, add pad_width to the left until it reaches that size.
Definition: RStr.h:1385
RStr & ToLower()
Make this RStr lowercase.
Definition: RStr.h:1620
u32 Get_hex32() const
Convert the beginning characters of this string as a hexadecimal to this integer type.
Definition: RStr.h:1112
RStr & assign(const RStr &s, size_t pos, size_t n)
Sets this RStr to n characters in s at index pos, or until the end.
Definition: RStr.h:393
size_t size() const
Returns the length of the string.
Definition: RStr.h:263
bool Contains(const RStr &s, size_t pos=0) const
Returns true if pos or later which matches string s.
Definition: RStr.h:1563
RStr & replace(RStrIter first, RStrIter last, InputIterator in_first, InputIterator in_last)
Replace from first through one before lsat with in1 through one before in2, or until null-termination...
Definition: RStr.h:608
static RStr ToBase64URL(const Data1D< u8 > &input, size_t wrap=0)
Encodes input to base64url in compliance with RFC 4648, safe for url and filename use.
Definition: RStr.h:2072
RStr & replace(size_t pos_this, size_t n_this, const char *s, size_t n_s)
Replace n_this characters at pos_this with n_s characters from s, or until s's null-termination.
Definition: RStr.h:564
size_t find_first_of(const char *s, size_t pos=0) const
Returns the first index at pos or later which matches a character in s, or npos if none match.
Definition: RStr.h:726
RStrIter erase(const RStrIter pos)
Erases one character at index pos.
Definition: RStr.h:523
RStr & assign(const char *s)
Sets this RStr to the characters at s until null-termination.
Definition: RStr.h:412
bool empty() const
True of the string is empty.
Definition: RStr.h:281
const char * c_str() const
Provides a null-terminated C style string corresponding to RStr.
Definition: RStr.h:622
RStr & replace(RStrIter first, RStrIter last, const char *s)
Replace from first to one before last with all of s, or nothing if s is NULL.
Definition: RStr.h:588
RStr(const std::string &str)
Initializes to str.
Definition: RStr.h:152
void resize(size_t n)
Resizes the string, filling with null characters if enlarging.
Definition: RStr.h:271
RStr(const char *s, size_t n)
Creates a new RStr from n characters at s, or until null-termination.
Definition: RStr.h:166
u64 Get_hex64() const
Convert the beginning characters of this string as a hexadecimal to this integer type.
Definition: RStr.h:1115
static const RStr NewLine()
Provides the OS-specific newline string.
Definition: RStr.h:2219
HoldRelated< std::wstring, const wchar_t * > ToLPCWSTR()
For Win32, provides an LPCWSTR to the string.
Definition: RStr.h:1304
size_t find_last_not_of(const RStr &s, size_t pos=npos) const
Returns the highest index at pos or before which does not match a character in s, or npos if all matc...
Definition: RStr.h:797
size_t After(const RStr &s, size_t pos=0) const
Returns the index after the first instance of string s at pos or later, or npos if no match.
Definition: RStr.h:1569
void insert(RStrIter p, size_t n, char c)
Inserts n copies of char c at iterator position p.
Definition: RStr.h:493
RStr & Trim(const RStr &trim_chars=" \t\r\n")
Remove all leading and trailing whitespace, or provided char set.
Definition: RStr.h:1592
void push_back(char c)
Appends character c.
Definition: RStr.h:384
bool Match(const RC_REGEX_NS::regex &reg, Data1D< RStr > &matches)
True if the regular expression reg matches this string, and returns the matches in matches.
Definition: RStr.h:1519
void Assert(size_t pos) const
Throws ErrorMsgBounds if the index pos is out of bounds.
Definition: RStr.h:1355
void reserve(size_t capsize=0)
Request a storage capacity increase to capsize.
Definition: RStr.h:277
Data1D< RStr > SplitLast(const RStr &dividers) const
Return an array of 2 strings split at the last character from dividers.
Definition: RStr.h:1684
size_t find_first_of(const RStr &s, size_t pos=0) const
Returns the first index at pos or later which matches a character in s, or npos if none match.
Definition: RStr.h:711
static RStr MakeCSV(const Data1D< T > &arr, const RStr &divider=", ")
Makes a comma-separated values string out of a Data1D<T> arr.
Definition: RStr.h:1858
u32 Get_u32(int base=0) const
Convert the beginning characters of this string to this integer type.
Definition: RStr.h:1098
std::string & Raw()
Provides raw access to the std::string this RStr wraps.
Definition: RStr.h:1325
void resize(size_t n, char c)
Resizes the string, filling with character c if enlarging.
Definition: RStr.h:269
RStrIter insert(RStrIter p, char c)
Inserts char c at iterator position p.
Definition: RStr.h:487
Data1D< char > ToData() const
Returns a Data1D<char> corresponding to the character data in the string.
Definition: RStr.h:1332
RStr(char x)
The default constructor for a char, treating it as a character.
Definition: RStr.h:990
static const RStr Whitespace()
Provides all the standard whitespace characters.
Definition: RStr.h:2217
RStr & insert(size_t pos_this, const char *s, size_t n)
Inserts at index pos_this, n characters from s or until NULL-termination.
Definition: RStr.h:460
Data1D< u32 > UTF8toUTF32() const
Treat the contents as a UTF-8 string, and return corresponding UTF-32 data.
Definition: RStr.h:1966
RStr(const RStr &s, size_t pos, size_t n=npos)
Creates a new RStr from a segment of s starting at index pos with length n or until the end.
Definition: RStr.h:159
bool Is_u32(int base=0, bool strict=false) const
True if the start of the string can be converted to an u32.
Definition: RStr.h:1188
int compare(const char *s) const
Returns negative, 0, or positive if this string is lesser, equal, or greater than s.
Definition: RStr.h:840
char & operator[](size_t pos)
Returns the char at index pos, or throws ErrorMsgBounds if out of bounds.
Definition: RStr.h:285
size_t find_first_not_of(const char *s, size_t pos, size_t n) const
Returns the first index at pos or later which does not match the first n characters in s,...
Definition: RStr.h:774
Data1D< RStr > Split(char c) const
Return an array of strings split at each instance of c.
Definition: RStr.h:1640
size_t rfind(char c, size_t pos=npos) const
Returns the index at pos or before which matches character c.
Definition: RStr.h:704
RStr & replace(size_t pos_this, size_t n_this, const RStr &s)
Replace n_this characters at pos_this with all of s.
Definition: RStr.h:542
f64 Get_f64() const
Convert the beginning characters of this string to a float.
Definition: RStr.h:1087
Data1D< RStr > SplitFirst(const RStr &dividers) const
Return an array of 2 strings split at the first character from dividers.
Definition: RStr.h:1664
size_t find(char c, size_t pos=0) const
Returns the index at pos or later which matches character c.
Definition: RStr.h:675
int compare(size_t pos_this, size_t n_this, const char *s, size_t n_s) const
Returns negative, 0, or positive if the n_this characters at pos_this are lesser, equal,...
Definition: RStr.h:871
bool Is_i32(int base=0, bool strict=false) const
True if the start of the string can be converted to an i32.
Definition: RStr.h:1224
RStr(size_t n, char c)
Initializes to n copies of character c.
Definition: RStr.h:183
size_t Distance(const RStr &other) const
Compute the Levenshtein distance to other.
Definition: RStr.h:1774
size_t Length8() const
Determine the length of the contents treated as a UTF-8 string.
Definition: RStr.h:1808
RStr & append(const char *s, size_t n)
Appends n characters starting at s to this RStr, or fewer if null-termination is reached in s.
Definition: RStr.h:344
friend std::istream & operator>>(std::istream &in, RStr &rstr)
Input text from a std::istream (e.g., std::cin) into an RStr.
Definition: RStr.h:2247
size_t find_first_not_of(const RStr &s, size_t pos=0) const
Returns the first index at pos or later which does not match a character in s, or npos if all match.
Definition: RStr.h:768
std::allocator< char > get_allocator() const
Get the allocator used for string storage.
Definition: RStr.h:633
RStr & append(const RStr &s, size_t pos, size_t n)
Appends n characters in s starting at pos to this RStr, or fewer characters if s is too short.
Definition: RStr.h:336
bool CheckPlus(size_t pos) const
True if the index pos is in bounds, permitting the null.
Definition: RStr.h:1350
RStr & append(const RStr &s)
Appends s to this RStr.
Definition: RStr.h:329
Data1D< RStr > SplitWords() const
Return an array of one or more whitespace separated words.
Definition: RStr.h:1730
RStr & erase(size_t pos=0, size_t n=npos)
Erases n characters at index pos, or until the end.
Definition: RStr.h:516
RStr & insert(size_t pos_this, size_t n, char c)
Inserts n copies of char c at pos_this.
Definition: RStr.h:480
f80 Get_f80() const
Convert the beginning characters of this string to a float.
Definition: RStr.h:1090
int compare(size_t pos_this, size_t n_this, const char *s) const
Returns negative, 0, or positive if the n_this characters at pos_this are lesser, equal,...
Definition: RStr.h:854
RStr & replace(size_t pos_this, size_t n_this, size_t n_c, char c)
Replace n_this characters at pos_this with n_c copies of c.
Definition: RStr.h:593
RStr & insert(const RStrIter p, std::initializer_list< char > characters)
At iterator position p, inserts list of characters.
Definition: RStr.h:508
Data1D< RStr > SplitCSV(char divider=',') const
Return comma-separated values with whitespace trimmed.
Definition: RStr.h:1839
size_t find_last_of(char c, size_t pos=npos) const
Returns the highest index at pos or before which matches character c, or npos if none match.
Definition: RStr.h:761
RStrIter erase(const RStrIter first, const RStrIter last)
Erases from index first through one before index last.
Definition: RStr.h:529
char & at(size_t pos)
Identical to operator[].
Definition: RStr.h:297
QString ToQString() const
Convert the RStr to a QString.
Definition: RStr.h:1283
Data1D< RStr > Wrap(const size_t width)
Wraps each line in this RStr to be no longer than width.
Definition: RStr.h:1420
const char * ToLPCTSTR()
For Win32, provides an LPCTSTR to the string.
Definition: RStr.h:1317
void swap(RStr &s)
Swap contents with s.
Definition: RStr.h:617
bool Is_f80(bool strict=false) const
True if the start of the string can be converted to an f80.
Definition: RStr.h:1172
RStr & replace(size_t pos_this, size_t n_this, const RStr &s, size_t pos_s, size_t n_s)
Replace n_this characters at pos_this with n_s characters from s starting at pos_s.
Definition: RStr.h:555
RStr & replace(size_t pos_this, size_t n_this, const char *s)
Replace n_this characters at pos_this with all of s, or nothing if s is NULL.
Definition: RStr.h:580
f32 Get_f32() const
Convert the beginning characters of this string to a float.
Definition: RStr.h:1085
size_t copy(char *s, size_t n, size_t pos=0) const
Copies n characters to s, starting from pos_this.
Definition: RStr.h:644
size_t find(const char *s, size_t pos=0) const
Returns the index at pos or later which matches s until null-termination, or npos if no match.
Definition: RStr.h:669
size_t find_last_of(const char *s, size_t pos=npos) const
Returns the highest index at pos or before which matches a character in s, or npos if none match.
Definition: RStr.h:754
bool Is_bool() const
True if the string is a "0", "1", or case insensitive "true", "false", "T", or "F".
Definition: RStr.h:1266
RStr & assign(size_t n, char c)
Sets this RStr to n copies of character c.
Definition: RStr.h:421
size_t rfind(const RStr &s, size_t pos=npos) const
Returns the index at pos or before which starts a match of string s, or npos if no match.
Definition: RStr.h:682
bool Is_u64(int base=0, bool strict=false) const
True if the start of the can be converted to an u64.
Definition: RStr.h:1206
RStr(const RStr &other)
Copy constructor.
Definition: RStr.h:147
static Data1D< u8 > FromHexStr(const RStr &hexstr)
Converts hexstr to a byte array, like "a4c208" -> { 0xa4, 0xc2, 0x08 }.
Definition: RStr.h:2109
RStr & insert(size_t pos_this, const RStr &s)
Inserts s starting at index pos_this of this RStr, or throws ErrorMsgBounds.
Definition: RStr.h:438
int compare(const RStr &s) const
Returns negative, 0, or positive if this string is lesser, equal, or greater than s.
Definition: RStr.h:834
Data1D< RStr > SplitAny(const RStr &dividers) const
Return an array of strings split by any characters in dividers.
Definition: RStr.h:1706
RStrIter end()
Returns a bounds-safe iterator which points past the last element.
Definition: RStr.h:257
RStr & insert(size_t pos_this, const char *s)
Inserts s at index pos_this until null-termination, or nothing if s is NULL.
Definition: RStr.h:471
RStr(InputIterator begin, InputIterator end)
Initializes the string from the values in the iterator range.
Definition: RStr.h:189
RStr & PadCenter(const size_t pad_to, const char pad_with=' ')
If the length is less than pad_to, add pad_width evenly to the right and left until it reaches that s...
Definition: RStr.h:1408
Data1D< RStr > WordWrap(const size_t width)
Wraps each line in this RStr to be no longer than width, but tries to keep whole words together.
Definition: RStr.h:1452
int compare(size_t pos_this, size_t n_this, const RStr &s) const
Returns negative, 0, or positive if the n_this characters at pos_this are lesser, equal,...
Definition: RStr.h:847
RStr ISOtoUTF8() const
Treat this string as ISO-8859-1 and return a UTF8 string.
Definition: RStr.h:1928
RStr & replace(RStrIter first, RStrIter last, const char *s, size_t n_s)
Replace from first through one before last with n_s characters from s, or until s's null-termination.
Definition: RStr.h:573
bool Check(size_t pos) const
True if the index pos is in bounds.
Definition: RStr.h:1345
RStr & append(InputIterator first, InputIterator last)
Appends from first to one before last, or until a null character.
Definition: RStr.h:369
RStr & replace(RStrIter first, RStrIter last, size_t n_c, char c)
Replace from first through one before last with n_c copies of c.
Definition: RStr.h:601
size_t find_last_of(const char *s, size_t pos, size_t n) const
Returns the highest index at pos or before which matches the first n characters in s,...
Definition: RStr.h:745
RStr & operator=(const RStr &s)
Copies the contents of s to this RStr.
Definition: RStr.h:206
RStr & assign(InputIterator first, InputIterator last)
Sets the RStr to characters from first to one before last, or until a null character.
Definition: RStr.h:429
size_t length() const
Returns the length of the string.
Definition: RStr.h:265
size_t find(const char *s, size_t pos, size_t n) const
Returns the index at pos or later which matches n characters of s, or npos if no match.
Definition: RStr.h:659
size_t find_first_of(const char *s, size_t pos, size_t n) const
Returns the first index at pos or later which matches one of the first n characters in s,...
Definition: RStr.h:717
RStr & append(std::initializer_list< char > characters)
Append the initializer list of characters.
Definition: RStr.h:377
bool Get_bool() const
Returns true if case-insensitive "true", "T", or non-zero.
Definition: RStr.h:1118
bool GetLine(std::istream &in=std::cin, char delim='\n')
Set the string equal to the next line from istream in, up to character delim.
Definition: RStr.h:2194
void clear()
Make the string empty.
Definition: RStr.h:279
size_t rfind(const char *s, size_t pos, size_t n) const
Returns the index at pos or before which matches n characters of s, or npos if no match.
Definition: RStr.h:688
RStr & append(size_t n, char c)
Appends n copies of char c.
Definition: RStr.h:362
size_t max_size() const
Returns the maximum size of the string.
Definition: RStr.h:267
size_t find_last_not_of(const char *s, size_t pos, size_t n) const
Returns the highest index at pos or before which does not match the first n characters in s,...
Definition: RStr.h:803
static Data1D< u8 > FromBase64(const RStr &input)
Decodes input from base64 in compliance with RFC 4648, standard or URL encoding.
Definition: RStr.h:2078
RStr & append(const char *s)
Append s to this RStr if s is non-NULL.
Definition: RStr.h:354
RStr substr(size_t pos=0, size_t n=npos) const
Creates a substring from n characters starting at position pos, or until the end of the string.
Definition: RStr.h:826
u64 Get_u64(int base=0) const
Convert the beginning characters of this string to this integer type.
Definition: RStr.h:1101
RStr(char x, RStr_IntStyle style, i32 precision=-1)
Formats x as a string in the given style, and with at least precision 0-padded digits.
Definition: RStr.h:997
size_t find_last_of(const RStr &s, size_t pos=npos) const
Returns the highest index at pos or before which matches a character in s, or npos if none match.
Definition: RStr.h:739
int compare(size_t pos_this, size_t n_this, const RStr &s, size_t pos_s, size_t n_s) const
Returns negative, 0, or positive if the n_this characters at pos_this are lesser, equal,...
Definition: RStr.h:862
RStr(const std::initializer_list< char > characters)
Initializes the string with the list of characters.
Definition: RStr.h:195
size_t find_last_not_of(char c, size_t pos=npos) const
Returns the highest index at pos or before which does not match character c, or npos if all match.
Definition: RStr.h:819
RStrIter begin()
Returns a bounds-safe iterator to the first element.
Definition: RStr.h:248
RStr & ToUpper()
Make this RStr uppercase.
Definition: RStr.h:1630
bool Match(const RC_REGEX_NS::regex &reg)
True if the regular expression reg matches this string.
Definition: RStr.h:1507
RStr(RStr &&other) noexcept
Moves other to this RStr.
Definition: RStr.h:200
static const size_t npos
The largest possible value of size_t.
Definition: RStr.h:2215
size_t find(const RStr &s, size_t pos=0) const
Returns the index at pos or later which matches string s, or npos if no match.
Definition: RStr.h:653
RStr()
Default constructor, initializes to blank string.
Definition: RStr.h:143
void insert(RStrIter p, InputIterator first, InputIterator last)
At iterator position p, inserts characters from first through one before last or until null-terminati...
Definition: RStr.h:500
void AssertPlus(size_t pos) const
Throws ErrorMsgBounds if the index pos is out of bounds, permitting the null.
Definition: RStr.h:1363
static RStr Join(const Data1D< T > &str_arr, const RStr &spacer="", RStr(*func)(const T &)=nullptr)
Takes a Data1D<T> array and joins them as one string with spacer between each element while applying ...
Definition: RStr.h:1742
const char & at(size_t pos) const
Const version of at.
Definition: RStr.h:303
size_t find_first_not_of(char c, size_t pos=0) const
Returns the first index at pos or later which does not match character c, or npos if all match.
Definition: RStr.h:790
size_t find_first_not_of(const char *s, size_t pos=0) const
Returns the first index at pos or later which does not match a character in s, or npos if all match.
Definition: RStr.h:783
RStr & PadRight(const size_t pad_to, const char pad_with=' ')
If the length is less than pad_to, add pad_width to the right until it reaches that size.
Definition: RStr.h:1398
Definition: APtr.h:25
const RStr REG_FLTP("([-+]?[0-9]*\\.?[0-9]+[eE][-+]?[0-9]+|[-+]?[0-9]*\\.?[0-9]+)")
A regular expression component to match and return a floating point number.
RStr_IntStyle
The styles in which an integral number can be formatted.
Definition: RStr.h:64
bool operator!=(const RStr &lhs, const RStr &rhs)
True if lhs does not equal rhs.
Definition: RStr.h:2276
bool operator>(const RStr &lhs, const RStr &rhs)
True if lhs is greater than rhs.
Definition: RStr.h:2286
std::istream & getline(std::istream &is, RStr &str, char delim='\n')
Sets str equal to one line from the input stream, up to end of file or the delim, which is discarded.
Definition: RStr.h:2265
void UnusedVar(const T &)
Mark an unused variable to suppress warnings.
Definition: Macros.h:170
std::ostream & operator<<(std::ostream &out, APtr< T > obj)
A convenience stream output for displaying the enclosed object.
Definition: APtr.h:120
std::istream & operator>>(std::istream &in, RStr &rstr)
Input text from a std::istream (e.g., std::cin) into an RStr.
Definition: RStr.h:2247
bool operator>=(const RStr &lhs, const RStr &rhs)
True if lhs is greater than or equal to rhs.
Definition: RStr.h:2296
bool operator<=(const RStr &lhs, const RStr &rhs)
True if lhs is less than or equal to rhs.
Definition: RStr.h:2291
bool operator<(const RStr &lhs, const RStr &rhs)
True if lhs is less than rhs.
Definition: RStr.h:2281
void swap(RC::Data1D< T > &a, RC::Data1D< T > &b)
Efficiently swap all the contents of a and b.
Definition: Data1D.h:1184
RAIter< Cont, T > operator+(size_t x, const RAIter< Cont, T > &iter)
Returns a new iterator with an offset incremented by x.
Definition: Iter.h:144
bool operator==(const RStr &lhs, const RStr &rhs)
True if lhs equals rhs.
Definition: RStr.h:2271
RStr_FloatStyle
The styles in which a floating point number can be formatted.
Definition: RStr.h:74
RAIter< RStr, char > RStrIter
The random-access iterator for RStr begin() and end()
Definition: RStr.h:77
const RStr REG_FLT("[-+]?[0-9]*\\.?[0-9]+[eE][-+]?[0-9]+|[-+]?[0-9]*\\.?[0-9]+")
A regular expression component to match a floating point number.
email address
— (c) 2015