checked_iterators.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. // Copyright 2018 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_CONTAINERS_CHECKED_ITERATORS_H_
  5. #define BASE_CONTAINERS_CHECKED_ITERATORS_H_
  6. #include <iterator>
  7. #include <memory>
  8. #include <type_traits>
  9. #include "base/check_op.h"
  10. #include "base/containers/util.h"
  11. namespace base {
  12. template <typename T>
  13. class CheckedContiguousIterator {
  14. public:
  15. using difference_type = std::ptrdiff_t;
  16. using value_type = std::remove_cv_t<T>;
  17. using pointer = T*;
  18. using reference = T&;
  19. using iterator_category = std::random_access_iterator_tag;
  20. // Required for converting constructor below.
  21. template <typename U>
  22. friend class CheckedContiguousIterator;
  23. constexpr CheckedContiguousIterator() = default;
  24. #if defined(_LIBCPP_VERSION)
  25. // The following using declaration, single argument implicit constructor and
  26. // friended `__unwrap_iter` overload are required to use an optimized code
  27. // path when using a CheckedContiguousIterator with libc++ algorithms such as
  28. // std::copy(first, last, result), std::copy_backward(first, last, result),
  29. // std::move(first, last, result) and std::move_backward(first, last, result).
  30. //
  31. // Each of these algorithms dispatches to a std::memmove if this is safe to do
  32. // so, i.e. when all of `first`, `last` and `result` are iterators over
  33. // contiguous storage of the same type modulo const qualifiers.
  34. //
  35. // libc++ implements this for its contiguous iterators by invoking the
  36. // unqualified __unwrap_iter, which returns the underlying pointer for
  37. // iterators over std::vector and std::string, and returns the original
  38. // iterator otherwise.
  39. //
  40. // Thus in order to opt into this optimization for CCI, we need to provide our
  41. // own __unwrap_iter, returning the underlying raw pointer if it is safe to do
  42. // so.
  43. //
  44. // Furthermore, considering that std::copy is implemented as follows, the
  45. // return type of __unwrap_iter(CCI) needs to be convertible to CCI, which is
  46. // why an appropriate implicit single argument constructor is provided for the
  47. // optimized case:
  48. //
  49. // template <class InIter, class OutIter>
  50. // OutIter copy(InIter first, InIter last, OutIter result) {
  51. // return __copy(__unwrap_iter(first), __unwrap_iter(last),
  52. // __unwrap_iter(result));
  53. // }
  54. //
  55. // Unoptimized __copy() signature:
  56. // template <class InIter, class OutIter>
  57. // OutIter __copy(InIter first, InIter last, OutIter result);
  58. //
  59. // Optimized __copy() signature:
  60. // template <class T, class U>
  61. // U* __copy(T* first, T* last, U* result);
  62. //
  63. // Finally, this single argument constructor sets all internal fields to the
  64. // passed in pointer. This allows the resulting CCI to be used in other
  65. // optimized calls to std::copy (or std::move, std::copy_backward,
  66. // std::move_backward). However, it should not be used otherwise, since
  67. // invoking any of its public API will result in a CHECK failure. This also
  68. // means that callers should never use the single argument constructor
  69. // directly.
  70. template <typename U>
  71. using PtrIfSafeToMemmove = std::enable_if_t<
  72. std::is_trivially_copy_assignable<std::remove_const_t<U>>::value,
  73. U*>;
  74. template <int&... ExplicitArgumentBarrier, typename U = T>
  75. constexpr CheckedContiguousIterator(PtrIfSafeToMemmove<U> ptr)
  76. : start_(ptr), current_(ptr), end_(ptr) {}
  77. template <int&... ExplicitArgumentBarrier, typename U = T>
  78. friend constexpr PtrIfSafeToMemmove<U> __unwrap_iter(
  79. CheckedContiguousIterator iter) {
  80. return iter.current_;
  81. }
  82. #endif
  83. constexpr CheckedContiguousIterator(T* start, const T* end)
  84. : CheckedContiguousIterator(start, start, end) {}
  85. constexpr CheckedContiguousIterator(const T* start, T* current, const T* end)
  86. : start_(start), current_(current), end_(end) {
  87. CHECK_LE(start, current);
  88. CHECK_LE(current, end);
  89. }
  90. constexpr CheckedContiguousIterator(const CheckedContiguousIterator& other) =
  91. default;
  92. // Converting constructor allowing conversions like CCI<T> to CCI<const T>,
  93. // but disallowing CCI<const T> to CCI<T> or CCI<Derived> to CCI<Base>, which
  94. // are unsafe. Furthermore, this is the same condition as used by the
  95. // converting constructors of std::span<T> and std::unique_ptr<T[]>.
  96. // See https://wg21.link/n4042 for details.
  97. template <
  98. typename U,
  99. std::enable_if_t<std::is_convertible<U (*)[], T (*)[]>::value>* = nullptr>
  100. constexpr CheckedContiguousIterator(const CheckedContiguousIterator<U>& other)
  101. : start_(other.start_), current_(other.current_), end_(other.end_) {
  102. // We explicitly don't delegate to the 3-argument constructor here. Its
  103. // CHECKs would be redundant, since we expect |other| to maintain its own
  104. // invariant. However, DCHECKs never hurt anybody. Presumably.
  105. DCHECK_LE(other.start_, other.current_);
  106. DCHECK_LE(other.current_, other.end_);
  107. }
  108. ~CheckedContiguousIterator() = default;
  109. constexpr CheckedContiguousIterator& operator=(
  110. const CheckedContiguousIterator& other) = default;
  111. friend constexpr bool operator==(const CheckedContiguousIterator& lhs,
  112. const CheckedContiguousIterator& rhs) {
  113. lhs.CheckComparable(rhs);
  114. return lhs.current_ == rhs.current_;
  115. }
  116. friend constexpr bool operator!=(const CheckedContiguousIterator& lhs,
  117. const CheckedContiguousIterator& rhs) {
  118. lhs.CheckComparable(rhs);
  119. return lhs.current_ != rhs.current_;
  120. }
  121. friend constexpr bool operator<(const CheckedContiguousIterator& lhs,
  122. const CheckedContiguousIterator& rhs) {
  123. lhs.CheckComparable(rhs);
  124. return lhs.current_ < rhs.current_;
  125. }
  126. friend constexpr bool operator<=(const CheckedContiguousIterator& lhs,
  127. const CheckedContiguousIterator& rhs) {
  128. lhs.CheckComparable(rhs);
  129. return lhs.current_ <= rhs.current_;
  130. }
  131. friend constexpr bool operator>(const CheckedContiguousIterator& lhs,
  132. const CheckedContiguousIterator& rhs) {
  133. lhs.CheckComparable(rhs);
  134. return lhs.current_ > rhs.current_;
  135. }
  136. friend constexpr bool operator>=(const CheckedContiguousIterator& lhs,
  137. const CheckedContiguousIterator& rhs) {
  138. lhs.CheckComparable(rhs);
  139. return lhs.current_ >= rhs.current_;
  140. }
  141. constexpr CheckedContiguousIterator& operator++() {
  142. CHECK_NE(current_, end_);
  143. ++current_;
  144. return *this;
  145. }
  146. constexpr CheckedContiguousIterator operator++(int) {
  147. CheckedContiguousIterator old = *this;
  148. ++*this;
  149. return old;
  150. }
  151. constexpr CheckedContiguousIterator& operator--() {
  152. CHECK_NE(current_, start_);
  153. --current_;
  154. return *this;
  155. }
  156. constexpr CheckedContiguousIterator operator--(int) {
  157. CheckedContiguousIterator old = *this;
  158. --*this;
  159. return old;
  160. }
  161. constexpr CheckedContiguousIterator& operator+=(difference_type rhs) {
  162. if (rhs > 0) {
  163. CHECK_LE(rhs, end_ - current_);
  164. } else {
  165. CHECK_LE(-rhs, current_ - start_);
  166. }
  167. current_ += rhs;
  168. return *this;
  169. }
  170. constexpr CheckedContiguousIterator operator+(difference_type rhs) const {
  171. CheckedContiguousIterator it = *this;
  172. it += rhs;
  173. return it;
  174. }
  175. constexpr CheckedContiguousIterator& operator-=(difference_type rhs) {
  176. if (rhs < 0) {
  177. CHECK_LE(-rhs, end_ - current_);
  178. } else {
  179. CHECK_LE(rhs, current_ - start_);
  180. }
  181. current_ -= rhs;
  182. return *this;
  183. }
  184. constexpr CheckedContiguousIterator operator-(difference_type rhs) const {
  185. CheckedContiguousIterator it = *this;
  186. it -= rhs;
  187. return it;
  188. }
  189. constexpr friend difference_type operator-(
  190. const CheckedContiguousIterator& lhs,
  191. const CheckedContiguousIterator& rhs) {
  192. lhs.CheckComparable(rhs);
  193. return lhs.current_ - rhs.current_;
  194. }
  195. constexpr reference operator*() const {
  196. CHECK_NE(current_, end_);
  197. return *current_;
  198. }
  199. constexpr pointer operator->() const {
  200. CHECK_NE(current_, end_);
  201. return current_;
  202. }
  203. constexpr reference operator[](difference_type rhs) const {
  204. CHECK_GE(rhs, 0);
  205. CHECK_LT(rhs, end_ - current_);
  206. return current_[rhs];
  207. }
  208. static bool IsRangeMoveSafe(const CheckedContiguousIterator& from_begin,
  209. const CheckedContiguousIterator& from_end,
  210. const CheckedContiguousIterator& to)
  211. WARN_UNUSED_RESULT {
  212. if (from_end < from_begin)
  213. return false;
  214. const auto from_begin_uintptr = get_uintptr(from_begin.current_);
  215. const auto from_end_uintptr = get_uintptr(from_end.current_);
  216. const auto to_begin_uintptr = get_uintptr(to.current_);
  217. const auto to_end_uintptr =
  218. get_uintptr((to + std::distance(from_begin, from_end)).current_);
  219. return to_begin_uintptr >= from_end_uintptr ||
  220. to_end_uintptr <= from_begin_uintptr;
  221. }
  222. private:
  223. constexpr void CheckComparable(const CheckedContiguousIterator& other) const {
  224. CHECK_EQ(start_, other.start_);
  225. CHECK_EQ(end_, other.end_);
  226. }
  227. const T* start_ = nullptr;
  228. T* current_ = nullptr;
  229. const T* end_ = nullptr;
  230. };
  231. template <typename T>
  232. using CheckedContiguousConstIterator = CheckedContiguousIterator<const T>;
  233. } // namespace base
  234. #endif // BASE_CONTAINERS_CHECKED_ITERATORS_H_