Skip to content

Commit 4be7f48

Browse files
committed
[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
1 parent 0658bab commit 4be7f48

File tree

6 files changed

+169
-1
lines changed

6 files changed

+169
-1
lines changed

libcxx/docs/Status/Cxx20Papers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@
134134
"`P1754 <https://wg21.link/P1754>`__","LWG","Rename concepts to standard_case for C++20, while we still can","Cologne","|In Progress|",""
135135
"","","","","",""
136136
"`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","* *",""
137+
"`P1391 <https://wg21.link/P1391>`__","LWG","Range constructor for std::string_view","Belfast","|Complete|","14.0"
138138
"`P1394 <https://wg21.link/P1394>`__","LWG","Range constructor for std::span","Belfast","* *",""
139139
"`P1456 <https://wg21.link/P1456>`__","LWG","Move-only views","Belfast","* *",""
140140
"`P1622 <https://wg21.link/P1622>`__","LWG","Mandating the Standard Library: Clause 32 - Thread support library","Belfast","* *",""

libcxx/include/string_view

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ namespace std {
8585
constexpr basic_string_view(const charT* str);
8686
basic_string_view(nullptr_t) = delete; // C++2b
8787
constexpr basic_string_view(const charT* str, size_type len);
88+
template <class It, class End>
89+
constexpr basic_string_view(It begin, End end); // C++20
8890
8991
// 7.4, basic_string_view iterator support
9092
constexpr const_iterator begin() const noexcept;
@@ -166,6 +168,10 @@ namespace std {
166168
size_type size_; // exposition only
167169
};
168170
171+
// basic_string_view deduction guides
172+
template<class It, class End>
173+
basic_string_view(It, End) -> basic_string_view<iter_value_t<It>>; // C++20
174+
169175
// 7.11, Hash support
170176
template <class T> struct hash;
171177
template <> struct hash<string_view>;
@@ -185,6 +191,8 @@ namespace std {
185191
186192
*/
187193

194+
#include <__concepts/convertible_to.h>
195+
#include <__concepts/same_as.h>
188196
#include <__config>
189197
#include <__debug>
190198
#include <__ranges/enable_borrowed_range.h>
@@ -270,6 +278,16 @@ public:
270278
#endif
271279
}
272280

281+
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
282+
template <contiguous_iterator _It, sized_sentinel_for<_It> _End>
283+
requires (same_as<iter_value_t<_It>, _CharT> && !convertible_to<_End, size_type>)
284+
constexpr _LIBCPP_HIDE_FROM_ABI basic_string_view(_It __begin, _End __end)
285+
: __data(_VSTD::to_address(__begin)), __size(__end - __begin)
286+
{
287+
_LIBCPP_ASSERT((__end - __begin) >= 0, "std::string_view::string_view(iterator, sentinel) received invalid range");
288+
}
289+
#endif
290+
273291
_LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
274292
basic_string_view(const _CharT* __s)
275293
: __data(__s), __size(_VSTD::__char_traits_length_checked<_Traits>(__s)) {}
@@ -670,6 +688,13 @@ template <class _CharT, class _Traits>
670688
inline constexpr bool ranges::enable_borrowed_range<basic_string_view<_CharT, _Traits> > = true;
671689
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
672690

691+
// [string.view.deduct]
692+
693+
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
694+
template <contiguous_iterator _It, sized_sentinel_for<_It> _End>
695+
basic_string_view(_It, _End) -> basic_string_view<iter_value_t<_It>>;
696+
#endif
697+
673698
// [string.view.comparison]
674699
// operator ==
675700
template<class _CharT, class _Traits>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// UNSUPPORTED: c++03, c++11, c++14, c++17
9+
// UNSUPPORTED: libcpp-no-concepts
10+
11+
// <string_view>
12+
13+
// template <contiguous_iterator _It, sized_sentinel_for<_It> _End>
14+
// basic_string_view(_It, _End) -> basic_string_view<iter_value_t<_It>>;
15+
16+
#include <string_view>
17+
#include <cassert>
18+
19+
#include "make_string.h"
20+
#include "test_macros.h"
21+
#include "test_iterators.h"
22+
23+
template<class CharT, class Sentinel>
24+
constexpr void test() {
25+
auto val = MAKE_STRING_VIEW(CharT, "test");
26+
auto sv = std::basic_string_view(val.begin(), Sentinel(val.end()));
27+
ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view<CharT>);
28+
assert(sv.size() == val.size());
29+
assert(sv.data() == val.data());
30+
}
31+
32+
constexpr void test() {
33+
test<char, char*>();
34+
test<wchar_t, wchar_t*>();
35+
test<char8_t, char8_t*>();
36+
test<char16_t, char16_t*>();
37+
test<char32_t, char32_t*>();
38+
test<char, const char*>();
39+
test<char, sized_sentinel<const char*>>();
40+
}
41+
42+
int main(int, char**) {
43+
test();
44+
45+
return 0;
46+
}
47+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// UNSUPPORTED: c++03, c++11, c++14, c++17
9+
// UNSUPPORTED: libcpp-no-concepts
10+
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
11+
12+
// <string_view>
13+
14+
// template <class It, class End>
15+
// constexpr basic_string_view(It begin, End end)
16+
17+
#include <string_view>
18+
#include <cassert>
19+
#include <ranges>
20+
21+
#include "make_string.h"
22+
#include "test_iterators.h"
23+
24+
template<class CharT, class Sentinel>
25+
constexpr void test() {
26+
auto val = MAKE_STRING_VIEW(CharT, "test");
27+
auto sv = std::basic_string_view<CharT>(val.begin(), Sentinel(val.end()));
28+
ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view<CharT>);
29+
assert(sv.size() == val.size());
30+
assert(sv.data() == val.data());
31+
}
32+
33+
constexpr bool test() {
34+
test<char, char*>();
35+
test<wchar_t, wchar_t*>();
36+
test<char8_t, char8_t*>();
37+
test<char16_t, char16_t*>();
38+
test<char32_t, char32_t*>();
39+
test<char, const char*>();
40+
test<char, sized_sentinel<const char*>>();
41+
return true;
42+
}
43+
44+
static_assert( std::is_constructible_v<std::string_view, const char*, char*>);
45+
static_assert( std::is_constructible_v<std::string_view, char*, const char*>);
46+
static_assert(!std::is_constructible_v<std::string_view, char*, void*>); // not a sentinel
47+
static_assert(!std::is_constructible_v<std::string_view, signed char*, signed char*>); // wrong char type
48+
static_assert(!std::is_constructible_v<std::string_view, random_access_iterator<char*>, random_access_iterator<char*>>); // not contiguous
49+
static_assert( std::is_constructible_v<std::string_view, contiguous_iterator<char*>, contiguous_iterator<char*>>);
50+
51+
int main(int, char**) {
52+
test();
53+
static_assert(test());
54+
55+
return 0;
56+
}
57+

