mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-25 20:02:37 +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:
parent
5ae3efb823
commit
8fe80f1630
@ -55,14 +55,6 @@ String::String(StringSumHelper &&rval) noexcept {
|
||||
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) {
|
||||
init();
|
||||
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) {
|
||||
init();
|
||||
char buf[2 + 8 * sizeof(long)];
|
||||
if (base==10) {
|
||||
if (base == 10) {
|
||||
sprintf(buf, "%ld", value);
|
||||
} else {
|
||||
ltoa(value, buf, base);
|
||||
@ -118,31 +110,21 @@ String::String(double value, unsigned char decimalPlaces) {
|
||||
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
|
||||
}
|
||||
|
||||
String::~String() {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Memory Management */
|
||||
/*********************************************/
|
||||
|
||||
inline void String::init(void) {
|
||||
setSSO(true);
|
||||
setLen(0);
|
||||
wbuffer()[0] = 0;
|
||||
}
|
||||
|
||||
void String::invalidate(void) {
|
||||
if(!isSSO() && wbuffer())
|
||||
if (!isSSO() && wbuffer())
|
||||
free(wbuffer());
|
||||
init();
|
||||
}
|
||||
|
||||
unsigned char String::reserve(unsigned int size) {
|
||||
if(buffer() && capacity() >= size)
|
||||
if (buffer() && capacity() >= size)
|
||||
return 1;
|
||||
if(changeBuffer(size)) {
|
||||
if(len() == 0)
|
||||
if (changeBuffer(size)) {
|
||||
if (len() == 0)
|
||||
wbuffer()[0] = 0;
|
||||
return 1;
|
||||
}
|
||||
@ -157,35 +139,32 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
|
||||
uint16_t oldLen = len();
|
||||
setSSO(true);
|
||||
setLen(oldLen);
|
||||
return 1;
|
||||
} else { // if bufptr && !isSSO()
|
||||
// Using bufptr, need to shrink into sso.buff
|
||||
char temp[sizeof(sso.buff)];
|
||||
memcpy(temp, buffer(), maxStrLen);
|
||||
free(wbuffer());
|
||||
const char *temp = buffer();
|
||||
uint16_t oldLen = len();
|
||||
setSSO(true);
|
||||
setLen(oldLen);
|
||||
memcpy(wbuffer(), temp, maxStrLen);
|
||||
return 1;
|
||||
free((void *)temp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// Fallthrough to normal allocator
|
||||
size_t newSize = (maxStrLen + 16) & (~0xf);
|
||||
// Make sure we can fit newsize in the buffer
|
||||
if (newSize > CAPACITY_MAX) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
uint16_t oldLen = len();
|
||||
char *newbuffer = (char *) realloc(isSSO() ? nullptr : wbuffer(), newSize);
|
||||
char *newbuffer = (char *)realloc(isSSO() ? nullptr : wbuffer(), newSize);
|
||||
if (newbuffer) {
|
||||
size_t oldSize = capacity() + 1; // include NULL.
|
||||
if (isSSO()) {
|
||||
// Copy the SSO buffer into allocated space
|
||||
memmove_P(newbuffer, sso.buff, sizeof(sso.buff));
|
||||
}
|
||||
if (newSize > oldSize)
|
||||
{
|
||||
if (newSize > oldSize) {
|
||||
memset(newbuffer + oldSize, 0, newSize - oldSize);
|
||||
}
|
||||
setSSO(false);
|
||||
@ -201,7 +180,7 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
|
||||
/* Copy and Move */
|
||||
/*********************************************/
|
||||
|
||||
String & String::copy(const char *cstr, unsigned int length) {
|
||||
String &String::copy(const char *cstr, unsigned int length) {
|
||||
if (!reserve(length)) {
|
||||
invalidate();
|
||||
return *this;
|
||||
@ -211,7 +190,7 @@ String & String::copy(const char *cstr, unsigned int length) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
String & String::copy(const __FlashStringHelper *pstr, unsigned int length) {
|
||||
String &String::copy(const __FlashStringHelper *pstr, unsigned int length) {
|
||||
if (!reserve(length)) {
|
||||
invalidate();
|
||||
return *this;
|
||||
@ -227,44 +206,35 @@ void String::move(String &rhs) noexcept {
|
||||
rhs.init();
|
||||
}
|
||||
|
||||
String & String::operator =(const String &rhs) {
|
||||
String &String::operator =(const String &rhs) {
|
||||
if (this == &rhs)
|
||||
return *this;
|
||||
|
||||
if (rhs.buffer())
|
||||
copy(rhs.buffer(), rhs.len());
|
||||
else
|
||||
invalidate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String & String::operator =(String &&rval) noexcept {
|
||||
String &String::operator =(String &&rval) noexcept {
|
||||
if (this != &rval)
|
||||
move(rval);
|
||||
return *this;
|
||||
}
|
||||
|
||||
String & String::operator =(StringSumHelper &&rval) noexcept {
|
||||
if (this != &rval)
|
||||
move(rval);
|
||||
return *this;
|
||||
}
|
||||
|
||||
String & String::operator =(const char *cstr) {
|
||||
String &String::operator =(const char *cstr) {
|
||||
if (cstr)
|
||||
copy(cstr, strlen(cstr));
|
||||
else
|
||||
invalidate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String & String::operator = (const __FlashStringHelper *pstr)
|
||||
{
|
||||
if (pstr) copy(pstr, strlen_P((PGM_P)pstr));
|
||||
else invalidate();
|
||||
|
||||
String &String::operator =(const __FlashStringHelper *pstr) {
|
||||
if (pstr)
|
||||
copy(pstr, strlen_P((PGM_P)pstr));
|
||||
else
|
||||
invalidate();
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -285,7 +255,7 @@ unsigned char String::concat(const String &s) {
|
||||
return 0;
|
||||
memmove_P(wbuffer() + len(), buffer(), len());
|
||||
setLen(newlen);
|
||||
wbuffer()[len()] = 0;
|
||||
wbuffer()[newlen] = 0;
|
||||
return 1;
|
||||
} else {
|
||||
return concat(s.buffer(), s.len());
|
||||
@ -313,22 +283,17 @@ unsigned char String::concat(const char *cstr) {
|
||||
}
|
||||
|
||||
unsigned char String::concat(char c) {
|
||||
char buf[2];
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
return concat(buf, 1);
|
||||
return concat(&c, 1);
|
||||
}
|
||||
|
||||
unsigned char String::concat(unsigned char num) {
|
||||
char buf[1 + 3 * sizeof(unsigned char)];
|
||||
sprintf(buf, "%d", num);
|
||||
return concat(buf, strlen(buf));
|
||||
return concat(buf, sprintf(buf, "%d", num));
|
||||
}
|
||||
|
||||
unsigned char String::concat(int num) {
|
||||
char buf[2 + 3 * sizeof(int)];
|
||||
sprintf(buf, "%d", num);
|
||||
return concat(buf, strlen(buf));
|
||||
return concat(buf, sprintf(buf, "%d", 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) {
|
||||
char buf[2 + 3 * sizeof(long)];
|
||||
sprintf(buf, "%ld", num);
|
||||
return concat(buf, strlen(buf));
|
||||
return concat(buf, sprintf(buf, "%ld", 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) {
|
||||
char buf[20];
|
||||
char* string = dtostrf(num, 4, 2, buf);
|
||||
char *string = dtostrf(num, 4, 2, buf);
|
||||
return concat(string, strlen(string));
|
||||
}
|
||||
|
||||
unsigned char String::concat(double num) {
|
||||
char buf[20];
|
||||
char* string = dtostrf(num, 4, 2, buf);
|
||||
char *string = dtostrf(num, 4, 2, buf);
|
||||
return concat(string, strlen(string));
|
||||
}
|
||||
|
||||
unsigned char String::concat(const __FlashStringHelper * str) {
|
||||
if (!str) return 0;
|
||||
unsigned char String::concat(const __FlashStringHelper *str) {
|
||||
if (!str)
|
||||
return 0;
|
||||
int length = strlen_P((PGM_P)str);
|
||||
if (length == 0) return 1;
|
||||
if (length == 0)
|
||||
return 1;
|
||||
unsigned int newlen = len() + length;
|
||||
if (!reserve(newlen)) return 0;
|
||||
if (!reserve(newlen))
|
||||
return 0;
|
||||
memcpy_P(wbuffer() + len(), (PGM_P)str, length + 1);
|
||||
setLen(newlen);
|
||||
return 1;
|
||||
@ -376,79 +343,78 @@ unsigned char String::concat(const __FlashStringHelper * str) {
|
||||
/* Concatenate */
|
||||
/*********************************************/
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
StringSumHelper &operator +(const StringSumHelper &lhs, const String &rhs) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
|
||||
if (!a.concat(rhs.buffer(), rhs.len()))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
StringSumHelper &operator +(const StringSumHelper &lhs, const char *cstr) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
|
||||
if (!cstr || !a.concat(cstr, strlen(cstr)))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, char c) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
StringSumHelper &operator +(const StringSumHelper &lhs, char c) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
|
||||
if (!a.concat(c))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
StringSumHelper &operator +(const StringSumHelper &lhs, unsigned char num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
|
||||
if (!a.concat(num))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, int num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
StringSumHelper &operator +(const StringSumHelper &lhs, int num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
|
||||
if (!a.concat(num))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
StringSumHelper &operator +(const StringSumHelper &lhs, unsigned int num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
|
||||
if (!a.concat(num))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, long num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
StringSumHelper &operator +(const StringSumHelper &lhs, long num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
|
||||
if (!a.concat(num))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
StringSumHelper &operator +(const StringSumHelper &lhs, unsigned long num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
|
||||
if (!a.concat(num))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, float num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
StringSumHelper &operator +(const StringSumHelper &lhs, float num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
|
||||
if (!a.concat(num))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, double num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
StringSumHelper &operator +(const StringSumHelper &lhs, double num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
|
||||
if (!a.concat(num))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
StringSumHelper &operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper &>(lhs);
|
||||
if (!a.concat(rhs))
|
||||
a.invalidate();
|
||||
return a;
|
||||
@ -459,11 +425,11 @@ StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHel
|
||||
/*********************************************/
|
||||
|
||||
int String::compareTo(const String &s) const {
|
||||
if(!buffer() || !s.buffer()) {
|
||||
if(s.buffer() && s.len() > 0)
|
||||
return 0 - *(unsigned char *) s.buffer();
|
||||
if(buffer() && len() > 0)
|
||||
return *(unsigned char *) buffer();
|
||||
if (!buffer() || !s.buffer()) {
|
||||
if (s.buffer() && s.len() > 0)
|
||||
return 0 - *(unsigned char *)s.buffer();
|
||||
if (buffer() && len() > 0)
|
||||
return *(unsigned char *)buffer();
|
||||
return 0;
|
||||
}
|
||||
return strcmp(buffer(), s.buffer());
|
||||
@ -521,7 +487,7 @@ unsigned char String::equalsConstantTime(const String &s2) const {
|
||||
//at this point lengths are the same
|
||||
if (len() == 0)
|
||||
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 *p2 = s2.buffer();
|
||||
unsigned int equalchars = 0;
|
||||
@ -541,19 +507,19 @@ unsigned char String::equalsConstantTime(const String &s2) const {
|
||||
}
|
||||
|
||||
unsigned char String::startsWith(const String &s2) const {
|
||||
if(len() < s2.len())
|
||||
if (len() < s2.len())
|
||||
return 0;
|
||||
return startsWith(s2, 0);
|
||||
}
|
||||
|
||||
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 strncmp(&buffer()[offset], s2.buffer(), s2.len()) == 0;
|
||||
}
|
||||
|
||||
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 strcmp(&buffer()[len() - s2.len()], s2.buffer()) == 0;
|
||||
}
|
||||
@ -562,16 +528,12 @@ unsigned char String::endsWith(const String &s2) const {
|
||||
/* Character Access */
|
||||
/*********************************************/
|
||||
|
||||
char String::charAt(unsigned int loc) const {
|
||||
return operator[](loc);
|
||||
}
|
||||
|
||||
void String::setCharAt(unsigned int loc, char c) {
|
||||
if (loc < len())
|
||||
wbuffer()[loc] = c;
|
||||
}
|
||||
|
||||
char & String::operator[](unsigned int index) {
|
||||
char &String::operator[](unsigned int index) {
|
||||
static char dummy_writable_char;
|
||||
if (index >= len() || !buffer()) {
|
||||
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;
|
||||
if (n > len() - index)
|
||||
n = len() - index;
|
||||
strncpy((char *) buf, buffer() + index, n);
|
||||
strncpy((char *)buf, buffer() + index, n);
|
||||
buf[n] = 0;
|
||||
}
|
||||
|
||||
@ -604,31 +566,15 @@ void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int ind
|
||||
/* Search */
|
||||
/*********************************************/
|
||||
|
||||
int String::indexOf(char c) const {
|
||||
return indexOf(c, 0);
|
||||
}
|
||||
|
||||
int String::indexOf(char ch, unsigned int fromIndex) const {
|
||||
if (fromIndex >= len())
|
||||
return -1;
|
||||
const char* temp = strchr(buffer() + fromIndex, ch);
|
||||
const char *temp = strchr(buffer() + fromIndex, ch);
|
||||
if (temp == NULL)
|
||||
return -1;
|
||||
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 {
|
||||
if (fromIndex >= len())
|
||||
return -1;
|
||||
@ -638,28 +584,25 @@ int String::indexOf(const char *s2, unsigned int fromIndex) const {
|
||||
return found - buffer();
|
||||
}
|
||||
|
||||
int String::indexOf(const String &s2) const {
|
||||
return indexOf(s2, 0);
|
||||
}
|
||||
|
||||
int String::indexOf(const String &s2, unsigned int fromIndex) const {
|
||||
return indexOf(s2.c_str(), fromIndex);
|
||||
}
|
||||
|
||||
int String::lastIndexOf(char theChar) const {
|
||||
return lastIndexOf(theChar, len() - 1);
|
||||
int String::lastIndexOf(char ch) const {
|
||||
return lastIndexOf(ch, len() - 1);
|
||||
}
|
||||
|
||||
int String::lastIndexOf(char ch, unsigned int fromIndex) const {
|
||||
if (fromIndex >= len())
|
||||
return -1;
|
||||
char tempchar = buffer()[fromIndex + 1];
|
||||
wbuffer()[fromIndex + 1] = '\0';
|
||||
char* temp = strrchr(wbuffer(), ch);
|
||||
wbuffer()[fromIndex + 1] = tempchar;
|
||||
char *writeTo = wbuffer();
|
||||
char tempchar = writeTo[fromIndex + 1]; // save the replaced character
|
||||
writeTo[fromIndex + 1] = '\0';
|
||||
char *temp = strrchr(writeTo, ch);
|
||||
writeTo[fromIndex + 1] = tempchar; // restore character
|
||||
if (temp == NULL)
|
||||
return -1;
|
||||
return temp - buffer();
|
||||
return temp - writeTo;
|
||||
}
|
||||
|
||||
int String::lastIndexOf(const String &s2) const {
|
||||
@ -672,11 +615,11 @@ int String::lastIndexOf(const String &s2, unsigned int fromIndex) const {
|
||||
if (fromIndex >= len())
|
||||
fromIndex = len() - 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());
|
||||
if (!p)
|
||||
break;
|
||||
if ((unsigned int) (p - wbuffer()) <= fromIndex)
|
||||
if ((unsigned int)(p - buffer()) <= fromIndex)
|
||||
found = p - buffer();
|
||||
}
|
||||
return found;
|
||||
@ -693,10 +636,11 @@ String String::substring(unsigned int left, unsigned int right) const {
|
||||
return out;
|
||||
if (right > len())
|
||||
right = len();
|
||||
char temp = buffer()[right]; // save the replaced character
|
||||
wbuffer()[right] = '\0';
|
||||
out = wbuffer() + left; // pointer arithmetic
|
||||
wbuffer()[right] = temp; //restore character
|
||||
char *writeTo = wbuffer();
|
||||
char tempchar = writeTo[right]; // save the replaced character
|
||||
writeTo[right] = '\0';
|
||||
out = writeTo + left; // pointer arithmetic
|
||||
writeTo[right] = tempchar; // restore character
|
||||
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)
|
||||
return;
|
||||
int diff = replace.len() - find.len();
|
||||
@ -735,7 +679,7 @@ void String::replace(const String& find, const String& replace) {
|
||||
readFrom = foundAt + find.len();
|
||||
setLen(len() + diff);
|
||||
}
|
||||
memmove_P(writeTo, readFrom, strlen(readFrom)+1);
|
||||
memmove_P(writeTo, readFrom, strlen(readFrom) + 1);
|
||||
} else {
|
||||
unsigned int size = len(); // compute size needed for result
|
||||
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) {
|
||||
if (index >= len()) {
|
||||
return;
|
||||
@ -828,11 +765,10 @@ long String::toInt(void) const {
|
||||
float String::toFloat(void) const {
|
||||
if (buffer())
|
||||
return atof(buffer());
|
||||
return 0;
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
double String::toDouble(void) const
|
||||
{
|
||||
double String::toDouble(void) const {
|
||||
if (buffer())
|
||||
return atof(buffer());
|
||||
return 0.0;
|
||||
|
@ -53,7 +53,7 @@ class String {
|
||||
// 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
|
||||
// be false).
|
||||
String() {
|
||||
String() __attribute__((always_inline)) { // See init()
|
||||
init();
|
||||
}
|
||||
String(const char *cstr);
|
||||
@ -61,7 +61,12 @@ class String {
|
||||
String(const __FlashStringHelper *str);
|
||||
String(String &&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(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(float, unsigned char decimalPlaces = 2);
|
||||
explicit String(double, unsigned char decimalPlaces = 2);
|
||||
~String(void);
|
||||
~String() {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// memory management
|
||||
// return true on success, false on failure (in which case, the string
|
||||
// is left unchanged). reserve(0), if successful, will validate an
|
||||
// invalid string (i.e., "if (s)" will be true afterwards)
|
||||
unsigned char reserve(unsigned int size);
|
||||
inline unsigned int length(void) const {
|
||||
if(buffer()) {
|
||||
return len();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
unsigned int length(void) const {
|
||||
return buffer() ? len() : 0;
|
||||
}
|
||||
inline void clear(void) {
|
||||
void clear(void) {
|
||||
setLen(0);
|
||||
}
|
||||
inline bool isEmpty(void) const {
|
||||
bool isEmpty(void) const {
|
||||
return length() == 0;
|
||||
}
|
||||
|
||||
// creates a copy of the assigned value. if the value is null or
|
||||
// invalid, or if the memory allocation fails, the string will be
|
||||
// marked as invalid ("if (s)" will be false).
|
||||
String & operator =(const String &rhs);
|
||||
String & operator =(const char *cstr);
|
||||
String & operator = (const __FlashStringHelper *str);
|
||||
String & operator =(String &&rval) noexcept;
|
||||
String & operator =(StringSumHelper &&rval) noexcept;
|
||||
String &operator =(const String &rhs);
|
||||
String &operator =(const char *cstr);
|
||||
String &operator =(const __FlashStringHelper *str);
|
||||
String &operator =(String &&rval) noexcept;
|
||||
String &operator =(StringSumHelper &&rval) noexcept {
|
||||
return operator =((String &&)rval);
|
||||
}
|
||||
|
||||
// concatenate (works w/ built-in types)
|
||||
|
||||
@ -114,67 +119,67 @@ class String {
|
||||
unsigned char concat(unsigned long num);
|
||||
unsigned char concat(float 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);
|
||||
|
||||
// if there's not enough memory for the concatenated value, the string
|
||||
// will be left unchanged (but this isn't signalled in any way)
|
||||
String & operator +=(const String &rhs) {
|
||||
String &operator +=(const String &rhs) {
|
||||
concat(rhs);
|
||||
return (*this);
|
||||
return *this;
|
||||
}
|
||||
String & operator +=(const char *cstr) {
|
||||
String &operator +=(const char *cstr) {
|
||||
concat(cstr);
|
||||
return (*this);
|
||||
return *this;
|
||||
}
|
||||
String & operator +=(char c) {
|
||||
String &operator +=(char c) {
|
||||
concat(c);
|
||||
return (*this);
|
||||
return *this;
|
||||
}
|
||||
String & operator +=(unsigned char num) {
|
||||
String &operator +=(unsigned char num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
return *this;
|
||||
}
|
||||
String & operator +=(int num) {
|
||||
String &operator +=(int num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
return *this;
|
||||
}
|
||||
String & operator +=(unsigned int num) {
|
||||
String &operator +=(unsigned int num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
return *this;
|
||||
}
|
||||
String & operator +=(long num) {
|
||||
String &operator +=(long num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
return *this;
|
||||
}
|
||||
String & operator +=(unsigned long num) {
|
||||
String &operator +=(unsigned long num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
return *this;
|
||||
}
|
||||
String & operator +=(float num) {
|
||||
String &operator +=(float num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
return *this;
|
||||
}
|
||||
String & operator +=(double num) {
|
||||
String &operator +=(double num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
return *this;
|
||||
}
|
||||
String & operator += (const __FlashStringHelper *str){
|
||||
String &operator +=(const __FlashStringHelper *str) {
|
||||
concat(str);
|
||||
return (*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, char c);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, 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, unsigned long num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, float 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 String &rhs);
|
||||
friend StringSumHelper &operator +(const StringSumHelper &lhs, const char *cstr);
|
||||
friend StringSumHelper &operator +(const StringSumHelper &lhs, char c);
|
||||
friend StringSumHelper &operator +(const StringSumHelper &lhs, unsigned char num);
|
||||
friend StringSumHelper &operator +(const StringSumHelper &lhs, 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, unsigned long num);
|
||||
friend StringSumHelper &operator +(const StringSumHelper &lhs, float num);
|
||||
friend StringSumHelper &operator +(const StringSumHelper &lhs, double num);
|
||||
friend StringSumHelper &operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
||||
|
||||
// comparison (only works w/ Strings and "strings")
|
||||
operator StringIfHelperType() const {
|
||||
@ -202,45 +207,45 @@ class String {
|
||||
unsigned char equalsIgnoreCase(const String &s) const;
|
||||
unsigned char equalsConstantTime(const String &s) 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));
|
||||
}
|
||||
unsigned char startsWith(const __FlashStringHelper * prefix) const {
|
||||
unsigned char startsWith(const __FlashStringHelper *prefix) const {
|
||||
return this->startsWith(String(prefix));
|
||||
}
|
||||
unsigned char startsWith(const String &prefix, unsigned int offset) 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));
|
||||
}
|
||||
unsigned char endsWith(const __FlashStringHelper * suffix) const {
|
||||
unsigned char endsWith(const __FlashStringHelper *suffix) const {
|
||||
return this->endsWith(String(suffix));
|
||||
}
|
||||
|
||||
// character access
|
||||
char charAt(unsigned int index) const;
|
||||
char charAt(unsigned int index) const {
|
||||
return operator [](index);
|
||||
}
|
||||
void setCharAt(unsigned int index, char c);
|
||||
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 toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const {
|
||||
getBytes((unsigned char *) buf, bufsize, index);
|
||||
}
|
||||
const char* c_str() const { return buffer(); }
|
||||
char* begin() { return wbuffer(); }
|
||||
char* end() { return wbuffer() + length(); }
|
||||
const char* begin() const { return c_str(); }
|
||||
const char* end() const { return c_str() + length(); }
|
||||
const char *c_str() const { return buffer(); }
|
||||
char *begin() { return wbuffer(); }
|
||||
char *end() { return wbuffer() + length(); }
|
||||
const char *begin() const { return c_str(); }
|
||||
const char *end() const { return c_str() + length(); }
|
||||
|
||||
// search
|
||||
int indexOf(char ch) const;
|
||||
int indexOf(char ch, unsigned int fromIndex) const;
|
||||
int indexOf(const char *str) const;
|
||||
int indexOf(const char *str, unsigned int fromIndex) const;
|
||||
int indexOf(const __FlashStringHelper *str) const;
|
||||
int indexOf(const __FlashStringHelper *str, unsigned int fromIndex) const;
|
||||
int indexOf(const String &str) const;
|
||||
int indexOf(const String &str, unsigned int fromIndex) const;
|
||||
int indexOf(char ch, unsigned int fromIndex = 0) const;
|
||||
int indexOf(const char *str, unsigned int fromIndex = 0) const;
|
||||
int indexOf(const __FlashStringHelper *str, unsigned int fromIndex = 0) const {
|
||||
return indexOf((const char*)str, fromIndex);
|
||||
}
|
||||
int indexOf(const String &str, unsigned int fromIndex = 0) const;
|
||||
int lastIndexOf(char ch) const;
|
||||
int lastIndexOf(char ch, unsigned int fromIndex) const;
|
||||
int lastIndexOf(const String &str) const;
|
||||
@ -248,29 +253,29 @@ class String {
|
||||
String substring(unsigned int beginIndex) const {
|
||||
return substring(beginIndex, len());
|
||||
}
|
||||
;
|
||||
String substring(unsigned int beginIndex, unsigned int endIndex) const;
|
||||
|
||||
// modification
|
||||
void replace(char find, char replace);
|
||||
void replace(const String& find, const String& replace);
|
||||
void replace(const char * find, const String& replace) {
|
||||
void replace(const String &find, const String &replace);
|
||||
void replace(const char *find, const String &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);
|
||||
}
|
||||
void replace(const char * find, const char * replace) {
|
||||
void replace(const char *find, const char *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));
|
||||
}
|
||||
void replace(const __FlashStringHelper * find, const __FlashStringHelper * replace) {
|
||||
void replace(const __FlashStringHelper *find, const __FlashStringHelper *replace) {
|
||||
this->replace(String(find), String(replace));
|
||||
}
|
||||
void remove(unsigned int index);
|
||||
void remove(unsigned int index, unsigned int count);
|
||||
// Pass the biggest integer if the count is not specified.
|
||||
// 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 toUpperCase(void);
|
||||
void trim(void);
|
||||
@ -278,7 +283,7 @@ class String {
|
||||
// parsing/conversion
|
||||
long toInt(void) const;
|
||||
float toFloat(void) const;
|
||||
double toDouble(void) const;
|
||||
double toDouble(void) const;
|
||||
|
||||
protected:
|
||||
// Contains the string info when we're not in SSO mode
|
||||
@ -291,8 +296,8 @@ class String {
|
||||
enum { SSOSIZE = sizeof(struct _ptr) + 4 - 1 }; // Characters to allocate space for SSO, must be 12 or more
|
||||
struct _sso {
|
||||
char buff[SSOSIZE];
|
||||
unsigned char len : 7; // Ensure only one byte is allocated by GCC for the bitfields
|
||||
unsigned char isSSO : 1;
|
||||
unsigned char len : 7; // Ensure only one byte is allocated by GCC for the bitfields
|
||||
unsigned char isHeap : 1;
|
||||
} __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
|
||||
union {
|
||||
@ -300,25 +305,47 @@ class String {
|
||||
struct _sso sso;
|
||||
};
|
||||
// Accessor functions
|
||||
inline bool isSSO() const { return sso.isSSO; }
|
||||
inline 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
|
||||
inline void setSSO(bool set) { sso.isSSO = set; }
|
||||
inline void setLen(int len) { if (isSSO()) sso.len = len; else ptr.len = len; }
|
||||
inline void setCapacity(int cap) { if (!isSSO()) ptr.cap = cap; }
|
||||
inline void setBuffer(char *buff) { if (!isSSO()) ptr.buff = buff; }
|
||||
bool isSSO() const { return !sso.isHeap; }
|
||||
unsigned int len() const { return isSSO() ? sso.len : ptr.len; }
|
||||
unsigned int capacity() const { return isSSO() ? (unsigned int)SSOSIZE - 1 : ptr.cap; } // Size of max string not including terminal NUL
|
||||
void setSSO(bool set) { sso.isHeap = !set; }
|
||||
void setLen(int len) {
|
||||
if (isSSO()) {
|
||||
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
|
||||
inline const char *buffer() const { return (const char *)(isSSO() ? sso.buff : ptr.buff); }
|
||||
inline char *wbuffer() const { return isSSO() ? const_cast<char *>(sso.buff) : ptr.buff; } // Writable version of buffer
|
||||
const char *buffer() const { return wbuffer(); }
|
||||
char *wbuffer() const { return isSSO() ? const_cast<char *>(sso.buff) : ptr.buff; } // Writable version of buffer
|
||||
|
||||
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);
|
||||
unsigned char changeBuffer(unsigned int maxStrLen);
|
||||
|
||||
// copy and move
|
||||
String & copy(const char *cstr, unsigned int length);
|
||||
String & copy(const __FlashStringHelper *pstr, unsigned int length);
|
||||
String ©(const char *cstr, unsigned int length);
|
||||
String ©(const __FlashStringHelper *pstr, unsigned int length);
|
||||
void move(String &rhs) noexcept;
|
||||
};
|
||||
|
||||
@ -354,6 +381,9 @@ class StringSumHelper: public String {
|
||||
StringSumHelper(double num) :
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(const __FlashStringHelper *s) :
|
||||
String(s) {
|
||||
}
|
||||
};
|
||||
|
||||
extern const String emptyString;
|
||||
|
Loading…
x
Reference in New Issue
Block a user