libUTL++
String.h
1 #pragma once
2 
4 
5 #include <libutl/FlagsMI.h>
6 
8 
9 UTL_NS_BEGIN;
10 
12 
29 
31 class String : public Object, public FlagsMI
32 {
34 
35 public:
43  String(const char* s, bool owner = true, bool duplicate = true, bool caseSensitive = true);
44 
49  String(size_t size);
50 
55  String(char c)
56  {
57  _s = new char[8];
58  _s[0] = c;
59  _s[1] = '\0';
60  _size = 8;
61  _length = size_t_max;
62  }
63 
64  virtual int compare(const Object& rhs) const;
65 
66  virtual void copy(const Object& rhs);
67 
68  virtual void steal(Object& rhs);
69 
70  virtual size_t hash(size_t size) const;
71 
72  virtual void serialize(Stream& stream, uint_t io, uint_t mode = ser_default);
73 
74  virtual size_t innerAllocatedSize() const;
75 
76  virtual String toString() const;
77 
79 
80 
81  bool
82  isOwner() const
83  {
84  return (_size != 0);
85  }
86 
88  void
89  setOwner(bool owner)
90  {
91  if (owner)
92  {
93  if (_size == 0) _size = length() + 1;
94  }
95  else
96  {
97  _size = 0;
98  }
99  }
100 
102  bool
104  {
105  return !getFlag(flg_caseInsensitive);
106  }
107 
109  void
110  setCaseSensitive(bool caseSensitive)
111  {
112  setFlag(flg_caseInsensitive, !caseSensitive);
113  }
114 
116  bool
117  isMarked() const
118  {
119  return getFlag(flg_marked);
120  }
121 
123  void
124  setMarked(bool marked = true)
125  {
126  setFlag(flg_marked, marked);
127  }
129 
131 
132 
133  int compareSubstring(size_t begin, const String& rhs, size_t n);
134 
136  int
137  compareSubstring(size_t begin, const char* rhs, size_t len)
138  {
139  return compareSubstring(begin, String(rhs, false), len);
140  }
141 
143  int comparePrefix(const String& rhs) const;
144 
146  int
147  comparePrefix(const char* rhs) const
148  {
149  return comparePrefix(String(rhs, false));
150  }
151 
153  int compareSuffix(const String& rhs) const;
154 
156  int
157  compareSuffix(const char* rhs) const
158  {
159  return compareSuffix(String(rhs, false));
160  }
161 
163  inline int
164  strcmp(const char* lhs, const char* rhs) const
165  {
166  if (isCaseSensitive())
167  {
168  int d = (int)*lhs - (int)*rhs;
169  if (d != 0) return d;
170  return ::strcmp(lhs + 1, rhs + 1);
171  }
172  else
173  {
174  int d = tolower(*lhs) - tolower(*rhs);
175  if (d != 0) return d;
176  return ::strcasecmp(lhs + 1, rhs + 1);
177  }
178  }
179 
181  inline std::function<int(const char*, const char*)>
182  strcmp() const
183  {
184  return isCaseSensitive() ? ::strcmp : ::strcasecmp;
185  }
186 
188  inline int
189  strncmp(const char* lhs, const char* rhs, size_t n) const
190  {
191  return isCaseSensitive() ? ::strncmp(lhs, rhs, n) : ::strncasecmp(lhs, rhs, n);
192  }
193 
195  inline std::function<int(const char*, const char*, size_t)>
196  strncmp() const
197  {
198  return isCaseSensitive() ? ::strncmp : ::strncasecmp;
199  }
201 
203 
204 
205  String
206  backslashEscaped(const char* specials) const
207  {
208  return backslashEscaped(String(specials, false));
209  }
210 
212  String backslashEscaped(const String& specials) const;
213 
215  String backslashUnescaped() const;
216 
218  bool
219  empty() const
220  {
221  return (length() == 0);
222  }
223 
230  size_t find(const String& str, size_t begin = 0) const;
231 
238  size_t
239  find(const char* str, size_t begin = 0) const
240  {
241  return find(String(str, false), begin);
242  }
243 
250  size_t find(char c, size_t begin = 0) const;
251 
257  size_t findBM(const String& str, size_t begin = 0) const;
258 
264  size_t
265  findBM(const char* str, size_t begin = 0) const
266  {
267  return findBM(String(str, false), begin);
268  }
269 
271  char
272  firstChar() const
273  {
274  return *_s;
275  }
276 
278  char
279  lastChar() const
280  {
281  size_t len = length();
282  if (len == 0) return '\0';
283  return _s[len - 1];
284  }
285 
287  const char*
288  get() const
289  {
290  return _s;
291  }
292 
294  size_t
295  length() const
296  {
297  if (_length == size_t_max) _length = strlen(_s);
298  ASSERTD(_length == strlen(_s));
299  return _length;
300  }
301 
303  void
305  {
306  _length = size_t_max;
307  }
308 
313  String
314  prefix(size_t n) const
315  {
316  return subString(0, n);
317  }
318 
320  size_t
321  size() const
322  {
323  return _size;
324  }
325 
332  String subString(size_t begin, size_t len = size_t_max) const;
333 
338  String
339  suffix(size_t n) const
340  {
341  size_t len = length();
342  if (n >= len) return self;
343  return subString(len - n, n);
344  }
345 
347  String reversed() const;
348 
355  String nextToken(size_t& idx, char delim = ' ', bool processQuotes = false) const;
357 
359 
360 
361  String&
363  {
364  if (isOwner())
365  *_s = '\0';
366  else
367  _s = &nullChar;
368  _length = 0;
369  return self;
370  }
371 
375  String& excise();
376 
378  char*
379  get()
380  {
381  return _s;
382  }
383 
385  char
386  get(size_t i) const
387  {
388  ASSERTD(i <= length());
389  return _s[i];
390  }
391 
393  inline String&
395  {
396  if (_size == 0) _assertOwner();
397  return *this;
398  }
399 
405  inline void
406  assertOwner(size_t size, size_t increment = 8)
407  {
408  if (_size < size) _assertOwner(size, increment);
409  }
410 
412  void economize();
413 
419  void
420  reserve(size_t size, size_t increment = 8)
421  {
422  if (_size < size) _assertOwner(size, increment);
423  }
424 
426  String& append(char c);
427 
429  String&
430  append(const String& s)
431  {
432  return append(s._s, s.length());
433  }
434 
436  String&
437  append(const char* s)
438  {
439  ASSERTD(s != nullptr);
440  return append(s, strlen(s));
441  }
442 
448  String& append(const char* s, size_t len);
449 
456  String chop(size_t begin, size_t len = size_t_max);
457 
463  void remove(size_t begin, size_t len = size_t_max);
464 
466  String& replace(const String& lhs, const String& rhs);
467 
469  String&
470  replace(const char* lhs, const char* rhs)
471  {
472  return replace(String(lhs, false), String(rhs, false));
473  }
474 
476  String&
477  replace(const char* lhs, const String& rhs)
478  {
479  return replace(String(lhs, false), rhs);
480  }
481 
483  String&
484  replace(const String& lhs, const char* rhs)
485  {
486  return replace(lhs, String(rhs, false));
487  }
488 
496  String& replace(size_t begin, size_t len, const String& str);
497 
499  String& reverse();
500 
508  void set(const char* s, bool owner = true, bool duplicate = true, size_t length = size_t_max);
509 
516  String& toLower(size_t begin = 0, size_t len = size_t_max);
517 
524  String& toUpper(size_t begin = 0, size_t len = size_t_max);
525 
532  String& padBegin(size_t len, char c = ' ');
533 
540  String& padEnd(size_t len, char c = ' ');
541 
543  String& trim();
544 
546  String& trimBegin();
547 
549  String& trimEnd();
551 
553 
554 
560  static String repeat(char c, size_t num);
561 
563  static String spaces(size_t num);
565 
567 
568 
569  inline String operator+(char c) const
570  {
571  String res(this->length() + 2);
572  res.append(self);
573  res.append(c);
574  return res;
575  }
576 
578  inline String operator+(const char* str) const
579  {
580  ASSERTD(str != nullptr);
581  return self + String(str, false);
582  }
583 
585  inline String operator+(const String& rhs) const
586  {
587  String res(this->length() + rhs.length() + 1);
588  res = self;
589  res += rhs;
590  return res;
591  }
592 
594  inline String& operator+=(char c)
595  {
596  return append(c);
597  }
598 
600  inline String& operator+=(const char* rhs)
601  {
602  return append(String(rhs, false));
603  }
604 
606  inline String& operator+=(const String& rhs)
607  {
608  return append(rhs);
609  }
610 
612  inline String& operator=(const char* str)
613  {
614  set(str);
615  return self;
616  }
617 
619  inline String& operator=(char c)
620  {
621  clear();
622  append(c);
623  return self;
624  }
625 
627  inline char& operator[](size_t i)
628  {
629  ASSERTD(i <= length());
630  return _s[i];
631  }
632 
634  inline const char& operator[](size_t i) const
635  {
636  ASSERTD(i <= length());
637  return _s[i];
638  }
639 
641  inline operator char*()
642  {
643  return _s;
644  }
645 
647  inline operator const char*()
648  {
649  return _s;
650  }
651 
653  inline operator const char*() const
654  {
655  return _s;
656  }
657 
659  inline operator void*()
660  {
661  return _s;
662  }
663 
665  inline operator const void*()
666  {
667  return _s;
668  }
669 
671  inline operator const void*() const
672  {
673  return _s;
674  }
675 
676  inline bool operator<(const Object& rhs) const
677  {
678  return (compare(rhs) < 0);
679  }
680  inline bool operator<=(const Object& rhs) const
681  {
682  return (compare(rhs) <= 0);
683  }
684  inline bool operator>(const Object& rhs) const
685  {
686  return (compare(rhs) > 0);
687  }
688  inline bool operator>=(const Object& rhs) const
689  {
690  return (compare(rhs) >= 0);
691  }
692  inline bool operator==(const Object& rhs) const
693  {
694  return (compare(rhs) == 0);
695  }
696  inline bool operator!=(const Object& rhs) const
697  {
698  return (compare(rhs) != 0);
699  }
700 
701  inline bool operator<(const String& rhs) const
702  {
703  return (compare(rhs) < 0);
704  }
705  inline bool operator<=(const String& rhs) const
706  {
707  return (compare(rhs) <= 0);
708  }
709  inline bool operator>(const String& rhs) const
710  {
711  return (compare(rhs) > 0);
712  }
713  inline bool operator>=(const String& rhs) const
714  {
715  return (compare(rhs) >= 0);
716  }
717  inline bool operator==(const String& rhs) const
718  {
719  return (compare(rhs) == 0);
720  }
721  inline bool operator!=(const String& rhs) const
722  {
723  return (compare(rhs) != 0);
724  }
726 protected:
727  static void
728  setBounds(size_t& begin, size_t& end, size_t& len, size_t myLen)
729  {
730  if (begin > myLen) begin = myLen;
731  if (len > myLen) len = myLen;
732  end = begin + len;
733  if (end > myLen) end = myLen;
734  len = end - begin;
735  }
736 
737 protected:
738  char* _s;
739  size_t _size;
740  mutable size_t _length;
741 
742 private:
743  enum flg_t
744  {
745  flg_marked,
746  flg_caseInsensitive
747  };
748 
749 private:
750  void
751  init(bool caseSensitive = true)
752  {
753  _s = &nullChar;
754  _size = 0;
755  _length = 0;
756  if (!caseSensitive) setCaseSensitive(false);
757  }
758 
759  void
760  deInit()
761  {
762 // check length in DEBUG mode, and allow an easy breakpoint
763 #ifdef DEBUG
764  bool lengthOK = ((_length == size_t_max) || (_length == strlen(_s)));
765  ASSERT(lengthOK);
766  ASSERT(nullChar == '\0');
767 #endif
768 
769  // if we own the string, delete it
770  if (isOwner()) delete[] _s;
771  }
772 
773  void _assertOwner();
774  void _assertOwner(size_t size, size_t increment);
775 
776 private:
777  static char nullChar;
778 };
779 
781 
786 extern const String emptyString;
787 
789 
790 UTL_NS_END;
791 
793 
794 inline bool operator==(const utl::String& lhs_, const char* rhs)
795 {
796  ASSERTD(rhs != nullptr);
797  const char* lhs = lhs_.get();
798  return (lhs_.strcmp(lhs, rhs) == 0);
799 }
800 
802 
803 inline bool operator!=(const utl::String& lhs_, const char* rhs)
804 {
805  ASSERTD(rhs != nullptr);
806  const char* lhs = lhs_.get();
807  return (lhs_.strcmp(lhs, rhs) != 0);
808 }
809 
811 
812 inline bool operator==(const char* lhs, const utl::String& rhs_)
813 {
814  ASSERTD(lhs != nullptr);
815  const char* rhs = rhs_.get();
816  return (rhs_.strcmp(lhs, rhs) == 0);
817 }
818 
820 
821 inline bool operator!=(const char* lhs, const utl::String& rhs_)
822 {
823  ASSERTD(lhs != nullptr);
824  const char* rhs = rhs_.get();
825  return (rhs_.strcmp(lhs, rhs) != 0);
826 }
827 
829 
830 inline bool operator==(const utl::String& lhs_, const char rhs)
831 {
832  ASSERTD(rhs != '\0');
833  const char* lhs = lhs_.get();
834  if (lhs_.isCaseSensitive()) return (*lhs == rhs) && (lhs[1] == '\0');
835  return (tolower(*lhs) == tolower(rhs)) && (lhs[1] == '\0');
836 }
837 
839 
840 inline bool operator!=(const utl::String& lhs_, const char rhs)
841 {
842  ASSERTD(rhs != '\0');
843  const char* lhs = lhs_.get();
844  if (lhs_.isCaseSensitive()) return (*lhs != rhs) || (lhs[1] != '\0');
845  return (tolower(*lhs) != tolower(rhs)) || (lhs[1] != '\0');
846 }
847 
849 
850 inline bool operator==(char lhs, const utl::String& rhs_)
851 {
852  ASSERTD(lhs != '\0');
853  const char* rhs = rhs_.get();
854  if (rhs_.isCaseSensitive()) return (lhs == *rhs) && (rhs[1] == '\0');
855  return (tolower(lhs) == tolower(*rhs)) && (rhs[1] == '\0');
856 }
857 
859 
860 inline bool operator!=(char lhs, const utl::String& rhs_)
861 {
862  ASSERTD(lhs != '\0');
863  const char* rhs = rhs_.get();
864  if (rhs_.isCaseSensitive()) return (lhs != *rhs) || (rhs[1] != '\0');
865  return (tolower(lhs) != tolower(*rhs)) || (rhs[1] != '\0');
866 }
867 
869 
870 inline utl::String operator+(const char* lhs, const utl::String& rhs)
871 {
872  return utl::String(lhs, false) + rhs;
873 }
874 
876 
877 inline utl::String operator+(char lhs, const utl::String& rhs)
878 {
879  utl::String res(rhs.length() + 2);
880  res.append(lhs);
881  res.append(rhs);
882  return res;
883 }
String & operator+=(const char *rhs)
Append the given string to self.
Definition: String.h:600
String toString(const FwdIt &begin, const FwdIt &end, const String &sep, bool key=false)
Obtain a string representation of a sequence (via Object::toString()).
int strncmp(const char *lhs, const char *rhs, size_t n) const
Compare (up to) the first n bytes of two strings (case sensitive iff isCaseSensitive()).
Definition: String.h:189
void serialize(bool &b, Stream &stream, uint_t io, uint_t mode=ser_default)
Serialize a boolean.
size_t find(const char *str, size_t begin=0) const
Find the first instance of the given string in self.
Definition: String.h:239
String operator+(char c) const
Get a copy of self with the given character appended.
Definition: String.h:569
String backslashEscaped(const char *specials) const
Backslash-escape a string.
Definition: String.h:206
String & operator=(char c)
Make self equal to the given character.
Definition: String.h:619
void deInit()
De-initialize UTL++.
void setMarked(bool marked=true)
Set the marked flag.
Definition: String.h:124
String & append(const char *s)
Append the given string.
Definition: String.h:437
char firstChar() const
Get the first character in the string (nul if empty).
Definition: String.h:272
String & replace(const String &lhs, const char *rhs)
Replace all instances of lhs with rhs.
Definition: String.h:484
std::function< int(const char *, const char *)> strcmp() const
Get the string comparison function (strcmp or strcasecmp).
Definition: String.h:182
int compareSubstring(size_t begin, const char *rhs, size_t len)
Compare the given string against a substring of self.
Definition: String.h:137
String suffix(size_t n) const
Get the last n characters of the string.
Definition: String.h:339
int comparePrefix(const char *rhs) const
Compare the given string against the beginning of self.
Definition: String.h:147
default representation (via getSerializeMode())
Definition: util.h:75
#define UTL_CLASS_DECL(DC, BC)
Declaration of standard UTL++ functionality for a non-template class.
Definition: macros.h:688
Character string.
Definition: String.h:31
String operator+(const String &rhs) const
Get a copy of self with the given string appended.
Definition: String.h:585
String(char c)
Constructor.
Definition: String.h:55
void reverse(const BidIt &begin, const BidIt &end)
Reverse a sequence.
bool isOwner() const
Get the ownership flag.
Definition: String.h:82
Mix-in to provide 64-bits for space-efficient storage of up to 64 boolean flags.
Definition: FlagsMI.h:25
const size_t size_t_max
Maximum size_t value.
#define ASSERT(x)
Declares a defect if x is false (or 0).
Definition: macros.h:50
bool isCaseSensitive() const
Get the case-sensitive flag.
Definition: String.h:103
char & operator[](size_t i)
Array access operator.
Definition: String.h:627
const String emptyString
An empty string.
String & clear()
Reset to empty string.
Definition: String.h:362
void copy(T *dest, const T *src, size_t len)
Copy one array of objects to another.
Definition: util_inl.h:690
String & operator+=(const String &rhs)
Append the given string to self.
Definition: String.h:606
String operator+(const char *str) const
Get a copy of self with the given string appended.
Definition: String.h:578
const char & operator[](size_t i) const
Array access operator.
Definition: String.h:634
size_t length() const
Get the length of the string.
Definition: String.h:295
bool isMarked() const
Get the marked flag.
Definition: String.h:117
String & replace(const char *lhs, const char *rhs)
Replace all instances of lhs with rhs.
Definition: String.h:470
size_t findBM(const char *str, size_t begin=0) const
Use Boyer-Moore algorithm to find the first instance of the given string.
Definition: String.h:265
int strcmp(const char *lhs, const char *rhs) const
Compare two strings (case sensitive comparison iff isCaseSensitive()).
Definition: String.h:164
unsigned int uint_t
Unsigned integer.
Definition: types.h:59
Stream I/O abstraction.
Definition: Stream.h:68
String & operator+=(char c)
Append the given character to self.
Definition: String.h:594
String & append(char c)
Append the given character.
String & replace(const char *lhs, const String &rhs)
Replace all instances of lhs with rhs.
Definition: String.h:477
void assertOwner(size_t size, size_t increment=8)
Make sure self has its own copy of the string.
Definition: String.h:406
bool empty() const
Is the string empty?
Definition: String.h:219
void setCaseSensitive(bool caseSensitive)
Set the case-sensitive flag.
Definition: String.h:110
char lastChar() const
Get the last character in the string (nul if empty).
Definition: String.h:279
size_t size() const
Get the size of the allocated character array.
Definition: String.h:321
std::function< int(const char *, const char *, size_t)> strncmp() const
Get the length-limited string comparison function (strncmp or strncasecmp).
Definition: String.h:196
String prefix(size_t n) const
Get the first n characters of the string.
Definition: String.h:314
String & operator=(const char *str)
Make self equal to a copy of the given character array.
Definition: String.h:612
Root of UTL++ class hierarchy.
Definition: Object.h:52
int compare(bool lhs, bool rhs)
Compare two boolean values.
String & append(const String &s)
Append the given string.
Definition: String.h:430
int compareSuffix(const char *rhs) const
Compare the given string against the end of self.
Definition: String.h:157
void lengthInvalidate() const
Invalidate the cached length of the string.
Definition: String.h:304
void init()
Initialize UTL++.
void setOwner(bool owner)
Set the ownership flag (without doing anything else).
Definition: String.h:89
const char * get() const
Get const char*.
Definition: String.h:288
#define ASSERTD
Do an assertion in DEBUG mode only.
String & assertOwner()
Make sure self has its own copy of the string.
Definition: String.h:394
void reserve(size_t size, size_t increment=8)
Grow to the specified size.
Definition: String.h:420