[libc++] Implement P1391 for string_view

Implement P1391 (https://wg21.link/p1391) which allows
`std::string_view` to be constructible from any contiguous range of
characters.

Note that a different paper (http://wg21.link/P1989) handles the generic
range constructor for `std::string_view`.

Reviewed By: ldionne, Quuxplusone, Mordante, #libc

Differential Revision: https://reviews.llvm.org/D110718
This commit is contained in:
Joe Loser 2021-10-06 14:17:02 -04:00
parent 0658bab870
commit 4be7f48960
No known key found for this signature in database
GPG Key ID: 1CDBEBC050EA230D
6 changed files with 169 additions and 1 deletions

View File

@ -134,7 +134,7 @@
"`P1754 <https://wg21.link/P1754>`__","LWG","Rename concepts to standard_case for C++20, while we still can","Cologne","|In Progress|",""
"","","","","",""
"`P0883 <https://wg21.link/P0883>`__","LWG","Fixing Atomic Initialization","Belfast","|Complete| [#note-P0883]_","13.0"
"`P1391 <https://wg21.link/P1391>`__","LWG","Range constructor for std::string_view","Belfast","* *",""
"`P1391 <https://wg21.link/P1391>`__","LWG","Range constructor for std::string_view","Belfast","|Complete|","14.0"
"`P1394 <https://wg21.link/P1394>`__","LWG","Range constructor for std::span","Belfast","* *",""
"`P1456 <https://wg21.link/P1456>`__","LWG","Move-only views","Belfast","* *",""
"`P1622 <https://wg21.link/P1622>`__","LWG","Mandating the Standard Library: Clause 32 - Thread support library","Belfast","* *",""

1 Paper # Group Paper Name Meeting Status First released version
134 `P1754 <https://wg21.link/P1754>`__ LWG Rename concepts to standard_case for C++20, while we still can Cologne |In Progress|
135
136 `P0883 <https://wg21.link/P0883>`__ LWG Fixing Atomic Initialization Belfast |Complete| [#note-P0883]_ 13.0
137 `P1391 <https://wg21.link/P1391>`__ LWG Range constructor for std::string_view Belfast * * |Complete| 14.0
138 `P1394 <https://wg21.link/P1394>`__ LWG Range constructor for std::span Belfast * *
139 `P1456 <https://wg21.link/P1456>`__ LWG Move-only views Belfast * *
140 `P1622 <https://wg21.link/P1622>`__ LWG Mandating the Standard Library: Clause 32 - Thread support library Belfast * *

View File

@ -85,6 +85,8 @@ namespace std {
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 <class It, class End>
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 @@ namespace std {
size_type size_; // exposition only
};
// basic_string_view deduction guides
template<class It, class End>
basic_string_view(It, End) -> basic_string_view<iter_value_t<It>>; // C++20
// 7.11, Hash support
template <class T> struct hash;
template <> struct hash<string_view>;
@ -185,6 +191,8 @@ namespace std {
*/
#include <__concepts/convertible_to.h>
#include <__concepts/same_as.h>
#include <__config>
#include <__debug>
#include <__ranges/enable_borrowed_range.h>
@ -270,6 +278,16 @@ public:
#endif
}
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
template <contiguous_iterator _It, sized_sentinel_for<_It> _End>
requires (same_as<iter_value_t<_It>, _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 @@ template <class _CharT, class _Traits>
inline constexpr bool ranges::enable_borrowed_range<basic_string_view<_CharT, _Traits> > = 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 <contiguous_iterator _It, sized_sentinel_for<_It> _End>
basic_string_view(_It, _End) -> basic_string_view<iter_value_t<_It>>;
#endif
// [string.view.comparison]
// operator ==
template<class _CharT, class _Traits>

View File

@ -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
// <string_view>
// template <contiguous_iterator _It, sized_sentinel_for<_It> _End>
// basic_string_view(_It, _End) -> basic_string_view<iter_value_t<_It>>;
#include <string_view>
#include <cassert>
#include "make_string.h"
#include "test_macros.h"
#include "test_iterators.h"
template<class CharT, class Sentinel>
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<CharT>);
assert(sv.size() == val.size());
assert(sv.data() == val.data());
}
constexpr void test() {
test<char, char*>();
test<wchar_t, wchar_t*>();
test<char8_t, char8_t*>();
test<char16_t, char16_t*>();
test<char32_t, char32_t*>();
test<char, const char*>();
test<char, sized_sentinel<const char*>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -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
// <string_view>
// template <class It, class End>
// constexpr basic_string_view(It begin, End end)
#include <string_view>
#include <cassert>
#include <ranges>
#include "make_string.h"
#include "test_iterators.h"
template<class CharT, class Sentinel>
constexpr void test() {
auto val = MAKE_STRING_VIEW(CharT, "test");
auto sv = std::basic_string_view<CharT>(val.begin(), Sentinel(val.end()));
ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view<CharT>);
assert(sv.size() == val.size());
assert(sv.data() == val.data());
}
constexpr bool test() {
test<char, char*>();
test<wchar_t, wchar_t*>();
test<char8_t, char8_t*>();
test<char16_t, char16_t*>();
test<char32_t, char32_t*>();
test<char, const char*>();
test<char, sized_sentinel<const char*>>();
return true;
}
static_assert( std::is_constructible_v<std::string_view, const char*, char*>);
static_assert( std::is_constructible_v<std::string_view, char*, const char*>);
static_assert(!std::is_constructible_v<std::string_view, char*, void*>); // not a sentinel
static_assert(!std::is_constructible_v<std::string_view, signed char*, signed char*>); // wrong char type
static_assert(!std::is_constructible_v<std::string_view, random_access_iterator<char*>, random_access_iterator<char*>>); // not contiguous
static_assert( std::is_constructible_v<std::string_view, contiguous_iterator<char*>, contiguous_iterator<char*>>);
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -16,6 +16,7 @@
#endif
#include <string>
#include <string_view>
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
#define CHAR8_ONLY(x) x,
@ -56,6 +57,11 @@ struct MultiStringType {
static_cast<const CharT*>(MultiStringType MKSTR(Str)) \
}
#define MAKE_STRING_VIEW(CharT, Str) \
std::basic_string_view<CharT> { \
static_cast<const CharT*>(MultiStringType MKSTR(Str)) \
}
// Like MAKE_STRING but converts to a const CharT*.
#define MAKE_CSTRING(CharT, Str) \
static_cast<const CharT*>(MultiStringType MKSTR(Str))

View File

@ -885,6 +885,39 @@ private:
I base_ = I();
};
template <std::input_or_output_iterator I>
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<I> {
return base_ == other;
}
constexpr const I& base() const& { return base_; }
constexpr I base() && { return std::move(base_); }
template<std::input_or_output_iterator I2>
requires sentinel_for_base<I, I2>
constexpr bool operator==(const I2& other) const {
return base_ == other.base();
}
private:
I base_ = I();
};
template <std::input_or_output_iterator I>
constexpr auto operator-(sized_sentinel<I> sent, std::input_or_output_iterator auto iter) {
return sent.base() - iter;
}
template <std::input_or_output_iterator I>
constexpr auto operator-(std::input_or_output_iterator auto iter, sized_sentinel<I> sent) {
return iter - sent.base();
}
template <class It>
class three_way_contiguous_iterator
{