blob: 641bbaf2c7576669222f1d4454bd405a2a240fce [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_RANGES_RANGES_H_
#define BASE_RANGES_RANGES_H_
#include <array>
#include <iterator>
#include <type_traits>
#include <utility>
#include "base/template_util.h"
namespace base {
namespace internal {
// Overload for C array.
template <typename T, size_t N>
constexpr T* begin(T (&array)[N], priority_tag<2>) {
return array;
}
// Overload for mutable std::array. Required since std::array::begin is not
// constexpr prior to C++17. Needs to dispatch to the const overload since only
// const operator[] is constexpr in C++14.
template <typename T, size_t N>
constexpr T* begin(std::array<T, N>& array, priority_tag<2> tag) {
return const_cast<T*>(begin(const_cast<const std::array<T, N>&>(array), tag));
}
// Overload for const std::array. Required since std::array::begin is not
// constexpr prior to C++17.
template <typename T, size_t N>
constexpr const T* begin(const std::array<T, N>& array, priority_tag<2>) {
return N != 0 ? &array[0] : nullptr;
}
// Generic container overload.
template <typename Range>
constexpr auto begin(Range&& range, priority_tag<1>)
-> decltype(std::forward<Range>(range).begin()) {
return std::forward<Range>(range).begin();
}
// Overload for free begin() function.
template <typename Range>
constexpr auto begin(Range&& range, priority_tag<0>)
-> decltype(begin(std::forward<Range>(range))) {
return begin(std::forward<Range>(range));
}
// Overload for C array.
template <typename T, size_t N>
constexpr T* end(T (&array)[N], priority_tag<2>) {
return array + N;
}
// Overload for mutable std::array. Required since std::array::end is not
// constexpr prior to C++17. Needs to dispatch to the const overload since only
// const operator[] is constexpr in C++14.
template <typename T, size_t N>
constexpr T* end(std::array<T, N>& array, priority_tag<2> tag) {
return const_cast<T*>(end(const_cast<const std::array<T, N>&>(array), tag));
}
// Overload for const std::array. Required since std::array::end is not
// constexpr prior to C++17.
template <typename T, size_t N>
constexpr const T* end(const std::array<T, N>& array, priority_tag<2>) {
return N != 0 ? (&array[0]) + N : nullptr;
}
// Generic container overload.
template <typename Range>
constexpr auto end(Range&& range, priority_tag<1>)
-> decltype(std::forward<Range>(range).end()) {
return std::forward<Range>(range).end();
}
// Overload for free end() function.
template <typename Range>
constexpr auto end(Range&& range, priority_tag<0>)
-> decltype(end(std::forward<Range>(range))) {
return end(std::forward<Range>(range));
}
} // namespace internal
namespace ranges {
// Simplified implementation of C++20's std::ranges::begin.
// As opposed to std::ranges::begin, this implementation does does not check
// whether begin() returns an iterator and does not inhibit ADL.
//
// The trailing return type and dispatch to the internal implementation is
// necessary to be SFINAE friendly.
//
// Reference: https://wg21.link/range.access.begin
template <typename Range>
constexpr auto begin(Range&& range) noexcept
-> decltype(internal::begin(std::forward<Range>(range),
internal::priority_tag<2>())) {
return internal::begin(std::forward<Range>(range),
internal::priority_tag<2>());
}
// Simplified implementation of C++20's std::ranges::end.
// As opposed to std::ranges::end, this implementation does does not check
// whether end() returns an iterator and does not inhibit ADL.
//
// The trailing return type and dispatch to the internal implementation is
// necessary to be SFINAE friendly.
//
// Reference: - https://wg21.link/range.access.end
template <typename Range>
constexpr auto end(Range&& range) noexcept
-> decltype(internal::end(std::forward<Range>(range),
internal::priority_tag<2>())) {
return internal::end(std::forward<Range>(range), internal::priority_tag<2>());
}
// Implementation of C++20's std::ranges::iterator_t.
//
// Reference: https://wg21.link/ranges.syn#:~:text=iterator_t
template <typename Range>
using iterator_t = decltype(ranges::begin(std::declval<Range&>()));
// Implementation of C++20's std::ranges::range_value_t.
//
// Reference: https://wg21.link/ranges.syn#:~:text=range_value_t
template <typename Range>
using range_value_t = iter_value_t<iterator_t<Range>>;
} // namespace ranges
} // namespace base
#endif // BASE_RANGES_RANGES_H_