Skip to content
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

Implement P2438R2 string::substr() && #3057

Merged
merged 30 commits into from
Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b0f2401
Implement P2438R2 and (un)fix allocator propagation
frederick-vs-ja Aug 26, 2022
7b283ce
Add test files for GH-3022
frederick-vs-ja Aug 26, 2022
f623376
Add test files for P2438R2
frederick-vs-ja Aug 26, 2022
518cd1b
Add missing license
frederick-vs-ja Aug 26, 2022
e184af5
Add tests for GH-3022 and P2438R2 to list
frederick-vs-ja Aug 26, 2022
f60413d
Also test well-formedness change before/after P2438R2
frederick-vs-ja Aug 26, 2022
bd6e75e
Fix mis-formatting
frederick-vs-ja Aug 26, 2022
5ab204a
<cstddef> should be included
frederick-vs-ja Aug 26, 2022
36ca7d1
<string_view> should be included
frederick-vs-ja Aug 26, 2022
c88d4b7
Workaround for EDG's __builtin_memcmp
frederick-vs-ja Aug 26, 2022
9f0f6ed
Skip P2438R2 test for EDG
frederick-vs-ja Aug 26, 2022
28db86e
Only use workaround for EDG since C++20
frederick-vs-ja Aug 30, 2022
aa93602
Merge branch 'main' into p2438r2
StephanTLavavej Aug 30, 2022
d5fe238
Mention basic_string_view in static_assert.
StephanTLavavej Aug 30, 2022
d9f588e
Mention unqualified _BUF_SIZE.
StephanTLavavej Aug 30, 2022
7983801
_Eos() takes care of updating _Mysize.
StephanTLavavej Aug 30, 2022
5df2855
Mention new feature in yvals_core.h.
StephanTLavavej Aug 30, 2022
6b10c8b
Include <utility> for move().
StephanTLavavej Aug 30, 2022
ef33954
Style: constexpr explicit.
StephanTLavavej Aug 30, 2022
7ca2319
Typo: quiet => quite.
StephanTLavavej Aug 30, 2022
92d2ac9
Clarify static_assert messages.
StephanTLavavej Aug 30, 2022
2520e87
Extract offset/count for clarity.
StephanTLavavej Aug 30, 2022
cb643ed
Style: _Ind => _Idx.
StephanTLavavej Aug 30, 2022
53ca196
Use _STD is_constant_evaluated() in C++20 mode.
StephanTLavavej Aug 30, 2022
c6337f0
Newline between non-chained if-statements.
StephanTLavavej Aug 30, 2022
52481f5
Use direct-init.
StephanTLavavej Aug 30, 2022
198554b
Preprocessor comment nitpicks.
StephanTLavavej Aug 30, 2022
87b6012
Reported VSO-1601168.
StephanTLavavej Aug 31, 2022
3fd829e
Reported VSO-1601179.
StephanTLavavej Aug 31, 2022
4dcc0d7
Merge branch 'main' into p2438r2
StephanTLavavej Aug 31, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 82 additions & 17 deletions stl/inc/xstring
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,23 @@ public:
_In_reads_(_Count) const _Elem* const _First2, const size_t _Count) noexcept /* strengthened */ {
// compare [_First1, _First1 + _Count) with [_First2, ...)
#if _HAS_CXX17
#if _HAS_CXX20 && defined(__EDG__) // TRANSITION, EDG's __builtin_memcmp is buggy for constexpr dynamic allocation
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
if (_Is_constant_evaluated()) {
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
for (size_t _Ind = 0; _Ind != _Count; ++_Ind) {
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
if (static_cast<unsigned char>(_First1[_Ind]) < static_cast<unsigned char>(_First2[_Ind])) {
return -1;
}
if (static_cast<unsigned char>(_First2[_Ind]) < static_cast<unsigned char>(_First1[_Ind])) {
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
return 1;
}
}
return 0;
} else {
return _CSTD memcmp(_First1, _First2, _Count);
}
#else // ^^^ workaround for EDG / no workaround needed for MSVC and Clang vvv
return __builtin_memcmp(_First1, _First2, _Count);
#endif // ^^^ no workaround needed for MSVC and Clang ^^^
#else // _HAS_CXX17
return _CSTD memcmp(_First1, _First2, _Count);
#endif // _HAS_CXX17
Expand Down Expand Up @@ -606,7 +622,7 @@ constexpr size_t _Traits_find(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits>
// search [_Haystack, _Haystack + _Hay_size) for [_Needle, _Needle + _Needle_size), at/after _Start_at
if (_Needle_size > _Hay_size || _Start_at > _Hay_size - _Needle_size) {
// xpos cannot exist, report failure
// N4659 24.3.2.7.2 [string.find]/1 says:
// N4910 23.3.3.8 [string.view.find]/3 says:
// 1. _Start_at <= xpos
// 2. xpos + _Needle_size <= _Hay_size;
// therefore:
Expand Down Expand Up @@ -1200,12 +1216,12 @@ template <class _Elem, class _Traits>
class basic_string_view { // wrapper for any kind of contiguous character buffer
public:
static_assert(is_same_v<_Elem, typename _Traits::char_type>,
"Bad char_traits for basic_string_view; "
"N4659 24.4.2 [string.view.template]/1 \"the type traits::char_type shall name the same type as charT.\"");
"Bad char_traits for basic_string_view; N4910 23.3.3.1 [string.view.template.general]/1 "
"\"The program is ill-formed if traits::char_type is not the same type as charT.\"");

static_assert(!is_array_v<_Elem> && is_trivial_v<_Elem> && is_standard_layout_v<_Elem>,
"The character type of basic_string_view must be a non-array trivial standard-layout type. See N4861 "
"[strings.general]/1.");
"The character type of basic_string must be a non-array trivial standard-layout type. See N4910 "
"23.1 [strings.general]/1.");
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved

using traits_type = _Traits;
using value_type = _Elem;
Expand Down Expand Up @@ -1806,7 +1822,7 @@ struct _Get_comparison_category<_Traits, void_t<typename _Traits::comparison_cat
using type = typename _Traits::comparison_category;

static_assert(_Is_any_of_v<type, partial_ordering, weak_ordering, strong_ordering>,
"N4878 [string.view.comparison]/4: Mandates: R denotes a comparison category type.");
"N4910 23.3.5 [string.view.comparison]/4: Mandates: R denotes a comparison category type.");
};

