diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -134,7 +134,7 @@ "`P1754 `__","LWG","Rename concepts to standard_case for C++20, while we still can","Cologne","|In Progress|","" "","","","","","" "`P0883 `__","LWG","Fixing Atomic Initialization","Belfast","|Complete| [#note-P0883]_","13.0" -"`P1391 `__","LWG","Range constructor for std::string_view","Belfast","* *","" +"`P1391 `__","LWG","Range constructor for std::string_view","Belfast","|Complete|","14.0" "`P1394 `__","LWG","Range constructor for std::span","Belfast","* *","" "`P1456 `__","LWG","Move-only views","Belfast","* *","" "`P1622 `__","LWG","Mandating the Standard Library: Clause 32 - Thread support library","Belfast","* *","" diff --git a/libcxx/include/string_view b/libcxx/include/string_view --- a/libcxx/include/string_view +++ b/libcxx/include/string_view @@ -85,6 +85,8 @@ constexpr basic_string_view(const charT* str); basic_string_view(nullptr_t) = delete; // C++2b constexpr basic_string_view(const charT* str, size_type len); + template + constexpr basic_string_view(It begin, End end); // C++20 // 7.4, basic_string_view iterator support constexpr const_iterator begin() const noexcept; @@ -166,6 +168,10 @@ size_type size_; // exposition only }; + // basic_string_view deduction guides + template + basic_string_view(It, End) -> basic_string_view>; // C++20 + // 7.11, Hash support template struct hash; template <> struct hash; @@ -185,6 +191,8 @@ */ +#include <__concepts/convertible_to.h> +#include <__concepts/same_as.h> #include <__config> #include <__debug> #include <__ranges/enable_borrowed_range.h> @@ -270,6 +278,16 @@ #endif } +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES) + template _End> + requires (same_as, _CharT> && !convertible_to<_End, size_type>) + constexpr _LIBCPP_HIDE_FROM_ABI basic_string_view(_It __begin, _End __end) + : __data(_VSTD::to_address(__begin)), __size(__end - __begin) + { + _LIBCPP_ASSERT((__end - __begin) >= 0, "std::string_view::string_view(iterator, sentinel) received invalid range"); + } +#endif + _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY basic_string_view(const _CharT* __s) : __data(__s), __size(_VSTD::__char_traits_length_checked<_Traits>(__s)) {} @@ -670,6 +688,13 @@ inline constexpr bool ranges::enable_borrowed_range > = true; #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES) +// [string.view.deduct] + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES) +template _End> + basic_string_view(_It, _End) -> basic_string_view>; +#endif + // [string.view.comparison] // operator == template diff --git a/libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp b/libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts + +// + +// template _End> +// basic_string_view(_It, _End) -> basic_string_view>; + +#include +#include + +#include "make_string.h" +#include "test_macros.h" +#include "test_iterators.h" + +template +constexpr void test() { + auto val = MAKE_STRING_VIEW(CharT, "test"); + auto sv = std::basic_string_view(val.begin(), Sentinel(val.end())); + ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view); + assert(sv.size() == val.size()); + assert(sv.data() == val.data()); +} + +constexpr void test() { + test(); + test(); + test(); + test(); + test(); + test(); + test>(); +} + +int main(int, char**) { + test(); + + return 0; +} + diff --git a/libcxx/test/std/strings/string.view/string.view.cons/from_iterator_sentinel.pass.cpp b/libcxx/test/std/strings/string.view/string.view.cons/from_iterator_sentinel.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/string.view/string.view.cons/from_iterator_sentinel.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// + +// template +// constexpr basic_string_view(It begin, End end) + +#include +#include +#include + +#include "make_string.h" +#include "test_iterators.h" + +template +constexpr void test() { + auto val = MAKE_STRING_VIEW(CharT, "test"); + auto sv = std::basic_string_view(val.begin(), Sentinel(val.end())); + ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view); + assert(sv.size() == val.size()); + assert(sv.data() == val.data()); +} + +constexpr bool test() { + test(); + test(); + test(); + test(); + test(); + test(); + test>(); + return true; +} + +static_assert( std::is_constructible_v); +static_assert( std::is_constructible_v); +static_assert(!std::is_constructible_v); // not a sentinel +static_assert(!std::is_constructible_v); // wrong char type +static_assert(!std::is_constructible_v, random_access_iterator>); // not contiguous +static_assert( std::is_constructible_v, contiguous_iterator>); + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} + diff --git a/libcxx/test/support/make_string.h b/libcxx/test/support/make_string.h --- a/libcxx/test/support/make_string.h +++ b/libcxx/test/support/make_string.h @@ -16,6 +16,7 @@ #endif #include +#include #if TEST_STD_VER > 17 && defined(__cpp_char8_t) #define CHAR8_ONLY(x) x, @@ -56,6 +57,11 @@ static_cast(MultiStringType MKSTR(Str)) \ } +#define MAKE_STRING_VIEW(CharT, Str) \ + std::basic_string_view { \ + static_cast(MultiStringType MKSTR(Str)) \ + } + // Like MAKE_STRING but converts to a const CharT*. #define MAKE_CSTRING(CharT, Str) \ static_cast(MultiStringType MKSTR(Str)) diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -885,6 +885,39 @@ I base_ = I(); }; +template +class sized_sentinel { +public: + sized_sentinel() = default; + constexpr explicit sized_sentinel(I base) : base_(std::move(base)) {} + + constexpr bool operator==(const I& other) const requires std::equality_comparable { + return base_ == other; + } + + constexpr const I& base() const& { return base_; } + constexpr I base() && { return std::move(base_); } + + template + requires sentinel_for_base + constexpr bool operator==(const I2& other) const { + return base_ == other.base(); + } + +private: + I base_ = I(); +}; + +template +constexpr auto operator-(sized_sentinel sent, std::input_or_output_iterator auto iter) { + return sent.base() - iter; +} + +template +constexpr auto operator-(std::input_or_output_iterator auto iter, sized_sentinel sent) { + return iter - sent.base(); +} + template class three_way_contiguous_iterator {