-
-
Notifications
You must be signed in to change notification settings - Fork 165
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
Use string views #1177
Use string views #1177
Conversation
This will make the library easier to use for std::string_view users as a LOT of explicit std::string creations are needed atm. There should be some performance improvements as well (less allocations, blablabla). This is mostly backwards compatible, but will cause issues with implicit conversions. For example, within the library itself, there were some assignments of a utility::icon to a string that would implicitly create a utility::iconhash - now it does not, and does not compile without explicitly creating the iconhash. This could be accounted for with a bit more code, or just reverting the usage of std::string_view, if it's important enough. There's also some new stuff / changes outside of just changing std::strings to std::string_views: - A new utility function for maps, dpp::utility::emplace_or_assign, which essentially is insert_or_assign but with the in-place construction that emplace offers. - All non-floating point instances of std::stoX that would take in a std::string_view have been changed to use std::from_chars. - 2 new types, dpp::membuf and dpp::imemstream, in stringops.h, which allow input streams over a raw character array, necessary for std::string_view. These are not compiled if std::ispanstream is available, which was added in C++23, as it is far superior. All instances of std::istringstream that would take in a std::string_view have been replaced to use one or the other, depending on what's available.
✅ Deploy Preview for dpp-dev ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
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.
Thanks for the contribution!
Please correct your indentation to comply with the Coding Style Standards. You're using spaces, not tabs.
@@ -78,10 +137,11 @@ inline std::string rtrim(std::string s) | |||
* @param s string to trim | |||
* @return std::string trimmed string | |||
*/ | |||
inline std::string ltrim(std::string s) | |||
inline std::string ltrim(std::string_view s) |
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.
Ditto the comment from rtrim.
/** | ||
* @brief trim from end of string (right) | ||
* | ||
* @param s String to trim | ||
* @return std::string trimmed string | ||
*/ | ||
inline std::string rtrim(std::string s) | ||
inline std::string rtrim(std::string_view s) |
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.
I don't agree with this change. You're now having to create a new string which adds more bytes (as you've now got the bytes from s
+ the bytes from s_cpy
), which now adds 16 more bytes every time you call this function. This should be left as std::string.
I'm not sure why every instance of a string parameter, plus various strings in objects must all be changed to string views. this is a huge change which is impossible to review and impossible to say what side effects it has as it changes literally every function. it's better to concentrate on one subsystem at a time doing a gradual refactor than what looks like global search and replace. string view is not a magic bullet. |
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.
far too big to review sorry
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.
So overall yes there are places that could use string_view, but blanket replacing all of them has no benefit and is even a downgrade. If someone passes a string which you convert to sv and then construct again a string, what's the benefit exactly?
We also don't need the c++23-specific features, keep in mind this is code we have to use and improve and, and making a change to something that uses c++23 if it's enabled and doesn't if not means we have to change and test both, which isn't tenable.
There are some positive changes in there but those could be in separate PRs that would be easier to review and test.
Also, be mindful of intendation changes.
if (dpp::lowercase(number_string.substr(0, 2)) == "0x") { | ||
BN_hex2bn(&ssl_bn->bn, number_string.substr(2, number_string.length() - 2).c_str()); | ||
BN_hex2bn(&ssl_bn->bn, std::string(number_string.substr(2)).c_str()); |
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.
If you construct a std::string anyways then what's the point? You now have an extra allocation when someone passes an std::string
void cluster::post_rest(const std::string &endpoint, const std::string &major_parameters, const std::string ¶meters, http_method method, const std::string &postdata, json_encode_t callback, const std::string &filename, const std::string &filecontent, const std::string &filemimetype, const std::string &protocol) { | ||
rest->post_request(std::make_unique<http_request>(endpoint + (!major_parameters.empty() ? "/" : "") + major_parameters, parameters, [endpoint, callback](http_request_completion_t rv) { | ||
void cluster::post_rest(std::string_view endpoint, std::string_view major_parameters, std::string_view parameters, http_method method, std::string_view postdata, json_encode_t callback, std::string_view filename, std::string_view filecontent, std::string_view filemimetype, std::string_view protocol) { | ||
rest->post_request(std::make_unique<http_request>(std::string(endpoint) + (!major_parameters.empty() ? "/" : "") + std::string(major_parameters), parameters, [callback](http_request_completion_t rv) { |
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.
Same thing, what's the point here of changing the parameter
@@ -349,7 +349,7 @@ void cluster::post_rest_multipart(const std::string &endpoint, const std::string | |||
file_mimetypes.push_back(data.mimetype); | |||
} | |||
|
|||
rest->post_request(std::make_unique<http_request>(endpoint + (!major_parameters.empty() ? "/" : "") + major_parameters, parameters, [endpoint, callback](http_request_completion_t rv) { | |||
rest->post_request(std::make_unique<http_request>(std::string(endpoint) + (!major_parameters.empty() ? "/" : "") + std::string(major_parameters), parameters, [callback](http_request_completion_t rv) { |
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.
Again, what's the point
@@ -62,15 +62,15 @@ void cluster::entitlements_get(snowflake user_id, const std::vector<snowflake>& | |||
|
|||
j["exclude_ended"] = exclude_ended; | |||
|
|||
rest_request_list<entitlement>(this, API_PATH "/applications", me.id.str(), "entitlements", m_get, j, callback); | |||
rest_request_list<entitlement>(this, API_PATH "/applications", me.id.str(), "entitlements", m_get, std::string(j), callback); |
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.
Again what's the point™
I'll stop commenting that because there are tens of these
{ | ||
command_info_t i; | ||
i.func = std::move(handler); | ||
i.guild_id = guild_id; | ||
i.parameters = parameters; | ||
commands[lowercase(command)] = i; | ||
|
||
std::string command_lower = lowercase(command); |
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.
This is good, could have been a separate PR
reassign(vc, _user_id, pcm, length); | ||
} | ||
|
||
voice_receive_t::voice_receive_t(discord_client* client, std::string&& raw, discord_voice_client* vc, snowflake _user_id, const uint8_t* pcm, size_t length) : event_dispatch_t(client, std::move(raw)), voice_client(vc), user_id(_user_id) { |
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.
Why? This was good for performance, what it needed was add std::move to the usage of raw
. With your change you have an extra allocation
{ | ||
addrinfo hints, *addrs; | ||
dns_cache_t::const_iterator iter; | ||
time_t now = time(nullptr); | ||
int error; | ||
bool exists = false; | ||
std::string hostname_str(hostname); |
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.
😭
const std::string https_client::get_header(std::string header_name) const { | ||
std::transform(header_name.begin(), header_name.end(), header_name.begin(), [](unsigned char c){ | ||
const std::string https_client::get_header(std::string_view header_name) const { | ||
std::string header_name_str(header_name); |
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.
Extra alloc here again
hci.hostname = url.substr(0, colon_pos); | ||
|
||
std::string_view port_str = url.substr(colon_pos + 1, url.length()); | ||
auto [_, err] = std::from_chars(port_str.data(), port_str.data() + port_str.size(), hci.port); |
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.
This is good
std::istringstream iss(s); | ||
iss >> f, iss >> t; | ||
|
||
#ifdef __cpp_lib_spanstream |
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.
This will be harder to maintain for very little benefit
Yeah, good points. I had an initial idea for this which is probably better and that I'll do instead. |
This will make the library easier to use for std::string_view users as a LOT of explicit std::string creations are needed atm. There should be some performance improvements as well (less allocations, blablabla). Tested with my own bot which is pretty complex and works 100%.
This is completely backwards compatible in my testing, with the exception of implicit conversions. For example, within the library itself, there were some assignments of a utility::icon to a string that would implicitly create a utility::iconhash - now it does not, and does not compile without explicitly creating the iconhash. With my own bot this happened with std::smatch.
There's also some new stuff / changes outside of just changing std::strings to std::string_views:
Code change checklist