ranges.h (4587B)
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> 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> 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> 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> 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> 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> 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_