Coverage Report

Created: 2023-09-25 06:29

/src/flatbuffers/include/flatbuffers/vector_downward.h
Line
Count
Source (jump to first uncovered line)
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 <algorithm>
21
#include <cstdint>
22
23
#include "flatbuffers/base.h"
24
#include "flatbuffers/default_allocator.h"
25
#include "flatbuffers/detached_buffer.h"
26
27
namespace flatbuffers {
28
29
// This is a minimal replication of std::vector<uint8_t> functionality,
30
// except growing from higher to lower addresses. i.e. push_back() inserts data
31
// in the lowest address in the vector.
32
// Since this vector leaves the lower part unused, we support a "scratch-pad"
33
// that can be stored there for temporary data, to share the allocated space.
34
// Essentially, this supports 2 std::vectors in a single buffer.
35
template<typename SizeT = uoffset_t> class vector_downward {
36
 public:
37
  explicit vector_downward(size_t initial_size, Allocator *allocator,
38
                           bool own_allocator, size_t buffer_minalign,
39
                           const SizeT max_size = FLATBUFFERS_MAX_BUFFER_SIZE)
40
      : allocator_(allocator),
41
        own_allocator_(own_allocator),
42
        initial_size_(initial_size),
43
        max_size_(max_size),
44
        buffer_minalign_(buffer_minalign),
45
        reserved_(0),
46
        size_(0),
47
        buf_(nullptr),
48
        cur_(nullptr),
49
132k
        scratch_(nullptr) {}
50
51
  vector_downward(vector_downward &&other) noexcept
52
      // clang-format on
53
      : allocator_(other.allocator_),
54
        own_allocator_(other.own_allocator_),
55
        initial_size_(other.initial_size_),
56
        max_size_(other.max_size_),
57
        buffer_minalign_(other.buffer_minalign_),
58
        reserved_(other.reserved_),
59
        size_(other.size_),
60
        buf_(other.buf_),
61
        cur_(other.cur_),
62
        scratch_(other.scratch_) {
63
    // No change in other.allocator_
64
    // No change in other.initial_size_
65
    // No change in other.buffer_minalign_
66
    other.own_allocator_ = false;
67
    other.reserved_ = 0;
68
    other.buf_ = nullptr;
69
    other.cur_ = nullptr;
70
    other.scratch_ = nullptr;
71
  }
72
73
  vector_downward &operator=(vector_downward &&other) noexcept {
74
    // Move construct a temporary and swap idiom
75
    vector_downward temp(std::move(other));
76
    swap(temp);
77
    return *this;
78
  }
79
80
132k
  ~vector_downward() {
81
132k
    clear_buffer();
82
132k
    clear_allocator();
83
132k
  }
84
85
  void reset() {
86
    clear_buffer();
87
    clear();
88
  }
89
90
823k
  void clear() {
91
823k
    if (buf_) {
92
210k
      cur_ = buf_ + reserved_;
93
613k
    } else {
94
613k
      reserved_ = 0;
95
613k
      cur_ = nullptr;
96
613k
    }
97
823k
    size_ = 0;
98
823k
    clear_scratch();
99
823k
  }
100
101
1.13M
  void clear_scratch() { scratch_ = buf_; }
flatbuffers::vector_downward<unsigned int>::clear_scratch()
Line
Count
Source
101
1.13M
  void clear_scratch() { scratch_ = buf_; }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::clear_scratch()
102
103
132k
  void clear_allocator() {
104
132k
    if (own_allocator_ && allocator_) { delete allocator_; }
105
132k
    allocator_ = nullptr;
106
132k
    own_allocator_ = false;
107
132k
  }
108
109
132k
  void clear_buffer() {
110
132k
    if (buf_) Deallocate(allocator_, buf_, reserved_);
111
132k
    buf_ = nullptr;
112
132k
  }
113
114
  // Relinquish the pointer to the caller.
115
  uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) {
116
    auto *buf = buf_;
117
    allocated_bytes = reserved_;
118
    offset = vector_downward::offset();
119
120
    // release_raw only relinquishes the buffer ownership.
121
    // Does not deallocate or reset the allocator. Destructor will do that.
122
    buf_ = nullptr;
123
    clear();
124
    return buf;
125
  }
126
127
  // Relinquish the pointer to the caller.
128
  DetachedBuffer release() {
129
    // allocator ownership (if any) is transferred to DetachedBuffer.
130
    DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
131
                      size());
132
    if (own_allocator_) {
133
      allocator_ = nullptr;
134
      own_allocator_ = false;
135
    }
136
    buf_ = nullptr;
137
    clear();
138
    return fb;
139
  }
