Skip to content

Commit 40dfff0

Browse files
WString: Optimize a bit more
* remove common subexpressions from `concat()`, `replace(const String&, const String&)`, `remove()` and `trim()` * optimize `substring()`, due to the fact that `concat(const char*, unsigned int)` accepts non-null-terminated char sequence * optimize `insert(size_t, char)`, same as the abovementioned way * optimize `replace(char, char)`, `toLowerCase()` and `toUpperCase()` by range-based `for` loop, due to the fact that `end()` also returns `nullptr` when `begin()` returns `nullptr` * mark `length()`, `setCharAt()`, `operator[]`, `end()` and `replace(char, char)` as `__attribute__((flatten))` that inlines their bodies completely and performs more aggressive optimizations * eliminate unneeded truncation-to-16bit-op `extui Ay,Ax,0,16` in `changeBuffer()` by replacing `uint16_t` with `unsigned int` * make `setLen()` implicit null-terminating (as per espressif/arduino-esp32@22a488c), and rearrange to eliminate explicit null-termination around calling `setLen()` * move some of function bodies in '.h', which their functions call ctor from inside of, to '.cpp' (@TD-er's suggestion) "FSBrowser" building result indicates savings 224 bytes of IROM. [before] IROM : 313468 IRAM : 26957 DATA : 1516 RODATA : 1612 BSS : 26136 [after] IROM : 313244 IRAM : 26957 DATA : 1516 RODATA : 1612 BSS : 26136
1 parent 60fe7b4 commit 40dfff0

File tree

2 files changed

+108
-108
lines changed

2 files changed

+108
-108
lines changed

cores/esp8266/WString.cpp

+87-72
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,8 @@ void String::invalidate(void) {
150150
bool String::reserve(unsigned int size) {
151151
if (buffer() && capacity() >= size)
152152
return true;
153-
if (changeBuffer(size)) {
154-
if (len() == 0)
155-
wbuffer()[0] = 0;
153+
if (changeBuffer(size))
156154
return true;
157-
}
158155
return false;
159156
}
160157

@@ -163,17 +160,17 @@ bool String::changeBuffer(unsigned int maxStrLen) {
163160
if (maxStrLen < sizeof(sso.buff) - 1) {
164161
if (isSSO() || !buffer()) {
165162
// Already using SSO, nothing to do
166-
uint16_t oldLen = len();
163+
unsigned int oldLen = len();
167164
setSSO(true);
168165
setLen(oldLen);
169166
} else { // if bufptr && !isSSO()
170167
// Using bufptr, need to shrink into sso.buff
171168
const char *temp = buffer();
172-
uint16_t oldLen = len();
169+
unsigned int oldLen = len();
173170
setSSO(true);
174-
setLen(oldLen);
175171
memcpy(wbuffer(), temp, maxStrLen);
176172
free((void *)temp);
173+
setLen(oldLen);
177174
}
178175
return true;
179176
}
@@ -191,7 +188,7 @@ bool String::changeBuffer(unsigned int maxStrLen) {
191188
if (newSize > CAPACITY_MAX) {
192189
return false;
193190
}
194-
uint16_t oldLen = len();
191+
unsigned int oldLen = len();
195192
char *newbuffer = (char *)realloc(isSSO() ? nullptr : wbuffer(), newSize);
196193
if (newbuffer) {
197194
size_t oldSize = capacity() + 1; // include NULL.
@@ -220,8 +217,8 @@ String &String::copy(const char *cstr, unsigned int length) {
220217
invalidate();
221218
return *this;
222219
}
220+
memmove_P(wbuffer(), cstr, length);
223221
setLen(length);
224-
memmove_P(wbuffer(), cstr, length + 1);
225222
return *this;
226223
}
227224

@@ -230,8 +227,8 @@ String &String::copy(const __FlashStringHelper *pstr, unsigned int length) {
230227
invalidate();
231228
return *this;
232229
}
230+
memcpy_P(wbuffer(), (PGM_P)pstr, length); // We know wbuffer() cannot ever be in PROGMEM, so memcpy safe here
233231
setLen(length);
234-
memcpy_P(wbuffer(), (PGM_P)pstr, length + 1); // We know wbuffer() cannot ever be in PROGMEM, so memcpy safe here
235232
return *this;
236233
}
237234

@@ -282,15 +279,15 @@ bool String::concat(const String &s) {
282279
// realloc'ing the buffer and moving s.buffer in the method called
283280
if (&s == this) {
284281
unsigned int newlen = 2 * len();
285-
if (!s.buffer())
282+
if (!buffer())
286283
return false;
287-
if (s.len() == 0)
284+
if (len() == 0)
288285
return true;
289286
if (!reserve(newlen))
290287
return false;
291-
memmove_P(wbuffer() + len(), buffer(), len());
288+
char *writeTo = wbuffer();
289+
memmove_P(writeTo + len(), writeTo, len());
292290
setLen(newlen);
293-
wbuffer()[newlen] = 0;
294291
return true;
295292
} else {
296293
return concat(s.buffer(), s.len());
@@ -305,9 +302,8 @@ bool String::concat(const char *cstr, unsigned int length) {
305302
return true;
306303
if (!reserve(newlen))
307304
return false;
308-
memmove_P(wbuffer() + len(), cstr, length + 1);
305+
memmove_P(wbuffer() + len(), cstr, length);
309306
setLen(newlen);
310-
wbuffer()[newlen] = 0;
311307
return true;
312308
}
313309

@@ -371,15 +367,14 @@ bool String::concat(double num) {
371367
}
372368

373369
bool String::concat(const __FlashStringHelper *str) {
370+
unsigned int length = strlen_P((PGM_P)str), newlen = len() + length;
374371
if (!str)
375372
return false;
376-
int length = strlen_P((PGM_P)str);
377373
if (length == 0)
378374
return true;
379-
unsigned int newlen = len() + length;
380375
if (!reserve(newlen))
381376
return false;
382-
memcpy_P(wbuffer() + len(), (PGM_P)str, length + 1);
377+
memcpy_P(wbuffer() + len(), (PGM_P)str, length);
383378
setLen(newlen);
384379
return true;
385380
}
@@ -398,12 +393,10 @@ String &String::insert(size_t position, const char *other, size_t other_length)
398393
return *this;
399394

400395
auto left = len - position;
401-
setLen(total);
402-
403396
auto *start = wbuffer() + position;
404397
memmove(start + other_length, start, left);
405398
memmove_P(start, other, other_length);
406-
wbuffer()[total] = '\0';
399+
setLen(total);
407400

408401
return *this;
409402
}
@@ -414,8 +407,7 @@ String &String::insert(size_t position, const __FlashStringHelper *other) {
414407
}
415408

416409
String &String::insert(size_t position, char other) {
417-
char tmp[2] { other, '\0' };
418-
return insert(position, tmp, 1);
410+
return insert(position, &other, 1);
419411
}
420412

421413
String &String::insert(size_t position, const char *other) {
@@ -565,6 +557,14 @@ bool String::startsWith(const String &s2) const {
565557
return startsWith(s2, 0);
566558
}
567559

560+
bool String::startsWith(const char *prefix) const {
561+
return this->startsWith(String(prefix));
562+
}
563+
564+
bool String::startsWith(const __FlashStringHelper *prefix) const {
565+
return this->startsWith(String(prefix));
566+
}
567+
568568
bool String::startsWith(const String &s2, unsigned int offset) const {
569569
if (offset > (unsigned)(len() - s2.len()) || !buffer() || !s2.buffer())
570570
return false;
@@ -577,6 +577,14 @@ bool String::endsWith(const String &s2) const {
577577
return strcmp(&buffer()[len() - s2.len()], s2.buffer()) == 0;
578578
}
579579

580+
bool String::endsWith(const char *suffix) const {
581+
return this->endsWith(String(suffix));
582+
}
583+
584+
bool String::endsWith(const __FlashStringHelper *suffix) const {
585+
return this->endsWith(String(suffix));
586+
}
587+
580588
/*********************************************/
581589
/* Character Access */
582590
/*********************************************/
@@ -684,16 +692,12 @@ String String::substring(unsigned int left, unsigned int right) const {
684692
right = left;
685693
left = temp;
686694
}
687-
String out;
688-
if (left >= len())
689-
return out;
695+
if (left > len())
696+
left = len();
690697
if (right > len())
691698
right = len();
692-
char *writeTo = wbuffer();
693-
char tempchar = writeTo[right]; // save the replaced character
694-
writeTo[right] = '\0';
695-
out = writeTo + left; // pointer arithmetic
696-
writeTo[right] = tempchar; // restore character
699+
String out;
700+
out.concat(buffer() + left, right - left);
697701
return out;
698702
}
699703

@@ -702,41 +706,41 @@ String String::substring(unsigned int left, unsigned int right) const {
702706
/*********************************************/
703707

704708
void String::replace(char find, char replace) {
705-
if (!buffer())
706-
return;
707-
for (char *p = wbuffer(); *p; p++) {
708-
if (*p == find)
709-
*p = replace;
709+
for (auto &c : *this) {
710+
if (c == find)
711+
c = replace;
710712
}
711713
}
712714

713715
void String::replace(const String &find, const String &replace) {
714-
if (len() == 0 || find.len() == 0)
716+
unsigned int find_len = find.len(), replace_len = replace.len();
717+
const char *find_buffer = find.buffer(), *replace_buffer = replace.buffer();
718+
if (len() == 0 || find_len == 0)
715719
return;
716-
int diff = replace.len() - find.len();
720+
int diff = replace_len - find_len;
717721
char *readFrom = wbuffer();
718722
char *foundAt;
719723
if (diff == 0) {
720-
while ((foundAt = strstr(readFrom, find.buffer())) != NULL) {
721-
memmove_P(foundAt, replace.buffer(), replace.len());
722-
readFrom = foundAt + replace.len();
724+
while ((foundAt = strstr(readFrom, find_buffer)) != NULL) {
725+
memmove_P(foundAt, replace_buffer, replace_len);
726+
readFrom = foundAt + replace_len;
723727
}
724728
} else if (diff < 0) {
725729
char *writeTo = wbuffer();
726-
while ((foundAt = strstr(readFrom, find.buffer())) != NULL) {
730+
while ((foundAt = strstr(readFrom, find_buffer)) != NULL) {
727731
unsigned int n = foundAt - readFrom;
728732
memmove_P(writeTo, readFrom, n);
729733
writeTo += n;
730-
memmove_P(writeTo, replace.buffer(), replace.len());
731-
writeTo += replace.len();
732-
readFrom = foundAt + find.len();
734+
memmove_P(writeTo, replace_buffer, replace_len);
735+
writeTo += replace_len;
736+
readFrom = foundAt + find_len;
733737
setLen(len() + diff);
734738
}
735739
memmove_P(writeTo, readFrom, strlen(readFrom) + 1);
736740
} else {
737741
unsigned int size = len(); // compute size needed for result
738-
while ((foundAt = strstr(readFrom, find.buffer())) != NULL) {
739-
readFrom = foundAt + find.len();
742+
while ((foundAt = strstr(readFrom, find_buffer)) != NULL) {
743+
readFrom = foundAt + find_len;
740744
size += diff;
741745
}
742746
if (size == len())
@@ -745,64 +749,75 @@ void String::replace(const String &find, const String &replace) {
745749
return; // XXX: tell user!
746750
int index = len() - 1;
747751
while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) {
748-
readFrom = wbuffer() + index + find.len();
752+
readFrom = wbuffer() + index + find_len;
749753
memmove_P(readFrom + diff, readFrom, len() - (readFrom - buffer()));
750754
int newLen = len() + diff;
751-
memmove_P(wbuffer() + index, replace.buffer(), replace.len());
755+
memmove_P(wbuffer() + index, replace_buffer, replace_len);
752756
setLen(newLen);
753-
wbuffer()[newLen] = 0;
754757
index--;
755758
}
756759
}
757760
}
758761

762+
void String::replace(const char *find, const String &replace) {
763+
this->replace(String(find), replace);
764+
}
765+
766+
void String::replace(const __FlashStringHelper *find, const String &replace) {
767+
this->replace(String(find), replace);
768+
}
769+
770+
void String::replace(const char *find, const char *replace) {
771+
this->replace(String(find), String(replace));
772+
}
773+
774+
void String::replace(const __FlashStringHelper *find, const char *replace) {
775+
this->replace(String(find), String(replace));
776+
}
777+
778+
void String::replace(const __FlashStringHelper *find, const __FlashStringHelper *replace) {
779+
this->replace(String(find), String(replace));
780+
}
781+
759782
void String::remove(unsigned int index, unsigned int count) {
760-
if (index >= len()) {
761-
return;
762-
}
763-
if (count <= 0) {
783+
if (count == 0 || index >= len()) {
764784
return;
765785
}
766786
if (count > len() - index) {
767787
count = len() - index;
768788
}
769-
char *writeTo = wbuffer() + index;
770789
unsigned int newlen = len() - count;
790+
char *writeTo = wbuffer();
791+
memmove_P(writeTo + index, writeTo + index + count, newlen - index);
771792
setLen(newlen);
772-
memmove_P(writeTo, wbuffer() + index + count, newlen - index);
773-
wbuffer()[newlen] = 0;
774793
}
775794

776795
void String::toLowerCase(void) {
777-
if (!buffer())
778-
return;
779-
for (char *p = wbuffer(); *p; p++) {
780-
*p = tolower(*p);
796+
for (auto &c : *this) {
797+
c = tolower(c);
781798
}
782799
}
783800

784801
void String::toUpperCase(void) {
785-
if (!buffer())
786-
return;
787-
for (char *p = wbuffer(); *p; p++) {
788-
*p = toupper(*p);
802+
for (auto &c : *this) {
803+
c = toupper(c);
789804
}
790805
}
791806

792807
void String::trim(void) {
793-
if (!buffer() || len() == 0)
808+
char *writeTo = wbuffer();
809+
if (!writeTo || len() == 0)
794810
return;
795-
char *begin = wbuffer();
811+
char *begin = writeTo;
796812
while (isspace(*begin))
797813
begin++;
798-
char *end = wbuffer() + len() - 1;
814+
char *end = writeTo + len() - 1;
799815
while (isspace(*end) && end >= begin)
800816
end--;
801817
unsigned int newlen = end + 1 - begin;
818+
if (begin > writeTo)
819+
memmove_P(writeTo, begin, newlen);
802820
setLen(newlen);
803-
if (begin > buffer())
804-
memmove_P(wbuffer(), begin, newlen);
805-
wbuffer()[newlen] = 0;
806821
}
807822

808823
/*********************************************/

0 commit comments

Comments
 (0)