WString.h
Go to the documentation of this file.
1 /* $Id: WString.h 1156 2011-06-07 04:01:16Z bhagman $
2 ||
3 || @author Paul Stoffregen <paul@pjrc.com>
4 || @url http://wiring.org.co/
5 || @contribution Hernando Barragan <b@wiring.org.co>
6 || @contribution Brett Hagman <bhagman@wiring.org.co>
7 || @contribution Alexander Brevig <abrevig@wiring.org.co>
8 ||
9 || @description
10 || | String class.
11 || |
12 || | Wiring Common API
13 || #
14 ||
15 || @license Please see cores/Common/License.txt.
16 ||
17 */
18 
19 /*
20  * @author: 2 Oct 2018 - mikee47 <mike@sillyhouse.net>
21  *
22  * The standard String object default constructor creates an empty string, which requires a heap allocation of 1 byte.
23  * I changed this behaviour to default to a null string (invalid) to avoid this (usually) un-necessary allocation.
24  * If the value of the string hasn't actually been assigned yet then an 'invalid' (or null) string is the more logical choice.
25  * Additional changes ensure that the content of such a string are equivalent to an empty string "".
26  *
27  * Background
28  *
29  * The intent of the Wiring authors seems to be that an expression producing a String object will fail and produce
30  * an 'invalid' String (that evaluates to False) if any of the allocations within that expression fail. This could
31  * be due to heap fragmentation, low memory or a String which is just too big.
32  *
33  * By example:
34  *
35  * String tmp = String("A") + String("B");
36  *
37  * If a heap allocation fails on either "A" or "B" the the result should be a null string. However, this is not actually
38  * the case. In practice, if "A" fails but "B" does not then the result will be "B", while if "A" succeeds but "B" fails
39  * then the result will be 'invalid'. This would appear to be an oversight in the Wiring library (last updated July 2016).
40  *
41  * I made a decision with these changes that heap allocation errors are a rare enough occurrence that attempting to deal with
42  * them in such a manner causes more problems than it solves.
43  *
44  * These changes have a knock-on effect in that if any of the allocations in an expression fail, then the result, tmp,
45  * will be unpredictable.
46  *
47  * @author Nov 2019 mikee47 <mike@sillyhouse.net>
48  *
49  * Small String Optimisation (SSO). Based on the Arduino ESP8266 core implentation.
50  * An empty String object now consumes 12 bytes (from 8) but provides an SSO capacity of 11 characters.
51  * Capacity and length types changed to size_t, thus String is no longer restricted to 64K.
52  *
53  */
54 
55 #pragma once
56 
57 #ifdef __cplusplus
58 
59 #include "WConstants.h"
60 #include <cstddef>
61 #include <string.h>
62 #include <sming_attr.h>
63 
64 #include <FlashString/String.hpp>
65 
70 
71 #ifndef __GXX_EXPERIMENTAL_CXX0X__
72 #define __GXX_EXPERIMENTAL_CXX0X__
73 #endif
74 
75 // When compiling programs with this class, the following gcc parameters
76 // dramatically increase performance and memory (RAM) efficiency, typically
77 // with little or no increase in code size.
78 // -felide-constructors
79 // -std=c++0x
80 
81 // An inherited class for holding the result of a concatenation. These
82 // result objects are assumed to be writable by subsequent concatenations.
83 class StringSumHelper;
84 
90 // Arduino-style flash strings
91 class __FlashStringHelper; // Never actually defined
96 using flash_string_t = const __FlashStringHelper*;
97 
102 #define FPSTR(pstr_pointer) reinterpret_cast<flash_string_t>(pstr_pointer)
103 
113 #define F(string_literal) String(FPSTR(PSTR_COUNTED(string_literal)), sizeof(string_literal) - 1)
114 
136 class String
137 {
138  // use a function pointer to allow for "if (s)" without the
139  // complications of an operator bool(). for more information, see:
140  // http://www.artima.com/cppsource/safebool.html
141  using StringIfHelperType = void (String::*)() const;
142  void StringIfHelper() const
143  {
144  }
145 
146 public:
147  // Use these for const references, e.g. in function return values
148  static const String nullstr;
149  static const String empty;
150 
155  String() : ptr{nullptr, 0, 0}
156  {
157  }
158 
167  String(const char* cstr);
168  String(const char* cstr, size_t length) : String()
169  {
170  if(cstr)
171  copy(cstr, length);
172  }
173  String(const String& str) : String()
174  {
175  *this = str;
176  }
177  explicit String(flash_string_t pstr, size_t length) : String()
178  {
179  setString(pstr, length);
180  }
181  explicit String(flash_string_t pstr) : String()
182  {
183  setString(pstr);
184  }
185 
186 #ifdef __GXX_EXPERIMENTAL_CXX0X__
187  String(String&& rval) noexcept : String()
188  {
189  move(rval);
190  }
191  String(StringSumHelper&& rval) noexcept;
192 #endif
193  explicit String(char c);
194  explicit String(unsigned char, unsigned char base = 10);
195  explicit String(int, unsigned char base = 10);
196  explicit String(unsigned int, unsigned char base = 10);
197  explicit String(long, unsigned char base = 10);
198  explicit String(long long, unsigned char base = 10);
199  explicit String(unsigned long, unsigned char base = 10);
200  explicit String(unsigned long long, unsigned char base = 10);
201  explicit String(float, unsigned char decimalPlaces = 2);
202  explicit String(double, unsigned char decimalPlaces = 2);
205  ~String(void)
206  {
207  invalidate();
208  }
209 
210  void setString(const char* cstr);
211  void setString(const char* cstr, size_t length);
212  void setString(flash_string_t pstr);
213  void setString(flash_string_t pstr, size_t length);
214 
215  // memory management
216 
225  bool reserve(size_t size);
226 
232  bool setLength(size_t length);
233 
237  inline size_t length(void) const
238  {
239  return sso.set ? sso.len : ptr.len;
240  }
241 
245  struct Buffer {
246  char* data;
247  size_t size;
248  size_t length;
249  };
250 
257  bool setBuffer(const Buffer& buffer);
258 
264  Buffer getBuffer();
265 
274  String& operator=(const String& rhs);
275  String& operator=(const char* cstr);
296 #ifdef __GXX_EXPERIMENTAL_CXX0X__
297  String& operator=(String&& rval) noexcept
298  {
299  if(this != &rval)
300  move(rval);
301  return *this;
302  }
303  String& operator=(StringSumHelper&& rval) noexcept;
304 #endif
305 
317  bool concat(const String& str)
318  {
319  return concat(str.cbuffer(), str.length());
320  }
321  bool concat(const FlashString& fstr);
322  bool concat(const char* cstr);
323  bool concat(const char* cstr, size_t length);
324  bool concat(char c)
325  {
326  return concat(&c, 1);
327  }
328  bool concat(unsigned char num);
329  bool concat(int num);
330  bool concat(unsigned int num);
331  bool concat(long num);
332  bool concat(long long num);
333  bool concat(unsigned long num);
334  bool concat(unsigned long long num);
335  bool concat(float num);
336  bool concat(double num);
347  String& operator+=(const String& rhs)
348  {
349  concat(rhs);
350  return (*this);
351  }
353  {
354  concat(rhs);
355  return (*this);
356  }
357  String& operator+=(const char* cstr)
358  {
359  concat(cstr);
360  return (*this);
361  }
363  {
364  concat(c);
365  return (*this);
366  }
367  String& operator+=(unsigned char num)
368  {
369  concat(num);
370  return (*this);
371  }
372  String& operator+=(int num)
373  {
374  concat(num);
375  return (*this);
376  }
377  String& operator+=(unsigned int num)
378  {
379  concat(num);
380  return (*this);
381  }
382  String& operator+=(long num)
383  {
384  concat(num);
385  return (*this);
386  }
387  String& operator+=(long long num)
388  {
389  concat(num);
390  return (*this);
391  }
392  String& operator+=(unsigned long num)
393  {
394  concat(num);
395  return (*this);
396  }
397  String& operator+=(unsigned long long num)
398  {
399  concat(num);
400  return (*this);
401  }
402  String& operator+=(float num)
403  {
404  concat(num);
405  return (*this);
406  }
407  String& operator+=(double num)
408  {
409  concat(num);
410  return (*this);
411  }
414  friend StringSumHelper& operator+(const StringSumHelper& lhs, const String& rhs);
415  friend StringSumHelper& operator+(const StringSumHelper& lhs, const char* cstr);
416  friend StringSumHelper& operator+(const StringSumHelper& lhs, char c);
417  friend StringSumHelper& operator+(const StringSumHelper& lhs, unsigned char num);
418  friend StringSumHelper& operator+(const StringSumHelper& lhs, int num);
419  friend StringSumHelper& operator+(const StringSumHelper& lhs, unsigned int num);
420  friend StringSumHelper& operator+(const StringSumHelper& lhs, long num);
421  friend StringSumHelper& operator+(const StringSumHelper& lhs, unsigned long num);
422  friend StringSumHelper& operator+(const StringSumHelper& lhs, unsigned long long num);
423  friend StringSumHelper& operator+(const StringSumHelper& lhs, float num);
424  friend StringSumHelper& operator+(const StringSumHelper& lhs, double num);
425 
431  operator StringIfHelperType() const
432  {
433  return isNull() ? 0 : &String::StringIfHelper;
434  }
435 
446  int compareTo(const char* cstr, size_t length) const;
447  int compareTo(const String& s) const
448  {
449  return compareTo(s.cbuffer(), s.length());
450  }
462  bool equals(const String& s) const
463  {
464  return equals(s.cbuffer(), s.length());
465  }
466  bool equals(const char* cstr) const;
467  bool equals(const char* cstr, size_t length) const;
468  bool equals(const FlashString& fstr) const
469  {
470  return fstr.equals(*this);
471  }
479  bool operator==(const String& rhs) const
480  {
481  return equals(rhs);
482  }
483  bool operator==(const char* cstr) const
484  {
485  return equals(cstr);
486  }
487  bool operator==(const FlashString& fstr) const
488  {
489  return equals(fstr);
490  }
498  bool operator!=(const String& rhs) const
499  {
500  return !equals(rhs);
501  }
502  bool operator!=(const char* cstr) const
503  {
504  return !equals(cstr);
505  }
512  bool operator<(const String& rhs) const
513  {
514  return compareTo(rhs) < 0;
515  }
516  bool operator>(const String& rhs) const
517  {
518  return compareTo(rhs) > 0;
519  }
520  bool operator<=(const String& rhs) const
521  {
522  return compareTo(rhs) <= 0;
523  }
524  bool operator>=(const String& rhs) const
525  {
526  return compareTo(rhs) >= 0;
527  }
538  bool equalsIgnoreCase(const char* cstr) const;
539  bool equalsIgnoreCase(const char* cstr, size_t length) const;
540  bool equalsIgnoreCase(const String& s2) const
541  {
542  return equalsIgnoreCase(s2.cbuffer(), s2.length());
543  }
544  bool equalsIgnoreCase(const FlashString& fstr) const
545  {
546  return fstr.equalsIgnoreCase(*this);
547  }
556  bool startsWith(const String& prefix) const
557  {
558  return startsWith(prefix, 0);
559  }
560 
570  bool startsWith(const String& prefix, size_t offset) const;
571 
577  bool endsWith(char suffix) const;
578 
584  bool endsWith(const String& suffix) const;
585 
586  // character acccess
587 
594  char charAt(size_t index) const
595  {
596  return operator[](index);
597  }
598 
605  void setCharAt(size_t index, char c);
606 
614  char operator[](size_t index) const;
615  char& operator[](size_t index);
626  size_t getBytes(unsigned char* buf, size_t bufsize, size_t index = 0) const;
627 
632  void toCharArray(char* buf, size_t bufsize, size_t index = 0) const
633  {
634  getBytes((unsigned char*)buf, bufsize, index);
635  }
636 
641  const char* c_str() const
642  {
643  return cbuffer() ?: empty.cbuffer();
644  }
645 
650  char* begin()
651  {
652  return buffer();
653  }
654 
660  char* end()
661  {
662  return buffer() + length();
663  }
664  const char* begin() const
665  {
666  return c_str();
667  }
668  const char* end() const
669  {
670  return c_str() + length();
671  }
672 
673  // search
674 
685  int indexOf(char ch, size_t fromIndex = 0) const;
686  int indexOf(const char* s2_buf, size_t fromIndex, size_t s2_len) const;
687  int indexOf(const char* s2_buf, size_t fromIndex = 0) const
688  {
689  return indexOf(s2_buf, fromIndex, strlen(s2_buf));
690  }
691  int indexOf(const String& s2, size_t fromIndex = 0) const
692  {
693  return indexOf(s2.cbuffer(), fromIndex, s2.length());
694  }
707  int lastIndexOf(char ch) const;
708  int lastIndexOf(char ch, size_t fromIndex) const;
709  int lastIndexOf(const String& s2) const;
710  int lastIndexOf(const String& s2, size_t fromIndex) const;
711  int lastIndexOf(const char* s2_buf, size_t fromIndex, size_t s2_len) const;
736  String substring(size_t from, size_t to) const;
737  String substring(size_t from) const
738  {
739  return substring(from, length());
740  }
743  // modification
744 
757  void replace(char find, char replace);
758  bool replace(const String& find, const String& replace);
759  bool replace(const char* find_buf, size_t find_len, const char* replace_buf, size_t replace_len);
774  void remove(size_t index)
775  {
776  remove(index, SIZE_MAX);
777  }
778  void remove(size_t index, size_t count);
784  void toLowerCase(void);
785 
789  void toUpperCase(void);
790 
794  void trim(void);
795 
796  // parsing/conversion
797  long toInt(void) const;
798  float toFloat(void) const;
799 
801  static constexpr size_t SSO_CAPACITY = STRING_OBJECT_SIZE - 2;
802 
803 protected:
805  struct PtrBuf {
806  char* buffer; // the actual char array
807  size_t len; // the String length (not counting the '\0')
808  size_t capacity; // the array length minus one (for the '\0')
809  };
810  // For small strings we can store data directly without requiring the heap
811  struct SsoBuf {
812  char buffer[SSO_CAPACITY + 1];
813  unsigned char len : 7;
814  unsigned char set : 1;
815  };
816  union {
819  };
820 
821  static_assert(STRING_OBJECT_SIZE == sizeof(SsoBuf), "SSO Buffer alignment problem");
822  static_assert(STRING_OBJECT_SIZE >= sizeof(PtrBuf), "STRING_OBJECT_SIZE too small");
823  static_assert(STRING_OBJECT_SIZE <= 128, "STRING_OBJECT_SIZE too large (max. 128)");
824  static_assert(STRING_OBJECT_SIZE % 4 == 0, "STRING_OBJECT_SIZE must be a multiple of 4");
825 
826 protected:
827  // Free any heap memory and set to non-SSO mode; isNull() will return true
828  void invalidate(void);
829 
830  // String is Null (invalid) by default, i.e. non-SSO and null buffer
831  __forceinline bool isNull() const
832  {
833  return !sso.set && (ptr.buffer == nullptr);
834  }
835 
836  // Get writeable buffer pointer
838  {
839  return sso.set ? sso.buffer : ptr.buffer;
840  }
841 
842  // Get read-only buffer pointer
843  __forceinline const char* cbuffer() const
844  {
845  return sso.set ? sso.buffer : ptr.buffer;
846  }
847 
848  // Get currently assigned capacity for current mode
849  __forceinline size_t capacity() const
850  {
851  return sso.set ? SSO_CAPACITY : ptr.capacity;
852  }
853 
854  // Called whenever string length changes to ensure NUL terminator is set
855  __forceinline void setlen(size_t len)
856  {
857  if(sso.set) {
858  sso.len = len;
859  sso.buffer[len] = '\0';
860  } else {
861  ptr.len = len;
862  if(ptr.buffer != nullptr) {
863  ptr.buffer[len] = '\0';
864  }
865  }
866  }
867 
868  // copy and move
869  String& copy(const char* cstr, size_t length);
870  String& copy(flash_string_t pstr, size_t length);
871 #ifdef __GXX_EXPERIMENTAL_CXX0X__
872  void move(String& rhs);
873 #endif
874 };
875 
878 class StringSumHelper : public String
879 {
880 public:
882  {
883  }
884  StringSumHelper(const char* p) : String(p)
885  {
886  }
887  StringSumHelper(char c) : String(c)
888  {
889  }
890  StringSumHelper(unsigned char num) : String(num)
891  {
892  }
893  StringSumHelper(int num) : String(num)
894  {
895  }
896  StringSumHelper(unsigned int num) : String(num)
897  {
898  }
899  StringSumHelper(long num) : String(num)
900  {
901  }
902  StringSumHelper(long long num) : String(num)
903  {
904  }
905  StringSumHelper(unsigned long num) : String(num)
906  {
907  }
908  StringSumHelper(unsigned long long num) : String(num)
909  {
910  }
911  StringSumHelper(float num) : String(num)
912  {
913  }
914  StringSumHelper(double num) : String(num)
915  {
916  }
917 };
918 
919 #include "SplitString.h"
920 
921 #endif // __cplusplus
bool equalsIgnoreCase(const FlashString &fstr) const
Definition: WString.h:544
int lastIndexOf(char ch) const
bool operator==(const String &rhs) const
Definition: WString.h:479
bool operator!=(const char *cstr) const
Definition: WString.h:502
bool operator==(const char *cstr) const
Definition: WString.h:483
bool operator<=(const String &rhs) const
Definition: WString.h:520
bool operator>=(const String &rhs) const
Definition: WString.h:524
String(flash_string_t pstr, size_t length)
Definition: WString.h:177
String & operator+=(float num)
Definition: WString.h:402
bool concat(char c)
Definition: WString.h:324
bool startsWith(const String &prefix) const
Compare the start of a String Comparison is case-sensitive, must match exactly.
Definition: WString.h:556
#define __forceinline
Definition: sming_attr.h:13
StringSumHelper(unsigned long long num)
Definition: WString.h:908
String & operator=(String &&rval) noexcept
Definition: WString.h:297
StringSumHelper(int num)
Definition: WString.h:893
static const String empty
An empty string evaluates to true.
Definition: WString.h:149
String & operator+=(unsigned char num)
Definition: WString.h:367
const char * c_str() const
Get a constant (un-modifiable) pointer to String content.
Definition: WString.h:641
size_t getBytes(unsigned char *buf, size_t bufsize, size_t index=0) const
Read contents of a String into a buffer.
String & operator+=(long long num)
Definition: WString.h:387
static constexpr size_t SSO_CAPACITY
Max chars. (excluding NUL terminator) we can store in SSO mode.
Definition: WString.h:801
bool setBuffer(const Buffer &buffer)
Set String content using move semantics from external memory buffer.
#define str(s)
Definition: testrunner.h:124
String(flash_string_t pstr)
Definition: WString.h:181
String substring(size_t from) const
Definition: WString.h:737
String & operator+=(const String &rhs)
Definition: WString.h:347
void toUpperCase(void)
Convert the entire String content to upper case.
StringSumHelper(long num)
Definition: WString.h:899
void setlen(size_t len)
Definition: WString.h:855
StringSumHelper(long long num)
Definition: WString.h:902
StringSumHelper(const char *p)
Definition: WString.h:884
size_t capacity() const
Definition: WString.h:849
StringSumHelper(unsigned long num)
Definition: WString.h:905
const char * begin() const
Definition: WString.h:664
String & operator+=(const char *cstr)
Definition: WString.h:357
const char * cbuffer() const
Definition: WString.h:843
Used when contents allocated on heap.
Definition: WString.h:805
String substring(size_t from, size_t to) const
The String class.
Definition: WString.h:136
String & operator=(const String &rhs)
bool equalsIgnoreCase(const WString &str) const
int indexOf(char ch, size_t fromIndex=0) const
int indexOf(const char *s2_buf, size_t fromIndex=0) const
Definition: WString.h:687
String & operator+=(double num)
Definition: WString.h:407
char * begin()
Get a modifiable pointer to String content.
Definition: WString.h:650
StringSumHelper(char c)
Definition: WString.h:887
String(const String &str)
Definition: WString.h:173
size_t length
Length of content, MUST be < size.
Definition: WString.h:248
void move(String &rhs)
float toFloat(void) const
bool equals(const char *cstr, size_t len=0) const
Check for equality with a C-string.
bool operator>(const String &rhs) const
Definition: WString.h:516
char charAt(size_t index) const
Obtain the character at the given index.
Definition: WString.h:594
StringSumHelper(float num)
Definition: WString.h:911
bool operator!=(const String &rhs) const
Definition: WString.h:498
static const String nullstr
A null string evaluates to false.
Definition: WString.h:148
const __FlashStringHelper * flash_string_t
Provides a strongly-typed pointer to allow safe implicit operation using String class methods...
Definition: WString.h:96
bool endsWith(char suffix) const
Compare the end of a String.
void invalidate(void)
int compareTo(const String &s) const
Definition: WString.h:447
friend StringSumHelper & operator+(const StringSumHelper &lhs, const String &rhs)
String & operator+=(unsigned long long num)
Definition: WString.h:397
char * buffer()
Definition: WString.h:837
String & operator+=(unsigned long num)
Definition: WString.h:392
String(String &&rval) noexcept
Definition: WString.h:187
size_t length(void) const
Obtain the String length in characters, excluding NUL terminator.
Definition: WString.h:237
bool setLength(size_t length)
set the string length accordingly, expanding if necessary
StringSumHelper(const String &s)
Definition: WString.h:881
size_t size
Size of memory allocation.
Definition: WString.h:247
Used with setBuffer and getBuffer methods.
Definition: WString.h:245
String & operator+=(long num)
Definition: WString.h:382
bool operator<(const String &rhs) const
Definition: WString.h:512
String()
Default constructor.
Definition: WString.h:155
unsigned char set
true for SSO mode
Definition: WString.h:814
bool equalsIgnoreCase(const String &s2) const
Definition: WString.h:540
describes a counted string stored in flash memory
Definition: String.hpp:173
void toCharArray(char *buf, size_t bufsize, size_t index=0) const
Read contents of String into a buffer.
Definition: WString.h:632
void setCharAt(size_t index, char c)
Sets the character at a given index.
char * buffer
Definition: WString.h:806
String & operator+=(int num)
Definition: WString.h:372
String(const char *cstr, size_t length)
Definition: WString.h:168
PtrBuf ptr
Definition: WString.h:817
Definition: WString.h:878
String & operator+=(unsigned int num)
Definition: WString.h:377
Buffer getBuffer()
Get String content using move semantics.
void toLowerCase(void)
Convert the entire String content to lower case.
unsigned char len
Definition: WString.h:813
bool equals(const FlashString &fstr) const
Definition: WString.h:468
char operator[](size_t index) const
String & operator+=(const FlashString &rhs)
Definition: WString.h:352
void trim(void)
Remove all leading and trailing whitespace characters from the String.
bool reserve(size_t size)
Pre-allocate String memory.
char * data
Allocated using malloc.
Definition: WString.h:246
bool operator==(const FlashString &fstr) const
Definition: WString.h:487
char buffer[SSO_CAPACITY+1]
Definition: WString.h:812
bool equals(const String &s) const
Definition: WString.h:462
StringSumHelper(unsigned char num)
Definition: WString.h:890
bool equalsIgnoreCase(const char *cstr) const
int indexOf(const String &s2, size_t fromIndex=0) const
Definition: WString.h:691
SsoBuf sso
Definition: WString.h:818
StringSumHelper(unsigned int num)
Definition: WString.h:896
bool isNull() const
Definition: WString.h:831
size_t len
Definition: WString.h:807
void setString(const char *cstr)
size_t capacity
Definition: WString.h:808
const char * end() const
Definition: WString.h:668
char * end()
Get a modifiable pointer to one-past the end of the String.
Definition: WString.h:660
String & copy(const char *cstr, size_t length)
void replace(char find, char replace)
String & operator+=(char c)
Definition: WString.h:362
Definition: WString.h:811
StringSumHelper(double num)
Definition: WString.h:914
long toInt(void) const
bool concat(const String &str)
Definition: WString.h:317
~String(void)
Definition: WString.h:205
int compareTo(const char *cstr, size_t length) const