Skip to content

Commit 211606f

Browse files
authored
[WString] Reduce build size by implementing flash string calls in .cpp (#8106)
A function called with a flash string, which only has an implementation with `const String&` as argument will be compiled as if it is called with a `String` constructor wrapped around it. For example this implementation in the .h file: ```c++ bool startsWith(const __FlashStringHelper *prefix) const { return this->startsWith(String(prefix)); } ``` This is completely useless as the compiler will generate exactly the same code with or without this function implementation in the .h file. However if we move the implementation to the .cpp file, this conversion to `String` is only added once in the compiled binary. In my own project I already managed to shrink the largest (ESP32) build by more than 70k in size (!!) by just adding extra function calls with the conversion in the .cpp file. This PR is just a simple optimisation which already shrinks a very small build of my project by almost 3k in build size. (custom_beta_ESP8266_4M1M PIO env of ESPEasy) ``` Flash: [======== ] 82.5% (used 862137 bytes from 1044464 bytes) Flash: [======== ] 82.3% (used 859545 bytes from 1044464 bytes) ``` Larger builds may benefit even more.
1 parent 140d0ff commit 211606f

File tree

2 files changed

+83
-32
lines changed

2 files changed

+83
-32
lines changed

cores/esp8266/WString.cpp

+61
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,13 @@ String &String::operator =(const __FlashStringHelper *pstr) {
273273
return *this;
274274
}
275275

276+
String &String::operator =(char c) {
277+
char buffer[2] { c, '\0' };
278+
*this = buffer;
279+
return *this;
280+
}
281+
282+
276283
/*********************************************/
277284
/* concat */
278285
/*********************************************/
@@ -500,6 +507,10 @@ bool String::equals(const char *cstr) const {
500507
return strcmp(buffer(), cstr) == 0;
501508
}
502509

510+
bool String::equals(const __FlashStringHelper *s) const {
511+
return equals(String(s));
512+
}
513+
503514
bool String::operator<(const String &rhs) const {
504515
return compareTo(rhs) < 0;
505516
}
@@ -532,6 +543,10 @@ bool String::equalsIgnoreCase(const String &s2) const {
532543
return true;
533544
}
534545

546+
bool String::equalsIgnoreCase(const __FlashStringHelper *s) const {
547+
return equalsIgnoreCase(String(s));
548+
}
549+
535550
unsigned char String::equalsConstantTime(const String &s2) const {
536551
// To avoid possible time-based attacks present function
537552
// compares given strings in a constant time.
@@ -565,18 +580,37 @@ bool String::startsWith(const String &s2) const {
565580
return startsWith(s2, 0);
566581
}
567582

583+
bool String::startsWith(const char *prefix) const {
584+
return this->startsWith(String(prefix));
585+
}
586+
bool String::startsWith(const __FlashStringHelper *prefix) const {
587+
return this->startsWith(String(prefix));
588+
}
589+
568590
bool String::startsWith(const String &s2, unsigned int offset) const {
569591
if (offset > (unsigned)(len() - s2.len()) || !buffer() || !s2.buffer())
570592
return false;
571593
return strncmp(&buffer()[offset], s2.buffer(), s2.len()) == 0;
572594
}
573595

596+
bool String::startsWith(const __FlashStringHelper *prefix, unsigned int offset) const {
597+
return startsWith(String(prefix), offset);
598+
}
599+
574600
bool String::endsWith(const String &s2) const {
575601
if (len() < s2.len() || !buffer() || !s2.buffer())
576602
return false;
577603
return strcmp(&buffer()[len() - s2.len()], s2.buffer()) == 0;
578604
}
579605

606+
bool String::endsWith(const char *suffix) const {
607+
return this->endsWith(String(suffix));
608+
}
609+
bool String::endsWith(const __FlashStringHelper *suffix) const {
610+
return this->endsWith(String(suffix));
611+
}
612+
613+
580614
/*********************************************/
581615
/* Character Access */
582616
/*********************************************/
@@ -678,6 +712,15 @@ int String::lastIndexOf(const String &s2, unsigned int fromIndex) const {
678712
return found;
679713
}
680714

715+
int String::lastIndexOf(const __FlashStringHelper *str) const {
716+
return lastIndexOf(String(str));
717+
}
718+
719+
int String::lastIndexOf(const __FlashStringHelper *str, unsigned int fromIndex) const {
720+
return lastIndexOf(String(str), fromIndex);
721+
}
722+
723+
681724
String String::substring(unsigned int left, unsigned int right) const {
682725
if (left > right) {
683726
unsigned int temp = right;
@@ -756,6 +799,24 @@ void String::replace(const String &find, const String &replace) {
756799
}
757800
}
758801

802+
803+
void String::replace(const char *find, const String &replace) {
804+
this->replace(String(find), replace);
805+
}
806+
void String::replace(const __FlashStringHelper *find, const String &replace) {
807+
this->replace(String(find), replace);
808+
}
809+
void String::replace(const char *find, const char *replace) {
810+
this->replace(String(find), String(replace));
811+
}
812+
void String::replace(const __FlashStringHelper *find, const char *replace) {
813+
this->replace(String(find), String(replace));
814+
}
815+
void String::replace(const __FlashStringHelper *find, const __FlashStringHelper *replace) {
816+
this->replace(String(find), String(replace));
817+
}
818+
819+
759820
void String::remove(unsigned int index, unsigned int count) {
760821
if (index >= len()) {
761822
return;

cores/esp8266/WString.h

+22-32
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,7 @@ class String {
101101
String &operator =(const char *cstr);
102102
String &operator =(const __FlashStringHelper *str);
103103
String &operator =(String &&rval) noexcept;
104-
String &operator =(char c) {
105-
char buffer[2] { c, '\0' };
106-
*this = buffer;
107-
return *this;
108-
}
104+
String &operator =(char c);
109105

110106
// concatenate (works w/ built-in types)
111107

@@ -142,39 +138,40 @@ class String {
142138
int compareTo(const String &s) const;
143139
bool equals(const String &s) const;
144140
bool equals(const char *cstr) const;
141+
bool equals(const __FlashStringHelper *s) const;
145142
bool operator ==(const String &rhs) const {
146143
return equals(rhs);
147144
}
148145
bool operator ==(const char *cstr) const {
149146
return equals(cstr);
150147
}
148+
bool operator ==(const __FlashStringHelper *rhs) const {
149+
return equals(rhs);
150+
}
151151
bool operator !=(const String &rhs) const {
152152
return !equals(rhs);
153153
}
154154
bool operator !=(const char *cstr) const {
155155
return !equals(cstr);
156156
}
157+
bool operator !=(const __FlashStringHelper *rhs) const {
158+
return !equals(rhs);
159+
}
157160
bool operator <(const String &rhs) const;
158161
bool operator >(const String &rhs) const;
159162
bool operator <=(const String &rhs) const;
160163
bool operator >=(const String &rhs) const;
161164
bool equalsIgnoreCase(const String &s) const;
165+
bool equalsIgnoreCase(const __FlashStringHelper *s) const;
162166
unsigned char equalsConstantTime(const String &s) const;
163167
bool startsWith(const String &prefix) const;
164-
bool startsWith(const char *prefix) const {
165-
return this->startsWith(String(prefix));
166-
}
167-
bool startsWith(const __FlashStringHelper *prefix) const {
168-
return this->startsWith(String(prefix));
169-
}
168+
bool startsWith(const char *prefix) const;
169+
bool startsWith(const __FlashStringHelper *prefix) const;
170170
bool startsWith(const String &prefix, unsigned int offset) const;
171+
bool startsWith(const __FlashStringHelper *prefix, unsigned int offset) const;
171172
bool endsWith(const String &suffix) const;
172-
bool endsWith(const char *suffix) const {
173-
return this->endsWith(String(suffix));
174-
}
175-
bool endsWith(const __FlashStringHelper *suffix) const {
176-
return this->endsWith(String(suffix));
177-
}
173+
bool endsWith(const char *suffix) const;
174+
bool endsWith(const __FlashStringHelper *suffix) const;
178175

179176
// character access
180177
char charAt(unsigned int index) const {
@@ -204,6 +201,8 @@ class String {
204201
int lastIndexOf(char ch, unsigned int fromIndex) const;
205202
int lastIndexOf(const String &str) const;
206203
int lastIndexOf(const String &str, unsigned int fromIndex) const;
204+
int lastIndexOf(const __FlashStringHelper *str) const;
205+
int lastIndexOf(const __FlashStringHelper *str, unsigned int fromIndex) const;
207206
String substring(unsigned int beginIndex) const {
208207
return substring(beginIndex, len());
209208
}
@@ -212,21 +211,12 @@ class String {
212211
// modification
213212
void replace(char find, char replace);
214213
void replace(const String &find, const String &replace);
215-
void replace(const char *find, const String &replace) {
216-
this->replace(String(find), replace);
217-
}
218-
void replace(const __FlashStringHelper *find, const String &replace) {
219-
this->replace(String(find), replace);
220-
}
221-
void replace(const char *find, const char *replace) {
222-
this->replace(String(find), String(replace));
223-
}
224-
void replace(const __FlashStringHelper *find, const char *replace) {
225-
this->replace(String(find), String(replace));
226-
}
227-
void replace(const __FlashStringHelper *find, const __FlashStringHelper *replace) {
228-
this->replace(String(find), String(replace));
229-
}
214+
void replace(const char *find, const String &replace);
215+
void replace(const __FlashStringHelper *find, const String &replace);
216+
void replace(const char *find, const char *replace);
217+
void replace(const __FlashStringHelper *find, const char *replace);
218+
void replace(const __FlashStringHelper *find, const __FlashStringHelper *replace);
219+
230220
// Pass the biggest integer if the count is not specified.
231221
// The remove method below will take care of truncating it at the end of the string.
232222
void remove(unsigned int index, unsigned int count = (unsigned int)-1);

0 commit comments

Comments
 (0)