diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -19,7 +19,7 @@ "`P1518R2 `__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0" "`P1659R3 `__","LWG","starts_with and ends_with","June 2021","","" "`P1951R1 `__","LWG","Default Arguments for pair Forwarding Constructor","June 2021","|Complete|","14.0" -"`P1989R2 `__","LWG","Range constructor for std::string_view","June 2021","","" +"`P1989R2 `__","LWG","Range constructor for std::string_view","June 2021","|Complete|","14.0" "`P2136R3 `__","LWG","invoke_r","June 2021","","" "`P2166R1 `__","LWG","A Proposal to Prohibit std::basic_string and std::basic_string_view construction from nullptr","June 2021","|Complete|","13.0" "","","","","","" diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem --- a/libcxx/include/filesystem +++ b/libcxx/include/filesystem @@ -1492,22 +1492,22 @@ #endif // !_LIBCPP_HAS_NO_LOCALIZATION friend _LIBCPP_INLINE_VISIBILITY bool operator==(const path& __lhs, const path& __rhs) noexcept { - return __lhs.compare(__rhs) == 0; + return __lhs.__compare(__rhs.__pn_) == 0; } friend _LIBCPP_INLINE_VISIBILITY bool operator!=(const path& __lhs, const path& __rhs) noexcept { - return __lhs.compare(__rhs) != 0; + return __lhs.__compare(__rhs.__pn_) != 0; } friend _LIBCPP_INLINE_VISIBILITY bool operator<(const path& __lhs, const path& __rhs) noexcept { - return __lhs.compare(__rhs) < 0; + return __lhs.__compare(__rhs.__pn_) < 0; } friend _LIBCPP_INLINE_VISIBILITY bool operator<=(const path& __lhs, const path& __rhs) noexcept { - return __lhs.compare(__rhs) <= 0; + return __lhs.__compare(__rhs.__pn_) <= 0; } friend _LIBCPP_INLINE_VISIBILITY bool operator>(const path& __lhs, const path& __rhs) noexcept { - return __lhs.compare(__rhs) > 0; + return __lhs.__compare(__rhs.__pn_) > 0; } friend _LIBCPP_INLINE_VISIBILITY bool operator>=(const path& __lhs, const path& __rhs) noexcept { - return __lhs.compare(__rhs) >= 0; + return __lhs.__compare(__rhs.__pn_) >= 0; } friend _LIBCPP_INLINE_VISIBILITY path operator/(const path& __lhs, diff --git a/libcxx/include/string_view b/libcxx/include/string_view --- a/libcxx/include/string_view +++ b/libcxx/include/string_view @@ -87,6 +87,8 @@ constexpr basic_string_view(const charT* str, size_type len); template constexpr basic_string_view(It begin, End end); // C++20 + template + constexpr basic_string_view(Range&& r); // C++23 // 7.4, basic_string_view iterator support constexpr const_iterator begin() const noexcept; @@ -171,6 +173,8 @@ // basic_string_view deduction guides template basic_string_view(It, End) -> basic_string_view>; // C++20 + template + basic_string_view(Range&&) -> basic_string_view>; // C++23 // 7.11, Hash support template struct hash; @@ -191,12 +195,13 @@ */ -#include <__concepts/convertible_to.h> -#include <__concepts/same_as.h> #include <__config> #include <__debug> +#include <__ranges/concepts.h> +#include <__ranges/data.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/enable_view.h> +#include <__ranges/size.h> #include <__string> #include #include @@ -204,6 +209,7 @@ #include #include #include +#include #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -282,7 +288,7 @@ #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES) template _End> - requires (same_as, _CharT> && !convertible_to<_End, size_type>) + requires (is_same_v, _CharT> && !is_convertible_v<_End, size_type>) constexpr _LIBCPP_HIDE_FROM_ABI basic_string_view(_It __begin, _End __end) : __data(_VSTD::to_address(__begin)), __size(__end - __begin) { @@ -290,6 +296,25 @@ } #endif +#if _LIBCPP_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_RANGES) + template + requires ( + !is_same_v, basic_string_view> && + ranges::contiguous_range<_Range> && + ranges::sized_range<_Range> && + is_same_v, _CharT> && + (!is_convertible_v<_Range, const _CharT*>) && + (!requires(remove_cvref_t<_Range>& d) { + d.operator _VSTD::basic_string_view<_CharT, _Traits>(); + }) && + (!requires { + typename remove_reference_t<_Range>::traits_type; + } || is_same_v::traits_type, _Traits>) + ) + constexpr _LIBCPP_HIDE_FROM_ABI + basic_string_view(_Range&& __r) : __data(ranges::data(__r)), __size(ranges::size(__r)) {} +#endif + _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY basic_string_view(const _CharT* __s) : __data(__s), __size(_VSTD::__char_traits_length_checked<_Traits>(__s)) {} @@ -697,6 +722,12 @@ basic_string_view(_It, _End) -> basic_string_view>; #endif + +#if _LIBCPP_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_RANGES) +template + basic_string_view(_Range) -> basic_string_view>; +#endif + // [string.view.comparison] // operator == template diff --git a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp @@ -10,6 +10,11 @@ // UNSUPPORTED: libcpp-no-concepts // UNSUPPORTED: libcpp-has-no-incomplete-ranges +// This test fails due to atomic constraints caching on clang-cl. Specifically, the constraints of +// std::ranges::range concept changes over the lifetime of this TU. Similar story with libc++ and MinGW. +// XFAIL: target={{.+}}-w64-windows-gnu +// XFAIL: msvc + // path #include "filesystem_include.h" diff --git a/libcxx/test/std/strings/string.view/string.view.cons/from_range.pass.cpp b/libcxx/test/std/strings/string.view/string.view.cons/from_range.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/string.view/string.view.cons/from_range.pass.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// 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++20 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// + +// template +// constexpr basic_string_view(Range&& range); + +#include +#include +#include +#include +#include +#include +#include + +#include "constexpr_char_traits.h" +#include "make_string.h" +#include "test_iterators.h" +#include "test_range.h" + +template +constexpr void test() { + auto data = MAKE_STRING_VIEW(CharT, "test"); + std::array arr; + for(int i = 0; i < 4; ++i) { + arr[i] = data[i]; + } + auto sv = std::basic_string_view(arr); + + ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view); + assert(sv.size() == arr.size()); + assert(sv.data() == arr.data()); +} + +constexpr void test_deleted_string_view_conversion_operator() { + struct DeletedStringViewConversionOperator { + const char* data_ = "test"; + constexpr const char* begin() const { return data_; } + constexpr const char* end() const { return data_ + 4; } + operator std::string_view() = delete; + }; + + struct DeletedConstStringViewConversionOperator { + const char* data_ = "test"; + constexpr const char* begin() const { return data_; } + constexpr const char* end() const { return data_ + 4; } + operator std::string_view() const = delete; + }; + + DeletedStringViewConversionOperator d; + std::string_view csv = std::as_const(d); + assert(csv == "test"); + + DeletedConstStringViewConversionOperator dc; + std::string_view sv = dc; + assert(sv == "test"); +} + +constexpr bool test() { + test(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + test(); + test(); + test(); + + test_deleted_string_view_conversion_operator(); + + return true; +} + +static_assert(std::is_constructible_v&>); +static_assert(std::is_constructible_v&>); +static_assert(std::is_constructible_v&&>); +static_assert(std::is_constructible_v&&>); + +using SizedButNotContiguousRange = std::ranges::subrange>; +static_assert(!std::ranges::contiguous_range); +static_assert(std::ranges::sized_range); +static_assert(!std::is_constructible_v); + +using ContiguousButNotSizedRange = std::ranges::subrange, sentinel_wrapper, std::ranges::subrange_kind::unsized>; +static_assert(std::ranges::contiguous_range); +static_assert(!std::ranges::sized_range); +static_assert(!std::is_constructible_v); + +static_assert(!std::is_constructible_v>); // different CharT + +struct WithStringViewConversionOperator { + char* begin() const; + char* end() const; + operator std::string_view() const { return {}; } +}; + +static_assert(std::is_constructible_v); // lvalue +static_assert(std::is_constructible_v); // const lvalue +static_assert(std::is_constructible_v); // rvalue + +template +struct WithTraitsType { + typename CharTraits::char_type* begin() const; + typename CharTraits::char_type* end() const; + using traits_type = CharTraits; +}; + +using CCT = constexpr_char_traits; +static_assert(std::is_constructible_v>>); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(std::is_constructible_v>>); +#endif +static_assert(std::is_constructible_v, WithTraitsType>); +static_assert(!std::is_constructible_v>); // wrong traits type +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(!std::is_constructible_v>>); // wrong traits type +#endif + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} + diff --git a/libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp b/libcxx/test/std/strings/string.view/string.view.deduct/iterator_sentinel.pass.cpp rename from libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp rename to libcxx/test/std/strings/string.view/string.view.deduct/iterator_sentinel.pass.cpp diff --git a/libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp b/libcxx/test/std/strings/string.view/string.view.deduct/range.pass.cpp rename from libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp rename to libcxx/test/std/strings/string.view/string.view.deduct/range.pass.cpp --- a/libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp +++ b/libcxx/test/std/strings/string.view/string.view.deduct/range.pass.cpp @@ -5,40 +5,38 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // UNSUPPORTED: libcpp-no-concepts // -// template _End> -// basic_string_view(_It, _End) -> basic_string_view>; +// template +// basic_string_view(Range&&) -> basic_string_view>; // C++23 #include #include #include "make_string.h" #include "test_macros.h" -#include "test_iterators.h" -template +template constexpr void test() { - auto val = MAKE_STRING_VIEW(CharT, "test"); - auto sv = std::basic_string_view(val.begin(), Sentinel(val.end())); + auto val = MAKE_STRING(CharT, "test"); + auto sv = std::basic_string_view(val); ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view); assert(sv.size() == val.size()); assert(sv.data() == val.data()); } constexpr void test() { - test(); + test(); #ifndef TEST_HAS_NO_WIDE_CHARACTERS - test(); + test(); #endif - test(); - test(); - test(); - test(); - test>(); + test(); + test(); + test(); + test(); } int main(int, char**) {