template <class _Traits>
Expand Down Expand Up @@ -2440,12 +2456,12 @@ private:
_MISMATCHED_ALLOCATOR_MESSAGE("basic_string<T, Traits, Allocator>", "T"));

static_assert(is_same_v<_Elem, typename _Traits::char_type>,
"N4659 24.3.2.1 [string.require]/3 requires that the supplied "
"N4910 23.4.3.2 [string.require]/3 requires that the supplied "
"char_traits character type match the string's character type.");

static_assert(!is_array_v<_Elem> && is_trivial_v<_Elem> && is_standard_layout_v<_Elem>,
"The character type of basic_string must be a non-array trivial standard-layout type. See N4861 "
"[strings.general]/1.");
"The character type of basic_string must be a non-array trivial standard-layout type. See N4910 "
"23.1 [strings.general]/1.");

public:
using traits_type = _Traits;
Expand Down Expand Up @@ -2474,7 +2490,7 @@ private:
// _String_val::_Bx::_Ptr (type is pointer)
// _String_val::_Mysize (type is size_type)
// _String_val::_Myres (type is size_type)
// N4810 21.1 [strings.general]/1 says _Elem must be trivial standard-layout, so memcpy is safe.
// N4910 23.1 [strings.general]/1 says _Elem must be trivial standard-layout, so memcpy is safe.
// We need to ask if pointer is safe to memcpy.
// size_type must be an unsigned integral type so memcpy is safe.
// We also need to disable memcpy if the user has supplied _Traits, since
Expand Down Expand Up @@ -2629,6 +2645,19 @@ public:
_Right._Mypair._Myval2._Myptr() + _Roff, _Right._Mypair._Myval2._Clamp_suffix_size(_Roff, _Count));
}

#if _HAS_CXX23
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
constexpr basic_string(basic_string&& _Right, const size_type _Roff, const _Alloc& _Al = _Alloc())
: _Mypair(_One_then_variadic_args_t{}, _Al) { // construct from _Right [_Roff, <end>), potentially move
_Move_construct_from_substr(_Right, _Roff, npos, _Al);
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
}

constexpr basic_string(
basic_string&& _Right, const size_type _Roff, const size_type _Count, const _Alloc& _Al = _Alloc())
: _Mypair(_One_then_variadic_args_t{}, _Al) { // construct from _Right [_Roff, _Roff + _Count), potentially move
_Move_construct_from_substr(_Right, _Roff, _Count, _Al);
}
#endif // _HAS_CXX23

_CONSTEXPR20 basic_string(_In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count)
: _Mypair(_Zero_then_variadic_args_t{}) {
_Construct<_Construct_strategy::_From_ptr>(_Ptr, _Count);
Expand Down Expand Up @@ -3165,6 +3194,29 @@ private:
_Right._Tidy_init();
}

