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/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; @@ -195,8 +199,11 @@ #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 @@ -290,6 +297,24 @@ } #endif +#if _LIBCPP_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_RANGES) + template + requires ( + !same_as, basic_string_view> && + ranges::contiguous_range<_Range> && + ranges::sized_range<_Range> && + same_as, _CharT> && + !convertible_to<_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; + } || same_as::traits_type, _CharT>) + ) + 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/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,124 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "make_string.h" +#include "test_iterators.h" +#include "test_range.h" + +template +void test() { + auto data = MAKE_STRING(CharT, "test"); + // TODO: use array of characters for data to be constexpr-friendly + auto sv = std::basic_string_view(data); + + ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view); + assert(sv.size() == data.size()); + assert(sv.data() == data.data()); +} + +bool test() { + test(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + test(); + test(); + test(); + + return true; +} + +static_assert( std::is_constructible_v&>); // contiguous sized range lvalue +static_assert( std::is_constructible_v&>); // contiguous sized range const lvalue +static_assert( std::is_constructible_v&&>); // contiguous sized range rvalue + +using NonContiguousRange = 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); + +template +struct WithCharConversionOperator { + CharT* begin() { return nullptr; } + CharT* end() { return nullptr; } + operator const CharT*() const { return {}; } +}; + +static_assert(!std::is_constructible_v>); // different CharT +// TODO: these don't pass yet +//static_assert(!std::is_constructible_v>); // has conversion operator to const CharT* +//static_assert( std::is_constructible_v>); // has conversion operator to different CharT + +template +struct WithStringViewConversionOperator { + CharT* begin() { return nullptr; } + CharT* end() { return nullptr; } + operator std::basic_string_view() const { return {}; } +}; + +// TODO: these don't pass yet +//static_assert(!std::is_constructible_v>); // lvalue +//static_assert(!std::is_constructible_v&>); // const lvalue +//static_assert(!std::is_constructible_v&&>); // rvalue +static_assert( std::is_constructible_v>); // different CharT for string_view conversion operator + +class InaccessibleTraitsType { +public: + char* begin() { return nullptr; } + char* end() { return nullptr; } +private: + using traits_type = char; +}; +// TODO: why doesn't this pass with inaccessible traits_type? +//static_assert(!std::is_constructible_v); // invalid (not accessible) traits_type type +static_assert(!std::is_constructible_v>); // wrong traits_type + +void test_deleted_string_view_conversion_operator() { + struct DeletedStringViewConversionOperator : public std::vector + { + DeletedStringViewConversionOperator() : std::vector({'t', 'e', 's', 't'}) {}; + operator std::string_view() const noexcept = delete; + }; + + DeletedStringViewConversionOperator d; + std::string_view sv(d); + assert(sv.size() == d.size()); + assert(sv.data() == d.data()); +} + +int main(int, char**) { + // TODO: make test() constexpr-friendly too + test(); + + test_deleted_string_view_conversion_operator(); + + 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**) {