1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

WString: Optimize a bit (#7553)

* WString: Optimize a bit

* move bodies of dtor, `init()` and `charAt()` to .h (implicitly inlined)

* unify descriptions of the initialization into one: `init()` (literally), that is called from each ctors, `invalidate()` and `move()`

* invert the SSO state logic in order to make init state zeroed (as a result, each inlined `init()` saves 1 insn)

* detab and trim

* remove `inline` from .h

* cosmetics

* optimize the non-SSO -> SSO transition part of `changeBuffer()`

* remove duped body of `operator =(StringSumHelper &&rval)`

* remove common subexpressions from `lastIndexOf()` and `substring()`

* eliminate `strlen(buf)` after calling `sprintf(buf, ...)` that returns # of chars written

* eliminate `len()` after calling `setLen(newlen)`

* make ctor`(char c)` inlineable

* optimize `setLen()`

* replace constant-forwarding overload functions with default argument ones

* optimize `concat(char c)`

* * optimize `init()` more
This commit is contained in:
Takayuki 'January June' Suwa 2020-11-16 18:40:48 +09:00 committed by GitHub
parent 5ae3efb823
commit 8fe80f1630
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 212 additions and 246 deletions

View File

@ -55,14 +55,6 @@ String::String(StringSumHelper &&rval) noexcept {
move(rval); move(rval);
} }
String::String(char c) {
init();
char buf[2];
buf[0] = c;
buf[1] = 0;
*this = buf;
}
String::String(unsigned char value, unsigned char base) { String::String(unsigned char value, unsigned char base) {
init(); init();
char buf[1 + 8 * sizeof(unsigned char)]; char buf[1 + 8 * sizeof(unsigned char)];
@ -91,7 +83,7 @@ String::String(unsigned int value, unsigned char base) {
String::String(long value, unsigned char base) { String::String(long value, unsigned char base) {
init(); init();
char buf[2 + 8 * sizeof(long)]; char buf[2 + 8 * sizeof(long)];
if (base==10) { if (base == 10) {
sprintf(buf, "%ld", value); sprintf(buf, "%ld", value);
} else { } else {
ltoa(value, buf, base); ltoa(value, buf, base);
@ -118,31 +110,21 @@ String::String(double value, unsigned char decimalPlaces) {
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
} }
String::~String() {
invalidate();
}
/*********************************************/ /*********************************************/
/* Memory Management */ /* Memory Management */
/*********************************************/ /*********************************************/
inline void String::init(void) {
setSSO(true);
setLen(0);
wbuffer()[0] = 0;
}
void String::invalidate(void) { void String::invalidate(void) {
if(!isSSO() && wbuffer()) if (!isSSO() && wbuffer())
free(wbuffer()); free(wbuffer());
init(); init();
} }
unsigned char String::reserve(unsigned int size) { unsigned char String::reserve(unsigned int size) {
if(buffer() && capacity() >= size) if (buffer() && capacity() >= size)
return 1; return 1;
if(changeBuffer(size)) { if (changeBuffer(size)) {
if(len() == 0) if (len() == 0)
wbuffer()[0] = 0; wbuffer()[0] = 0;
return 1; return 1;
} }
@ -157,35 +139,32 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
uint16_t oldLen = len(); uint16_t oldLen = len();
setSSO(true); setSSO(true);
setLen(oldLen); setLen(oldLen);
return 1;
} else { // if bufptr && !isSSO() } else { // if bufptr && !isSSO()
// Using bufptr, need to shrink into sso.buff // Using bufptr, need to shrink into sso.buff
char temp[sizeof(sso.buff)]; const char *temp = buffer();
memcpy(temp, buffer(), maxStrLen);
free(wbuffer());
uint16_t oldLen = len(); uint16_t oldLen = len();
setSSO(true); setSSO(true);
setLen(oldLen); setLen(oldLen);
memcpy(wbuffer(), temp, maxStrLen); memcpy(wbuffer(), temp, maxStrLen);
return 1; free((void *)temp);
} }
return 1;
} }
// Fallthrough to normal allocator // Fallthrough to normal allocator
size_t newSize = (maxStrLen + 16) & (~0xf); size_t newSize = (maxStrLen + 16) & (~0xf);
// Make sure we can fit newsize in the buffer // Make sure we can fit newsize in the buffer
if (newSize > CAPACITY_MAX) { if (newSize > CAPACITY_MAX) {
return false; return 0;
} }
uint16_t oldLen = len(); uint16_t oldLen = len();
char *newbuffer = (char *) realloc(isSSO() ? nullptr : wbuffer(), newSize); char *newbuffer = (char *)realloc(isSSO() ? nullptr : wbuffer(), newSize);
if (newbuffer) { if (newbuffer) {
size_t oldSize = capacity() + 1; // include NULL. size_t oldSize = capacity() + 1; // include NULL.
if (isSSO()) { if (isSSO()) {
// Copy the SSO buffer into allocated space // Copy the SSO buffer into allocated space
memmove_P(newbuffer, sso.buff, sizeof(sso.buff)); memmove_P(newbuffer, sso.buff, sizeof(sso.buff));
} }
if (newSize > oldSize) if (newSize > oldSize) {
{
memset(newbuffer + oldSize, 0, newSize - oldSize); memset(newbuffer + oldSize, 0, newSize - oldSize);
} }
setSSO(false); setSSO(false);
@ -201,7 +180,7 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
/* Copy and Move */ /* Copy and Move */
/*********************************************/ /*********************************************/
String & String::copy(const char *cstr, unsigned int length) { String &String::copy(const char *cstr, unsigned int length) {
if (!reserve(length)) { if (!reserve(length)) {
invalidate(); invalidate();
return *this; return *this;
@ -211,7 +190,7 @@ String & String::copy(const char *cstr, unsigned int length) {
return *this; return *this;
} }
String & String::copy(const __FlashStringHelper *pstr, unsigned int length) { String &String::copy(const __FlashStringHelper *pstr, unsigned int length) {
if (!reserve(length)) { if (!reserve(length)) {
invalidate(); invalidate();
return *this; return *this;
@ -227,44 +206,35 @@ void String::move(String &rhs) noexcept {
rhs.init(); rhs.init();
} }
String & String::operator =(const String &rhs) { String &String::operator =(const String &rhs) {
if (this == &rhs) if (this == &rhs)
return *this; return *this;
if (rhs.buffer()) if (rhs.buffer())
copy(rhs.buffer(), rhs.len()); copy(rhs.buffer(), rhs.len());
else else
invalidate(); invalidate();
return *this; return *this;
} }
String & String::operator =(String &&rval) noexcept { String &String::operator =(String &&rval) noexcept {
if (this != &rval) if (this != &rval)
move(rval); move(rval);
return *this; return *this;
} }
String & String::operator =(StringSumHelper &&rval) noexcept { String &String::operator =(const char *cstr) {
if (this != &rval)
move(rval);
return *this;
}
String & String::operator =(const char *cstr) {
if (cstr) if (cstr)
copy(cstr, strlen(cstr)); copy(cstr, strlen(cstr));
else else
invalidate(); invalidate();
return *this; return *this;
} }
String & String::operator = (const __FlashStringHelper *pstr) String &String::operator =(const __FlashStringHelper *pstr) {
{ if (pstr)
if (pstr) copy(pstr, strlen_P((PGM_P)pstr)); copy(pstr, strlen_P((PGM_P)pstr));
else invalidate(); else
invalidate();
return *this; return *this;
} }
@ -285,7 +255,7 @@ unsigned char String::concat(const String &s) {
return 0; return 0;
memmove_P(wbuffer() + len(), buffer(), len()); memmove_P(wbuffer() + len(), buffer(), len());
setLen(newlen); setLen(newlen);
wbuffer()[len()] = 0; wbuffer()[newlen] = 0;
return 1; return 1;
} else { } else {
return concat(s.buffer(), s.len()); return concat(s.buffer(), s.len());
@ -313,22 +283,17 @@ unsigned char String::concat(const char *cstr) {
} }
unsigned char String::concat(char c) { unsigned char String::concat(char c) {
char buf[2]; return concat(&c, 1);
buf[0] = c;
buf[1] = 0;
return concat(buf, 1);
} }
unsigned char String::concat(unsigned char num) { unsigned char String::concat(unsigned char num) {
char buf[1 + 3 * sizeof(unsigned char)]; char buf[1 + 3 * sizeof(unsigned char)];
sprintf(buf, "%d", num); return concat(buf, sprintf(buf, "%d", num));
return concat(buf, strlen(buf));
} }
unsigned char String::concat(int num) { unsigned char String::concat(int num) {
char buf[2 + 3 * sizeof(int)]; char buf[2 + 3 * sizeof(int)];
sprintf(buf, "%d", num); return concat(buf, sprintf(buf, "%d", num));
return concat(buf, strlen(buf));
} }
unsigned char String::concat(unsigned int num) { unsigned char String::concat(unsigned int num) {
@ -339,8 +304,7 @@ unsigned char String::concat(unsigned int num) {
unsigned char String::concat(long num) { unsigned char String::concat(long num) {
char buf[2 + 3 * sizeof(long)]; char buf[2 + 3 * sizeof(long)];
sprintf(buf, "%ld", num); return concat(buf, sprintf(buf, "%ld", num));
return concat(buf, strlen(buf));
} }
unsigned char String::concat(unsigned long num) { unsigned char String::concat(unsigned long num) {
@ -351,22 +315,25 @@ unsigned char String::concat(unsigned long num) {
unsigned char String::concat(float num) { unsigned char String::concat(float num) {
char buf[20]; char buf[20];
char* string = dtostrf(num, 4, 2, buf); char *string = dtostrf(num, 4, 2, buf);
return concat(string, strlen(string)); return concat(string, strlen(string));
} }
unsigned char String::concat(double num) { unsigned char String::concat(double num) {
char buf[20]; char buf[20];
char* string = dtostrf(num, 4, 2, buf); char *string = dtostrf(num, 4, 2, buf);
return concat(string, strlen(string)); return concat(string, strlen(string));
} }
unsigned char String::concat(const __FlashStringHelper * str) { unsigned char String::concat(const __FlashStringHelper *str) {
if (!str) return 0; if (!str)
return 0;
int length = strlen_P((PGM_P)str); int length = strlen_P((PGM_P)str);
if (length == 0) return 1; if (length == 0)
return 1;
unsigned int newlen = len() + length; unsigned int newlen = len() + length;
if (!reserve(newlen)) return 0; if (!reserve(newlen))
return 0;
memcpy_P(wbuffer() + len(), (PGM_P)str, length + 1); memcpy_P(wbuffer() + len(), (PGM_P)str, length + 1);
setLen(newlen); setLen(newlen);
return 1; return 1;
@ -376,79 +343,78 @@ unsigned char String::concat(const __FlashStringHelper * str) {
/* Concatenate */ /* Concatenate */
/*********************************************/ /*********************************************/
StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs) { StringSumHelper &operator +(const StringSumHelper &lhs, const String &rhs) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs); StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
if (!a.concat(rhs.buffer(), rhs.len())) if (!a.concat(rhs.buffer(), rhs.len()))
a.invalidate(); a.invalidate();
return a; return a;
} }
StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr) { StringSumHelper &operator +(const StringSumHelper &lhs, const char *cstr) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs); StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
if (!cstr || !a.concat(cstr, strlen(cstr))) if (!cstr || !a.concat(cstr, strlen(cstr)))
a.invalidate(); a.invalidate();
return a; return a;
} }
StringSumHelper & operator +(const StringSumHelper &lhs, char c) { StringSumHelper &operator +(const StringSumHelper &lhs, char c) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs); StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
if (!a.concat(c)) if (!a.concat(c))
a.invalidate(); a.invalidate();
return a; return a;
} }
StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num) { StringSumHelper &operator +(const StringSumHelper &lhs, unsigned char num) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs); StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
if (!a.concat(num)) if (!a.concat(num))
a.invalidate(); a.invalidate();
return a; return a;
} }
StringSumHelper & operator +(const StringSumHelper &lhs, int num) { StringSumHelper &operator +(const StringSumHelper &lhs, int num) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs); StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
if (!a.concat(num)) if (!a.concat(num))
a.invalidate(); a.invalidate();
return a; return a;
} }
StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num) { StringSumHelper &operator +(const StringSumHelper &lhs, unsigned int num) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs); StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
if (!a.concat(num)) if (!a.concat(num))
a.invalidate(); a.invalidate();
return a; return a;
} }
StringSumHelper & operator +(const StringSumHelper &lhs, long num) { StringSumHelper &operator +(const StringSumHelper &lhs, long num) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs); StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
if (!a.concat(num)) if (!a.concat(num))
a.invalidate(); a.invalidate();
return a; return a;
} }
StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num) { StringSumHelper &operator +(const StringSumHelper &lhs, unsigned long num) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs); StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
if (!a.concat(num)) if (!a.concat(num))
a.invalidate(); a.invalidate();
return a; return a;
} }
StringSumHelper & operator +(const StringSumHelper &lhs, float num) { StringSumHelper &operator +(const StringSumHelper &lhs, float num) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs); StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
if (!a.concat(num)) if (!a.concat(num))
a.invalidate(); a.invalidate();
return a; return a;
} }
StringSumHelper & operator +(const StringSumHelper &lhs, double num) { StringSumHelper &operator +(const StringSumHelper &lhs, double num) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs); StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
if (!a.concat(num)) if (!a.concat(num))
a.invalidate(); a.invalidate();
return a; return a;
} }
StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs) StringSumHelper &operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs) {
{ StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!a.concat(rhs)) if (!a.concat(rhs))
a.invalidate(); a.invalidate();
return a; return a;
@ -459,11 +425,11 @@ StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHel
/*********************************************/ /*********************************************/
int String::compareTo(const String &s) const { int String::compareTo(const String &s) const {
if(!buffer() || !s.buffer()) { if (!buffer() || !s.buffer()) {
if(s.buffer() && s.len() > 0) if (s.buffer() && s.len() > 0)
return 0 - *(unsigned char *) s.buffer(); return 0 - *(unsigned char *)s.buffer();
if(buffer() && len() > 0) if (buffer() && len() > 0)
return *(unsigned char *) buffer(); return *(unsigned char *)buffer();
return 0; return 0;
} }
return strcmp(buffer(), s.buffer()); return strcmp(buffer(), s.buffer());
@ -521,7 +487,7 @@ unsigned char String::equalsConstantTime(const String &s2) const {
//at this point lengths are the same //at this point lengths are the same
if (len() == 0) if (len() == 0)
return 1; return 1;
//at this point lenghts are the same and non-zero //at this point lengths are the same and non-zero
const char *p1 = buffer(); const char *p1 = buffer();
const char *p2 = s2.buffer(); const char *p2 = s2.buffer();
unsigned int equalchars = 0; unsigned int equalchars = 0;
@ -541,19 +507,19 @@ unsigned char String::equalsConstantTime(const String &s2) const {
} }
unsigned char String::startsWith(const String &s2) const { unsigned char String::startsWith(const String &s2) const {
if(len() < s2.len()) if (len() < s2.len())
return 0; return 0;
return startsWith(s2, 0); return startsWith(s2, 0);
} }
unsigned char String::startsWith(const String &s2, unsigned int offset) const { unsigned char String::startsWith(const String &s2, unsigned int offset) const {
if(offset > (unsigned)(len() - s2.len()) || !buffer() || !s2.buffer()) if (offset > (unsigned)(len() - s2.len()) || !buffer() || !s2.buffer())
return 0; return 0;
return strncmp(&buffer()[offset], s2.buffer(), s2.len()) == 0; return strncmp(&buffer()[offset], s2.buffer(), s2.len()) == 0;
} }
unsigned char String::endsWith(const String &s2) const { unsigned char String::endsWith(const String &s2) const {
if(len() < s2.len() || !buffer() || !s2.buffer()) if (len() < s2.len() || !buffer() || !s2.buffer())
return 0; return 0;
return strcmp(&buffer()[len() - s2.len()], s2.buffer()) == 0; return strcmp(&buffer()[len() - s2.len()], s2.buffer()) == 0;
} }
@ -562,16 +528,12 @@ unsigned char String::endsWith(const String &s2) const {
/* Character Access */ /* Character Access */
/*********************************************/ /*********************************************/
char String::charAt(unsigned int loc) const {
return operator[](loc);
}
void String::setCharAt(unsigned int loc, char c) { void String::setCharAt(unsigned int loc, char c) {
if (loc < len()) if (loc < len())
wbuffer()[loc] = c; wbuffer()[loc] = c;
} }
char & String::operator[](unsigned int index) { char &String::operator[](unsigned int index) {
static char dummy_writable_char; static char dummy_writable_char;
if (index >= len() || !buffer()) { if (index >= len() || !buffer()) {
dummy_writable_char = 0; dummy_writable_char = 0;
@ -596,7 +558,7 @@ void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int ind
unsigned int n = bufsize - 1; unsigned int n = bufsize - 1;
if (n > len() - index) if (n > len() - index)
n = len() - index; n = len() - index;
strncpy((char *) buf, buffer() + index, n); strncpy((char *)buf, buffer() + index, n);
buf[n] = 0; buf[n] = 0;
} }
@ -604,31 +566,15 @@ void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int ind
/* Search */ /* Search */
/*********************************************/ /*********************************************/
int String::indexOf(char c) const {
return indexOf(c, 0);
}
int String::indexOf(char ch, unsigned int fromIndex) const { int String::indexOf(char ch, unsigned int fromIndex) const {
if (fromIndex >= len()) if (fromIndex >= len())
return -1; return -1;
const char* temp = strchr(buffer() + fromIndex, ch); const char *temp = strchr(buffer() + fromIndex, ch);
if (temp == NULL) if (temp == NULL)
return -1; return -1;
return temp - buffer(); return temp - buffer();
} }
int String::indexOf(const __FlashStringHelper *s2) const {
return indexOf(s2, 0);
}
int String::indexOf(const __FlashStringHelper *s2, unsigned int fromIndex) const {
return indexOf((const char*) s2, fromIndex);
}
int String::indexOf(const char *s2) const {
return indexOf(s2, 0);
}
int String::indexOf(const char *s2, unsigned int fromIndex) const { int String::indexOf(const char *s2, unsigned int fromIndex) const {
if (fromIndex >= len()) if (fromIndex >= len())
return -1; return -1;
@ -638,28 +584,25 @@ int String::indexOf(const char *s2, unsigned int fromIndex) const {
return found - buffer(); return found - buffer();
} }
int String::indexOf(const String &s2) const {
return indexOf(s2, 0);
}
int String::indexOf(const String &s2, unsigned int fromIndex) const { int String::indexOf(const String &s2, unsigned int fromIndex) const {
return indexOf(s2.c_str(), fromIndex); return indexOf(s2.c_str(), fromIndex);
} }
int String::lastIndexOf(char theChar) const { int String::lastIndexOf(char ch) const {
return lastIndexOf(theChar, len() - 1); return lastIndexOf(ch, len() - 1);
} }
int String::lastIndexOf(char ch, unsigned int fromIndex) const { int String::lastIndexOf(char ch, unsigned int fromIndex) const {
if (fromIndex >= len()) if (fromIndex >= len())
return -1; return -1;
char tempchar = buffer()[fromIndex + 1]; char *writeTo = wbuffer();
wbuffer()[fromIndex + 1] = '\0'; char tempchar = writeTo[fromIndex + 1]; // save the replaced character
char* temp = strrchr(wbuffer(), ch); writeTo[fromIndex + 1] = '\0';
wbuffer()[fromIndex + 1] = tempchar; char *temp = strrchr(writeTo, ch);
writeTo[fromIndex + 1] = tempchar; // restore character
if (temp == NULL) if (temp == NULL)
return -1; return -1;
return temp - buffer(); return temp - writeTo;
} }
int String::lastIndexOf(const String &s2) const { int String::lastIndexOf(const String &s2) const {
@ -672,11 +615,11 @@ int String::lastIndexOf(const String &s2, unsigned int fromIndex) const {
if (fromIndex >= len()) if (fromIndex >= len())
fromIndex = len() - 1; fromIndex = len() - 1;
int found = -1; int found = -1;
for (char *p = wbuffer(); p <= wbuffer() + fromIndex; p++) { for (const char *p = buffer(); p <= buffer() + fromIndex; p++) {
p = strstr(p, s2.buffer()); p = strstr(p, s2.buffer());
if (!p) if (!p)
break; break;
if ((unsigned int) (p - wbuffer()) <= fromIndex) if ((unsigned int)(p - buffer()) <= fromIndex)
found = p - buffer(); found = p - buffer();
} }
return found; return found;
@ -693,10 +636,11 @@ String String::substring(unsigned int left, unsigned int right) const {
return out; return out;
if (right > len()) if (right > len())
right = len(); right = len();
char temp = buffer()[right]; // save the replaced character char *writeTo = wbuffer();
wbuffer()[right] = '\0'; char tempchar = writeTo[right]; // save the replaced character
out = wbuffer() + left; // pointer arithmetic writeTo[right] = '\0';
wbuffer()[right] = temp; //restore character out = writeTo + left; // pointer arithmetic
writeTo[right] = tempchar; // restore character
return out; return out;
} }
@ -713,7 +657,7 @@ void String::replace(char find, char replace) {
} }
} }
void String::replace(const String& find, const String& replace) { void String::replace(const String &find, const String &replace) {
if (len() == 0 || find.len() == 0) if (len() == 0 || find.len() == 0)
return; return;
int diff = replace.len() - find.len(); int diff = replace.len() - find.len();
@ -735,7 +679,7 @@ void String::replace(const String& find, const String& replace) {
readFrom = foundAt + find.len(); readFrom = foundAt + find.len();
setLen(len() + diff); setLen(len() + diff);
} }
memmove_P(writeTo, readFrom, strlen(readFrom)+1); memmove_P(writeTo, readFrom, strlen(readFrom) + 1);
} else { } else {
unsigned int size = len(); // compute size needed for result unsigned int size = len(); // compute size needed for result
while ((foundAt = strstr(readFrom, find.buffer())) != NULL) { while ((foundAt = strstr(readFrom, find.buffer())) != NULL) {
@ -759,13 +703,6 @@ void String::replace(const String& find, const String& replace) {
} }
} }
void String::remove(unsigned int index) {
// Pass the biggest integer as the count. The remove method
// below will take care of truncating it at the end of the
// string.
remove(index, (unsigned int) -1);
}
void String::remove(unsigned int index, unsigned int count) { void String::remove(unsigned int index, unsigned int count) {
if (index >= len()) { if (index >= len()) {
return; return;
@ -828,11 +765,10 @@ long String::toInt(void) const {
float String::toFloat(void) const { float String::toFloat(void) const {
if (buffer()) if (buffer())
return atof(buffer()); return atof(buffer());
return 0; return 0.0F;
} }
double String::toDouble(void) const double String::toDouble(void) const {
{
if (buffer()) if (buffer())
return atof(buffer()); return atof(buffer());
return 0.0; return 0.0;

View File

@ -53,7 +53,7 @@ class String {
// if the initial value is null or invalid, or if memory allocation // if the initial value is null or invalid, or if memory allocation
// fails, the string will be marked as invalid (i.e. "if (s)" will // fails, the string will be marked as invalid (i.e. "if (s)" will
// be false). // be false).
String() { String() __attribute__((always_inline)) { // See init()
init(); init();
} }
String(const char *cstr); String(const char *cstr);
@ -61,7 +61,12 @@ class String {
String(const __FlashStringHelper *str); String(const __FlashStringHelper *str);
String(String &&rval) noexcept; String(String &&rval) noexcept;
String(StringSumHelper &&rval) noexcept; String(StringSumHelper &&rval) noexcept;
explicit String(char c); explicit String(char c) {
sso.buff[0] = c;
sso.buff[1] = 0;
sso.len = 1;
sso.isHeap = 0;
}
explicit String(unsigned char, unsigned char base = 10); explicit String(unsigned char, unsigned char base = 10);
explicit String(int, unsigned char base = 10); explicit String(int, unsigned char base = 10);
explicit String(unsigned int, unsigned char base = 10); explicit String(unsigned int, unsigned char base = 10);
@ -69,35 +74,35 @@ class String {
explicit String(unsigned long, unsigned char base = 10); explicit String(unsigned long, unsigned char base = 10);
explicit String(float, unsigned char decimalPlaces = 2); explicit String(float, unsigned char decimalPlaces = 2);
explicit String(double, unsigned char decimalPlaces = 2); explicit String(double, unsigned char decimalPlaces = 2);
~String(void); ~String() {
invalidate();
}
// memory management // memory management
// return true on success, false on failure (in which case, the string // return true on success, false on failure (in which case, the string
// is left unchanged). reserve(0), if successful, will validate an // is left unchanged). reserve(0), if successful, will validate an
// invalid string (i.e., "if (s)" will be true afterwards) // invalid string (i.e., "if (s)" will be true afterwards)
unsigned char reserve(unsigned int size); unsigned char reserve(unsigned int size);
inline unsigned int length(void) const { unsigned int length(void) const {
if(buffer()) { return buffer() ? len() : 0;
return len();
} else {
return 0;
}
} }
inline void clear(void) { void clear(void) {
setLen(0); setLen(0);
} }
inline bool isEmpty(void) const { bool isEmpty(void) const {
return length() == 0; return length() == 0;
} }
// creates a copy of the assigned value. if the value is null or // creates a copy of the assigned value. if the value is null or
// invalid, or if the memory allocation fails, the string will be // invalid, or if the memory allocation fails, the string will be
// marked as invalid ("if (s)" will be false). // marked as invalid ("if (s)" will be false).
String & operator =(const String &rhs); String &operator =(const String &rhs);
String & operator =(const char *cstr); String &operator =(const char *cstr);
String & operator = (const __FlashStringHelper *str); String &operator =(const __FlashStringHelper *str);
String & operator =(String &&rval) noexcept; String &operator =(String &&rval) noexcept;
String & operator =(StringSumHelper &&rval) noexcept; String &operator =(StringSumHelper &&rval) noexcept {
return operator =((String &&)rval);
}
// concatenate (works w/ built-in types) // concatenate (works w/ built-in types)
@ -114,67 +119,67 @@ class String {
unsigned char concat(unsigned long num); unsigned char concat(unsigned long num);
unsigned char concat(float num); unsigned char concat(float num);
unsigned char concat(double num); unsigned char concat(double num);
unsigned char concat(const __FlashStringHelper * str); unsigned char concat(const __FlashStringHelper *str);
unsigned char concat(const char *cstr, unsigned int length); unsigned char concat(const char *cstr, unsigned int length);
// if there's not enough memory for the concatenated value, the string // if there's not enough memory for the concatenated value, the string
// will be left unchanged (but this isn't signalled in any way) // will be left unchanged (but this isn't signalled in any way)
String & operator +=(const String &rhs) { String &operator +=(const String &rhs) {
concat(rhs); concat(rhs);
return (*this); return *this;
} }
String & operator +=(const char *cstr) { String &operator +=(const char *cstr) {
concat(cstr); concat(cstr);
return (*this); return *this;
} }
String & operator +=(char c) { String &operator +=(char c) {
concat(c); concat(c);
return (*this); return *this;
} }
String & operator +=(unsigned char num) { String &operator +=(unsigned char num) {
concat(num); concat(num);
return (*this); return *this;
} }
String & operator +=(int num) { String &operator +=(int num) {
concat(num); concat(num);
return (*this); return *this;
} }
String & operator +=(unsigned int num) { String &operator +=(unsigned int num) {
concat(num); concat(num);
return (*this); return *this;
} }
String & operator +=(long num) { String &operator +=(long num) {
concat(num); concat(num);
return (*this); return *this;
} }
String & operator +=(unsigned long num) { String &operator +=(unsigned long num) {
concat(num); concat(num);
return (*this); return *this;
} }
String & operator +=(float num) { String &operator +=(float num) {
concat(num); concat(num);
return (*this); return *this;
} }
String & operator +=(double num) { String &operator +=(double num) {
concat(num); concat(num);
return (*this); return *this;
} }
String & operator += (const __FlashStringHelper *str){ String &operator +=(const __FlashStringHelper *str) {
concat(str); concat(str);
return (*this); return *this;
} }
friend StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs); friend StringSumHelper &operator +(const StringSumHelper &lhs, const String &rhs);
friend StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr); friend StringSumHelper &operator +(const StringSumHelper &lhs, const char *cstr);
friend StringSumHelper & operator +(const StringSumHelper &lhs, char c); friend StringSumHelper &operator +(const StringSumHelper &lhs, char c);
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num); friend StringSumHelper &operator +(const StringSumHelper &lhs, unsigned char num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, int num); friend StringSumHelper &operator +(const StringSumHelper &lhs, int num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num); friend StringSumHelper &operator +(const StringSumHelper &lhs, unsigned int num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, long num); friend StringSumHelper &operator +(const StringSumHelper &lhs, long num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num); friend StringSumHelper &operator +(const StringSumHelper &lhs, unsigned long num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, float num); friend StringSumHelper &operator +(const StringSumHelper &lhs, float num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, double num); friend StringSumHelper &operator +(const StringSumHelper &lhs, double num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs); friend StringSumHelper &operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
// comparison (only works w/ Strings and "strings") // comparison (only works w/ Strings and "strings")
operator StringIfHelperType() const { operator StringIfHelperType() const {
@ -202,45 +207,45 @@ class String {
unsigned char equalsIgnoreCase(const String &s) const; unsigned char equalsIgnoreCase(const String &s) const;
unsigned char equalsConstantTime(const String &s) const; unsigned char equalsConstantTime(const String &s) const;
unsigned char startsWith(const String &prefix) const; unsigned char startsWith(const String &prefix) const;
unsigned char startsWith(const char * prefix) const { unsigned char startsWith(const char *prefix) const {
return this->startsWith(String(prefix)); return this->startsWith(String(prefix));
} }
unsigned char startsWith(const __FlashStringHelper * prefix) const { unsigned char startsWith(const __FlashStringHelper *prefix) const {
return this->startsWith(String(prefix)); return this->startsWith(String(prefix));
} }
unsigned char startsWith(const String &prefix, unsigned int offset) const; unsigned char startsWith(const String &prefix, unsigned int offset) const;
unsigned char endsWith(const String &suffix) const; unsigned char endsWith(const String &suffix) const;
unsigned char endsWith(const char * suffix) const { unsigned char endsWith(const char *suffix) const {
return this->endsWith(String(suffix)); return this->endsWith(String(suffix));
} }
unsigned char endsWith(const __FlashStringHelper * suffix) const { unsigned char endsWith(const __FlashStringHelper *suffix) const {
return this->endsWith(String(suffix)); return this->endsWith(String(suffix));
} }
// character access // character access
char charAt(unsigned int index) const; char charAt(unsigned int index) const {
return operator [](index);
}
void setCharAt(unsigned int index, char c); void setCharAt(unsigned int index, char c);
char operator [](unsigned int index) const; char operator [](unsigned int index) const;
char& operator [](unsigned int index); char &operator [](unsigned int index);
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index = 0) const; void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index = 0) const;
void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const { void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const {
getBytes((unsigned char *) buf, bufsize, index); getBytes((unsigned char *) buf, bufsize, index);
} }
const char* c_str() const { return buffer(); } const char *c_str() const { return buffer(); }
char* begin() { return wbuffer(); } char *begin() { return wbuffer(); }
char* end() { return wbuffer() + length(); } char *end() { return wbuffer() + length(); }
const char* begin() const { return c_str(); } const char *begin() const { return c_str(); }
const char* end() const { return c_str() + length(); } const char *end() const { return c_str() + length(); }
// search // search
int indexOf(char ch) const; int indexOf(char ch, unsigned int fromIndex = 0) const;
int indexOf(char ch, unsigned int fromIndex) const; int indexOf(const char *str, unsigned int fromIndex = 0) const;
int indexOf(const char *str) const; int indexOf(const __FlashStringHelper *str, unsigned int fromIndex = 0) const {
int indexOf(const char *str, unsigned int fromIndex) const; return indexOf((const char*)str, fromIndex);
int indexOf(const __FlashStringHelper *str) const; }
int indexOf(const __FlashStringHelper *str, unsigned int fromIndex) const; int indexOf(const String &str, unsigned int fromIndex = 0) const;
int indexOf(const String &str) const;
int indexOf(const String &str, unsigned int fromIndex) const;
int lastIndexOf(char ch) const; int lastIndexOf(char ch) const;
int lastIndexOf(char ch, unsigned int fromIndex) const; int lastIndexOf(char ch, unsigned int fromIndex) const;
int lastIndexOf(const String &str) const; int lastIndexOf(const String &str) const;
@ -248,29 +253,29 @@ class String {
String substring(unsigned int beginIndex) const { String substring(unsigned int beginIndex) const {
return substring(beginIndex, len()); return substring(beginIndex, len());
} }
;
String substring(unsigned int beginIndex, unsigned int endIndex) const; String substring(unsigned int beginIndex, unsigned int endIndex) const;
// modification // modification
void replace(char find, char replace); void replace(char find, char replace);
void replace(const String& find, const String& replace); void replace(const String &find, const String &replace);
void replace(const char * find, const String& replace) { void replace(const char *find, const String &replace) {
this->replace(String(find), replace); this->replace(String(find), replace);
} }
void replace(const __FlashStringHelper * find, const String& replace) { void replace(const __FlashStringHelper *find, const String &replace) {
this->replace(String(find), replace); this->replace(String(find), replace);
} }
void replace(const char * find, const char * replace) { void replace(const char *find, const char *replace) {
this->replace(String(find), String(replace)); this->replace(String(find), String(replace));
} }
void replace(const __FlashStringHelper * find, const char * replace) { void replace(const __FlashStringHelper *find, const char *replace) {
this->replace(String(find), String(replace)); this->replace(String(find), String(replace));
} }
void replace(const __FlashStringHelper * find, const __FlashStringHelper * replace) { void replace(const __FlashStringHelper *find, const __FlashStringHelper *replace) {
this->replace(String(find), String(replace)); this->replace(String(find), String(replace));
} }
void remove(unsigned int index); // Pass the biggest integer if the count is not specified.
void remove(unsigned int index, unsigned int count); // The remove method below will take care of truncating it at the end of the string.
void remove(unsigned int index, unsigned int count = (unsigned int)-1);
void toLowerCase(void); void toLowerCase(void);
void toUpperCase(void); void toUpperCase(void);
void trim(void); void trim(void);
@ -278,11 +283,11 @@ class String {
// parsing/conversion // parsing/conversion
long toInt(void) const; long toInt(void) const;
float toFloat(void) const; float toFloat(void) const;
double toDouble(void) const; double toDouble(void) const;
protected: protected:
// Contains the string info when we're not in SSO mode // Contains the string info when we're not in SSO mode
struct _ptr { struct _ptr {
char * buff; char * buff;
uint16_t cap; uint16_t cap;
uint16_t len; uint16_t len;
@ -291,8 +296,8 @@ class String {
enum { SSOSIZE = sizeof(struct _ptr) + 4 - 1 }; // Characters to allocate space for SSO, must be 12 or more enum { SSOSIZE = sizeof(struct _ptr) + 4 - 1 }; // Characters to allocate space for SSO, must be 12 or more
struct _sso { struct _sso {
char buff[SSOSIZE]; char buff[SSOSIZE];
unsigned char len : 7; // Ensure only one byte is allocated by GCC for the bitfields unsigned char len : 7; // Ensure only one byte is allocated by GCC for the bitfields
unsigned char isSSO : 1; unsigned char isHeap : 1;
} __attribute__((packed)); // Ensure that GCC doesn't expand the flag byte to a 32-bit word for alignment issues } __attribute__((packed)); // Ensure that GCC doesn't expand the flag byte to a 32-bit word for alignment issues
enum { CAPACITY_MAX = 65535 }; // If typeof(cap) changed from uint16_t, be sure to update this enum to the max value storable in the type enum { CAPACITY_MAX = 65535 }; // If typeof(cap) changed from uint16_t, be sure to update this enum to the max value storable in the type
union { union {
@ -300,25 +305,47 @@ class String {
struct _sso sso; struct _sso sso;
}; };
// Accessor functions // Accessor functions
inline bool isSSO() const { return sso.isSSO; } bool isSSO() const { return !sso.isHeap; }
inline unsigned int len() const { return isSSO() ? sso.len : ptr.len; } unsigned int len() const { return isSSO() ? sso.len : ptr.len; }
inline unsigned int capacity() const { return isSSO() ? (unsigned int)SSOSIZE - 1 : ptr.cap; } // Size of max string not including terminal NUL unsigned int capacity() const { return isSSO() ? (unsigned int)SSOSIZE - 1 : ptr.cap; } // Size of max string not including terminal NUL
inline void setSSO(bool set) { sso.isSSO = set; } void setSSO(bool set) { sso.isHeap = !set; }
inline void setLen(int len) { if (isSSO()) sso.len = len; else ptr.len = len; } void setLen(int len) {
inline void setCapacity(int cap) { if (!isSSO()) ptr.cap = cap; } if (isSSO()) {
inline void setBuffer(char *buff) { if (!isSSO()) ptr.buff = buff; } setSSO(true); // Avoid emitting of bitwise EXTRACT-AND-OR ops (store-merging optimization)
sso.len = len;
} else
ptr.len = len;
}
void setCapacity(int cap) { if (!isSSO()) ptr.cap = cap; }
void setBuffer(char *buff) { if (!isSSO()) ptr.buff = buff; }
// Buffer accessor functions // Buffer accessor functions
inline const char *buffer() const { return (const char *)(isSSO() ? sso.buff : ptr.buff); } const char *buffer() const { return wbuffer(); }
inline char *wbuffer() const { return isSSO() ? const_cast<char *>(sso.buff) : ptr.buff; } // Writable version of buffer char *wbuffer() const { return isSSO() ? const_cast<char *>(sso.buff) : ptr.buff; } // Writable version of buffer
protected: protected:
void init(void); void init(void) __attribute__((always_inline)) {
sso.buff[0] = 0;
sso.len = 0;
sso.isHeap = 0;
// Without the 6 statements shown below, GCC simply emits such as: "MOVI.N aX,0", "S8I aX,a2,0" and "S8I aX,a2,11" (8 bytes in total)
sso.buff[1] = 0;
sso.buff[2] = 0;
sso.buff[3] = 0;
sso.buff[8] = 0;
sso.buff[9] = 0;
sso.buff[10] = 0;
// With the above, thanks to store-merging, GCC can use the narrow form of 32-bit store insn ("S32I.N") and emits:
// "MOVI.N aX,0", "S32I.N aX,a2,0" and "S32I.N aX,a2,8" (6 bytes in total)
// (Literature: Xtensa(R) Instruction Set Reference Manual, "S8I - Store 8-bit" [p.504] and "S32I.N - Narrow Store 32-bit" [p.512])
// Unfortunately, GCC seems not to re-evaluate the cost of inlining after the store-merging optimizer stage,
// `always_inline` attribute is necessary in order to keep inlining.
}
void invalidate(void); void invalidate(void);
unsigned char changeBuffer(unsigned int maxStrLen); unsigned char changeBuffer(unsigned int maxStrLen);
// copy and move // copy and move
String & copy(const char *cstr, unsigned int length); String &copy(const char *cstr, unsigned int length);
String & copy(const __FlashStringHelper *pstr, unsigned int length); String &copy(const __FlashStringHelper *pstr, unsigned int length);
void move(String &rhs) noexcept; void move(String &rhs) noexcept;
}; };
@ -354,6 +381,9 @@ class StringSumHelper: public String {
StringSumHelper(double num) : StringSumHelper(double num) :
String(num) { String(num) {
} }
StringSumHelper(const __FlashStringHelper *s) :
String(s) {
}
}; };
extern const String emptyString; extern const String emptyString;