140
141
4.48M
  size_t ensure_space(size_t len) {
142
4.48M
    FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_);
143
    // If the length is larger than the unused part of the buffer, we need to
144
    // grow.
145
4.48M
    if (len > unused_buffer_size()) { reallocate(len); }
146
4.48M
    FLATBUFFERS_ASSERT(size() < max_size_);
147
0
    return len;
148
4.48M
  }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::ensure_space(unsigned long)
flatbuffers::vector_downward<unsigned int>::ensure_space(unsigned long)
Line
Count
Source
141
4.48M
  size_t ensure_space(size_t len) {
142
4.48M
    FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_);
143
    // If the length is larger than the unused part of the buffer, we need to
144
    // grow.
145
4.48M
    if (len > unused_buffer_size()) { reallocate(len); }
146
4.48M
    FLATBUFFERS_ASSERT(size() < max_size_);
147
0
    return len;
148
4.48M
  }
149
150
7.68M
  inline uint8_t *make_space(size_t len) {
151
7.68M
    if (len) {
152
3.69M
      ensure_space(len);
153
3.69M
      cur_ -= len;
154
3.69M
      size_ += static_cast<SizeT>(len);
155
3.69M
    }
156
7.68M
    return cur_;
157
7.68M
  }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::make_space(unsigned long)
flatbuffers::vector_downward<unsigned int>::make_space(unsigned long)
Line
Count
Source
150
7.68M
  inline uint8_t *make_space(size_t len) {
151
7.68M
    if (len) {
152
3.69M
      ensure_space(len);
153
3.69M
      cur_ -= len;
154
3.69M
      size_ += static_cast<SizeT>(len);
155
3.69M
    }
156
7.68M
    return cur_;
157
7.68M
  }
158
159
  // Returns nullptr if using the DefaultAllocator.
160
  Allocator *get_custom_allocator() { return allocator_; }
161
162
  // The current offset into the buffer.
163
  size_t offset() const { return cur_ - buf_; }
164
165
  // The total size of the vector (both the buffer and scratch parts).
166
14.7M
  inline SizeT size() const { return size_; }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::size() const
flatbuffers::vector_downward<unsigned int>::size() const
Line
Count
Source
166
14.7M
  inline SizeT size() const { return size_; }
167
168
  // The size of the buffer part of the vector that is currently unused.
169
4.48M
  SizeT unused_buffer_size() const {
170
4.48M
    return static_cast<SizeT>(cur_ - scratch_);
171
4.48M
  }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::unused_buffer_size() const
flatbuffers::vector_downward<unsigned int>::unused_buffer_size() const
Line
Count
Source
169
4.48M
  SizeT unused_buffer_size() const {
170
4.48M
    return static_cast<SizeT>(cur_ - scratch_);
171
4.48M
  }
172
173
  // The size of the scratch part of the vector.
174
125k
  SizeT scratch_size() const { return static_cast<SizeT>(scratch_ - buf_); }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::scratch_size() const
flatbuffers::vector_downward<unsigned int>::scratch_size() const
Line
Count
Source
174
125k
  SizeT scratch_size() const { return static_cast<SizeT>(scratch_ - buf_); }
175
176
  size_t capacity() const { return reserved_; }
177
178
3.10M
  uint8_t *data() const {
179
3.10M
    FLATBUFFERS_ASSERT(cur_);
180
0
    return cur_;
181
3.10M
  }
flatbuffers::vector_downward<unsigned int>::data() const
Line
Count
Source
178
3.10M
  uint8_t *data() const {
179
3.10M
    FLATBUFFERS_ASSERT(cur_);
180
0
    return cur_;
181
3.10M
  }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::data() const
182
183
588k
  uint8_t *scratch_data() const {
184
588k
    FLATBUFFERS_ASSERT(buf_);
185
0
    return buf_;
186
588k
  }
flatbuffers::vector_downward<unsigned int>::scratch_data() const
Line
Count
Source
183
588k
  uint8_t *scratch_data() const {
184
588k
    FLATBUFFERS_ASSERT(buf_);
185
0
    return buf_;
186
588k
  }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::scratch_data() const
