diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -298,6 +298,6 @@ ------------------------------------------------- ----------------- ``__cpp_lib_stdatomic_h`` *unimplemented* ------------------------------------------------- ----------------- - ``__cpp_lib_string_contains`` *unimplemented* + ``__cpp_lib_string_contains`` ``202011L`` ================================================= ================= diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -324,6 +324,10 @@ bool ends_with(charT c) const noexcept; // C++20 bool ends_with(const charT* s) const; // C++20 + constexpr bool contains(basic_string_view sv) const noexcept; // C++2b + constexpr bool contains(charT c) const noexcept; // C++2b + constexpr bool contains(const charT* s) const; // C++2b + bool __invariants() const; }; @@ -1433,6 +1437,20 @@ { return ends_with(__self_view(__s)); } #endif +#if _LIBCPP_STD_VER > 20 + constexpr _LIBCPP_INLINE_VISIBILITY + bool contains(__self_view __sv) const noexcept + { return __self_view(data(), size()).contains(__sv); } + + constexpr _LIBCPP_INLINE_VISIBILITY + bool contains(value_type __c) const noexcept + { return __self_view(data(), size()).contains(__c); } + + constexpr _LIBCPP_INLINE_VISIBILITY + bool contains(const value_type* __s) const + { return __self_view(data(), size()).contains(__s); } +#endif + _LIBCPP_INLINE_VISIBILITY bool __invariants() const; _LIBCPP_INLINE_VISIBILITY void __clear_and_shrink() _NOEXCEPT; diff --git a/libcxx/include/string_view b/libcxx/include/string_view --- a/libcxx/include/string_view +++ b/libcxx/include/string_view @@ -149,6 +149,10 @@ constexpr bool ends_with(charT c) const noexcept; // C++20 constexpr bool ends_with(const charT* s) const; // C++20 + constexpr bool contains(basic_string_view s) const noexcept; // C++2b + constexpr bool contains(charT c) const noexcept; // C++2b + constexpr bool contains(const charT* s) const; // C++2b + private: const_pointer data_; // exposition only size_type size_; // exposition only @@ -622,6 +626,20 @@ { return ends_with(basic_string_view(__s)); } #endif +#if _LIBCPP_STD_VER > 20 + constexpr _LIBCPP_INLINE_VISIBILITY + bool contains(basic_string_view __sv) const noexcept + { return find(__sv) != npos; } + + constexpr _LIBCPP_INLINE_VISIBILITY + bool contains(value_type __c) const noexcept + { return find(__c) != npos; } + + constexpr _LIBCPP_INLINE_VISIBILITY + bool contains(const value_type* __s) const + { return find(__s) != npos; } +#endif + private: const value_type* __data; size_type __size; diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -358,7 +358,7 @@ # define __cpp_lib_is_scoped_enum 202011L // # define __cpp_lib_stacktrace 202011L // # define __cpp_lib_stdatomic_h 202011L -// # define __cpp_lib_string_contains 202011L +# define __cpp_lib_string_contains 202011L #endif #endif // _LIBCPP_VERSIONH diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp @@ -290,17 +290,11 @@ # error "__cpp_lib_starts_ends_with should have the value 201711L in c++2b" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_string_contains -# error "__cpp_lib_string_contains should be defined in c++2b" -# endif -# if __cpp_lib_string_contains != 202011L -# error "__cpp_lib_string_contains should have the value 202011L in c++2b" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_string_contains -# error "__cpp_lib_string_contains should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_string_contains +# error "__cpp_lib_string_contains should be defined in c++2b" +# endif +# if __cpp_lib_string_contains != 202011L +# error "__cpp_lib_string_contains should have the value 202011L in c++2b" # endif # ifndef __cpp_lib_string_udls diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp @@ -177,17 +177,11 @@ # error "__cpp_lib_starts_ends_with should have the value 201711L in c++2b" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_string_contains -# error "__cpp_lib_string_contains should be defined in c++2b" -# endif -# if __cpp_lib_string_contains != 202011L -# error "__cpp_lib_string_contains should have the value 202011L in c++2b" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_string_contains -# error "__cpp_lib_string_contains should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_string_contains +# error "__cpp_lib_string_contains should be defined in c++2b" +# endif +# if __cpp_lib_string_contains != 202011L +# error "__cpp_lib_string_contains should have the value 202011L in c++2b" # endif # ifndef __cpp_lib_string_view diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -4373,17 +4373,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_string_contains -# error "__cpp_lib_string_contains should be defined in c++2b" -# endif -# if __cpp_lib_string_contains != 202011L -# error "__cpp_lib_string_contains should have the value 202011L in c++2b" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_string_contains -# error "__cpp_lib_string_contains should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_string_contains +# error "__cpp_lib_string_contains should be defined in c++2b" +# endif +# if __cpp_lib_string_contains != 202011L +# error "__cpp_lib_string_contains should have the value 202011L in c++2b" # endif # ifndef __cpp_lib_string_udls diff --git a/libcxx/test/std/strings/basic.string/string.contains/contains.char.pass.cpp b/libcxx/test/std/strings/basic.string/string.contains/contains.char.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.contains/contains.char.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2a + +// + +// constexpr bool contains(charT x) const noexcept; + +#include +#include + +#include "test_macros.h" + +void test() +{ + using S = std::string; + + S s1 {}; + S s2 {"abcde", 5}; + + ASSERT_NOEXCEPT(s1.contains('e')); + + assert(!s1.contains('c')); + assert(!s1.contains('e')); + assert(!s1.contains('x')); + assert( s2.contains('c')); + assert( s2.contains('e')); + assert(!s2.contains('x')); +} + +int main(int, char**) +{ + test(); + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.contains/contains.ptr.pass.cpp b/libcxx/test/std/strings/basic.string/string.contains/contains.ptr.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.contains/contains.ptr.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2a + +// + +// constexpr bool contains(const CharT *x) const; + +#include +#include + +#include "test_macros.h" + +void test() +{ + using S = std::string; + + const char* s = "abcde"; + S s0; + S s1 {s + 4, 1}; + S s3 {s + 2, 3}; + S sNot {"xyz", 3}; + + assert(s0.contains("")); + assert(!s0.contains("e")); + + assert( s1.contains("")); + assert(!s1.contains("d")); + assert( s1.contains("e")); + assert(!s1.contains("de")); + assert(!s1.contains("cd")); + assert(!s1.contains("cde")); + assert(!s1.contains("bcde")); + assert(!s1.contains("abcde")); + assert(!s1.contains("xyz")); + + assert( s3.contains("")); + assert( s3.contains("d")); + assert( s3.contains("e")); + assert( s3.contains("de")); + assert( s3.contains("cd")); + assert(!s3.contains("ce")); + assert( s3.contains("cde")); + assert(!s3.contains("edc")); + assert(!s3.contains("bcde")); + assert(!s3.contains("abcde")); + assert(!s3.contains("xyz")); + + assert( sNot.contains("")); + assert(!sNot.contains("d")); + assert(!sNot.contains("e")); + assert(!sNot.contains("de")); + assert(!sNot.contains("cd")); + assert(!sNot.contains("cde")); + assert(!sNot.contains("bcde")); + assert(!sNot.contains("abcde")); + assert( sNot.contains("xyz")); + assert(!sNot.contains("zyx")); +} + +int main(int, char**) +{ + test(); + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.contains/contains.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.contains/contains.string_view.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.contains/contains.string_view.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2a + +// + +// constexpr bool contains(basic_string_view x) const noexcept; + +#include +#include + +#include "test_macros.h" + +void test() +{ + using S = std::string; + using SV = std::string_view; + + const char* s = "abcde"; + S s0; + S s1 {s + 1, 1}; + S s3 {s + 1, 3}; + S s5 {s , 5}; + S sNot {"xyz", 3}; + + SV sv0; + SV sv1 {s + 1, 1}; + SV sv2 {s + 1, 2}; + SV sv3 {s + 1, 3}; + SV sv4 {s + 1, 4}; + SV sv5 {s , 5}; + SV svNot {"xyz", 3}; + SV svNot2 {"bd" , 2}; + SV svNot3 {"dcb", 3}; + + ASSERT_NOEXCEPT(s0.contains(sv0)); + + assert( s0.contains(sv0)); + assert(!s0.contains(sv1)); + + assert( s1.contains(sv0)); + assert( s1.contains(sv1)); + assert(!s1.contains(sv2)); + assert(!s1.contains(sv3)); + assert(!s1.contains(sv4)); + assert(!s1.contains(sv5)); + assert(!s1.contains(svNot)); + assert(!s1.contains(svNot2)); + assert(!s1.contains(svNot3)); + + assert( s3.contains(sv0)); + assert( s3.contains(sv1)); + assert( s3.contains(sv2)); + assert( s3.contains(sv3)); + assert(!s3.contains(sv4)); + assert(!s3.contains(sv5)); + assert(!s3.contains(svNot)); + assert(!s3.contains(svNot2)); + assert(!s3.contains(svNot3)); + + assert( s5.contains(sv0)); + assert( s5.contains(sv1)); + assert( s5.contains(sv2)); + assert( s5.contains(sv3)); + assert( s5.contains(sv4)); + assert( s5.contains(sv5)); + assert(!s5.contains(svNot)); + assert(!s5.contains(svNot2)); + assert(!s5.contains(svNot3)); + + assert( sNot.contains(sv0)); + assert(!sNot.contains(sv1)); + assert(!sNot.contains(sv2)); + assert(!sNot.contains(sv3)); + assert(!sNot.contains(sv4)); + assert(!sNot.contains(sv5)); + assert( sNot.contains(svNot)); + assert(!sNot.contains(svNot2)); + assert(!sNot.contains(svNot3)); +} + +int main(int, char**) +{ + test(); + + return 0; +} diff --git a/libcxx/test/std/strings/string.view/string.view.template/contains.char.pass.cpp b/libcxx/test/std/strings/string.view/string.view.template/contains.char.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/string.view/string.view.template/contains.char.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2a + +// + +// constexpr bool contains(charT x) const noexcept; + +#include +#include + +#include "test_macros.h" + +constexpr bool test() +{ + using SV = std::string_view; + + SV sv1 {}; + SV sv2 {"abcde", 5}; + + ASSERT_NOEXCEPT(sv1.contains('e')); + + assert(!sv1.contains('c')); + assert(!sv1.contains('e')); + assert(!sv1.contains('x')); + assert( sv2.contains('c')); + assert( sv2.contains('e')); + assert(!sv2.contains('x')); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/strings/string.view/string.view.template/contains.ptr.pass.cpp b/libcxx/test/std/strings/string.view/string.view.template/contains.ptr.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/string.view/string.view.template/contains.ptr.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2a + +// + +// constexpr bool contains(const CharT *x) const; + +#include +#include + +#include "test_macros.h" + +constexpr bool test() +{ + using SV = std::string_view; + + const char* s = "abcde"; + SV sv0; + SV sv1 {s + 4, 1}; + SV sv3 {s + 2, 3}; + SV svNot {"xyz", 3}; + + assert( sv0.contains("")); + assert(!sv0.contains("e")); + + assert( sv1.contains("")); + assert(!sv1.contains("d")); + assert( sv1.contains("e")); + assert(!sv1.contains("de")); + assert(!sv1.contains("cd")); + assert(!sv1.contains("cde")); + assert(!sv1.contains("bcde")); + assert(!sv1.contains("abcde")); + assert(!sv1.contains("xyz")); + + assert( sv3.contains("")); + assert( sv3.contains("d")); + assert( sv3.contains("e")); + assert( sv3.contains("de")); + assert( sv3.contains("cd")); + assert(!sv3.contains("ce")); + assert( sv3.contains("cde")); + assert(!sv3.contains("edc")); + assert(!sv3.contains("bcde")); + assert(!sv3.contains("abcde")); + assert(!sv3.contains("xyz")); + + assert( svNot.contains("")); + assert(!svNot.contains("d")); + assert(!svNot.contains("e")); + assert(!svNot.contains("de")); + assert(!svNot.contains("cd")); + assert(!svNot.contains("cde")); + assert(!svNot.contains("bcde")); + assert(!svNot.contains("abcde")); + assert( svNot.contains("xyz")); + assert(!svNot.contains("zyx")); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/strings/string.view/string.view.template/contains.string_view.pass.cpp b/libcxx/test/std/strings/string.view/string.view.template/contains.string_view.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/string.view/string.view.template/contains.string_view.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2a + +// + +// constexpr bool contains(string_view x) const noexcept; + +#include +#include + +#include "test_macros.h" + +constexpr bool test() +{ + using SV = std::string_view; + + const char* s = "abcde"; + SV sv0; + SV sv1 {s + 1, 1}; + SV sv2 {s + 1, 2}; + SV sv3 {s + 1, 3}; + SV sv4 {s + 1, 4}; + SV sv5 {s , 5}; + SV svNot {"xyz", 3}; + SV svNot2 {"bd" , 2}; + SV svNot3 {"dcb", 3}; + + ASSERT_NOEXCEPT(sv0.contains(sv0)); + + assert( sv0.contains(sv0)); + assert(!sv0.contains(sv1)); + + assert( sv1.contains(sv0)); + assert( sv1.contains(sv1)); + assert(!sv1.contains(sv2)); + assert(!sv1.contains(sv3)); + assert(!sv1.contains(sv4)); + assert(!sv1.contains(sv5)); + assert(!sv1.contains(svNot)); + assert(!sv1.contains(svNot2)); + assert(!sv1.contains(svNot3)); + + assert( sv3.contains(sv0)); + assert( sv3.contains(sv1)); + assert( sv3.contains(sv2)); + assert( sv3.contains(sv3)); + assert(!sv3.contains(sv4)); + assert(!sv3.contains(sv5)); + assert(!sv3.contains(svNot)); + assert(!sv3.contains(svNot2)); + assert(!sv3.contains(svNot3)); + + assert( sv5.contains(sv0)); + assert( sv5.contains(sv1)); + assert( sv5.contains(sv2)); + assert( sv5.contains(sv3)); + assert( sv5.contains(sv4)); + assert( sv5.contains(sv5)); + assert(!sv5.contains(svNot)); + assert(!sv5.contains(svNot2)); + assert(!sv5.contains(svNot3)); + + assert( svNot.contains(sv0)); + assert(!svNot.contains(sv1)); + assert(!svNot.contains(sv2)); + assert(!svNot.contains(sv3)); + assert(!svNot.contains(sv4)); + assert(!svNot.contains(sv5)); + assert( svNot.contains(svNot)); + assert(!svNot.contains(svNot2)); + assert(!svNot.contains(svNot3)); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -559,7 +559,6 @@ "name": "__cpp_lib_string_contains", "values": { "c++2b": 202011 }, "headers": ["string", "string_view"], - "unimplemented": True, }, { "name": "__cpp_lib_string_udls", "values": { "c++14": 201304 },