Buffer.h (5908B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifndef mozilla_Buffer_h 6 #define mozilla_Buffer_h 7 8 #include "mozilla/Assertions.h" 9 #include "mozilla/Maybe.h" 10 #include "mozilla/Span.h" 11 #include "mozilla/UniquePtr.h" 12 #include "mozilla/UniquePtrExtensions.h" 13 14 #include <cstddef> 15 #include <iterator> 16 #include <utility> 17 18 namespace mozilla { 19 20 /** 21 * A move-only type that wraps a mozilla::UniquePtr<T[]> and the length of 22 * the T[]. 23 * 24 * Unlike mozilla::Array, the length is a run-time property. 25 * Unlike mozilla::Vector and nsTArray, does not have capacity and 26 * assocatiated growth functionality. 27 * Unlike mozilla::Span, mozilla::Buffer owns the allocation it points to. 28 */ 29 template <typename T> 30 class Buffer final { 31 private: 32 mozilla::UniquePtr<T[]> mData; 33 size_t mLength; 34 35 public: 36 Buffer(const Buffer<T>& aOther) = delete; 37 Buffer<T>& operator=(const Buffer<T>& aOther) = delete; 38 39 /** 40 * Construct zero-lenth Buffer (without actually pointing to a heap 41 * allocation). 42 */ 43 Buffer() : mData(nullptr), mLength(0) {}; 44 45 /** 46 * Construct from raw parts. 47 * 48 * aLength must not be greater than the actual length of the buffer pointed 49 * to by aData. 50 */ 51 Buffer(mozilla::UniquePtr<T[]>&& aData, size_t aLength) 52 : mData(std::move(aData)), mLength(aLength) {} 53 54 /** 55 * Move constructor. Sets the moved-from Buffer to zero-length 56 * state. 57 */ 58 Buffer(Buffer<T>&& aOther) 59 : mData(std::move(aOther.mData)), mLength(aOther.mLength) { 60 aOther.mLength = 0; 61 } 62 63 /** 64 * Move assignment. Sets the moved-from Buffer to zero-length 65 * state. 66 */ 67 Buffer<T>& operator=(Buffer<T>&& aOther) { 68 mData = std::move(aOther.mData); 69 mLength = aOther.mLength; 70 aOther.mLength = 0; 71 return *this; 72 } 73 74 /** 75 * Construct by copying the elements of a Span. 76 * 77 * Allocates the internal buffer infallibly. Use CopyFrom for fallible 78 * allocation. 79 */ 80 explicit Buffer(mozilla::Span<const T> aSpan) 81 : mData(mozilla::MakeUniqueForOverwrite<T[]>(aSpan.Length())), 82 mLength(aSpan.Length()) { 83 std::copy(aSpan.cbegin(), aSpan.cend(), mData.get()); 84 } 85 86 /** 87 * Create a new Buffer by copying the elements of a Span. 88 * 89 * Allocates the internal buffer fallibly. 90 */ 91 static mozilla::Maybe<Buffer<T>> CopyFrom(mozilla::Span<const T> aSpan) { 92 if (aSpan.IsEmpty()) { 93 return Some(Buffer()); 94 } 95 96 auto data = mozilla::MakeUniqueForOverwriteFallible<T[]>(aSpan.Length()); 97 if (!data) { 98 return mozilla::Nothing(); 99 } 100 std::copy(aSpan.cbegin(), aSpan.cend(), data.get()); 101 return mozilla::Some(Buffer(std::move(data), aSpan.Length())); 102 } 103 104 /** 105 * Construct a buffer of requested length. 106 * 107 * The contents will be initialized or uninitialized according 108 * to the behavior of mozilla::MakeUnique<T[]>(aLength) for T. 109 * 110 * Allocates the internal buffer infallibly. Use Alloc for fallible 111 * allocation. 112 */ 113 explicit Buffer(size_t aLength) 114 : mData(mozilla::MakeUnique<T[]>(aLength)), mLength(aLength) {} 115 116 /** 117 * Create a new Buffer with an internal buffer of requested length. 118 * 119 * The contents will be initialized or uninitialized according to the 120 * behavior of mozilla::MakeUnique<T[]>(aLength) for T. 121 * 122 * Allocates the internal buffer fallibly. 123 */ 124 static mozilla::Maybe<Buffer<T>> Alloc(size_t aLength) { 125 auto data = mozilla::MakeUniqueFallible<T[]>(aLength); 126 if (!data) { 127 return mozilla::Nothing(); 128 } 129 return mozilla::Some(Buffer(std::move(data), aLength)); 130 } 131 132 /** 133 * Create a new Buffer with an internal buffer of requested length. 134 * 135 * This uses MakeUniqueFallibleForOverwrite so the contents will be 136 * default-initialized. 137 * 138 * Allocates the internal buffer fallibly. 139 */ 140 static Maybe<Buffer<T>> AllocForOverwrite(size_t aLength) { 141 auto data = MakeUniqueForOverwriteFallible<T[]>(aLength); 142 if (!data) { 143 return Nothing(); 144 } 145 return Some(Buffer(std::move(data), aLength)); 146 } 147 148 auto AsSpan() const { return mozilla::Span<const T>{mData.get(), mLength}; } 149 auto AsWritableSpan() { return mozilla::Span<T>{mData.get(), mLength}; } 150 operator mozilla::Span<const T>() const { return AsSpan(); } 151 operator mozilla::Span<T>() { return AsWritableSpan(); } 152 153 /** 154 * Guarantees a non-null and aligned pointer 155 * even for the zero-length case. 156 */ 157 T* Elements() { return AsWritableSpan().Elements(); } 158 size_t Length() const { return mLength; } 159 160 T& operator[](size_t aIndex) { 161 MOZ_ASSERT(aIndex < mLength); 162 return mData.get()[aIndex]; 163 } 164 165 const T& operator[](size_t aIndex) const { 166 MOZ_ASSERT(aIndex < mLength); 167 return mData.get()[aIndex]; 168 } 169 170 typedef T* iterator; 171 typedef const T* const_iterator; 172 typedef std::reverse_iterator<T*> reverse_iterator; 173 typedef std::reverse_iterator<const T*> const_reverse_iterator; 174 175 // Methods for range-based for loops. 176 iterator begin() { return mData.get(); } 177 const_iterator begin() const { return mData.get(); } 178 const_iterator cbegin() const { return begin(); } 179 iterator end() { return mData.get() + mLength; } 180 const_iterator end() const { return mData.get() + mLength; } 181 const_iterator cend() const { return end(); } 182 183 // Methods for reverse iterating. 184 reverse_iterator rbegin() { return reverse_iterator(end()); } 185 const_reverse_iterator rbegin() const { 186 return const_reverse_iterator(end()); 187 } 188 const_reverse_iterator crbegin() const { return rbegin(); } 189 reverse_iterator rend() { return reverse_iterator(begin()); } 190 const_reverse_iterator rend() const { 191 return const_reverse_iterator(begin()); 192 } 193 const_reverse_iterator crend() const { return rend(); } 194 }; 195 196 } /* namespace mozilla */ 197 198 #endif /* mozilla_Buffer_h */