187
188
2.36M
  uint8_t *scratch_end() const {
189
2.36M
    FLATBUFFERS_ASSERT(scratch_);
190
0
    return scratch_;
191
2.36M
  }
flatbuffers::vector_downward<unsigned int>::scratch_end() const
Line
Count
Source
188
2.36M
  uint8_t *scratch_end() const {
189
2.36M
    FLATBUFFERS_ASSERT(scratch_);
190
0
    return scratch_;
191
2.36M
  }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::scratch_end() const
192
193
1.02M
  uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; }
flatbuffers::vector_downward<unsigned int>::data_at(unsigned long) const
Line
Count
Source
193
1.02M
  uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::data_at(unsigned long) const
194
195
232k
  void push(const uint8_t *bytes, size_t num) {
196
232k
    if (num > 0) { memcpy(make_space(num), bytes, num); }
197
232k
  }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::push(unsigned char const*, unsigned long)
flatbuffers::vector_downward<unsigned int>::push(unsigned char const*, unsigned long)
Line
Count
Source
195
232k
  void push(const uint8_t *bytes, size_t num) {
196
232k
    if (num > 0) { memcpy(make_space(num), bytes, num); }
197
232k
  }
198
199
  // Specialized version of push() that avoids memcpy call for small data.
200
2.28M
  template<typename T> void push_small(const T &little_endian_t) {
201
2.28M
    make_space(sizeof(T));
202
2.28M
    *reinterpret_cast<T *>(cur_) = little_endian_t;
203
2.28M
  }
Unexecuted instantiation: void flatbuffers::vector_downward<unsigned long>::push_small<unsigned int>(unsigned int const&)
void flatbuffers::vector_downward<unsigned int>::push_small<signed char>(signed char const&)
Line
Count
Source
200
31.7k
  template<typename T> void push_small(const T &little_endian_t) {
201
31.7k
    make_space(sizeof(T));
202
31.7k
    *reinterpret_cast<T *>(cur_) = little_endian_t;
203
31.7k
  }
void flatbuffers::vector_downward<unsigned int>::push_small<int>(int const&)
Line
Count
Source
200
623k
  template<typename T> void push_small(const T &little_endian_t) {
201
623k
    make_space(sizeof(T));
202
623k
    *reinterpret_cast<T *>(cur_) = little_endian_t;
203
623k
  }
void flatbuffers::vector_downward<unsigned int>::push_small<unsigned short>(unsigned short const&)
Line
Count
Source
200
19.4k
  template<typename T> void push_small(const T &little_endian_t) {
201
19.4k
    make_space(sizeof(T));
202
19.4k
    *reinterpret_cast<T *>(cur_) = little_endian_t;
203
19.4k
  }
void flatbuffers::vector_downward<unsigned int>::push_small<unsigned int>(unsigned int const&)
Line
Count
Source
200
1.03M
  template<typename T> void push_small(const T &little_endian_t) {
201
1.03M
    make_space(sizeof(T));
202
1.03M
    *reinterpret_cast<T *>(cur_) = little_endian_t;
203
1.03M
  }
void flatbuffers::vector_downward<unsigned int>::push_small<long>(long const&)
Line
Count
Source
200
150k
  template<typename T> void push_small(const T &little_endian_t) {
201
150k
    make_space(sizeof(T));
202
150k
    *reinterpret_cast<T *>(cur_) = little_endian_t;
203
150k
  }
void flatbuffers::vector_downward<unsigned int>::push_small<unsigned char>(unsigned char const&)
Line
Count
Source
200
93.5k
  template<typename T> void push_small(const T &little_endian_t) {
201
93.5k
    make_space(sizeof(T));
202
93.5k
    *reinterpret_cast<T *>(cur_) = little_endian_t;
203
93.5k
  }
void flatbuffers::vector_downward<unsigned int>::push_small<double>(double const&)
Line
Count
Source
200
138k
  template<typename T> void push_small(const T &little_endian_t) {
201
138k
    make_space(sizeof(T));
202
138k
    *reinterpret_cast<T *>(cur_) = little_endian_t;
203
138k
  }
