/src/gdal/third_party/flatbuffers/vector_downward.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2021 Google Inc. All rights reserved. |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #ifndef FLATBUFFERS_VECTOR_DOWNWARD_H_ |
18 | | #define FLATBUFFERS_VECTOR_DOWNWARD_H_ |
19 | | |
20 | | #include "flatbuffers/base.h" |
21 | | #include "flatbuffers/default_allocator.h" |
22 | | #include "flatbuffers/detached_buffer.h" |
23 | | |
24 | | namespace flatbuffers { |
25 | | |
26 | | // This is a minimal replication of std::vector<uint8_t> functionality, |
27 | | // except growing from higher to lower addresses. i.e. push_back() inserts data |
28 | | // in the lowest address in the vector. |
29 | | // Since this vector leaves the lower part unused, we support a "scratch-pad" |
30 | | // that can be stored there for temporary data, to share the allocated space. |
31 | | // Essentially, this supports 2 std::vectors in a single buffer. |
32 | | class vector_downward { |
33 | | public: |
34 | | explicit vector_downward(size_t initial_size, Allocator *allocator, |
35 | | bool own_allocator, size_t buffer_minalign) |
36 | 68.2k | : allocator_(allocator), |
37 | 68.2k | own_allocator_(own_allocator), |
38 | 68.2k | initial_size_(initial_size), |
39 | 68.2k | buffer_minalign_(buffer_minalign), |
40 | 68.2k | reserved_(0), |
41 | 68.2k | size_(0), |
42 | 68.2k | buf_(nullptr), |
43 | 68.2k | cur_(nullptr), |
44 | 68.2k | scratch_(nullptr) {} |
45 | | |
46 | | vector_downward(vector_downward &&other) |
47 | | // clang-format on |
48 | | : allocator_(other.allocator_), |
49 | | own_allocator_(other.own_allocator_), |
50 | | initial_size_(other.initial_size_), |
51 | | buffer_minalign_(other.buffer_minalign_), |
52 | | reserved_(other.reserved_), |
53 | | size_(other.size_), |
54 | | buf_(other.buf_), |
55 | | cur_(other.cur_), |
56 | 0 | scratch_(other.scratch_) { |
57 | 0 | // No change in other.allocator_ |
58 | 0 | // No change in other.initial_size_ |
59 | 0 | // No change in other.buffer_minalign_ |
60 | 0 | other.own_allocator_ = false; |
61 | 0 | other.reserved_ = 0; |
62 | 0 | other.buf_ = nullptr; |
63 | 0 | other.cur_ = nullptr; |
64 | 0 | other.scratch_ = nullptr; |
65 | 0 | } |
66 | | |
67 | 0 | vector_downward &operator=(vector_downward &&other) { |
68 | 0 | // Move construct a temporary and swap idiom |
69 | 0 | vector_downward temp(std::move(other)); |
70 | 0 | swap(temp); |
71 | 0 | return *this; |
72 | 0 | } |
73 | | |
74 | 68.2k | ~vector_downward() { |
75 | 68.2k | clear_buffer(); |
76 | 68.2k | clear_allocator(); |
77 | 68.2k | } |
78 | | |
79 | 0 | void reset() { |
80 | 0 | clear_buffer(); |
81 | 0 | clear(); |
82 | 0 | } |
83 | | |
84 | 0 | void clear() { |
85 | 0 | if (buf_) { |
86 | 0 | cur_ = buf_ + reserved_; |
87 | 0 | } else { |
88 | 0 | reserved_ = 0; |
89 | 0 | cur_ = nullptr; |
90 | 0 | } |
91 | 0 | size_ = 0; |
92 | 0 | clear_scratch(); |
93 | 0 | } |
94 | | |
95 | 421 | void clear_scratch() { scratch_ = buf_; } |
96 | | |
97 | 68.2k | void clear_allocator() { |
98 | 68.2k | if (own_allocator_ && allocator_) { delete allocator_; } |
99 | 68.2k | allocator_ = nullptr; |
100 | 68.2k | own_allocator_ = false; |
101 | 68.2k | } |
102 | | |
103 | 68.2k | void clear_buffer() { |
104 | 68.2k | if (buf_) Deallocate(allocator_, buf_, reserved_); |
105 | 68.2k | buf_ = nullptr; |
106 | 68.2k | } |
107 | | |
108 | | // Relinquish the pointer to the caller. |
109 | 0 | uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) { |
110 | 0 | auto *buf = buf_; |
111 | 0 | allocated_bytes = reserved_; |
112 | 0 | offset = static_cast<size_t>(cur_ - buf_); |
113 | 0 |
|
114 | 0 | // release_raw only relinquishes the buffer ownership. |
115 | 0 | // Does not deallocate or reset the allocator. Destructor will do that. |
116 | 0 | buf_ = nullptr; |
117 | 0 | clear(); |
118 | 0 | return buf; |
119 | 0 | } |
120 | | |
121 | | // Relinquish the pointer to the caller. |
122 | 0 | DetachedBuffer release() { |
123 | 0 | // allocator ownership (if any) is transferred to DetachedBuffer. |
124 | 0 | DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_, |
125 | 0 | size()); |
126 | 0 | if (own_allocator_) { |
127 | 0 | allocator_ = nullptr; |
128 | 0 | own_allocator_ = false; |
129 | 0 | } |
130 | 0 | buf_ = nullptr; |
131 | 0 | clear(); |
132 | 0 | return fb; |
133 | 0 | } |
134 | | |
135 | 88.6k | size_t ensure_space(size_t len) { |
136 | 88.6k | FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_); |
137 | 88.6k | if (len > static_cast<size_t>(cur_ - scratch_)) { reallocate(len); } |
138 | | // Beyond this, signed offsets may not have enough range: |
139 | | // (FlatBuffers > 2GB not supported). |
140 | 88.6k | FLATBUFFERS_ASSERT(size() < FLATBUFFERS_MAX_BUFFER_SIZE); |
141 | 88.6k | return len; |
142 | 88.6k | } |
143 | | |
144 | 116k | inline uint8_t *make_space(size_t len) { |
145 | 116k | if (len) { |
146 | 68.9k | ensure_space(len); |
147 | 68.9k | cur_ -= len; |
148 | 68.9k | size_ += static_cast<uoffset_t>(len); |
149 | 68.9k | } |
150 | 116k | return cur_; |
151 | 116k | } |
152 | | |
153 | | // Returns nullptr if using the DefaultAllocator. |
154 | 0 | Allocator *get_custom_allocator() { return allocator_; } |
155 | | |
156 | 232k | inline uoffset_t size() const { return size_; } |
157 | | |
158 | 557 | uoffset_t scratch_size() const { |
159 | 557 | return static_cast<uoffset_t>(scratch_ - buf_); |
160 | 557 | } |
161 | | |
162 | 0 | size_t capacity() const { return reserved_; } |
163 | | |
164 | 57.3k | uint8_t *data() const { |
165 | 57.3k | FLATBUFFERS_ASSERT(cur_); |
166 | 57.3k | return cur_; |
167 | 57.3k | } |
168 | | |
169 | 6.40k | uint8_t *scratch_data() const { |
170 | 6.40k | FLATBUFFERS_ASSERT(buf_); |
171 | 6.40k | return buf_; |
172 | 6.40k | } |
173 | | |
174 | 38.5k | uint8_t *scratch_end() const { |
175 | 38.5k | FLATBUFFERS_ASSERT(scratch_); |
176 | 38.5k | return scratch_; |
177 | 38.5k | } |
178 | | |
179 | 18.1k | uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; } |
180 | | |
181 | 6.50k | void push(const uint8_t *bytes, size_t num) { |
182 | 6.50k | if (num > 0) { memcpy(make_space(num), bytes, num); } |
183 | 6.50k | } |
184 | | |
185 | | // Specialized version of push() that avoids memcpy call for small data. |
186 | 38.4k | template<typename T> void push_small(const T &little_endian_t) { |
187 | 38.4k | make_space(sizeof(T)); |
188 | 38.4k | *reinterpret_cast<T *>(cur_) = little_endian_t; |
189 | 38.4k | } void gdal_flatbuffers::vector_downward::push_small<int>(int const&) Line | Count | Source | 186 | 12.1k | template<typename T> void push_small(const T &little_endian_t) { | 187 | 12.1k | make_space(sizeof(T)); | 188 | 12.1k | *reinterpret_cast<T *>(cur_) = little_endian_t; | 189 | 12.1k | } |
void gdal_flatbuffers::vector_downward::push_small<unsigned int>(unsigned int const&) Line | Count | Source | 186 | 20.1k | template<typename T> void push_small(const T &little_endian_t) { | 187 | 20.1k | make_space(sizeof(T)); | 188 | 20.1k | *reinterpret_cast<T *>(cur_) = little_endian_t; | 189 | 20.1k | } |
void gdal_flatbuffers::vector_downward::push_small<unsigned char>(unsigned char const&) Line | Count | Source | 186 | 5.97k | template<typename T> void push_small(const T &little_endian_t) { | 187 | 5.97k | make_space(sizeof(T)); | 188 | 5.97k | *reinterpret_cast<T *>(cur_) = little_endian_t; | 189 | 5.97k | } |
void gdal_flatbuffers::vector_downward::push_small<unsigned long>(unsigned long const&) Line | Count | Source | 186 | 84 | template<typename T> void push_small(const T &little_endian_t) { | 187 | 84 | make_space(sizeof(T)); | 188 | 84 | *reinterpret_cast<T *>(cur_) = little_endian_t; | 189 | 84 | } |
void gdal_flatbuffers::vector_downward::push_small<unsigned short>(unsigned short const&) Line | Count | Source | 186 | 119 | template<typename T> void push_small(const T &little_endian_t) { | 187 | 119 | make_space(sizeof(T)); | 188 | 119 | *reinterpret_cast<T *>(cur_) = little_endian_t; | 189 | 119 | } |
Unexecuted instantiation: void gdal_flatbuffers::vector_downward::push_small<gdal_generated_icechunk::ObjectId12>(gdal_generated_icechunk::ObjectId12 const&) Unexecuted instantiation: void gdal_flatbuffers::vector_downward::push_small<gdal_generated_icechunk::ObjectId8>(gdal_generated_icechunk::ObjectId8 const&) |
190 | | |
191 | 19.6k | template<typename T> void scratch_push_small(const T &t) { |
192 | 19.6k | ensure_space(sizeof(T)); |
193 | 19.6k | *reinterpret_cast<T *>(scratch_) = t; |
194 | 19.6k | scratch_ += sizeof(T); |
195 | 19.6k | } void gdal_flatbuffers::vector_downward::scratch_push_small<gdal_flatbuffers::FlatBufferBuilder::FieldLoc>(gdal_flatbuffers::FlatBufferBuilder::FieldLoc const&) Line | Count | Source | 191 | 18.8k | template<typename T> void scratch_push_small(const T &t) { | 192 | 18.8k | ensure_space(sizeof(T)); | 193 | 18.8k | *reinterpret_cast<T *>(scratch_) = t; | 194 | 18.8k | scratch_ += sizeof(T); | 195 | 18.8k | } |
void gdal_flatbuffers::vector_downward::scratch_push_small<unsigned int>(unsigned int const&) Line | Count | Source | 191 | 863 | template<typename T> void scratch_push_small(const T &t) { | 192 | 863 | ensure_space(sizeof(T)); | 193 | 863 | *reinterpret_cast<T *>(scratch_) = t; | 194 | 863 | scratch_ += sizeof(T); | 195 | 863 | } |
|
196 | | |
197 | | // fill() is most frequently called with small byte counts (<= 4), |
198 | | // which is why we're using loops rather than calling memset. |
199 | 65.2k | void fill(size_t zero_pad_bytes) { |
200 | 65.2k | make_space(zero_pad_bytes); |
201 | 102k | for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0; |
202 | 65.2k | } |
203 | | |
204 | | // Version for when we know the size is larger. |
205 | | // Precondition: zero_pad_bytes > 0 |
206 | 6.40k | void fill_big(size_t zero_pad_bytes) { |
207 | 6.40k | memset(make_space(zero_pad_bytes), 0, zero_pad_bytes); |
208 | 6.40k | } |
209 | | |
210 | 5.54k | void pop(size_t bytes_to_remove) { |
211 | 5.54k | cur_ += bytes_to_remove; |
212 | 5.54k | size_ -= static_cast<uoffset_t>(bytes_to_remove); |
213 | 5.54k | } |
214 | | |
215 | 6.40k | void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; } |
216 | | |
217 | 0 | void swap(vector_downward &other) { |
218 | 0 | using std::swap; |
219 | 0 | swap(allocator_, other.allocator_); |
220 | 0 | swap(own_allocator_, other.own_allocator_); |
221 | 0 | swap(initial_size_, other.initial_size_); |
222 | 0 | swap(buffer_minalign_, other.buffer_minalign_); |
223 | 0 | swap(reserved_, other.reserved_); |
224 | 0 | swap(size_, other.size_); |
225 | 0 | swap(buf_, other.buf_); |
226 | 0 | swap(cur_, other.cur_); |
227 | 0 | swap(scratch_, other.scratch_); |
228 | 0 | } |
229 | | |
230 | 0 | void swap_allocator(vector_downward &other) { |
231 | 0 | using std::swap; |
232 | 0 | swap(allocator_, other.allocator_); |
233 | 0 | swap(own_allocator_, other.own_allocator_); |
234 | 0 | } |
235 | | |
236 | | private: |
237 | | // You shouldn't really be copying instances of this class. |
238 | | FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &)); |
239 | | FLATBUFFERS_DELETE_FUNC(vector_downward &operator=(const vector_downward &)); |
240 | | |
241 | | Allocator *allocator_; |
242 | | bool own_allocator_; |
243 | | size_t initial_size_; |
244 | | size_t buffer_minalign_; |
245 | | size_t reserved_; |
246 | | uoffset_t size_; |
247 | | uint8_t *buf_; |
248 | | uint8_t *cur_; // Points at location between empty (below) and used (above). |
249 | | uint8_t *scratch_; // Points to the end of the scratchpad in use. |
250 | | |
251 | 557 | void reallocate(size_t len) { |
252 | 557 | auto old_reserved = reserved_; |
253 | 557 | auto old_size = size(); |
254 | 557 | auto old_scratch_size = scratch_size(); |
255 | 557 | reserved_ += |
256 | 557 | (std::max)(len, old_reserved ? old_reserved / 2 : initial_size_); |
257 | 557 | reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1); |
258 | 557 | if (buf_) { |
259 | 136 | buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_, |
260 | 136 | old_size, old_scratch_size); |
261 | 421 | } else { |
262 | 421 | buf_ = Allocate(allocator_, reserved_); |
263 | 421 | } |
264 | 557 | cur_ = buf_ + reserved_ - old_size; |
265 | 557 | scratch_ = buf_ + old_scratch_size; |
266 | 557 | } |
267 | | }; |
268 | | |
269 | | } // namespace flatbuffers |
270 | | |
271 | | #endif // FLATBUFFERS_VECTOR_DOWNWARD_H_ |