tor-browser

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

Range.h (2688B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_Range_h
      8 #define mozilla_Range_h
      9 
     10 #include "mozilla/RangedPtr.h"
     11 #include "mozilla/Span.h"
     12 
     13 #include <stddef.h>
     14 #include <type_traits>
     15 
     16 namespace mozilla {
     17 
     18 // Range<T> is a tuple containing a pointer and a length.
     19 template <typename T>
     20 class Range {
     21  template <typename U>
     22  friend class Range;
     23 
     24  // Reassignment of RangedPtrs is so (subtly) restrictive that we just make
     25  // Range immutable.
     26  const RangedPtr<T> mStart;
     27  const RangedPtr<T> mEnd;
     28 
     29 public:
     30  Range() : mStart(nullptr, 0), mEnd(nullptr, 0) {}
     31  Range(T* aPtr, size_t aLength)
     32      : mStart(aPtr, aPtr, aPtr + aLength),
     33        mEnd(aPtr + aLength, aPtr, aPtr + aLength) {
     34    if (!aPtr) {
     35      MOZ_ASSERT_DEBUG_OR_FUZZING(
     36          !aLength, "Range does not support nullptr with non-zero length.");
     37      // ...because merely having a pointer to `nullptr + 1` is undefined
     38      // behavior. UBSAN catches this as of clang-10.
     39    }
     40  }
     41  Range(const RangedPtr<T>& aStart, const RangedPtr<T>& aEnd)
     42      : mStart(aStart.get(), aStart.get(), aEnd.get()),
     43        mEnd(aEnd.get(), aStart.get(), aEnd.get()) {
     44    // Only accept two RangedPtrs within the same range.
     45    aStart.checkIdenticalRange(aEnd);
     46    MOZ_ASSERT_DEBUG_OR_FUZZING(aStart <= aEnd);
     47  }
     48 
     49  template <typename U, class = std::enable_if_t<
     50                            std::is_convertible_v<U (*)[], T (*)[]>, int>>
     51  MOZ_IMPLICIT Range(const Range<U>& aOther)
     52      : mStart(aOther.mStart), mEnd(aOther.mEnd) {}
     53 
     54  MOZ_IMPLICIT Range(Span<T> aSpan) : Range(aSpan.Elements(), aSpan.Length()) {}
     55 
     56  template <typename U, class = std::enable_if_t<
     57                            std::is_convertible_v<U (*)[], T (*)[]>, int>>
     58  MOZ_IMPLICIT Range(const Span<U>& aSpan)
     59      : Range(aSpan.Elements(), aSpan.Length()) {}
     60 
     61  RangedPtr<T> begin() const { return mStart; }
     62  RangedPtr<T> end() const { return mEnd; }
     63  size_t length() const { return mEnd - mStart; }
     64 
     65  T& operator[](size_t aOffset) const { return mStart[aOffset]; }
     66 
     67  explicit operator bool() const { return mStart != nullptr; }
     68 
     69  operator Span<T>() { return Span<T>(mStart.get(), length()); }
     70 
     71  operator Span<const T>() const { return Span<T>(mStart.get(), length()); }
     72 };
     73 
     74 template <typename T>
     75 Span(Range<T>&) -> Span<T>;
     76 
     77 template <typename T>
     78 Span(const Range<T>&) -> Span<const T>;
     79 
     80 }  // namespace mozilla
     81 
     82 #endif /* mozilla_Range_h */