• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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