1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-18 23:03:34 +03:00

Make SSO support \0s, use memmove, add test (#6155)

Supercedes #6027

Make SSO more generic by keeping track of its length explicitly,
allowing for embedded \0s to exist in the String (just like the non-SSO
ones).

Use memmove/memcpy_P when we know the length of a string to save CPU
time.

Add tests to inject \0s in a String to ensure it is still working as
designed.
This commit is contained in:
Earle F. Philhower, III
2019-06-05 08:11:53 -07:00
committed by GitHub
parent 79101213a5
commit 78a1a66e6d
3 changed files with 90 additions and 42 deletions

View File

@ -31,7 +31,7 @@
String::String(const char *cstr) {
init();
if(cstr)
if (cstr)
copy(cstr, strlen(cstr));
}
@ -136,7 +136,7 @@ inline void String::init(void) {
}
void String::invalidate(void) {
if(!sso() && wbuffer())
if(!isSSO() && wbuffer())
free(wbuffer());
init();
}
@ -154,17 +154,21 @@ unsigned char String::reserve(unsigned int size) {
unsigned char String::changeBuffer(unsigned int maxStrLen) {
// Can we use SSO here to avoid allocation?
if (maxStrLen < sizeof(sso_buf)) {
if (sso() || !buffer()) {
if (maxStrLen < sizeof(sso.buff) - 1) {
if (isSSO() || !buffer()) {
// Already using SSO, nothing to do
uint16_t oldLen = len();
setSSO(true);
setLen(oldLen);
return 1;
} else { // if bufptr && !sso()
// Using bufptr, need to shrink into sso_buff
char temp[sizeof(sso_buf)];
} else { // if bufptr && !isSSO()
// Using bufptr, need to shrink into sso.buff
char temp[sizeof(sso.buff)];
memcpy(temp, buffer(), maxStrLen);
free(wbuffer());
uint16_t oldLen = len();
setSSO(true);
setLen(oldLen);
memcpy(wbuffer(), temp, maxStrLen);
return 1;
}
@ -176,12 +180,12 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
return false;
}
uint16_t oldLen = len();
char *newbuffer = (char *) realloc(sso() ? nullptr : wbuffer(), newSize);
if(newbuffer) {
char *newbuffer = (char *) realloc(isSSO() ? nullptr : wbuffer(), newSize);
if (newbuffer) {
size_t oldSize = capacity() + 1; // include NULL.
if (sso()) {
if (isSSO()) {
// Copy the SSO buffer into allocated space
memcpy(newbuffer, sso_buf, sizeof(sso_buf));
memmove(newbuffer, sso.buff, sizeof(sso.buff));
}
if (newSize > oldSize)
{
@ -206,7 +210,7 @@ String & String::copy(const char *cstr, unsigned int length) {
return *this;
}
setLen(length);
strcpy(wbuffer(), cstr);
memmove(wbuffer(), cstr, length + 1);
return *this;
}
@ -216,7 +220,7 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) {
return *this;
}
setLen(length);
strcpy_P(wbuffer(), (PGM_P)pstr);
memcpy_P(wbuffer(), (PGM_P)pstr, length + 1); // We know wbuffer() cannot ever be in PROGMEM, so memcpy safe here
return *this;
}
@ -224,20 +228,20 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) {
void String::move(String &rhs) {
if(buffer()) {
if(capacity() >= rhs.len()) {
strcpy(wbuffer(), rhs.buffer());
memmove(wbuffer(), rhs.buffer(), rhs.length() + 1);
setLen(rhs.len());
rhs.invalidate();
return;
} else {
if (!sso()) {
if (!isSSO()) {
free(wbuffer());
setBuffer(nullptr);
}
}
}
if (rhs.sso()) {
if (rhs.isSSO()) {
setSSO(true);
memmove(sso_buf, rhs.sso_buf, sizeof(sso_buf));
memmove(sso.buff, rhs.sso.buff, sizeof(sso.buff));
} else {
setSSO(false);
setBuffer(rhs.wbuffer());
@ -309,7 +313,7 @@ unsigned char String::concat(const String &s) {
return 1;
if (!reserve(newlen))
return 0;
memcpy(wbuffer() + len(), buffer(), len());
memmove(wbuffer() + len(), buffer(), len());
setLen(newlen);
wbuffer()[len()] = 0;
return 1;
@ -326,7 +330,7 @@ unsigned char String::concat(const char *cstr, unsigned int length) {
return 1;
if(!reserve(newlen))
return 0;
strcpy(wbuffer() + len(), cstr);
memmove(wbuffer() + len(), cstr, length + 1);
setLen(newlen);
return 1;
}
@ -392,7 +396,7 @@ unsigned char String::concat(const __FlashStringHelper * str) {
if (length == 0) return 1;
unsigned int newlen = len() + length;
if (!reserve(newlen)) return 0;
strcpy_P(wbuffer() + len(), (PGM_P)str);
memcpy_P(wbuffer() + len(), (PGM_P)str, length + 1);
setLen(newlen);
return 1;
}