void flatbuffers::vector_downward<unsigned int>::push_small<unsigned long>(unsigned long const&)
Line
Count
Source
200
127k
  template<typename T> void push_small(const T &little_endian_t) {
201
127k
    make_space(sizeof(T));
202
127k
    *reinterpret_cast<T *>(cur_) = little_endian_t;
203
127k
  }
void flatbuffers::vector_downward<unsigned int>::push_small<short>(short const&)
Line
Count
Source
200
24.2k
  template<typename T> void push_small(const T &little_endian_t) {
201
24.2k
    make_space(sizeof(T));
202
24.2k
    *reinterpret_cast<T *>(cur_) = little_endian_t;
203
24.2k
  }
void flatbuffers::vector_downward<unsigned int>::push_small<float>(float const&)
Line
Count
Source
200
39.7k
  template<typename T> void push_small(const T &little_endian_t) {
201
39.7k
    make_space(sizeof(T));
202
39.7k
    *reinterpret_cast<T *>(cur_) = little_endian_t;
203
39.7k
  }
Unexecuted instantiation: void flatbuffers::vector_downward<unsigned long>::push_small<unsigned long>(unsigned long const&)
Unexecuted instantiation: void flatbuffers::vector_downward<unsigned long>::push_small<int>(int const&)
Unexecuted instantiation: void flatbuffers::vector_downward<unsigned int>::push_small<MyGame::Example::Vec3>(MyGame::Example::Vec3 const&)
Unexecuted instantiation: void flatbuffers::vector_downward<unsigned int>::push_small<MyGame::Example::Test>(MyGame::Example::Test const&)
204
205
788k
  template<typename T> void scratch_push_small(const T &t) {
206
788k
    ensure_space(sizeof(T));
207
788k
    *reinterpret_cast<T *>(scratch_) = t;
208
788k
    scratch_ += sizeof(T);
209
788k
  }
void flatbuffers::vector_downward<unsigned int>::scratch_push_small<flatbuffers::FlatBufferBuilderImpl<false>::FieldLoc>(flatbuffers::FlatBufferBuilderImpl<false>::FieldLoc const&)
Line
Count
Source
205
460k
  template<typename T> void scratch_push_small(const T &t) {
206
460k
    ensure_space(sizeof(T));
207
460k
    *reinterpret_cast<T *>(scratch_) = t;
208
460k
    scratch_ += sizeof(T);
209
460k
  }
void flatbuffers::vector_downward<unsigned int>::scratch_push_small<unsigned int>(unsigned int const&)
Line
Count
Source
205
328k
  template<typename T> void scratch_push_small(const T &t) {
206
328k
    ensure_space(sizeof(T));
207
328k
    *reinterpret_cast<T *>(scratch_) = t;
208
328k
    scratch_ += sizeof(T);
209
328k
  }
Unexecuted instantiation: void flatbuffers::vector_downward<unsigned int>::scratch_push_small<flatbuffers::Offset<flatbuffers::String> >(flatbuffers::Offset<flatbuffers::String> const&)
Unexecuted instantiation: void flatbuffers::vector_downward<unsigned long>::scratch_push_small<flatbuffers::FlatBufferBuilderImpl<true>::FieldLoc>(flatbuffers::FlatBufferBuilderImpl<true>::FieldLoc const&)
Unexecuted instantiation: void flatbuffers::vector_downward<unsigned long>::scratch_push_small<unsigned int>(unsigned int const&)
210
211
  // fill() is most frequently called with small byte counts (<= 4),
212
  // which is why we're using loops rather than calling memset.
213
4.69M
  void fill(size_t zero_pad_bytes) {
214
4.69M
    make_space(zero_pad_bytes);
215
6.64M
    for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0;
216
4.69M
  }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::fill(unsigned long)
flatbuffers::vector_downward<unsigned int>::fill(unsigned long)
Line
Count
Source
213
4.69M
  void fill(size_t zero_pad_bytes) {
214
4.69M
    make_space(zero_pad_bytes);
215
6.64M
    for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0;
216
4.69M
  }
217
218
  // Version for when we know the size is larger.
219
  // Precondition: zero_pad_bytes > 0
220
588k
  void fill_big(size_t zero_pad_bytes) {
221
588k
    memset(make_space(zero_pad_bytes), 0, zero_pad_bytes);
222
588k
  }
