-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Implement LWG-3662 string::append/assign(NTBS, pos, n) should not construct a temporary string #6235
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
base: main
Are you sure you want to change the base?
Implement LWG-3662 string::append/assign(NTBS, pos, n) should not construct a temporary string #6235
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1556,6 +1556,16 @@ public: | |
| } | ||
| #endif // _HAS_CXX17 | ||
|
|
||
| _CONSTEXPR20 basic_string& append( | ||
| _In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off, _CRT_GUARDOVERFLOW const size_type _Count) { | ||
| // append(string_view(_Ptr).substr(_Off, _Count)) | ||
| const size_type _Length = _Convert_size<size_type>(_Traits::length(_Ptr)); | ||
| if (_Off > _Length) { | ||
| _Scary_val::_Xran(); | ||
| } | ||
| return _Append(_Ptr + _Off, (_STD min) (_Length - _Off, _Count)); | ||
| } | ||
|
Comment on lines
+1559
to
+1567
|
||
|
|
||
| _CONSTEXPR20 basic_string& append( | ||
| _In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) { | ||
| // append [_Ptr, _Ptr + _Count) | ||
|
|
@@ -1645,6 +1655,16 @@ public: | |
| } | ||
| #endif // _HAS_CXX17 | ||
|
|
||
| _CONSTEXPR20 basic_string& assign( | ||
| _In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off, _CRT_GUARDOVERFLOW const size_type _Count) { | ||
| // assign(string_view(_Ptr).substr(_Off, _Count)) | ||
| const size_type _Length = _Convert_size<size_type>(_Traits::length(_Ptr)); | ||
| if (_Off > _Length) { | ||
| _Scary_val::_Xran(); | ||
| } | ||
| return _Assign(_Ptr + _Off, (_STD min) (_Length - _Off, _Count)); | ||
| } | ||
|
|
||
| _CONSTEXPR20 basic_string& assign( | ||
| _In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) { | ||
| // assign [_Ptr, _Ptr + _Count) | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -103,6 +103,50 @@ void test_shrink_to_fit() { | |||||||||||||
| assert(example == longerStr); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| template <typename T = char> | ||||||||||||||
| struct CharAllocator { | ||||||||||||||
| using value_type = T; | ||||||||||||||
|
|
||||||||||||||
| CharAllocator() = delete; | ||||||||||||||
| explicit CharAllocator(int) noexcept {} | ||||||||||||||
| template <typename U> | ||||||||||||||
| CharAllocator(const CharAllocator<U>&) noexcept {} | ||||||||||||||
|
|
||||||||||||||
| T* allocate(std::size_t n) { | ||||||||||||||
| return new T[n]; | ||||||||||||||
| } | ||||||||||||||
| void deallocate(T* p, std::size_t) noexcept { | ||||||||||||||
| delete[] p; | ||||||||||||||
| } | ||||||||||||||
| }; | ||||||||||||||
|
|
||||||||||||||
| void test_LWG3662() { | ||||||||||||||
| // append/assign(NTBS, pos, n) should not construct a temporary string | ||||||||||||||
| basic_string<char, char_traits<char>, CharAllocator<char>> s(CharAllocator<char>(0)); | ||||||||||||||
|
|
||||||||||||||
| s.append("hello", 1, 3); | ||||||||||||||
| assert(s == "ell"); | ||||||||||||||
| s.assign("world", 1, 3); | ||||||||||||||
| assert(s == "orl"); | ||||||||||||||
|
|
||||||||||||||
| s.clear(); | ||||||||||||||
|
|
||||||||||||||
| try { | ||||||||||||||
| s.append("hello", 10, 1); | ||||||||||||||
| puts("append with out-of-range position should throw"); | ||||||||||||||
| abort(); | ||||||||||||||
| } catch (const out_of_range&) { | ||||||||||||||
| // purposely do nothing on out_of_range | ||||||||||||||
| } | ||||||||||||||
| try { | ||||||||||||||
| s.assign("world", 10, 1); | ||||||||||||||
| puts("assign with out-of-range position should throw"); | ||||||||||||||
| abort(); | ||||||||||||||
| } catch (const out_of_range&) { | ||||||||||||||
| // purposely do nothing on out_of_range | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| int main() { | ||||||||||||||
| // Plain replacements with shrinking / same size / growing | ||||||||||||||
| test_replace(3, 3, "ab", "012ab6789"); | ||||||||||||||
|
|
@@ -142,4 +186,5 @@ int main() { | |||||||||||||
|
|
||||||||||||||
| test_index_boundary_cases(); | ||||||||||||||
| test_shrink_to_fit(); | ||||||||||||||
| test_LWG3662(); | ||||||||||||||
|
Comment on lines
188
to
+189
|
||||||||||||||
| test_shrink_to_fit(); | |
| test_LWG3662(); | |
| test_shrink_to_fit(); | |
| #if _HAS_CXX23 | |
| test_LWG3662(); | |
| #endif // _HAS_CXX23 |
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.
Nope. These overloads should be added to C++14 mode (the earliest mode we support),
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.
The SAL annotation
_In_reads_(_Count)is inaccurate for this NTBS overload because the implementation calls_Traits::length(_Ptr)(reads until null terminator, potentially beyond_Count) and then appends only a clamped subrange. For consistency with other NTBS-taking overloads in this file (e.g.append(_In_z_ const _Elem*)), this should be annotated as_In_z_(and similarly forassign).This issue also appears on line 1658 of the same file.