-
Notifications
You must be signed in to change notification settings - Fork 13.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WString: Optimize a bit more #7758
Conversation
btw, any idea why string has this helper? Looking at some string implementations like std::string or folly::fbstring, both use the original class |
it's for optimization of String addition, i understand. GCC recognizes such a phrase:
and will convert to:
|
Ah. I guess it's another case of pre-c++11 code? I tried a small test removing Helper and replacing it with: String operator+(const String& lhs, const String& rhs);
String operator+(String&& lhs, const String& rhs);
String operator+(const String& lhs, String&& rhs);
String operator+(String&& lhs, String&& rhs);
String operator+(const String& lhs, const char* rhs);
String operator+(String&& lhs, const char* rhs); (raw mcve patch here -> https://gist.github.com/mcspr/aab2d925b20af22282ee0959b840d3e1) Which seems to do the same thing - chained things avoid allocation, using moveable objects as temporaries. I'll test a bit more during the week to make it into something looking like a PR (which hopefully does not include all of 'concat(numeric type)' overrides...) |
thx for reply @mcspr, so looking forward to it :) |
cores/esp8266/WString.h
Outdated
@@ -388,7 +388,8 @@ class StringSumHelper: public String { | |||
} | |||
}; | |||
|
|||
extern const String emptyString; | |||
// global empty string to allow returning const String& with nothing | |||
inline const String emptyString; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this fix or improve?
be3df03
to
befd376
Compare
Just another request for optimization: unsigned char startsWith(const char *prefix) const { return this->startsWith(String(prefix)); }
unsigned char startsWith(const __FlashStringHelper *prefix) const { return this->startsWith(String(prefix)); } And for a few more basic functions. (e.g. So please implement this in the .cpp to reduce binary size. |
* 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
7f2ec01
to
40dfff0
Compare
I have spent quite a lot of time on my own project to prevent lots of casts to But there is still a lot to gain as a lot of compares like unsigned char operator ==(const __FlashStringHelper *fstr) const;
unsigned char String::operator ==(const __FlashStringHelper *fstr) const {
return equals(fstr);
} There isn't a version of Just to give an example of what is implemented for the unsigned char startsWith(const __FlashStringHelper * prefix) const {
return this->startsWith(String(prefix));
} Since it is implemented in the .h file, it is rather useless as it does generate the same (inline) code as the compiler would if only the function existed with @earlephilhower What do you think of such optimizations? |
ptr.len = len; | ||
ptr.buff[len] = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't there be a check to see if ptr.buff[len]
is allocated?
If allocation failed, ptr.buff may not be allocated at all, or not being the expected size.
Not sure if it may happen at all in all occurences where setLen
is called, but maybe best to at least have a check here to see if buff
isn't a nullptr. (and maybe only allow to reduce the value)
closing because outdated. |
concat()
,replace(const String&, const String&)
,remove()
andtrim()
substring()
, due to the fact thatconcat(const char*, unsigned int)
accepts non-null-terminated char sequenceinsert(size_t, char)
, same as the abovementioned wayreplace(char, char)
,toLowerCase()
andtoUpperCase()
by range-basedfor
loop, due to the fact thatend()
also returnsnullptr
whenbegin()
returnsnullptr
length()
,setCharAt()
,operator[]
,end()
andreplace(char, char)
as__attribute__((flatten))
that inlines their bodies completely and performs more aggressive optimizationsextui Ay,Ax,0,16
inchangeBuffer()
by replacinguint16_t
withunsigned int
setLen()
implicit null-terminating (as per espressif/arduino-esp32@22a488c), and rearrange to eliminate explicit null-termination around callingsetLen()
"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