libcxx/test/support/make_string.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#endif
1717

1818
#include <string>
19+
#include <string_view>
1920

2021
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
2122
#define CHAR8_ONLY(x) x,
@@ -56,6 +57,11 @@ struct MultiStringType {
5657
static_cast<const CharT*>(MultiStringType MKSTR(Str)) \
5758
}
5859

60+
#define MAKE_STRING_VIEW(CharT, Str) \
61+
std::basic_string_view<CharT> { \
62+
static_cast<const CharT*>(MultiStringType MKSTR(Str)) \
63+
}
64+
5965
// Like MAKE_STRING but converts to a const CharT*.
6066
#define MAKE_CSTRING(CharT, Str) \
6167
static_cast<const CharT*>(MultiStringType MKSTR(Str))

libcxx/test/support/test_iterators.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,39 @@ class sentinel_wrapper {
885885
I base_ = I();
886886
};
887887

888+
template <std::input_or_output_iterator I>
889+
class sized_sentinel {
890+
public:
891+
sized_sentinel() = default;
892+
constexpr explicit sized_sentinel(I base) : base_(std::move(base)) {}
893+
894+
constexpr bool operator==(const I& other) const requires std::equality_comparable<I> {
895+
return base_ == other;
896+
}
897+
898+
constexpr const I& base() const& { return base_; }
899+
constexpr I base() && { return std::move(base_); }
900+
901+
template<std::input_or_output_iterator I2>
902+
requires sentinel_for_base<I, I2>
903+
constexpr bool operator==(const I2& other) const {
904+
return base_ == other.base();
905+
}
906+
907+
private:
908+
I base_ = I();
909+
};
910+
911+
template <std::input_or_output_iterator I>
912+
constexpr auto operator-(sized_sentinel<I> sent, std::input_or_output_iterator auto iter) {
913+
return sent.base() - iter;
914+
}
915+
916+
template <std::input_or_output_iterator I>
917+
constexpr auto operator-(std::input_or_output_iterator auto iter, sized_sentinel<I> sent) {
918+
return iter - sent.base();
919+
}
920+
888921
template <class It>
889922
class three_way_contiguous_iterator
890923
{

0 commit comments

Comments
 (0)