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:
committed by
GitHub
parent
79101213a5
commit
78a1a66e6d
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user