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 typedef const __FlashStringHelper* flash_string_t;
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  typedef void (String::*StringIfHelperType)() const;
142  void StringIfHelper() const {}
143 
144  public:
145  // Use these for const references, e.g. in function return values
146  static const String nullstr;
147  static const String empty;
148 
153  String() : ptr{nullptr, 0, 0}
154  {
155  }
156 
165  String(const char *cstr);
166  String(const char *cstr, size_t length) : String()
167  {
168  if (cstr) copy(cstr, length);
169  }
170  String(const String &str) : String()
171  {
172  *this = str;
173  }
174  explicit String(flash_string_t pstr, int length = -1) : String()
175  {
176  setString(pstr, length);
177  }
178 
179 #ifdef __GXX_EXPERIMENTAL_CXX0X__
180  String(String && rval) : String()
181  {
182  move(rval);
183  }
184  String(StringSumHelper && rval);
185 #endif
186  explicit String(char c);
187  explicit String(unsigned char, unsigned char base = 10);
188  explicit String(int, unsigned char base = 10);
189  explicit String(unsigned int, unsigned char base = 10);
190  explicit String(long, unsigned char base = 10);
191  explicit String(long long, unsigned char base = 10);
192  explicit String(unsigned long, unsigned char base = 10);
193  explicit String(unsigned long long, unsigned char base = 10);
194  explicit String(float, unsigned char decimalPlaces=2);
195  explicit String(double, unsigned char decimalPlaces=2);
198  ~String(void)
199  {
200  invalidate();
201  }
202 
203  void setString(const char *cstr, int length = -1);
204  void setString(flash_string_t pstr, int length = -1);
205 
206  // memory management
207 
216  bool reserve(size_t size);
217 
223  bool setLength(size_t length);
224 
228  inline size_t length(void) const
229  {
230  return sso.set ? sso.len : ptr.len;
231  }
232 
241  String & operator = (const String &rhs);
242  String & operator = (const char *cstr);
263 #ifdef __GXX_EXPERIMENTAL_CXX0X__
265  {
266  if (this != &rval) move(rval);
267  return *this;
268  }
270 #endif
271 
283  bool concat(const String &str)
284  {
285  return concat(str.cbuffer(), str.length());
286  }
287  bool concat(const FlashString& fstr);
288  bool concat(const char *cstr);
289  bool concat(const char *cstr, size_t length);
290  bool concat(char c)
291  {
292  return concat(&c, 1);
293  }
294  bool concat(unsigned char num);
295  bool concat(int num);
296  bool concat(unsigned int num);
297  bool concat(long num);
298  bool concat(long long num);
299  bool concat(unsigned long num);
300  bool concat(unsigned long long num);
301  bool concat(float num);
302  bool concat(double num);
313  String & operator += (const String &rhs)
314  {
315  concat(rhs);
316  return (*this);
317  }
319  {
320  concat(rhs);
321  return (*this);
322  }
323  String & operator += (const char *cstr)
324  {
325  concat(cstr);
326  return (*this);
327  }
329  {
330  concat(c);
331  return (*this);
332  }
333  String & operator += (unsigned char num)
334  {
335  concat(num);
336  return (*this);
337  }
338  String & operator += (int num)
339  {
340  concat(num);
341  return (*this);
342  }
343  String & operator += (unsigned int num)
344  {
345  concat(num);
346  return (*this);
347  }
348  String & operator += (long num)
349  {
350  concat(num);
351  return (*this);
352  }
353  String & operator += (long long num)
354  {
355  concat(num);
356  return (*this);
357  }
358  String & operator += (unsigned long num)
359  {
360  concat(num);
361  return (*this);
362  }
363  String & operator += (unsigned long long num)
364  {
365  concat(num);
366  return (*this);
367  }
368  String & operator += (float num)
369  {
370  concat(num);
371  return (*this);
372  }
373  String & operator += (double num)
374  {
375  concat(num);
376  return (*this);
377  }
380  friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs);
381  friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr);
382  friend StringSumHelper & operator + (const StringSumHelper &lhs, char c);
383  friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num);
384  friend StringSumHelper & operator + (const StringSumHelper &lhs, int num);
385  friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num);
386  friend StringSumHelper & operator + (const StringSumHelper &lhs, long num);
387  friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num);
388  friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long long num);
389  friend StringSumHelper & operator + (const StringSumHelper &lhs, float num);
390  friend StringSumHelper & operator + (const StringSumHelper &lhs, double num);
391 
397  operator StringIfHelperType() const
398  {
399  return isNull() ? 0 : &String::StringIfHelper;
400  }
401 
412  int compareTo(const char* cstr, size_t length) const;
413  int compareTo(const String &s) const
414  {
415  return compareTo(s.cbuffer(), s.length());
416  }
428  bool equals(const String &s) const
429  {
430  return equals(s.cbuffer(), s.length());
431  }
432  bool equals(const char *cstr) const;
433  bool equals(const char *cstr, size_t length) const;
434  bool equals(const FlashString& fstr) const
435  {
436  return fstr.equals(*this);
437  }
445  bool operator == (const String &rhs) const
446  {
447  return equals(rhs);
448  }
449  bool operator == (const char *cstr) const
450  {
451  return equals(cstr);
452  }
453  bool operator==(const FlashString& fstr) const
454  {
455  return equals(fstr);
456  }
464  bool operator != (const String &rhs) const
465  {
466  return !equals(rhs);
467  }
468  bool operator != (const char *cstr) const
469  {
470  return !equals(cstr);
471  }
478  bool operator < (const String &rhs) const
479  {
480  return compareTo(rhs) < 0;
481  }
482  bool operator > (const String &rhs) const
483  {
484  return compareTo(rhs) > 0;
485  }
486  bool operator <= (const String &rhs) const
487  {
488  return compareTo(rhs) <= 0;
489  }
490  bool operator >= (const String &rhs) const
491  {
492  return compareTo(rhs) >= 0;
493  }
504  bool equalsIgnoreCase(const char* cstr) const;
505  bool equalsIgnoreCase(const char* cstr, size_t length) const;
506  bool equalsIgnoreCase(const String &s2) const
507  {
508  return equalsIgnoreCase(s2.cbuffer(), s2.length());
509  }
510  bool equalsIgnoreCase(const FlashString& fstr) const
511  {
512  return fstr.equalsIgnoreCase(*this);
513  }
522  bool startsWith(const String &prefix) const
523  {
524  return startsWith(prefix, 0);
525  }
526 
536  bool startsWith(const String &prefix, size_t offset) const;
537 
543  bool endsWith(const String &suffix) const;
544 
545  // character acccess
546 
553  char charAt(size_t index) const
554  {
555  return operator[](index);
556  }
557 
564  void setCharAt(size_t index, char c);
565 
573  char operator [](size_t index) const;
574  char& operator [](size_t index);
585  size_t getBytes(unsigned char *buf, size_t bufsize, size_t index = 0) const;
586 
591  void toCharArray(char *buf, size_t bufsize, size_t index = 0) const
592  {
593  getBytes((unsigned char *)buf, bufsize, index);
594  }
595 
600  const char* c_str() const { return cbuffer() ?: empty.cbuffer(); }
601 
606  char* begin() { return buffer(); }
607 
613  char* end() { return buffer() + length(); }
614  const char* begin() const { return c_str(); }
615  const char* end() const { return c_str() + length(); }
616 
617  // search
618 
629  int indexOf(char ch, size_t fromIndex = 0) const;
630  int indexOf(const char* s2_buf, size_t fromIndex, size_t s2_len) const;
631  int indexOf(const char* s2_buf, size_t fromIndex = 0) const
632  {
633  return indexOf(s2_buf, fromIndex, strlen(s2_buf));
634  }
635  int indexOf(const String &s2, size_t fromIndex = 0) const
636  {
637  return indexOf(s2.cbuffer(), fromIndex, s2.length());
638  }
651  int lastIndexOf(char ch) const;
652  int lastIndexOf(char ch, size_t fromIndex) const;
653  int lastIndexOf(const String &s2) const;
654  int lastIndexOf(const String &s2, size_t fromIndex) const;
655  int lastIndexOf(const char* s2_buf, size_t fromIndex, size_t s2_len) const;
680  String substring(size_t from, size_t to) const;
681  String substring(size_t from) const
682  {
683  return substring(from, length());
684  }
687  // modification
688 
701  void replace(char find, char replace);
702  bool replace(const String& find, const String& replace);
703  bool replace(const char* find_buf, size_t find_len, const char* replace_buf, size_t replace_len);
718  void remove(size_t index)
719  {
720  remove(index, SIZE_MAX);
721  }
722  void remove(size_t index, size_t count);
728  void toLowerCase(void);
729 
733  void toUpperCase(void);
734 
738  void trim(void);
739 
740  // parsing/conversion
741  long toInt(void) const;
742  float toFloat(void) const;
743 
745  static constexpr size_t SSO_CAPACITY = STRING_OBJECT_SIZE - 2;
746 
747 protected:
749  struct PtrBuf {
750  char* buffer; // the actual char array
751  size_t len; // the String length (not counting the '\0')
752  size_t capacity; // the array length minus one (for the '\0')
753  };
754  // For small strings we can store data directly without requiring the heap
755  struct SsoBuf {
756  char buffer[SSO_CAPACITY + 1];
757  unsigned char len : 7;
758  unsigned char set : 1;
759  };
760  union {
763  };
764 
765  static_assert(STRING_OBJECT_SIZE == sizeof(SsoBuf), "SSO Buffer alignment problem");
766  static_assert(STRING_OBJECT_SIZE >= sizeof(PtrBuf), "STRING_OBJECT_SIZE too small");
767  static_assert(STRING_OBJECT_SIZE <= 128, "STRING_OBJECT_SIZE too large (max. 128)");
768  static_assert(STRING_OBJECT_SIZE % 4 == 0, "STRING_OBJECT_SIZE must be a multiple of 4");
769 
770 protected:
771  // Free any heap memory and set to non-SSO mode; isNull() will return true
772  void invalidate(void);
773 
774  // String is Null (invalid) by default, i.e. non-SSO and null buffer
775  __forceinline bool isNull() const
776  {
777  return !sso.set && (ptr.buffer == nullptr);
778  }
779 
780  // Get writeable buffer pointer
782  {
783  return sso.set ? sso.buffer : ptr.buffer;
784  }
785 
786  // Get read-only buffer pointer
787  __forceinline const char* cbuffer() const
788  {
789  return sso.set ? sso.buffer : ptr.buffer;
790  }
791 
792  // Get currently assigned capacity for current mode
793  __forceinline size_t capacity() const
794  {
795  return sso.set ? SSO_CAPACITY : ptr.capacity;
796  }
797 
798  // Called whenever string length changes to ensure NUL terminator is set
799  __forceinline void setlen(size_t len)
800  {
801  if(sso.set) {
802  sso.len = len;
803  sso.buffer[len] = '\0';
804  } else {
805  ptr.len = len;
806  ptr.buffer[len] = '\0';
807  }
808  }
809 
810  // copy and move
811  String & copy(const char *cstr, size_t length);
812  String& copy(flash_string_t pstr, size_t length);
813 #ifdef __GXX_EXPERIMENTAL_CXX0X__
814  void move(String &rhs);
815 #endif
816 };
817 
820 class StringSumHelper : public String
821 {
822  public:
823  StringSumHelper(const String &s) : String(s) {}
824  StringSumHelper(const char *p) : String(p) {}
825  StringSumHelper(char c) : String(c) {}
826  StringSumHelper(unsigned char num) : String(num) {}
827  StringSumHelper(int num) : String(num) {}
828  StringSumHelper(unsigned int num) : String(num) {}
829  StringSumHelper(long num) : String(num) {}
830  StringSumHelper(long long num) : String(num) {}
831  StringSumHelper(unsigned long num) : String(num) {}
832  StringSumHelper(unsigned long long num) : String(num) {}
833  StringSumHelper(float num) : String(num) {}
834  StringSumHelper(double num) : String(num) {}
835 };
836 
837 #include "SplitString.h"
838 
839 #endif // __cplusplus
bool equalsIgnoreCase(const FlashString &fstr) const
Definition: WString.h:510
int lastIndexOf(char ch) const
bool operator==(const String &rhs) const
Definition: WString.h:445
bool operator<=(const String &rhs) const
Definition: WString.h:486
bool operator>=(const String &rhs) const
Definition: WString.h:490
bool concat(char c)
Definition: WString.h:290
bool startsWith(const String &prefix) const
Compare the start of a String Comparison is case-sensitive, must match exactly.
Definition: WString.h:522
#define __forceinline
Definition: sming_attr.h:13
StringSumHelper(unsigned long long num)
Definition: WString.h:832
StringSumHelper(int num)
Definition: WString.h:827
static const String empty
An empty string evaluates to true.
Definition: WString.h:147
const char * c_str() const
Get a constant (un-modifiable) pointer to String content.
Definition: WString.h:600
size_t getBytes(unsigned char *buf, size_t bufsize, size_t index=0) const
Read contents of a String into a buffer.
static constexpr size_t SSO_CAPACITY
Max chars. (excluding NUL terminator) we can store in SSO mode.
Definition: WString.h:745
#define str(s)
Definition: testrunner.h:124
String substring(size_t from) const
Definition: WString.h:681
String & operator+=(const String &rhs)
Definition: WString.h:313
void toUpperCase(void)
Convert the entire String content to upper case.
StringSumHelper(long num)
Definition: WString.h:829
const __FlashStringHelper * flash_string_t
Provides a strongly-typed pointer to allow safe implicit operation using String class methods...
Definition: WString.h:91
void setlen(size_t len)
Definition: WString.h:799
StringSumHelper(long long num)
Definition: WString.h:830
StringSumHelper(const char *p)
Definition: WString.h:824
size_t capacity() const
Definition: WString.h:793
StringSumHelper(unsigned long num)
Definition: WString.h:831
const char * begin() const
Definition: WString.h:614
const char * cbuffer() const
Definition: WString.h:787
Used when contents allocated on heap.
Definition: WString.h:749
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:631
char * begin()
Get a modifiable pointer to String content.
Definition: WString.h:606
StringSumHelper(char c)
Definition: WString.h:825
bool endsWith(const String &suffix) const
Compare the end of a String.
String(const String &str)
Definition: WString.h:170
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:482
char charAt(size_t index) const
Obtain the character at the given index.
Definition: WString.h:553
StringSumHelper(float num)
Definition: WString.h:833
bool operator!=(const String &rhs) const
Definition: WString.h:464
static const String nullstr
A null string evaluates to false.
Definition: WString.h:146
void invalidate(void)
int compareTo(const String &s) const
Definition: WString.h:413
friend StringSumHelper & operator+(const StringSumHelper &lhs, const String &rhs)
char * buffer()
Definition: WString.h:781
size_t length(void) const
Obtain the String length in characters, excluding NUL terminator.
Definition: WString.h:228
bool setLength(size_t length)
set the string length accordingly, expanding if necessary
StringSumHelper(const String &s)
Definition: WString.h:823
void setString(const char *cstr, int length=-1)
bool operator<(const String &rhs) const
Definition: WString.h:478
String()
Default constructor.
Definition: WString.h:153
unsigned char set
true for SSO mode
Definition: WString.h:758
bool equalsIgnoreCase(const String &s2) const
Definition: WString.h:506
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:591
void setCharAt(size_t index, char c)
Sets the character at a given index.
char * buffer
Definition: WString.h:750
String(const char *cstr, size_t length)
Definition: WString.h:166
PtrBuf ptr
Definition: WString.h:761
Definition: WString.h:820
void toLowerCase(void)
Convert the entire String content to lower case.
unsigned char len
Definition: WString.h:757
bool equals(const FlashString &fstr) const
Definition: WString.h:434
char operator[](size_t index) const
void trim(void)
Remove all leading and trailing whitespace characters from the String.
bool reserve(size_t size)
Pre-allocate String memory.
bool operator==(const FlashString &fstr) const
Definition: WString.h:453
char buffer[SSO_CAPACITY+1]
Definition: WString.h:756
bool equals(const String &s) const
Definition: WString.h:428
StringSumHelper(unsigned char num)
Definition: WString.h:826
bool equalsIgnoreCase(const char *cstr) const
int indexOf(const String &s2, size_t fromIndex=0) const
Definition: WString.h:635
SsoBuf sso
Definition: WString.h:762
StringSumHelper(unsigned int num)
Definition: WString.h:828
bool isNull() const
Definition: WString.h:775
String(String &&rval)
Definition: WString.h:180
size_t len
Definition: WString.h:751
size_t capacity
Definition: WString.h:752
const char * end() const
Definition: WString.h:615
char * end()
Get a modifiable pointer to one-past the end of the String.
Definition: WString.h:613
String & copy(const char *cstr, size_t length)
void replace(char find, char replace)
Definition: WString.h:755
StringSumHelper(double num)
Definition: WString.h:834
String(flash_string_t pstr, int length=-1)
Definition: WString.h:174
long toInt(void) const
bool concat(const String &str)
Definition: WString.h:283
~String(void)
Definition: WString.h:198
int compareTo(const char *cstr, size_t length) const