• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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