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)];
@ -118,20 +110,10 @@ 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());
@ -157,24 +139,22 @@ 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);
@ -184,8 +164,7 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
// 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);
@ -230,12 +209,10 @@ void String::move(String &rhs) noexcept {
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;
} }
@ -245,26 +222,19 @@ String & String::operator =(String &&rval) noexcept {
return *this; 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) 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) {
@ -362,11 +326,14 @@ unsigned char String::concat(double num) {
} }
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;
@ -446,8 +413,7 @@ StringSumHelper & operator +(const StringSumHelper &lhs, double num) {
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();
@ -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;
@ -562,10 +528,6 @@ 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;
@ -604,10 +566,6 @@ 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;
@ -617,18 +575,6 @@ int String::indexOf(char ch, unsigned int fromIndex) const {
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;
} }
@ -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,24 +74,22 @@ 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;
} }
} void clear(void) {
inline void clear(void) {
setLen(0); setLen(0);
} }
inline bool isEmpty(void) const { bool isEmpty(void) const {
return length() == 0; return length() == 0;
} }
@ -97,7 +100,9 @@ class String {
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)
@ -121,47 +126,47 @@ class 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);
@ -218,7 +223,9 @@ class String {
} }
// 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);
@ -233,14 +240,12 @@ class String {
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,7 +253,6 @@ 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
@ -269,8 +273,9 @@ class String {
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);
@ -292,7 +297,7 @@ class String {
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,19 +305,41 @@ 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);
@ -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;