#if _HAS_CXX23
constexpr void _Move_construct_from_substr(
basic_string& _Right, const size_type _Roff, const size_type _Size_max, const _Alloc& _Al) {
auto& _Right_data = _Right._Mypair._Myval2;
_Right_data._Check_offset(_Roff);

const auto _Result_size = _Right_data._Clamp_suffix_size(_Roff, _Size_max);
const auto _Right_ptr = _Right_data._Myptr();
if (_Allocators_equal(_Al, _Right._Getal()) && _Result_size >= _Scary_val::_BUF_SIZE) {
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
if (_Roff != 0) {
_Traits::move(_Right_ptr, _Right_ptr + _Roff, _Result_size);
}
_Right._Eos(_Result_size);
_Right_data._Mysize = _Result_size;
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved

_Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal()));
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
_Take_contents(_Right);
} else {
_Construct<_Construct_strategy::_From_ptr>(_Right_ptr + _Roff, _Result_size);
}
}
#endif // _HAS_CXX23

public:
_CONSTEXPR20 basic_string(initializer_list<_Elem> _Ilist, const _Alloc& _Al = allocator_type())
: _Mypair(_One_then_variadic_args_t{}, _Al) {
Expand Down Expand Up @@ -4675,11 +4727,24 @@ public:
}
#endif // _HAS_CXX17

_NODISCARD _CONSTEXPR20 basic_string substr(const size_type _Off = 0, const size_type _Count = npos) const {
// return [_Off, _Off + _Count) as new string
return basic_string{*this, _Off, _Count, get_allocator()};
_NODISCARD _CONSTEXPR20 basic_string substr(const size_type _Off = 0, const size_type _Count = npos)
#if _HAS_CXX23
const&
#else
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
const
#endif // _HAS_CXX23
{
// return [_Off, _Off + _Count) as new string, default-constructing its allocator
return basic_string{*this, _Off, _Count};
}

#if _HAS_CXX23
_NODISCARD constexpr basic_string substr(const size_type _Off = 0, const size_type _Count = npos) && {
// return [_Off, _Off + _Count) as new string, potentially moving, default-constructing its allocator
return basic_string{_STD move(*this), _Off, _Count};
}
#endif // _HAS_CXX23

_CONSTEXPR20 bool _Equal(const basic_string& _Right) const noexcept {
// compare [0, size()) with _Right for equality
return _Traits_equal<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize,
Expand Down Expand Up @@ -5082,10 +5147,10 @@ _NODISCARD _CONSTEXPR20 basic_string<_Elem, _Traits, _Alloc> operator+(
basic_string<_Elem, _Traits, _Alloc>&& _Left, basic_string<_Elem, _Traits, _Alloc>&& _Right) {
#if _ITERATOR_DEBUG_LEVEL == 2
_STL_VERIFY(_STD addressof(_Left) != _STD addressof(_Right),
"You cannot concatenate the same moved string to itself. See "
"N4849 [res.on.arguments]/1.3: If a function argument binds to an rvalue reference "
"parameter, the implementation may assume that this parameter is a unique reference "
"to this argument");
"You cannot concatenate the same moved string to itself. See N4910 16.4.5.9 [res.on.arguments]/1.3: "
"If a function argument is bound to an rvalue reference parameter, the implementation may assume that "
"this parameter is a unique reference to this argument, except that the argument passed to "
"a move-assignment operator may be a reference to *this (16.4.6.15 [lib.types.movedfrom]).");
#endif // _ITERATOR_DEBUG_LEVEL == 2
return {_String_constructor_concat_tag{}, _Left, _Right};
}
Expand Down
2 changes: 2 additions & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ tests\GH_002760_syncstream_memory_leak
tests\GH_002769_handle_deque_block_pointers
tests\GH_002789_Hash_vec_Tidy
tests\GH_002989_nothrow_unwrappable
tests\GH_003022_substr_allocator
tests\LWG2597_complex_branch_cut
tests\LWG3018_shared_ptr_function
tests\LWG3121_constrained_tuple_forwarding_ctor
Expand Down Expand Up @@ -549,6 +550,7 @@ tests\P2401R0_conditional_noexcept_for_exchange
tests\P2408R5_ranges_iterators_to_classic_algorithms
tests\P2415R2_owning_view
tests\P2417R2_constexpr_bitset
tests\P2438R2_substr_rvalue
tests\P2440R1_ranges_alg_shift_left
tests\P2440R1_ranges_alg_shift_right
tests\P2440R1_ranges_numeric_iota
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/GH_003022_substr_allocator/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_matrix.lst
Loading