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 
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 
11 // <memory>
12 
13 // template <nothrow-forward-iterator ForwardIterator, nothrow-sentinel-for<ForwardIterator> Sentinel, class T>
14 //   requires constructible_from<iter_value_t<ForwardIterator>, const T&>
15 // ForwardIterator ranges::uninitialized_fill(ForwardIterator first, Sentinel last, const T& x);
16 //
17 // template <nothrow-forward-range ForwardRange, class T>
18 //   requires constructible_from<range_value_t<ForwardRange>, const T&>
19 // borrowed_iterator_t<ForwardRange> ranges::uninitialized_fill(ForwardRange&& range, const T& x);
20 
21 #include <algorithm>
22 #include <cassert>
23 #include <iterator>
24 #include <memory>
25 #include <ranges>
26 #include <type_traits>
27 
28 #include "../buffer.h"
29 #include "../counted.h"
30 #include "test_macros.h"
31 #include "test_iterators.h"
32 
33 // TODO(varconst): consolidate the ADL checks into a single file.
34 // Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
35 // implementations are allowed to use a different mechanism to achieve this effect, so this check is
36 // libc++-specific.
37 LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_fill)>);
38 
39 struct NotConvertibleFromInt {};
40 static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_fill), NotConvertibleFromInt*,
41                                    NotConvertibleFromInt*, int>);
42 
43 int main(int, char**) {
44   constexpr int value = 42;
45   Counted x(value);
46   Counted::reset();
47   auto pred = [](const Counted& e) { return e.value == value; };
48 
49   // An empty range -- no default constructors should be invoked.
50   {
51     Buffer<Counted, 1> buf;
52 
53     std::ranges::uninitialized_fill(buf.begin(), buf.begin(), x);
54     assert(Counted::current_objects == 0);
55     assert(Counted::total_objects == 0);
56 
57     std::ranges::uninitialized_fill(std::ranges::empty_view<Counted>(), x);
58     assert(Counted::current_objects == 0);
59     assert(Counted::total_objects == 0);
60 
61     forward_iterator<Counted*> it(buf.begin());
62     auto range = std::ranges::subrange(it, sentinel_wrapper<forward_iterator<Counted*>>(it));
63     std::ranges::uninitialized_fill(range.begin(), range.end(), x);
64     assert(Counted::current_objects == 0);
65     assert(Counted::total_objects == 0);
66     Counted::reset();
67 
68     std::ranges::uninitialized_fill(range, x);
69     assert(Counted::current_objects == 0);
70     assert(Counted::total_objects == 0);
71     Counted::reset();
72   }
73 
74   // A range containing several objects, (iter, sentinel) overload.
75   {
76     constexpr int N = 5;
77     Buffer<Counted, N> buf;
78 
79     std::ranges::uninitialized_fill(buf.begin(), buf.end(), x);
80     assert(Counted::current_objects == N);
81     assert(Counted::total_objects == N);
82     assert(std::all_of(buf.begin(), buf.end(), pred));
83 
84     std::destroy(buf.begin(), buf.end());
85     Counted::reset();
86   }
87 
88   // A range containing several objects, (range) overload.
89   {
90     constexpr int N = 5;
91     Buffer<Counted, N> buf;
92 
93     auto range = std::ranges::subrange(buf.begin(), buf.end());
94     std::ranges::uninitialized_fill(range, x);
95     assert(Counted::current_objects == N);
96     assert(Counted::total_objects == N);
97     assert(std::all_of(buf.begin(), buf.end(), pred));
98 
99     std::destroy(buf.begin(), buf.end());
100     Counted::reset();
101   }
102 
103   // Using `counted_iterator`.
104   {
105     constexpr int N = 3;
106     Buffer<Counted, 5> buf;
107 
108     std::ranges::uninitialized_fill(std::counted_iterator(buf.begin(), N), std::default_sentinel, x);
109     assert(Counted::current_objects == N);
110     assert(Counted::total_objects == N);
111     assert(std::all_of(buf.begin(), buf.begin() + N, pred));
112 
113     std::destroy(buf.begin(), buf.begin() + N);
114     Counted::reset();
115   }
116 
117   // Using `views::counted`.
118   {
119     constexpr int N = 3;
120     Buffer<Counted, 5> buf;
121 
122     std::ranges::uninitialized_fill(std::views::counted(buf.begin(), N), x);
123     assert(Counted::current_objects == N);
124     assert(Counted::total_objects == N);
125     assert(std::all_of(buf.begin(), buf.begin() + N, pred));
126 
127     std::destroy(buf.begin(), buf.begin() + N);
128     Counted::reset();
129   }
130 
131   // Using `reverse_view`.
132   {
133     constexpr int N = 3;
134     Buffer<Counted, 5> buf;
135 
136     auto range = std::ranges::subrange(buf.begin(), buf.begin() + N);
137     std::ranges::uninitialized_fill(std::ranges::reverse_view(range), x);
138     assert(Counted::current_objects == N);
139     assert(Counted::total_objects == N);
140     assert(std::all_of(buf.begin(), buf.begin() + N, pred));
141 
142     std::destroy(buf.begin(), buf.begin() + N);
143     Counted::reset();
144   }
145 
146   // Any existing values should be overwritten by value constructors.
147   {
148     constexpr int N = 5;
149     int buffer[N] = {value, value, value, value, value};
150 
151     std::ranges::uninitialized_fill(buffer, buffer + 1, 0);
152     assert(buffer[0] == 0);
153     assert(buffer[1] == value);
154 
155     std::ranges::uninitialized_fill(buffer, buffer + N, 0);
156     assert(buffer[0] == 0);
157     assert(buffer[1] == 0);
158     assert(buffer[2] == 0);
159     assert(buffer[3] == 0);
160     assert(buffer[4] == 0);
161   }
162 
163   // An exception is thrown while objects are being created -- the existing objects should stay
164   // valid. (iterator, sentinel) overload.
165 #ifndef TEST_HAS_NO_EXCEPTIONS
166   {
167     constexpr int N = 3;
168     Buffer<Counted, 5> buf;
169 
170     Counted::throw_on = N; // When constructing the fourth object.
171     try {
172       std::ranges::uninitialized_fill(buf.begin(), buf.end(), x);
173     } catch (...) {
174     }
175     assert(Counted::current_objects == 0);
176     assert(Counted::total_objects == N);
177 
178     std::destroy(buf.begin(), buf.begin() + N);
179     Counted::reset();
180   }
181 
182   // An exception is thrown while objects are being created -- the existing objects should stay
183   // valid. (range) overload.
184   {
185     constexpr int N = 3;
186     Buffer<Counted, 5> buf;
187 
188     Counted::throw_on = N; // When constructing the fourth object.
189     try {
190       std::ranges::uninitialized_fill(buf, x);
191     } catch (...) {
192     }
193     assert(Counted::current_objects == 0);
194     assert(Counted::total_objects == N);
195 
196     std::destroy(buf.begin(), buf.begin() + N);
197     Counted::reset();
198   }
199 #endif // TEST_HAS_NO_EXCEPTIONS
200 
201   return 0;
202 }
203