operator+ currently calls __init. This patch removes the usage of implementation details.
Details
- Reviewers
ldionne Mordante - Group Reviewers
Restricted Project - Commits
- rG732920d847e5: [libc++] Remove the usage of __init in operator+
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
libcxx/include/string | ||
---|---|---|
4180–4189 | IMO this makes a lot more sense. However, I'm going to push the reasoning further and ask this: Would this *also* be equivalent? using _String = basic_string<_CharT, _Traits, _Allocator>; typename _String::size_type __lhs_sz = __lhs.size(); typename _String::size_type __rhs_sz = __rhs.size(); _String __r(_String::__alloc_traits::select_on_container_copy_construction(__lhs.get_allocator())); __r.reserve(__lhs_sz + __rhs_sz); __r.append(__lhs.data(), __lhs_sz); __r.append(__rhs.data(), __rhs_sz); return __r; If so, then perhaps we don't really need the constructor after all? |
libcxx/include/string | ||
---|---|---|
4180–4189 | It think this is equivalent for runtime. For constant evaluation the constructor saves an allocation, but I don't think we care enough about that to add a new constructor. |
We just looked at the codegen for the current code and the reserve-based version, and the reserve-based version ends up calling reserve, append and push_back separately, whereas the old version is simpler (it calls operator new and memcpy directly): https://godbolt.org/z/EWs78arre. I think this is due to the fact that the old version (with __init) can assume that we don't have any constructed state before, so it doesn't need to be as complicated. Also, push_back is exported in the dylib (which is a strange choice IMO since we ought to have a fast path). Can you run a quick benchmark to see if there's a noticeable difference? If so, we could go with this patch but also try to provide a fast path for push_back (which is probably a good idea regardless).
The old constructor style was a bit slower than the __init approach. The new one is significantly faster.
Here is the benchmark:
libcxx/include/string | ||
---|---|---|
751 | Let's make it explicit. Can you also add a comment documenting what this constructor does? Something like: // Construct a string with the given allocator and enough storage to hold `__size` characters, but // don't initialize the characters. The contents of the string, including the null terminator, must be // initialized separately. | |
753 | We need to handle the case where __size > max_size() like we used to in __init. | |
4205 | This would need to be value_type() instead of '\0'. We support non-char character types as well. |
Let's make it explicit.
Can you also add a comment documenting what this constructor does? Something like: