Use StringView and Span in Player#2293
Conversation
e61c30e to
af8c97b
Compare
|
Here are performance numbers for with with So 30% of the time in this function was being spent just allocating and freeing temporary arrays. |
Eliminates string copies in the replacement set
Eliminates memory allocations from temporary vectors
This makes WordWrap function zero-copy internally
|
Played some rm2k games with the battle system testing the changes to wordwrap and replaceplaceholders. Everything seem fine. |
Ghabry
left a comment
There was a problem hiding this comment.
Also have to learn about span, never used them before.
| * @return The async request. | ||
| */ | ||
| FileRequestAsync* RequestFile(const std::string& folder_name, const std::string& file_name); | ||
| FileRequestAsync* RequestFile(StringView folder_name, StringView file_name); |
There was a problem hiding this comment.
Question: So, a string view is always used when the target function does not take ownership on the string?
There was a problem hiding this comment.
I wish I could tell you yes, replace all const std::string& with StringView. Unfortunately this is C++ so there is always one big caveat.
StringView is not null terminated, so if at the end of your call stack you end up calling a C library which requires null terminated const char*, you'll end up having to make a copy so you can get a new string with a null byte at the end.
Aside from that caveat, yes use StringView where-ever you need a non-owning reference. Not only is it a generic adapter but the calling convention used is faster (see below).
Span does not have this caveat, fortunately so you can use it anywhere you'd pass a vector by reference.
Performance Note
const string& if you think about it in C terms, is essentially a double pointer const char**. The reference is a pointer to the string object, which contains another pointer to the bytes.
When you pass a StringView you're passing a const char*, removing one level of indirection. In some cases this can help the optimizer with it's aliasing analysis to produce faster code.
The same rule applies to vector and Span.
src/cache.cpp
Outdated
| std::string MakeHashKey(const std::string& folder_name, const std::string& filename, bool transparent) { | ||
| return folder_name + ":" + filename + ":" + (transparent ? "T" : " "); | ||
| std::string MakeHashKey(StringView folder_name, StringView filename, bool transparent) { | ||
| return std::string(folder_name) + ":" + std::string(filename) + ":" + (transparent ? "T" : " "); |
There was a problem hiding this comment.
Question: Couldn't you also use ToString() here instead of std::string(). Does it make a difference?
There was a problem hiding this comment.
Ahh this was from the other PR before I added ToString. Will fix.
They do the same thing in this case, but ToString is easier to grep for.
| {'V', 'U'}, | ||
| {std::to_string(exp), lcf::Data::terms.exp_short} | ||
| Utils::MakeArray('V', 'U'), | ||
| Utils::MakeSvArray(std::to_string(exp), lcf::Data::terms.exp_short) |
There was a problem hiding this comment.
Question: What's the advantage of using Make*()?
There was a problem hiding this comment.
So I don't have to say std::array<char,2>('V', 'U')
This was actually supposed to go in the standard library, but they dropped it after adding deduction guides in C++17.
Depends on: EasyRPG/liblcf#384
This adds StringView in many places to make code generic to different string types.
Utils::ReplacePlaceholdershas been greatly optimizing by removing all unnecessary copies from it's interface.