Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-08-27 09:30:29

0001 /*
0002  * Copyright 2021 Google Inc. All rights reserved.
0003  *
0004  * Licensed under the Apache License, Version 2.0 (the "License");
0005  * you may not use this file except in compliance with the License.
0006  * You may obtain a copy of the License at
0007  *
0008  *     http://www.apache.org/licenses/LICENSE-2.0
0009  *
0010  * Unless required by applicable law or agreed to in writing, software
0011  * distributed under the License is distributed on an "AS IS" BASIS,
0012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013  * See the License for the specific language governing permissions and
0014  * limitations under the License.
0015  */
0016 
0017 #ifndef FLATBUFFERS_VECTOR_DOWNWARD_H_
0018 #define FLATBUFFERS_VECTOR_DOWNWARD_H_
0019 
0020 #include <algorithm>
0021 #include <cstdint>
0022 
0023 #include "flatbuffers/base.h"
0024 #include "flatbuffers/default_allocator.h"
0025 #include "flatbuffers/detached_buffer.h"
0026 
0027 namespace flatbuffers {
0028 
0029 // This is a minimal replication of std::vector<uint8_t> functionality,
0030 // except growing from higher to lower addresses. i.e. push_back() inserts data
0031 // in the lowest address in the vector.
0032 // Since this vector leaves the lower part unused, we support a "scratch-pad"
0033 // that can be stored there for temporary data, to share the allocated space.
0034 // Essentially, this supports 2 std::vectors in a single buffer.
0035 template<typename SizeT = uoffset_t> class vector_downward {
0036  public:
0037   explicit vector_downward(size_t initial_size, Allocator *allocator,
0038                            bool own_allocator, size_t buffer_minalign,
0039                            const SizeT max_size = FLATBUFFERS_MAX_BUFFER_SIZE)
0040       : allocator_(allocator),
0041         own_allocator_(own_allocator),
0042         initial_size_(initial_size),
0043         max_size_(max_size),
0044         buffer_minalign_(buffer_minalign),
0045         reserved_(0),
0046         size_(0),
0047         buf_(nullptr),
0048         cur_(nullptr),
0049         scratch_(nullptr) {}
0050 
0051   vector_downward(vector_downward &&other) noexcept
0052       // clang-format on
0053       : allocator_(other.allocator_),
0054         own_allocator_(other.own_allocator_),
0055         initial_size_(other.initial_size_),
0056         max_size_(other.max_size_),
0057         buffer_minalign_(other.buffer_minalign_),
0058         reserved_(other.reserved_),
0059         size_(other.size_),
0060         buf_(other.buf_),
0061         cur_(other.cur_),
0062         scratch_(other.scratch_) {
0063     // No change in other.allocator_
0064     // No change in other.initial_size_
0065     // No change in other.buffer_minalign_
0066     other.own_allocator_ = false;
0067     other.reserved_ = 0;
0068     other.buf_ = nullptr;
0069     other.cur_ = nullptr;
0070     other.scratch_ = nullptr;
0071   }
0072 
0073   vector_downward &operator=(vector_downward &&other) noexcept {
0074     // Move construct a temporary and swap idiom
0075     vector_downward temp(std::move(other));
0076     swap(temp);
0077     return *this;
0078   }
0079 
0080   ~vector_downward() {
0081     clear_buffer();
0082     clear_allocator();
0083   }
0084 
0085   void reset() {
0086     clear_buffer();
0087     clear();
0088   }
0089 
0090   void clear() {
0091     if (buf_) {
0092       cur_ = buf_ + reserved_;
0093     } else {
0094       reserved_ = 0;
0095       cur_ = nullptr;
0096     }
0097     size_ = 0;
0098     clear_scratch();
0099   }
0100 
0101   void clear_scratch() { scratch_ = buf_; }
0102 
0103   void clear_allocator() {
0104     if (own_allocator_ && allocator_) { delete allocator_; }
0105     allocator_ = nullptr;
0106     own_allocator_ = false;
0107   }
0108 
0109   void clear_buffer() {
0110     if (buf_) Deallocate(allocator_, buf_, reserved_);
0111     buf_ = nullptr;
0112   }
0113 
0114   // Relinquish the pointer to the caller.
0115   uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) {
0116     auto *buf = buf_;
0117     allocated_bytes = reserved_;
0118     offset = vector_downward::offset();
0119 
0120     // release_raw only relinquishes the buffer ownership.
0121     // Does not deallocate or reset the allocator. Destructor will do that.
0122     buf_ = nullptr;
0123     clear();
0124     return buf;
0125   }
0126 
0127   // Relinquish the pointer to the caller.
0128   DetachedBuffer release() {
0129     // allocator ownership (if any) is transferred to DetachedBuffer.
0130     DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
0131                       size());
0132     if (own_allocator_) {
0133       allocator_ = nullptr;
0134       own_allocator_ = false;
0135     }
0136     buf_ = nullptr;
0137     clear();
0138     return fb;
0139   }
0140 
0141   size_t ensure_space(size_t len) {
0142     FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_);
0143     // If the length is larger than the unused part of the buffer, we need to
0144     // grow.
0145     if (len > unused_buffer_size()) { reallocate(len); }
0146     FLATBUFFERS_ASSERT(size() < max_size_);
0147     return len;
0148   }
0149 
0150   inline uint8_t *make_space(size_t len) {
0151     if (len) {
0152       ensure_space(len);
0153       cur_ -= len;
0154       size_ += static_cast<SizeT>(len);
0155     }
0156     return cur_;
0157   }
0158 
0159   // Returns nullptr if using the DefaultAllocator.
0160   Allocator *get_custom_allocator() { return allocator_; }
0161 
0162   // The current offset into the buffer.
0163   size_t offset() const { return cur_ - buf_; }
0164 
0165   // The total size of the vector (both the buffer and scratch parts).
0166   inline SizeT size() const { return size_; }
0167 
0168   // The size of the buffer part of the vector that is currently unused.
0169   SizeT unused_buffer_size() const {
0170     return static_cast<SizeT>(cur_ - scratch_);
0171   }
0172 
0173   // The size of the scratch part of the vector.
0174   SizeT scratch_size() const { return static_cast<SizeT>(scratch_ - buf_); }
0175 
0176   size_t capacity() const { return reserved_; }
0177 
0178   uint8_t *data() const {
0179     FLATBUFFERS_ASSERT(cur_);
0180     return cur_;
0181   }
0182 
0183   uint8_t *scratch_data() const {
0184     FLATBUFFERS_ASSERT(buf_);
0185     return buf_;
0186   }
0187 
0188   uint8_t *scratch_end() const {
0189     FLATBUFFERS_ASSERT(scratch_);
0190     return scratch_;
0191   }
0192 
0193   uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; }
0194 
0195   void push(const uint8_t *bytes, size_t num) {
0196     if (num > 0) { memcpy(make_space(num), bytes, num); }
0197   }
0198 
0199   // Specialized version of push() that avoids memcpy call for small data.
0200   template<typename T> void push_small(const T &little_endian_t) {
0201     make_space(sizeof(T));
0202     *reinterpret_cast<T *>(cur_) = little_endian_t;
0203   }
0204 
0205   template<typename T> void scratch_push_small(const T &t) {
0206     ensure_space(sizeof(T));
0207     *reinterpret_cast<T *>(scratch_) = t;
0208     scratch_ += sizeof(T);
0209   }
0210 
0211   // fill() is most frequently called with small byte counts (<= 4),
0212   // which is why we're using loops rather than calling memset.
0213   void fill(size_t zero_pad_bytes) {
0214     make_space(zero_pad_bytes);
0215     for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0;
0216   }
0217 
0218   // Version for when we know the size is larger.
0219   // Precondition: zero_pad_bytes > 0
0220   void fill_big(size_t zero_pad_bytes) {
0221     memset(make_space(zero_pad_bytes), 0, zero_pad_bytes);
0222   }
0223 
0224   void pop(size_t bytes_to_remove) {
0225     cur_ += bytes_to_remove;
0226     size_ -= static_cast<SizeT>(bytes_to_remove);
0227   }
0228 
0229   void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; }
0230 
0231   void swap(vector_downward &other) {
0232     using std::swap;
0233     swap(allocator_, other.allocator_);
0234     swap(own_allocator_, other.own_allocator_);
0235     swap(initial_size_, other.initial_size_);
0236     swap(buffer_minalign_, other.buffer_minalign_);
0237     swap(reserved_, other.reserved_);
0238     swap(size_, other.size_);
0239     swap(max_size_, other.max_size_);
0240     swap(buf_, other.buf_);
0241     swap(cur_, other.cur_);
0242     swap(scratch_, other.scratch_);
0243   }
0244 
0245   void swap_allocator(vector_downward &other) {
0246     using std::swap;
0247     swap(allocator_, other.allocator_);
0248     swap(own_allocator_, other.own_allocator_);
0249   }
0250 
0251  private:
0252   // You shouldn't really be copying instances of this class.
0253   FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &));
0254   FLATBUFFERS_DELETE_FUNC(vector_downward &operator=(const vector_downward &));
0255 
0256   Allocator *allocator_;
0257   bool own_allocator_;
0258   size_t initial_size_;
0259 
0260   // The maximum size the vector can be.
0261   SizeT max_size_;
0262   size_t buffer_minalign_;
0263   size_t reserved_;
0264   SizeT size_;
0265   uint8_t *buf_;
0266   uint8_t *cur_;  // Points at location between empty (below) and used (above).
0267   uint8_t *scratch_;  // Points to the end of the scratchpad in use.
0268 
0269   void reallocate(size_t len) {
0270     auto old_reserved = reserved_;
0271     auto old_size = size();
0272     auto old_scratch_size = scratch_size();
0273     reserved_ +=
0274         (std::max)(len, old_reserved ? old_reserved / 2 : initial_size_);
0275     reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1);
0276     if (buf_) {
0277       buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_,
0278                                 old_size, old_scratch_size);
0279     } else {
0280       buf_ = Allocate(allocator_, reserved_);
0281     }
0282     cur_ = buf_ + reserved_ - old_size;
0283     scratch_ = buf_ + old_scratch_size;
0284   }
0285 };
0286 
0287 }  // namespace flatbuffers
0288 
0289 #endif  // FLATBUFFERS_VECTOR_DOWNWARD_H_