tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

checked_iterators.h (9715B)


      1 // Copyright 2018 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_CONTAINERS_CHECKED_ITERATORS_H_
      6 #define BASE_CONTAINERS_CHECKED_ITERATORS_H_
      7 
      8 #include <iterator>
      9 #include <memory>
     10 #include <type_traits>
     11 
     12 #include "base/check_op.h"
     13 #include "base/containers/util.h"
     14 #include "base/memory/raw_ptr_exclusion.h"
     15 #include "build/build_config.h"
     16 
     17 namespace base {
     18 
     19 template <typename T>
     20 class CheckedContiguousIterator {
     21 public:
     22  using difference_type = std::ptrdiff_t;
     23  using value_type = std::remove_cv_t<T>;
     24  using pointer = T*;
     25  using reference = T&;
     26  using iterator_category = std::random_access_iterator_tag;
     27 #if defined(__cpp_lib_ranges)
     28  using iterator_concept = std::contiguous_iterator_tag;
     29 #endif
     30 
     31  // Required for converting constructor below.
     32  template <typename U>
     33  friend class CheckedContiguousIterator;
     34 
     35  // Required for certain libc++ algorithm optimizations that are not available
     36  // for NaCl.
     37  template <typename Ptr>
     38  friend struct std::pointer_traits;
     39 
     40  constexpr CheckedContiguousIterator() = default;
     41 
     42  constexpr CheckedContiguousIterator(T* start, const T* end)
     43      : CheckedContiguousIterator(start, start, end) {}
     44 
     45  constexpr CheckedContiguousIterator(const T* start, T* current, const T* end)
     46      : start_(start), current_(current), end_(end) {
     47    CHECK_LE(start, current);
     48    CHECK_LE(current, end);
     49  }
     50 
     51  constexpr CheckedContiguousIterator(const CheckedContiguousIterator& other) =
     52      default;
     53 
     54  // Converting constructor allowing conversions like CCI<T> to CCI<const T>,
     55  // but disallowing CCI<const T> to CCI<T> or CCI<Derived> to CCI<Base>, which
     56  // are unsafe. Furthermore, this is the same condition as used by the
     57  // converting constructors of std::span<T> and std::unique_ptr<T[]>.
     58  // See https://wg21.link/n4042 for details.
     59  template <
     60      typename U,
     61      std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>* = nullptr>
     62  constexpr CheckedContiguousIterator(const CheckedContiguousIterator<U>& other)
     63      : start_(other.start_), current_(other.current_), end_(other.end_) {
     64    // We explicitly don't delegate to the 3-argument constructor here. Its
     65    // CHECKs would be redundant, since we expect |other| to maintain its own
     66    // invariant. However, DCHECKs never hurt anybody. Presumably.
     67    DCHECK_LE(other.start_, other.current_);
     68    DCHECK_LE(other.current_, other.end_);
     69  }
     70 
     71  ~CheckedContiguousIterator() = default;
     72 
     73  constexpr CheckedContiguousIterator& operator=(
     74      const CheckedContiguousIterator& other) = default;
     75 
     76  friend constexpr bool operator==(const CheckedContiguousIterator& lhs,
     77                                   const CheckedContiguousIterator& rhs) {
     78    lhs.CheckComparable(rhs);
     79    return lhs.current_ == rhs.current_;
     80  }
     81 
     82  friend constexpr bool operator!=(const CheckedContiguousIterator& lhs,
     83                                   const CheckedContiguousIterator& rhs) {
     84    lhs.CheckComparable(rhs);
     85    return lhs.current_ != rhs.current_;
     86  }
     87 
     88  friend constexpr bool operator<(const CheckedContiguousIterator& lhs,
     89                                  const CheckedContiguousIterator& rhs) {
     90    lhs.CheckComparable(rhs);
     91    return lhs.current_ < rhs.current_;
     92  }
     93 
     94  friend constexpr bool operator<=(const CheckedContiguousIterator& lhs,
     95                                   const CheckedContiguousIterator& rhs) {
     96    lhs.CheckComparable(rhs);
     97    return lhs.current_ <= rhs.current_;
     98  }
     99  friend constexpr bool operator>(const CheckedContiguousIterator& lhs,
    100                                  const CheckedContiguousIterator& rhs) {
    101    lhs.CheckComparable(rhs);
    102    return lhs.current_ > rhs.current_;
    103  }
    104 
    105  friend constexpr bool operator>=(const CheckedContiguousIterator& lhs,
    106                                   const CheckedContiguousIterator& rhs) {
    107    lhs.CheckComparable(rhs);
    108    return lhs.current_ >= rhs.current_;
    109  }
    110 
    111  constexpr CheckedContiguousIterator& operator++() {
    112    CHECK_NE(current_, end_);
    113    ++current_;
    114    return *this;
    115  }
    116 
    117  constexpr CheckedContiguousIterator operator++(int) {
    118    CheckedContiguousIterator old = *this;
    119    ++*this;
    120    return old;
    121  }
    122 
    123  constexpr CheckedContiguousIterator& operator--() {
    124    CHECK_NE(current_, start_);
    125    --current_;
    126    return *this;
    127  }
    128 
    129  constexpr CheckedContiguousIterator operator--(int) {
    130    CheckedContiguousIterator old = *this;
    131    --*this;
    132    return old;
    133  }
    134 
    135  constexpr CheckedContiguousIterator& operator+=(difference_type rhs) {
    136    if (rhs > 0) {
    137      CHECK_LE(rhs, end_ - current_);
    138    } else {
    139      CHECK_LE(-rhs, current_ - start_);
    140    }
    141    current_ += rhs;
    142    return *this;
    143  }
    144 
    145  constexpr CheckedContiguousIterator operator+(difference_type rhs) const {
    146    CheckedContiguousIterator it = *this;
    147    it += rhs;
    148    return it;
    149  }
    150 
    151  constexpr friend CheckedContiguousIterator operator+(
    152      difference_type lhs,
    153      const CheckedContiguousIterator& rhs) {
    154    return rhs + lhs;
    155  }
    156 
    157  constexpr CheckedContiguousIterator& operator-=(difference_type rhs) {
    158    if (rhs < 0) {
    159      CHECK_LE(-rhs, end_ - current_);
    160    } else {
    161      CHECK_LE(rhs, current_ - start_);
    162    }
    163    current_ -= rhs;
    164    return *this;
    165  }
    166 
    167  constexpr CheckedContiguousIterator operator-(difference_type rhs) const {
    168    CheckedContiguousIterator it = *this;
    169    it -= rhs;
    170    return it;
    171  }
    172 
    173  constexpr friend difference_type operator-(
    174      const CheckedContiguousIterator& lhs,
    175      const CheckedContiguousIterator& rhs) {
    176    lhs.CheckComparable(rhs);
    177    return lhs.current_ - rhs.current_;
    178  }
    179 
    180  constexpr reference operator*() const {
    181    CHECK_NE(current_, end_);
    182    return *current_;
    183  }
    184 
    185  constexpr pointer operator->() const {
    186    CHECK_NE(current_, end_);
    187    return current_;
    188  }
    189 
    190  constexpr reference operator[](difference_type rhs) const {
    191    CHECK_GE(rhs, 0);
    192    CHECK_LT(rhs, end_ - current_);
    193    return current_[rhs];
    194  }
    195 
    196  [[nodiscard]] static bool IsRangeMoveSafe(
    197      const CheckedContiguousIterator& from_begin,
    198      const CheckedContiguousIterator& from_end,
    199      const CheckedContiguousIterator& to) {
    200    if (from_end < from_begin)
    201      return false;
    202    const auto from_begin_uintptr = get_uintptr(from_begin.current_);
    203    const auto from_end_uintptr = get_uintptr(from_end.current_);
    204    const auto to_begin_uintptr = get_uintptr(to.current_);
    205    const auto to_end_uintptr =
    206        get_uintptr((to + std::distance(from_begin, from_end)).current_);
    207 
    208    return to_begin_uintptr >= from_end_uintptr ||
    209           to_end_uintptr <= from_begin_uintptr;
    210  }
    211 
    212 private:
    213  constexpr void CheckComparable(const CheckedContiguousIterator& other) const {
    214    CHECK_EQ(start_, other.start_);
    215    CHECK_EQ(end_, other.end_);
    216  }
    217 
    218  // This field is not a raw_ptr<> because it was filtered by the rewriter for:
    219  // #union, #constexpr-ctor-field-initializer
    220  RAW_PTR_EXCLUSION const T* start_ = nullptr;
    221  // This field is not a raw_ptr<> because it was filtered by the rewriter for:
    222  // #union, #constexpr-ctor-field-initializer
    223  RAW_PTR_EXCLUSION T* current_ = nullptr;
    224  // This field is not a raw_ptr<> because it was filtered by the rewriter for:
    225  // #union, #constexpr-ctor-field-initializer
    226  RAW_PTR_EXCLUSION const T* end_ = nullptr;
    227 };
    228 
    229 template <typename T>
    230 using CheckedContiguousConstIterator = CheckedContiguousIterator<const T>;
    231 
    232 }  // namespace base
    233 
    234 // Specialize both std::__is_cpp17_contiguous_iterator and std::pointer_traits
    235 // for CCI in case we compile with libc++ outside of NaCl. The former is
    236 // required to enable certain algorithm optimizations (e.g. std::copy can be a
    237 // simple std::memmove under certain circumstances), and is a precursor to
    238 // C++20's std::contiguous_iterator concept [1]. Once we actually use C++20 it
    239 // will be enough to add `using iterator_concept = std::contiguous_iterator_tag`
    240 // to the iterator class [2], and we can get rid of this non-standard
    241 // specialization.
    242 //
    243 // The latter is required to obtain the underlying raw pointer without resulting
    244 // in CHECK failures. The important bit is the `to_address(pointer)` overload,
    245 // which is the standard blessed way to customize `std::to_address(pointer)` in
    246 // C++20 [3].
    247 //
    248 // [1] https://wg21.link/iterator.concept.contiguous
    249 // [2] https://wg21.link/std.iterator.tags
    250 // [3] https://wg21.link/pointer.traits.optmem
    251 
    252 #if defined(_LIBCPP_VERSION)
    253 
    254 // TODO(crbug.com/1284275): Remove when C++20 is on by default, as the use
    255 // of `iterator_concept` above should suffice.
    256 _LIBCPP_BEGIN_NAMESPACE_STD
    257 
    258 // TODO(crbug.com/1449299): https://reviews.llvm.org/D150801 renamed this from
    259 // `__is_cpp17_contiguous_iterator` to `__libcpp_is_contiguous_iterator`. Clean
    260 // up the old spelling after libc++ rolls.
    261 template <typename T>
    262 struct __is_cpp17_contiguous_iterator;
    263 template <typename T>
    264 struct __is_cpp17_contiguous_iterator<::base::CheckedContiguousIterator<T>>
    265    : true_type {};
    266 
    267 template <typename T>
    268 struct __libcpp_is_contiguous_iterator;
    269 template <typename T>
    270 struct __libcpp_is_contiguous_iterator<::base::CheckedContiguousIterator<T>>
    271    : true_type {};
    272 
    273 _LIBCPP_END_NAMESPACE_STD
    274 
    275 #endif
    276 
    277 namespace std {
    278 
    279 template <typename T>
    280 struct pointer_traits<::base::CheckedContiguousIterator<T>> {
    281  using pointer = ::base::CheckedContiguousIterator<T>;
    282  using element_type = T;
    283  using difference_type = ptrdiff_t;
    284 
    285  template <typename U>
    286  using rebind = ::base::CheckedContiguousIterator<U>;
    287 
    288  static constexpr pointer pointer_to(element_type& r) noexcept {
    289    return pointer(&r, &r);
    290  }
    291 
    292  static constexpr element_type* to_address(pointer p) noexcept {
    293    return p.current_;
    294  }
    295 };
    296 
    297 }  // namespace std
    298 
    299 #endif  // BASE_CONTAINERS_CHECKED_ITERATORS_H_