1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
11 // template<container-compatible-range<charT> R>
12 // constexpr basic_string(from_range_t, R&& rg, const Allocator& a = Allocator()); // since C++23
19 #include "../../../containers/from_range_helpers.h"
20 #include "../../../containers/sequences/from_range_sequence_containers.h"
21 #include "test_macros.h"
23 template <class Container
, class Range
, class Alloc
>
24 concept StringHasFromRangeAllocCtr
=
25 requires(Range
&& range
, const Alloc
& alloc
) { Container(std::from_range
, std::forward
<Range
>(range
), alloc
); };
27 constexpr bool test_constraints() {
28 // (from_range, range)
30 // Input range with the same value type.
31 static_assert(HasFromRangeCtr
<std::string
, InputRange
<char>>);
32 // Input range with a convertible value type.
33 static_assert(HasFromRangeCtr
<std::string
, InputRange
<int>>);
34 // Input range with a non-convertible value type.
35 static_assert(!HasFromRangeCtr
<std::string
, InputRange
<Empty
>>);
36 // Not an input range.
37 static_assert(!HasFromRangeCtr
<std::string
, InputRangeNotDerivedFrom
>);
38 static_assert(!HasFromRangeCtr
<std::string
, InputRangeNotIndirectlyReadable
>);
39 static_assert(!HasFromRangeCtr
<std::string
, InputRangeNotInputOrOutputIterator
>);
41 // (from_range, range, alloc)
43 // Input range with the same value type.
44 using Alloc
= test_allocator
<char>;
45 using StringWithAlloc
= std::basic_string
<char, std::char_traits
<char>, Alloc
>;
46 static_assert(StringHasFromRangeAllocCtr
<StringWithAlloc
, InputRange
<char>, Alloc
>);
47 // Input range with a convertible value type.
48 static_assert(StringHasFromRangeAllocCtr
<StringWithAlloc
, InputRange
<int>, Alloc
>);
49 // Input range with a non-convertible value type.
50 static_assert(!StringHasFromRangeAllocCtr
<StringWithAlloc
, InputRange
<Empty
>, Alloc
>);
51 // Not an input range.
52 static_assert(!StringHasFromRangeAllocCtr
<StringWithAlloc
, InputRangeNotDerivedFrom
, Alloc
>);
53 static_assert(!StringHasFromRangeAllocCtr
<StringWithAlloc
, InputRangeNotIndirectlyReadable
, Alloc
>);
54 static_assert(!StringHasFromRangeAllocCtr
<StringWithAlloc
, InputRangeNotInputOrOutputIterator
, Alloc
>);
56 static_assert(!StringHasFromRangeAllocCtr
<StringWithAlloc
, InputRange
<char>, Empty
>);
61 template <class Iter
, class Sent
, class Alloc
>
62 constexpr void test_with_input(std::vector
<char> input
) {
63 auto b
= Iter(input
.data());
64 auto e
= Iter(input
.data() + input
.size());
65 std::ranges::subrange
in(std::move(b
), Sent(std::move(e
)));
68 std::string
c(std::from_range
, in
);
70 LIBCPP_ASSERT(c
.__invariants());
71 assert(c
.size() == static_cast<std::size_t>(std::distance(c
.begin(), c
.end())));
72 assert(std::ranges::equal(in
, c
));
75 { // (range, allocator)
77 std::basic_string
<char, std::char_traits
<char>, Alloc
> c(std::from_range
, in
, alloc
);
79 LIBCPP_ASSERT(c
.__invariants());
80 assert(c
.get_allocator() == alloc
);
81 assert(c
.size() == static_cast<std::size_t>(std::distance(c
.begin(), c
.end())));
82 assert(std::ranges::equal(in
, c
));
86 void test_string_exception_safety_throwing_allocator() {
87 #if !defined(TEST_HAS_NO_EXCEPTIONS)
89 ThrowingAllocator
<char> alloc
;
91 globalMemCounter
.reset();
92 // Note: the input string must be long enough to prevent SSO, otherwise the allocator won't be used.
93 std::basic_string
<char, std::char_traits
<char>, ThrowingAllocator
<char>> c(
94 std::from_range
, std::vector
<char>(64, 'A'), alloc
);
95 assert(false); // The constructor call should throw.
98 assert(globalMemCounter
.new_called
== globalMemCounter
.delete_called
);
103 constexpr bool test_inputs() {
104 for_all_iterators_and_allocators
<char>([]<class Iter
, class Sent
, class Alloc
>() {
105 // Shorter input -- SSO.
106 test_with_input
<Iter
, Sent
, Alloc
>({'a', 'b', 'c', 'd', 'e'});
107 // Longer input -- no SSO.
108 test_with_input
<Iter
, Sent
, Alloc
>(std::vector
<char>(64, 'A'));
110 test_with_input
<Iter
, Sent
, Alloc
>({});
111 // Single-element input.
112 test_with_input
<Iter
, Sent
, Alloc
>({'a'});
118 int main(int, char**) {
120 static_assert(test_inputs());
122 static_assert(test_constraints());
124 // Note: `test_exception_safety_throwing_copy` doesn't apply because copying a `char` cannot throw.
125 test_string_exception_safety_throwing_allocator();