1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_RANGES_RANGES_H_
6 #define BASE_RANGES_RANGES_H_
7
8 #include <array>
9 #include <iterator>
10 #include <type_traits>
11 #include <utility>
12
13 #include "base/template_util.h"
14
15 namespace base {
16
17 namespace internal {
18
19 // Overload for C array.
20 template <typename T, size_t N>
begin(T (& array)[N],priority_tag<2>)21 constexpr T* begin(T (&array)[N], priority_tag<2>) {
22 return array;
23 }
24
25 // Overload for mutable std::array. Required since std::array::begin is not
26 // constexpr prior to C++17. Needs to dispatch to the const overload since only
27 // const operator[] is constexpr in C++14.
28 template <typename T, size_t N>
begin(std::array<T,N> & array,priority_tag<2> tag)29 constexpr T* begin(std::array<T, N>& array, priority_tag<2> tag) {
30 return const_cast<T*>(begin(const_cast<const std::array<T, N>&>(array), tag));
31 }
32
33 // Overload for const std::array. Required since std::array::begin is not
34 // constexpr prior to C++17.
35 template <typename T, size_t N>
begin(const std::array<T,N> & array,priority_tag<2>)36 constexpr const T* begin(const std::array<T, N>& array, priority_tag<2>) {
37 return N != 0 ? &array[0] : nullptr;
38 }
39
40 // Generic container overload.
41 template <typename Range>
42 constexpr auto begin(Range&& range, priority_tag<1>)
43 -> decltype(std::forward<Range>(range).begin()) {
44 return std::forward<Range>(range).begin();
45 }
46
47 // Overload for free begin() function.
48 template <typename Range>
49 constexpr auto begin(Range&& range, priority_tag<0>)
50 -> decltype(begin(std::forward<Range>(range))) {
51 return begin(std::forward<Range>(range));
52 }
53
54 // Overload for C array.
55 template <typename T, size_t N>
end(T (& array)[N],priority_tag<2>)56 constexpr T* end(T (&array)[N], priority_tag<2>) {
57 return array + N;
58 }
59
60 // Overload for mutable std::array. Required since std::array::end is not
61 // constexpr prior to C++17. Needs to dispatch to the const overload since only
62 // const operator[] is constexpr in C++14.
63 template <typename T, size_t N>
end(std::array<T,N> & array,priority_tag<2> tag)64 constexpr T* end(std::array<T, N>& array, priority_tag<2> tag) {
65 return const_cast<T*>(end(const_cast<const std::array<T, N>&>(array), tag));
66 }
67
68 // Overload for const std::array. Required since std::array::end is not
69 // constexpr prior to C++17.
70 template <typename T, size_t N>
end(const std::array<T,N> & array,priority_tag<2>)71 constexpr const T* end(const std::array<T, N>& array, priority_tag<2>) {
72 return N != 0 ? (&array[0]) + N : nullptr;
73 }
74
75 // Generic container overload.
76 template <typename Range>
77 constexpr auto end(Range&& range, priority_tag<1>)
78 -> decltype(std::forward<Range>(range).end()) {
79 return std::forward<Range>(range).end();
80 }
81
82 // Overload for free end() function.
83 template <typename Range>
84 constexpr auto end(Range&& range, priority_tag<0>)
85 -> decltype(end(std::forward<Range>(range))) {
86 return end(std::forward<Range>(range));
87 }
88
89 } // namespace internal
90
91 namespace ranges {
92
93 // Simplified implementation of C++20's std::ranges::begin.
94 // As opposed to std::ranges::begin, this implementation does does not check
95 // whether begin() returns an iterator and does not inhibit ADL.
96 //
97 // The trailing return type and dispatch to the internal implementation is
98 // necessary to be SFINAE friendly.
99 //
100 // Reference: https://wg21.link/range.access.begin
101 template <typename Range>
102 constexpr auto begin(Range&& range) noexcept
103 -> decltype(internal::begin(std::forward<Range>(range),
104 internal::priority_tag<2>())) {
105 return internal::begin(std::forward<Range>(range),
106 internal::priority_tag<2>());
107 }
108
109 // Simplified implementation of C++20's std::ranges::end.
110 // As opposed to std::ranges::end, this implementation does does not check
111 // whether end() returns an iterator and does not inhibit ADL.
112 //
113 // The trailing return type and dispatch to the internal implementation is
114 // necessary to be SFINAE friendly.
115 //
116 // Reference: - https://wg21.link/range.access.end
117 template <typename Range>
118 constexpr auto end(Range&& range) noexcept
119 -> decltype(internal::end(std::forward<Range>(range),
120 internal::priority_tag<2>())) {
121 return internal::end(std::forward<Range>(range), internal::priority_tag<2>());
122 }
123
124 // Implementation of C++20's std::ranges::iterator_t.
125 //
126 // Reference: https://wg21.link/ranges.syn#:~:text=iterator_t
127 template <typename Range>
128 using iterator_t = decltype(ranges::begin(std::declval<Range&>()));
129
130 // Implementation of C++20's std::ranges::range_value_t.
131 //
132 // Reference: https://wg21.link/ranges.syn#:~:text=range_value_t
133 template <typename Range>
134 using range_value_t = iter_value_t<iterator_t<Range>>;
135
136 } // namespace ranges
137
138 } // namespace base
139
140 #endif // BASE_RANGES_RANGES_H_
141