diff --git a/stl/inc/xstring b/stl/inc/xstring index 36cef22456a..c2b33415d94 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -1499,6 +1499,20 @@ public: } #endif // _HAS_CXX20 +#if _HAS_CXX23 + _NODISCARD constexpr bool contains(const basic_string_view _Right) const noexcept { + return find(_Right) != npos; + } + + _NODISCARD constexpr bool contains(const _Elem _Right) const noexcept { + return find(_Right) != npos; + } + + _NODISCARD constexpr bool contains(const _Elem* const _Right) const noexcept /* strengthened */ { + return find(_Right) != npos; + } +#endif // _HAS_CXX23 + _NODISCARD constexpr size_type find(const basic_string_view _Right, const size_type _Off = 0) const noexcept { // look for _Right beginning at or after _Off return _Traits_find<_Traits>(_Mydata, _Mysize, _Off, _Right._Mydata, _Right._Mysize); @@ -3854,7 +3868,7 @@ public: #if _HAS_CXX17 /* implicit */ _CONSTEXPR20_CONTAINER operator basic_string_view<_Elem, _Traits>() const noexcept { // return a string_view around *this's character-type sequence - return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize); + return basic_string_view<_Elem, _Traits>{_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize}; } #endif // _HAS_CXX17 @@ -4454,30 +4468,44 @@ public: #if _HAS_CXX20 _NODISCARD _CONSTEXPR20_CONTAINER bool starts_with(const basic_string_view<_Elem, _Traits> _Right) const noexcept { - return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).starts_with(_Right); + return basic_string_view<_Elem, _Traits>{_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize}.starts_with(_Right); } _NODISCARD _CONSTEXPR20_CONTAINER bool starts_with(const _Elem _Right) const noexcept { - return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).starts_with(_Right); + return basic_string_view<_Elem, _Traits>{_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize}.starts_with(_Right); } _NODISCARD _CONSTEXPR20_CONTAINER bool starts_with(const _Elem* const _Right) const noexcept /* strengthened */ { - return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).starts_with(_Right); + return basic_string_view<_Elem, _Traits>{_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize}.starts_with(_Right); } _NODISCARD _CONSTEXPR20_CONTAINER bool ends_with(const basic_string_view<_Elem, _Traits> _Right) const noexcept { - return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).ends_with(_Right); + return basic_string_view<_Elem, _Traits>{_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize}.ends_with(_Right); } _NODISCARD _CONSTEXPR20_CONTAINER bool ends_with(const _Elem _Right) const noexcept { - return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).ends_with(_Right); + return basic_string_view<_Elem, _Traits>{_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize}.ends_with(_Right); } _NODISCARD _CONSTEXPR20_CONTAINER bool ends_with(const _Elem* const _Right) const noexcept /* strengthened */ { - return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).ends_with(_Right); + return basic_string_view<_Elem, _Traits>{_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize}.ends_with(_Right); } #endif // _HAS_CXX20 +#if _HAS_CXX23 + _NODISCARD _CONSTEXPR20_CONTAINER bool contains(const basic_string_view<_Elem, _Traits> _Right) const noexcept { + return basic_string_view<_Elem, _Traits>{_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize}.contains(_Right); + } + + _NODISCARD _CONSTEXPR20_CONTAINER bool contains(const _Elem _Right) const noexcept { + return basic_string_view<_Elem, _Traits>{_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize}.contains(_Right); + } + + _NODISCARD _CONSTEXPR20_CONTAINER bool contains(const _Elem* const _Right) const noexcept /* strengthened */ { + return basic_string_view<_Elem, _Traits>{_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize}.contains(_Right); + } +#endif // _HAS_CXX23 + _NODISCARD _CONSTEXPR20_CONTAINER allocator_type get_allocator() const noexcept { return static_cast(_Getal()); } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 66a66b4464a..4a7b474bd97 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -257,6 +257,7 @@ // _HAS_CXX23 directly controls: // P1048R1 is_scoped_enum +// P1679R3 contains() For basic_string/basic_string_view // Parallel Algorithms Notes // C++ allows an implementation to implement parallel algorithms as calls to the serial algorithms. @@ -1340,7 +1341,8 @@ // C++23 #if _HAS_CXX23 -#define __cpp_lib_is_scoped_enum 202011L +#define __cpp_lib_is_scoped_enum 202011L +#define __cpp_lib_string_contains 202011L #endif // _HAS_CXX23 // EXPERIMENTAL diff --git a/tests/std/tests/P0220R1_string_view/test.cpp b/tests/std/tests/P0220R1_string_view/test.cpp index 3e611eef4d1..da27c381475 100644 --- a/tests/std/tests/P0220R1_string_view/test.cpp +++ b/tests/std/tests/P0220R1_string_view/test.cpp @@ -810,7 +810,115 @@ constexpr bool test_case_starts_with_ends_with() { return true; } -#endif //_HAS_CXX20 +#endif // _HAS_CXX20 + +// P1679R3 contains() For basic_string/basic_string_view +#if _HAS_CXX23 +template +constexpr bool test_case_contains() { + const basic_string_view empty_sv(TYPED_LITERAL(CharT, "")); + const CharT null_c = '\0'; + const CharT* const empty_cp(TYPED_LITERAL(CharT, "")); + + const basic_string_view a(TYPED_LITERAL(CharT, "a")); + const CharT b = 'b'; + const CharT* const c(TYPED_LITERAL(CharT, "c")); + + if constexpr (TestBasicString) { + basic_string text(TYPED_LITERAL(CharT, "text")); + basic_string empty_text(TYPED_LITERAL(CharT, "")); + + const basic_string_view te(TYPED_LITERAL(CharT, "te")); + const CharT x = 'x'; + const CharT* const ext(TYPED_LITERAL(CharT, "ext")); + const basic_string_view text_sv(TYPED_LITERAL(CharT, "text")); + const CharT* const text_cp(TYPED_LITERAL(CharT, "text")); + const basic_string_view next_sv(TYPED_LITERAL(CharT, "next")); + const CharT* const next_cp(TYPED_LITERAL(CharT, "next")); + const basic_string_view texture_sv(TYPED_LITERAL(CharT, "texture")); + const CharT* const texture_cp(TYPED_LITERAL(CharT, "texture")); + + assert(text.contains(te)); + assert(text.contains(x)); + assert(text.contains(ext)); + assert(text.contains(text)); + assert(text.contains(text_sv)); + assert(text.contains(text_cp)); + assert(!text.contains(next_sv)); + assert(!text.contains(next_cp)); + assert(!text.contains(texture_sv)); + assert(!text.contains(texture_cp)); + assert(text.contains(empty_sv)); + assert(!text.contains(null_c)); + assert(text.contains(empty_cp)); + assert(!text.contains(a)); + assert(!text.contains(b)); + assert(!text.contains(c)); + + assert(!empty_text.contains(te)); + assert(!empty_text.contains(x)); + assert(!empty_text.contains(ext)); + assert(empty_text.contains(empty_text)); + assert(empty_text.contains(empty_sv)); + assert(!empty_text.contains(null_c)); + assert(empty_text.contains(empty_cp)); + + basic_string rocking(TYPED_LITERAL(CharT, "rocking")); + + const basic_string_view rocket_sv(TYPED_LITERAL(CharT, "rocket")); + const CharT* const rocket_cp(TYPED_LITERAL(CharT, "rocket")); + + assert(!rocking.contains(rocket_sv)); + assert(!rocking.contains(rocket_cp)); + } + + const basic_string_view hello(TYPED_LITERAL(CharT, "hello")); + + const basic_string_view he(TYPED_LITERAL(CharT, "he")); + const CharT e = 'e'; + const CharT* const llo(TYPED_LITERAL(CharT, "llo")); + const basic_string_view hello_sv(TYPED_LITERAL(CharT, "hello")); + const CharT* const hello_cp(TYPED_LITERAL(CharT, "hello")); + const basic_string_view cello_sv(TYPED_LITERAL(CharT, "cello")); + const CharT* const cello_cp(TYPED_LITERAL(CharT, "cello")); + const basic_string_view helloworld_sv(TYPED_LITERAL(CharT, "helloworld")); + const CharT* const helloworld_cp(TYPED_LITERAL(CharT, "helloworld")); + + assert(hello.contains(he)); + assert(hello.contains(e)); + assert(hello.contains(llo)); + assert(hello.contains(hello)); + assert(hello.contains(hello_sv)); + assert(hello.contains(hello_cp)); + assert(!hello.contains(cello_sv)); + assert(!hello.contains(cello_cp)); + assert(!hello.contains(helloworld_sv)); + assert(!hello.contains(helloworld_cp)); + assert(hello.contains(empty_sv)); + assert(!hello.contains(null_c)); + assert(hello.contains(empty_cp)); + assert(!hello.contains(a)); + assert(!hello.contains(b)); + assert(!hello.contains(c)); + + assert(!empty_sv.contains(he)); + assert(!empty_sv.contains(e)); + assert(!empty_sv.contains(llo)); + assert(empty_sv.contains(empty_sv)); + assert(!empty_sv.contains(null_c)); + assert(empty_sv.contains(empty_cp)); + + const basic_string_view playing(TYPED_LITERAL(CharT, "playing")); + + const basic_string_view player_sv(TYPED_LITERAL(CharT, "player")); + const CharT* const player_cp(TYPED_LITERAL(CharT, "player")); + + assert(!playing.contains(player_sv)); + assert(!playing.contains(player_cp)); + + return true; +} +#endif // _HAS_CXX23 template constexpr bool test_case_find() { @@ -1062,6 +1170,9 @@ static_assert(test_case_copy()); static_assert(test_case_Copy_s()); static_assert(test_case_starts_with_ends_with()); #endif // _HAS_CXX20 +#if _HAS_CXX23 +static_assert(test_case_contains()); +#endif // _HAS_CXX23 static_assert(test_case_operators()); static_assert(test_case_find()); @@ -1115,6 +1226,10 @@ int main() { test_case_starts_with_ends_with, true>(); test_case_starts_with_ends_with, true>(); #endif // _HAS_CXX20 +#if _HAS_CXX23 + test_case_contains, true>(); + test_case_contains, true>(); +#endif // _HAS_CXX23 test_case_find>(); test_case_find>(); test_case_operators>(); diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp index dfd923d5b21..372dd3f82ed 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/test.cpp +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -887,6 +887,22 @@ _CONSTEXPR20_CONTAINER bool test_interface() { assert(!input_string_false.ends_with(get_literal_input())); } +#if _HAS_CXX23 + { // contains + const str hello_fluffy_kittens = get_literal_input(); // "Hello fluffy kittens" + constexpr auto kitten_ptr = get_cat(); // "kitten" + constexpr auto dog_ptr = get_dog(); // "dog" + + assert(hello_fluffy_kittens.contains(kitten_ptr)); + assert(hello_fluffy_kittens.contains(basic_string_view{kitten_ptr})); + assert(hello_fluffy_kittens.contains(CharType{'e'})); + + assert(!hello_fluffy_kittens.contains(dog_ptr)); + assert(!hello_fluffy_kittens.contains(basic_string_view{dog_ptr})); + assert(!hello_fluffy_kittens.contains(CharType{'z'})); + } +#endif // _HAS_CXX23 + { // replace const str input = get_dog(); diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 0da859a6bf9..96d88c4170b 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -1457,6 +1457,20 @@ STATIC_ASSERT(__cpp_lib_starts_ends_with == 201711L); #endif #endif +#if _HAS_CXX23 +#ifndef __cpp_lib_string_contains +#error __cpp_lib_string_contains is not defined +#elif __cpp_lib_string_contains != 202011L +#error __cpp_lib_string_contains is not 202011L +#else +STATIC_ASSERT(__cpp_lib_string_contains == 202011L); +#endif +#else +#ifdef __cpp_lib_string_contains +#error __cpp_lib_string_contains is defined +#endif +#endif + #ifndef __cpp_lib_string_udls #error __cpp_lib_string_udls is not defined #elif __cpp_lib_string_udls != 201304L