LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/flatgeobuf/flatbuffers - vector_downward.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 78 78 100.0 %
Date: 2024-05-15 17:37:59 Functions: 26 26 100.0 %

          Line data    Source code
       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         555 :   explicit vector_downward(size_t initial_size, Allocator *allocator,
      35             :                            bool own_allocator, size_t buffer_minalign)
      36         555 :       : allocator_(allocator),
      37             :         own_allocator_(own_allocator),
      38             :         initial_size_(initial_size),
      39             :         buffer_minalign_(buffer_minalign),
      40             :         reserved_(0),
      41             :         size_(0),
      42             :         buf_(nullptr),
      43             :         cur_(nullptr),
      44         555 :         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             :         scratch_(other.scratch_) {
      57             :     // No change in other.allocator_
      58             :     // No change in other.initial_size_
      59             :     // No change in other.buffer_minalign_
      60             :     other.own_allocator_ = false;
      61             :     other.reserved_ = 0;
      62             :     other.buf_ = nullptr;
      63             :     other.cur_ = nullptr;
      64             :     other.scratch_ = nullptr;
      65             :   }
      66             : 
      67             :   vector_downward &operator=(vector_downward &&other) {
      68             :     // Move construct a temporary and swap idiom
      69             :     vector_downward temp(std::move(other));
      70             :     swap(temp);
      71             :     return *this;
      72             :   }
      73             : 
      74        1110 :   ~vector_downward() {
      75         555 :     clear_buffer();
      76         555 :     clear_allocator();
      77         555 :   }
      78             : 
      79             :   void reset() {
      80             :     clear_buffer();
      81             :     clear();
      82             :   }
      83             : 
      84             :   void clear() {
      85             :     if (buf_) {
      86             :       cur_ = buf_ + reserved_;
      87             :     } else {
      88             :       reserved_ = 0;
      89             :       cur_ = nullptr;
      90             :     }
      91             :     size_ = 0;
      92             :     clear_scratch();
      93             :   }
      94             : 
      95         505 :   void clear_scratch() { scratch_ = buf_; }
      96             : 
      97         555 :   void clear_allocator() {
      98         555 :     if (own_allocator_ && allocator_) { delete allocator_; }
      99         555 :     allocator_ = nullptr;
     100         555 :     own_allocator_ = false;
     101         555 :   }
     102             : 
     103         555 :   void clear_buffer() {
     104         555 :     if (buf_) Deallocate(allocator_, buf_, reserved_);
     105         555 :     buf_ = nullptr;
     106         555 :   }
     107             : 
     108             :   // Relinquish the pointer to the caller.
     109             :   uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) {
     110             :     auto *buf = buf_;
     111             :     allocated_bytes = reserved_;
     112             :     offset = static_cast<size_t>(cur_ - buf_);
     113             : 
     114             :     // release_raw only relinquishes the buffer ownership.
     115             :     // Does not deallocate or reset the allocator. Destructor will do that.
     116             :     buf_ = nullptr;
     117             :     clear();
     118             :     return buf;
     119             :   }
     120             : 
     121             :   // Relinquish the pointer to the caller.
     122             :   DetachedBuffer release() {
     123             :     // allocator ownership (if any) is transferred to DetachedBuffer.
     124             :     DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
     125             :                       size());
     126             :     if (own_allocator_) {
     127             :       allocator_ = nullptr;
     128             :       own_allocator_ = false;
     129             :     }
     130             :     buf_ = nullptr;
     131             :     clear();
     132             :     return fb;
     133             :   }
     134             : 
     135     1835510 :   size_t ensure_space(size_t len) {
     136     1835510 :     FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_);
     137     1835510 :     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     1835510 :     FLATBUFFERS_ASSERT(size() < FLATBUFFERS_MAX_BUFFER_SIZE);
     141     1835510 :     return len;
     142             :   }
     143             : 
     144     2385090 :   inline uint8_t *make_space(size_t len) {
     145     2385090 :     if (len) {
     146     1437550 :       ensure_space(len);
     147     1437550 :       cur_ -= len;
     148     1437550 :       size_ += static_cast<uoffset_t>(len);
     149             :     }
     150     2385090 :     return cur_;
     151             :   }
     152             : 
     153             :   // Returns nullptr if using the DefaultAllocator.
     154             :   Allocator *get_custom_allocator() { return allocator_; }
     155             : 
     156     4750860 :   inline uoffset_t size() const { return size_; }
     157             : 
     158         553 :   uoffset_t scratch_size() const {
     159         553 :     return static_cast<uoffset_t>(scratch_ - buf_);
     160             :   }
     161             : 
     162             :   size_t capacity() const { return reserved_; }
     163             : 
     164     1191230 :   uint8_t *data() const {
     165     1191230 :     FLATBUFFERS_ASSERT(cur_);
     166     1191230 :     return cur_;
     167             :   }
     168             : 
     169      132220 :   uint8_t *scratch_data() const {
     170      132220 :     FLATBUFFERS_ASSERT(buf_);
     171      132220 :     return buf_;
     172             :   }
     173             : 
     174      794293 :   uint8_t *scratch_end() const {
     175      794293 :     FLATBUFFERS_ASSERT(scratch_);
     176      794293 :     return scratch_;
     177             :   }
     178             : 
     179      395509 :   uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; }
     180             : 
     181      132537 :   void push(const uint8_t *bytes, size_t num) {
     182      132537 :     if (num > 0) { memcpy(make_space(num), bytes, num); }
     183      132537 :   }
     184             : 
     185             :   // Specialized version of push() that avoids memcpy call for small data.
     186      794671 :   template<typename T> void push_small(const T &little_endian_t) {
     187      794671 :     make_space(sizeof(T));
     188      794671 :     *reinterpret_cast<T *>(cur_) = little_endian_t;
     189      794671 :   }
     190             : 
     191      397962 :   template<typename T> void scratch_push_small(const T &t) {
     192      397962 :     ensure_space(sizeof(T));
     193      397962 :     *reinterpret_cast<T *>(scratch_) = t;
     194      397962 :     scratch_ += sizeof(T);
     195      397962 :   }
     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     1325660 :   void fill(size_t zero_pad_bytes) {
     200     1325660 :     make_space(zero_pad_bytes);
     201     2193100 :     for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0;
     202     1325660 :   }
     203             : 
     204             :   // Version for when we know the size is larger.
     205             :   // Precondition: zero_pad_bytes > 0
     206      132220 :   void fill_big(size_t zero_pad_bytes) {
     207      132220 :     memset(make_space(zero_pad_bytes), 0, zero_pad_bytes);
     208      132220 :   }
     209             : 
     210      131290 :   void pop(size_t bytes_to_remove) {
     211      131290 :     cur_ += bytes_to_remove;
     212      131290 :     size_ -= static_cast<uoffset_t>(bytes_to_remove);
     213      131290 :   }
     214             : 
     215      132220 :   void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; }
     216             : 
     217             :   void swap(vector_downward &other) {
     218             :     using std::swap;
     219             :     swap(allocator_, other.allocator_);
     220             :     swap(own_allocator_, other.own_allocator_);
     221             :     swap(initial_size_, other.initial_size_);
     222             :     swap(buffer_minalign_, other.buffer_minalign_);
     223             :     swap(reserved_, other.reserved_);
     224             :     swap(size_, other.size_);
     225             :     swap(buf_, other.buf_);
     226             :     swap(cur_, other.cur_);
     227             :     swap(scratch_, other.scratch_);
     228             :   }
     229             : 
     230             :   void swap_allocator(vector_downward &other) {
     231             :     using std::swap;
     232             :     swap(allocator_, other.allocator_);
     233             :     swap(own_allocator_, other.own_allocator_);
     234             :   }
     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         553 :   void reallocate(size_t len) {
     252         553 :     auto old_reserved = reserved_;
     253         553 :     auto old_size = size();
     254         553 :     auto old_scratch_size = scratch_size();
     255         553 :     reserved_ +=
     256         553 :         (std::max)(len, old_reserved ? old_reserved / 2 : initial_size_);
     257         553 :     reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1);
     258         553 :     if (buf_) {
     259          48 :       buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_,
     260             :                                 old_size, old_scratch_size);
     261             :     } else {
     262         505 :       buf_ = Allocate(allocator_, reserved_);
     263             :     }
     264         553 :     cur_ = buf_ + reserved_ - old_size;
     265         553 :     scratch_ = buf_ + old_scratch_size;
     266         553 :   }
     267             : };
     268             : 
     269             : }  // namespace flatbuffers
     270             : 
     271             : #endif  // FLATBUFFERS_VECTOR_DOWNWARD_H_

Generated by: LCOV version 1.14