ranges.h 4.5 KB

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