flatbuffers::vector_downward<unsigned int>::fill_big(unsigned long)
Line
Count
Source
220
588k
  void fill_big(size_t zero_pad_bytes) {
221
588k
    memset(make_space(zero_pad_bytes), 0, zero_pad_bytes);
222
588k
  }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::fill_big(unsigned long)
223
224
289k
  void pop(size_t bytes_to_remove) {
225
289k
    cur_ += bytes_to_remove;
226
289k
    size_ -= static_cast<SizeT>(bytes_to_remove);
227
289k
  }
flatbuffers::vector_downward<unsigned int>::pop(unsigned long)
Line
Count
Source
224
289k
  void pop(size_t bytes_to_remove) {
225
289k
    cur_ += bytes_to_remove;
226
289k
    size_ -= static_cast<SizeT>(bytes_to_remove);
227
289k
  }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::pop(unsigned long)
228
229
1.47M
  void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; }
flatbuffers::vector_downward<unsigned int>::scratch_pop(unsigned long)
Line
Count
Source
229
1.47M
  void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::scratch_pop(unsigned long)
230
231
  void swap(vector_downward &other) {
232
    using std::swap;
233
    swap(allocator_, other.allocator_);
234
    swap(own_allocator_, other.own_allocator_);
235
    swap(initial_size_, other.initial_size_);
236
    swap(buffer_minalign_, other.buffer_minalign_);
237
    swap(reserved_, other.reserved_);
238
    swap(size_, other.size_);
239
    swap(max_size_, other.max_size_);
240
    swap(buf_, other.buf_);
241
    swap(cur_, other.cur_);
242
    swap(scratch_, other.scratch_);
243
  }
244
245
  void swap_allocator(vector_downward &other) {
246
    using std::swap;
247
    swap(allocator_, other.allocator_);
248
    swap(own_allocator_, other.own_allocator_);
249
  }
250
251
 private:
252
  // You shouldn't really be copying instances of this class.
253
  FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &));
254
  FLATBUFFERS_DELETE_FUNC(vector_downward &operator=(const vector_downward &));
255
256
  Allocator *allocator_;
257
  bool own_allocator_;
258
  size_t initial_size_;
259
260
  // The maximum size the vector can be.
261
  SizeT max_size_;
262
  size_t buffer_minalign_;
263
  size_t reserved_;
264
  SizeT size_;
265
  uint8_t *buf_;
266
  uint8_t *cur_;  // Points at location between empty (below) and used (above).
267
  uint8_t *scratch_;  // Points to the end of the scratchpad in use.
268
269
125k
  void reallocate(size_t len) {
270
125k
    auto old_reserved = reserved_;
271
125k
    auto old_size = size();
272
125k
    auto old_scratch_size = scratch_size();
273
125k
    reserved_ +=
274
125k
        (std::max)(len, old_reserved ? old_reserved / 2 : initial_size_);
275
125k
    reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1);
276
125k
    if (buf_) {
277
5.18k
      buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_,
278
5.18k
                                old_size, old_scratch_size);
279
119k
    } else {
280
119k
      buf_ = Allocate(allocator_, reserved_);
281
119k
    }
282
125k
    cur_ = buf_ + reserved_ - old_size;
283
125k
    scratch_ = buf_ + old_scratch_size;
284
125k
  }
Unexecuted instantiation: flatbuffers::vector_downward<unsigned long>::reallocate(unsigned long)
flatbuffers::vector_downward<unsigned int>::reallocate(unsigned long)
Line
Count
Source
269
125k
  void reallocate(size_t len) {
270
125k
    auto old_reserved = reserved_;
271
125k
    auto old_size = size();
272
125k
    auto old_scratch_size = scratch_size();
273
125k
    reserved_ +=
274
125k
        (std::max)(len, old_reserved ? old_reserved / 2 : initial_size_);
275
125k
    reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1);
276
125k
    if (buf_) {
277
5.18k
      buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_,
278
5.18k
                                old_size, old_scratch_size);
279
119k
    } else {
280
119k
      buf_ = Allocate(allocator_, reserved_);
281
119k
    }
282
125k
    cur_ = buf_ + reserved_ - old_size;
283
125k
    scratch_ = buf_ + old_scratch_size;
284
125k
  }
285
};
286
287
}  // namespace flatbuffers
288
289
#endif  // FLATBUFFERS_VECTOR_DOWNWARD_H_