1 // Copyright 2022 The PDFium 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 CORE_FXCRT_FIXED_SIZE_DATA_VECTOR_H_ 6 #define CORE_FXCRT_FIXED_SIZE_DATA_VECTOR_H_ 7 8 #include <stddef.h> 9 10 #include <memory> 11 #include <utility> 12 13 #include "core/fxcrt/check_op.h" 14 #include "core/fxcrt/compiler_specific.h" 15 #include "core/fxcrt/fx_memory_wrappers.h" 16 #include "core/fxcrt/span.h" 17 18 namespace fxcrt { 19 20 // A simple data container that has a fixed size. 21 // Unlike std::vector, it cannot be implicitly copied and its data is only 22 // accessible using spans. 23 // It can either initialize its data with zeros, or leave its data 24 // uninitialized. 25 template <typename T, 26 typename = std::enable_if_t<std::is_arithmetic<T>::value || 27 std::is_enum<T>::value || 28 IsFXDataPartitionException<T>::value>> 29 class FixedSizeDataVector { 30 public: 31 FixedSizeDataVector() = default; 32 33 // Allocates a vector of the given size with uninitialized memory. 34 // A CHECK() failure occurs when insufficient memory. Uninit(size_t size)35 static FixedSizeDataVector Uninit(size_t size) { 36 if (size == 0) { 37 return FixedSizeDataVector(); 38 } 39 // SAFETY: same `size` value passed to FX_Alloc() as to the ctor. 40 return UNSAFE_BUFFERS(FixedSizeDataVector(FX_AllocUninit(T, size), size)); 41 } 42 43 // Same as above, but return an empty vector when insufficient memory. TryUninit(size_t size)44 static FixedSizeDataVector TryUninit(size_t size) { 45 if (size == 0) { 46 return FixedSizeDataVector(); 47 } 48 T* ptr = FX_TryAllocUninit(T, size); 49 // SAFETY: same `size` value passed to FX_TryAlloc() above as 50 // passed to ctor when the ptr is non-null. 51 return UNSAFE_BUFFERS(FixedSizeDataVector(ptr, ptr ? size : 0u)); 52 } 53 54 // Allocates a vector of the given size with zeroed memory. 55 // A CHECK() failure occurs when insufficient memory. Zeroed(size_t size)56 static FixedSizeDataVector Zeroed(size_t size) { 57 if (size == 0) { 58 return FixedSizeDataVector(); 59 } 60 // SAFETY: same `size` value passed to FX_Alloc() as to the ctor. 61 return UNSAFE_BUFFERS(FixedSizeDataVector(FX_Alloc(T, size), size)); 62 } 63 64 // Same as above, but return an empty vector when insufficient memory. TryZeroed(size_t size)65 static FixedSizeDataVector TryZeroed(size_t size) { 66 if (size == 0) { 67 return FixedSizeDataVector(); 68 } 69 T* ptr = FX_TryAlloc(T, size); 70 // SAFETY: same `size` value passed to FX_TryAlloc() above as 71 // passed to ctor when the ptr is non-null. 72 return UNSAFE_BUFFERS(FixedSizeDataVector(ptr, ptr ? size : 0u)); 73 } 74 TruncatedFrom(FixedSizeDataVector && that,size_t new_size)75 static FixedSizeDataVector TruncatedFrom(FixedSizeDataVector&& that, 76 size_t new_size) { 77 CHECK_LE(new_size, that.size_); 78 FixedSizeDataVector result = std::move(that); 79 result.size_ = new_size; 80 return result; 81 } 82 83 FixedSizeDataVector(const FixedSizeDataVector&) = delete; 84 FixedSizeDataVector& operator=(const FixedSizeDataVector&) = delete; 85 FixedSizeDataVector(FixedSizeDataVector<T> && that)86 FixedSizeDataVector(FixedSizeDataVector<T>&& that) noexcept 87 : data_(std::move(that.data_)), size_(std::exchange(that.size_, 0)) {} 88 89 FixedSizeDataVector& operator=(FixedSizeDataVector<T>&& that) noexcept { 90 data_ = std::move(that.data_); 91 size_ = std::exchange(that.size_, 0); 92 return *this; 93 } 94 95 ~FixedSizeDataVector() = default; 96 empty()97 bool empty() const { return size_ == 0; } size()98 size_t size() const { return size_; } 99 100 // Implicit access to data via span. 101 operator pdfium::span<T>() { return span(); } 102 operator pdfium::span<const T>() const { return span(); } 103 104 // Explicit access to data via span. span()105 pdfium::span<T> span() { 106 // SAFETY: size_ describes size of data_. 107 return UNSAFE_BUFFERS(pdfium::make_span(data_.get(), size_)); 108 } span()109 pdfium::span<const T> span() const { 110 // SAFETY: size_ describes size of data_. 111 return UNSAFE_BUFFERS(pdfium::make_span(data_.get(), size_)); 112 } 113 114 // Convenience methods to slice the vector into spans. 115 pdfium::span<T> subspan(size_t offset, 116 size_t count = pdfium::dynamic_extent) { 117 return span().subspan(offset, count); 118 } 119 pdfium::span<const T> subspan(size_t offset, 120 size_t count = pdfium::dynamic_extent) const { 121 return span().subspan(offset, count); 122 } 123 first(size_t count)124 pdfium::span<T> first(size_t count) { return span().first(count); } first(size_t count)125 pdfium::span<const T> first(size_t count) const { 126 return span().first(count); 127 } 128 last(size_t count)129 pdfium::span<T> last(size_t count) { return span().last(count); } last(size_t count)130 pdfium::span<const T> last(size_t count) const { return span().last(count); } 131 132 private: FixedSizeDataVector(T * ptr,size_t size)133 UNSAFE_BUFFER_USAGE FixedSizeDataVector(T* ptr, size_t size) 134 : data_(ptr), size_(size) {} 135 136 std::unique_ptr<T, FxFreeDeleter> data_; 137 size_t size_ = 0; 138 }; 139 140 } // namespace fxcrt 141 142 using fxcrt::FixedSizeDataVector; 143 144 #endif // CORE_FXCRT_FIXED_SIZE_DATA_VECTOR_H_ 145