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 */