1 // Range v3 library
2 //
3 //  Copyright Eric Niebler 2014-present
4 //
5 //  Use, modification and distribution is subject to the
6 //  Boost Software License, Version 1.0. (See accompanying
7 //  file LICENSE_1_0.txt or copy at
8 //  http://www.boost.org/LICENSE_1_0.txt)
9 //
10 // Project home: https://github.com/ericniebler/range-v3
11 //
12 // The implementation of array has been adapted from libc++
13 // (http://libcxx.llvm.org).
14 //
15 //===----------------------------------------------------------------------===//
16 //
17 //                     The LLVM Compiler Infrastructure
18 //
19 // This file is dual licensed under the MIT and the University of Illinois Open
20 // Source Licenses. See LICENSE.TXT for details.
21 //
22 //===----------------------------------------------------------------------===//
23 
24 #ifndef RANGES_V3_TEST_ARRAY_HPP
25 #define RANGES_V3_TEST_ARRAY_HPP
26 
27 #include <stdexcept>
28 #include <range/v3/range_fwd.hpp>
29 #include <range/v3/iterator/operations.hpp>
30 #include <range/v3/algorithm/fill_n.hpp>
31 #include <range/v3/algorithm/swap_ranges.hpp>
32 #include <range/v3/algorithm/equal.hpp>
33 #include <range/v3/algorithm/lexicographical_compare.hpp>
34 #include <range/v3/utility/swap.hpp>
35 
36 namespace test {
37 
38     /// \addtogroup group-utility
39     /// A std::array with constexpr support
40     template<typename T, std::size_t N>
41     struct array
42     {
43         using self = array;
44         using value_type = T;
45         using reference = value_type&;
46         using const_reference = value_type const&;
47         using iterator = value_type*;
48         using const_iterator = value_type const*;
49         using pointer = value_type*;
50         using const_pointer = value_type const*;
51         using size_type = std::size_t;
52         using difference_type = std::ptrdiff_t;
53         using reverse_iterator = ranges::reverse_iterator<iterator>;
54         using const_reverse_iterator = ranges::reverse_iterator<const_iterator>;
55 
56         value_type elems_[N > 0 ? N : 1];
57 
filltest::array58         constexpr /*c++14*/ void fill(const value_type& u)
59         {
60             ranges::fill_n(elems_, N, u);
61         }
62         constexpr /*c++14*/
swaptest::array63         void swap(array& a) noexcept(ranges::is_nothrow_swappable<T>::value)
64         {
65             ranges::swap_ranges(elems_, elems_ + N, a.elems_);
66         }
67          // iterators:
68         constexpr /*c++14*/
begintest::array69         iterator begin() noexcept
70         {
71             return iterator(elems_);
72         }
73         constexpr /*c++14*/
begintest::array74         const_iterator begin() const noexcept
75         {
76             return const_iterator(elems_);
77         }
78         constexpr /*c++14*/
endtest::array79         iterator end() noexcept
80         {
81             return iterator(elems_ + N);
82         }
83         constexpr /*c++14*/
endtest::array84         const_iterator end() const noexcept
85         {
86             return const_iterator(elems_ + N);
87         }
88         constexpr /*c++14*/
rbegintest::array89         reverse_iterator rbegin() noexcept
90         {
91             return reverse_iterator(end());
92         }
93         constexpr /*c++14*/
rbegintest::array94         const_reverse_iterator rbegin() const noexcept
95         {
96             return const_reverse_iterator(end());
97         }
98         constexpr /*c++14*/
rendtest::array99         reverse_iterator rend() noexcept
100         {
101             return reverse_iterator(begin());
102         }
103         constexpr /*c++14*/
rendtest::array104         const_reverse_iterator rend() const noexcept
105         {
106             return const_reverse_iterator(begin());
107         }
108         constexpr /*c++14*/
cbegintest::array109         const_iterator cbegin() const noexcept
110         {
111             return begin();
112         }
113         constexpr /*c++14*/
cendtest::array114         const_iterator cend() const noexcept
115         {
116             return end();
117         }
118         constexpr /*c++14*/
crbegintest::array119         const_reverse_iterator crbegin() const noexcept
120         {
121             return rbegin();
122         }
123         constexpr /*c++14*/
crendtest::array124         const_reverse_iterator crend() const noexcept
125         {
126             return rend();
127         }
128         // capacity:
129         constexpr /*c++14*/
sizetest::array130         size_type size() const noexcept
131         {
132             return N;
133         }
134         constexpr /*c++14*/
max_sizetest::array135         size_type max_size() const noexcept
136         {
137             return N;
138         }
139         constexpr /*c++14*/
emptytest::array140         bool empty() const noexcept
141         {
142             return N == 0;
143         }
144          // element access:
operator []test::array145         constexpr /*c++14*/ reference operator[](size_type n)
146         {
147             return elems_[n];
148         }
operator []test::array149         constexpr /*c++14*/ const_reference operator[](size_type n) const
150         {
151             return elems_[n];
152         }
attest::array153         constexpr /*c++14*/ reference at(size_type n)
154         {
155             if (n >= N)
156                 throw std::out_of_range("array::at");
157             return elems_[n];
158         }
attest::array159         constexpr /*c++14*/ const_reference at(size_type n) const
160         {
161             if (n >= N)
162                 throw std::out_of_range("array::at");
163             return elems_[n];
164         }
fronttest::array165         constexpr /*c++14*/ reference front()
166         {
167             return elems_[0];
168         }
fronttest::array169         constexpr /*c++14*/ const_reference front() const
170         {
171             return elems_[0];
172         }
backtest::array173         constexpr /*c++14*/ reference back()
174         {
175             return elems_[N > 0 ? N-1 : 0];
176         }
backtest::array177         constexpr /*c++14*/ const_reference back() const
178         {
179             return elems_[N > 0 ? N-1 : 0];
180         }
181         constexpr /*c++14*/
datatest::array182         value_type* data() noexcept
183         {
184             return elems_;
185         }
186         constexpr /*c++14*/
datatest::array187         const value_type* data() const noexcept
188         {
189             return elems_;
190         }
191     };
192 
193     template<class T, size_t N>
194     constexpr /*c++14*/
195     bool
operator ==(const array<T,N> & x,const array<T,N> & y)196     operator==(const array<T, N>& x, const array<T, N>& y)
197     {
198         return ranges::equal(x.elems_, x.elems_ + N, y.elems_);
199     }
200     template<class T, size_t N>
201     constexpr /*c++14*/
202     bool
operator !=(const array<T,N> & x,const array<T,N> & y)203     operator!=(const array<T, N>& x, const array<T, N>& y)
204     {
205         return !(x == y);
206     }
207     template<class T, size_t N>
208     constexpr /*c++14*/
209     bool
operator <(const array<T,N> & x,const array<T,N> & y)210     operator<(const array<T, N>& x, const array<T, N>& y)
211     {
212         return ranges::lexicographical_compare(x.elems_, x.elems_ + N, y.elems_, y.elems_ + N);
213     }
214     template<class T, size_t N>
215     constexpr /*c++14*/
216     bool
operator >(const array<T,N> & x,const array<T,N> & y)217     operator>(const array<T, N>& x, const array<T, N>& y)
218     {
219         return y < x;
220     }
221     template<class T, size_t N>
222     constexpr /*c++14*/
223     bool
operator <=(const array<T,N> & x,const array<T,N> & y)224     operator<=(const array<T, N>& x, const array<T, N>& y)
225     {
226         return !(y < x);
227     }
228 
229     template<class T, size_t N>
230     constexpr /*c++14*/
231     bool
operator >=(const array<T,N> & x,const array<T,N> & y)232     operator>=(const array<T, N>& x, const array<T, N>& y)
233     {
234          return !(x < y);
235     }
236 
237     template<class T, size_t N>
238     constexpr /*c++14*/
swap(array<T,N> & x,array<T,N> & y)239     auto swap(array<T, N>& x, array<T, N>& y)
240     noexcept(ranges::is_nothrow_swappable<T>::value)
241     -> typename std::enable_if<ranges::is_swappable<T>::value, void>::type
242     {
243         x.swap(y);
244     }
245 
246     template<size_t I, class T, size_t N>
247     constexpr /*c++14*/
get(array<T,N> & a)248     T& get(array<T, N>& a) noexcept
249     {
250         static_assert(I < N, "Index out of bounds in ranges::get<> (ranges::array)");
251         return a.elems_[I];
252     }
253 
254     template<size_t I, class T, size_t N>
255     constexpr /*c++14*/
get(const array<T,N> & a)256     const T& get(const array<T, N>& a) noexcept
257     {
258         static_assert(I < N, "Index out of bounds in ranges::get<> (const ranges::array)");
259         return a.elems_[I];
260     }
261 
262     template<size_t I, class T, size_t N>
263     constexpr /*c++14*/
get(array<T,N> && a)264     T && get(array<T, N>&& a) noexcept
265     {
266         static_assert(I < N, "Index out of bounds in ranges::get<> (ranges::array &&)");
267         return std::move(a.elems_[I]);
268     }
269 
270     template<class T, std::size_t N>
swap(array<T,N> & a,array<T,N> & b)271     constexpr /*c++14*/ void swap(array<T, N>& a, array<T, N>& b) {
272         for(std::size_t i = 0; i != N; ++i) {
273             auto tmp = std::move(a[i]);
274             a[i] = std::move(b[i]);
275             b[i] = std::move(tmp);
276         }
277     }
278 }  // namespace test
279 
280 RANGES_DIAGNOSTIC_PUSH
281 RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
282 
283 namespace std
284 {
285 
286 template<class T, size_t N>
287 class tuple_size<test::array<T, N>>
288     : public integral_constant<size_t, N> {};
289 
290 template<size_t I, class T, size_t N>
291 class tuple_element<I, test::array<T, N> >
292 {
293  public:
294     using type = T;
295 };
296 
297 }  // namespace std
298 
299 RANGES_DIAGNOSTIC_POP
300 
301 #endif // RANGES_V3_TEST_ARRAY_HPP
302