Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-08-28 08:27:10

0001 // Licensed to the Apache Software Foundation (ASF) under one
0002 // or more contributor license agreements.  See the NOTICE file
0003 // distributed with this work for additional information
0004 // regarding copyright ownership.  The ASF licenses this file
0005 // to you under the Apache License, Version 2.0 (the
0006 // "License"); you may not use this file except in compliance
0007 // with the License.  You may obtain a copy of the License at
0008 //
0009 //   http://www.apache.org/licenses/LICENSE-2.0
0010 //
0011 // Unless required by applicable law or agreed to in writing,
0012 // software distributed under the License is distributed on an
0013 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0014 // KIND, either express or implied.  See the License for the
0015 // specific language governing permissions and limitations
0016 // under the License.
0017 
0018 #pragma once
0019 
0020 #include <algorithm>
0021 #include <cassert>
0022 #include <cstddef>
0023 #include <initializer_list>
0024 #include <iterator>
0025 #include <limits>
0026 #include <new>
0027 #include <type_traits>
0028 #include <utility>
0029 
0030 #include "arrow/util/aligned_storage.h"
0031 #include "arrow/util/macros.h"
0032 
0033 namespace arrow {
0034 namespace internal {
0035 
0036 template <typename T, size_t N, bool NonTrivialDestructor>
0037 struct StaticVectorStorageBase {
0038   using storage_type = AlignedStorage<T>;
0039 
0040   storage_type static_data_[N];
0041   size_t size_ = 0;
0042 
0043   void destroy() noexcept {}
0044 };
0045 
0046 template <typename T, size_t N>
0047 struct StaticVectorStorageBase<T, N, true> {
0048   using storage_type = AlignedStorage<T>;
0049 
0050   storage_type static_data_[N];
0051   size_t size_ = 0;
0052 
0053   ~StaticVectorStorageBase() noexcept { destroy(); }
0054 
0055   void destroy() noexcept { storage_type::destroy_several(static_data_, size_); }
0056 };
0057 
0058 template <typename T, size_t N, bool D = !std::is_trivially_destructible<T>::value>
0059 struct StaticVectorStorage : public StaticVectorStorageBase<T, N, D> {
0060   using Base = StaticVectorStorageBase<T, N, D>;
0061   using typename Base::storage_type;
0062 
0063   using Base::size_;
0064   using Base::static_data_;
0065 
0066   StaticVectorStorage() noexcept = default;
0067 
0068   constexpr storage_type* storage_ptr() { return static_data_; }
0069 
0070   constexpr const storage_type* const_storage_ptr() const { return static_data_; }
0071 
0072   // Adjust storage size, but don't initialize any objects
0073   void bump_size(size_t addend) {
0074     assert(size_ + addend <= N);
0075     size_ += addend;
0076   }
0077 
0078   void ensure_capacity(size_t min_capacity) { assert(min_capacity <= N); }
0079 
0080   // Adjust storage size, but don't destroy any objects
0081   void reduce_size(size_t reduce_by) {
0082     assert(reduce_by <= size_);
0083     size_ -= reduce_by;
0084   }
0085 
0086   // Move objects from another storage, but don't destroy any objects currently
0087   // stored in *this.
0088   // You need to call destroy() first if necessary (e.g. in a
0089   // move assignment operator).
0090   void move_construct(StaticVectorStorage&& other) noexcept {
0091     size_ = other.size_;
0092     if (size_ != 0) {
0093       // Use a compile-time memcpy size (N) for trivial types
0094       storage_type::move_construct_several(other.static_data_, static_data_, size_, N);
0095     }
0096   }
0097 
0098   constexpr size_t capacity() const { return N; }
0099 
0100   constexpr size_t max_size() const { return N; }
0101 
0102   void reserve(size_t n) {}
0103 
0104   void clear() {
0105     storage_type::destroy_several(static_data_, size_);
0106     size_ = 0;
0107   }
0108 };
0109 
0110 template <typename T, size_t N>
0111 struct SmallVectorStorage {
0112   using storage_type = AlignedStorage<T>;
0113 
0114   storage_type static_data_[N];
0115   size_t size_ = 0;
0116   storage_type* data_ = static_data_;
0117   size_t dynamic_capacity_ = 0;
0118 
0119   SmallVectorStorage() noexcept = default;
0120 
0121   ~SmallVectorStorage() { destroy(); }
0122 
0123   constexpr storage_type* storage_ptr() { return data_; }
0124 
0125   constexpr const storage_type* const_storage_ptr() const { return data_; }
0126 
0127   void bump_size(size_t addend) {
0128     const size_t new_size = size_ + addend;
0129     ensure_capacity(new_size);
0130     size_ = new_size;
0131   }
0132 
0133   void ensure_capacity(size_t min_capacity) {
0134     if (dynamic_capacity_) {
0135       // Grow dynamic storage if necessary
0136       if (min_capacity > dynamic_capacity_) {
0137         size_t new_capacity = std::max(dynamic_capacity_ * 2, min_capacity);
0138         reallocate_dynamic(new_capacity);
0139       }
0140     } else if (min_capacity > N) {
0141       switch_to_dynamic(min_capacity);
0142     }
0143   }
0144 
0145   void reduce_size(size_t reduce_by) {
0146     assert(reduce_by <= size_);
0147     size_ -= reduce_by;
0148   }
0149 
0150   void destroy() noexcept {
0151     storage_type::destroy_several(data_, size_);
0152     if (dynamic_capacity_) {
0153       delete[] data_;
0154     }
0155   }
0156 
0157   void move_construct(SmallVectorStorage&& other) noexcept {
0158     size_ = other.size_;
0159     dynamic_capacity_ = other.dynamic_capacity_;
0160     if (dynamic_capacity_) {
0161       data_ = other.data_;
0162       other.data_ = other.static_data_;
0163       other.dynamic_capacity_ = 0;
0164       other.size_ = 0;
0165     } else if (size_ != 0) {
0166       // Use a compile-time memcpy size (N) for trivial types
0167       storage_type::move_construct_several(other.static_data_, static_data_, size_, N);
0168     }
0169   }
0170 
0171   constexpr size_t capacity() const { return dynamic_capacity_ ? dynamic_capacity_ : N; }
0172 
0173   constexpr size_t max_size() const { return std::numeric_limits<size_t>::max(); }
0174 
0175   void reserve(size_t n) {
0176     if (dynamic_capacity_) {
0177       if (n > dynamic_capacity_) {
0178         reallocate_dynamic(n);
0179       }
0180     } else if (n > N) {
0181       switch_to_dynamic(n);
0182     }
0183   }
0184 
0185   void clear() {
0186     storage_type::destroy_several(data_, size_);
0187     size_ = 0;
0188   }
0189 
0190  private:
0191   void switch_to_dynamic(size_t new_capacity) {
0192     dynamic_capacity_ = new_capacity;
0193     data_ = new storage_type[new_capacity];
0194     storage_type::move_construct_several_and_destroy_source(static_data_, data_, size_);
0195   }
0196 
0197   void reallocate_dynamic(size_t new_capacity) {
0198     assert(new_capacity >= size_);
0199     auto new_data = new storage_type[new_capacity];
0200     storage_type::move_construct_several_and_destroy_source(data_, new_data, size_);
0201     delete[] data_;
0202     dynamic_capacity_ = new_capacity;
0203     data_ = new_data;
0204   }
0205 };
0206 
0207 template <typename T, size_t N, typename Storage>
0208 class StaticVectorImpl {
0209  private:
0210   Storage storage_;
0211 
0212   T* data_ptr() { return storage_.storage_ptr()->get(); }
0213 
0214   constexpr const T* const_data_ptr() const {
0215     return storage_.const_storage_ptr()->get();
0216   }
0217 
0218  public:
0219   using size_type = size_t;
0220   using difference_type = ptrdiff_t;
0221   using value_type = T;
0222   using pointer = T*;
0223   using const_pointer = const T*;
0224   using reference = T&;
0225   using const_reference = const T&;
0226   using iterator = T*;
0227   using const_iterator = const T*;
0228   using reverse_iterator = std::reverse_iterator<iterator>;
0229   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
0230 
0231   constexpr StaticVectorImpl() noexcept = default;
0232 
0233   // Move and copy constructors
0234   StaticVectorImpl(StaticVectorImpl&& other) noexcept {
0235     storage_.move_construct(std::move(other.storage_));
0236   }
0237 
0238   StaticVectorImpl& operator=(StaticVectorImpl&& other) noexcept {
0239     if (ARROW_PREDICT_TRUE(&other != this)) {
0240       // TODO move_assign?
0241       storage_.destroy();
0242       storage_.move_construct(std::move(other.storage_));
0243     }
0244     return *this;
0245   }
0246 
0247   StaticVectorImpl(const StaticVectorImpl& other) {
0248     init_by_copying(other.storage_.size_, other.const_data_ptr());
0249   }
0250 
0251   StaticVectorImpl& operator=(const StaticVectorImpl& other) noexcept {
0252     if (ARROW_PREDICT_TRUE(&other != this)) {
0253       assign_by_copying(other.storage_.size_, other.data());
0254     }
0255     return *this;
0256   }
0257 
0258   // Automatic conversion from std::vector<T>, for convenience
0259   StaticVectorImpl(const std::vector<T>& other) {  // NOLINT: explicit
0260     init_by_copying(other.size(), other.data());
0261   }
0262 
0263   StaticVectorImpl(std::vector<T>&& other) noexcept {  // NOLINT: explicit
0264     init_by_moving(other.size(), other.data());
0265   }
0266 
0267   StaticVectorImpl& operator=(const std::vector<T>& other) {
0268     assign_by_copying(other.size(), other.data());
0269     return *this;
0270   }
0271 
0272   StaticVectorImpl& operator=(std::vector<T>&& other) noexcept {
0273     assign_by_moving(other.size(), other.data());
0274     return *this;
0275   }
0276 
0277   // Constructing from count and optional initialization value
0278   explicit StaticVectorImpl(size_t count) {
0279     storage_.bump_size(count);
0280     auto* p = storage_.storage_ptr();
0281     for (size_t i = 0; i < count; ++i) {
0282       p[i].construct();
0283     }
0284   }
0285 
0286   StaticVectorImpl(size_t count, const T& value) {
0287     storage_.bump_size(count);
0288     auto* p = storage_.storage_ptr();
0289     for (size_t i = 0; i < count; ++i) {
0290       p[i].construct(value);
0291     }
0292   }
0293 
0294   StaticVectorImpl(std::initializer_list<T> values) {
0295     storage_.bump_size(values.size());
0296     auto* p = storage_.storage_ptr();
0297     for (auto&& v : values) {
0298       // Unfortunately, cannot move initializer values
0299       p++->construct(v);
0300     }
0301   }
0302 
0303   // Size inspection
0304 
0305   constexpr bool empty() const { return storage_.size_ == 0; }
0306 
0307   constexpr size_t size() const { return storage_.size_; }
0308 
0309   constexpr size_t capacity() const { return storage_.capacity(); }
0310 
0311   constexpr size_t max_size() const { return storage_.max_size(); }
0312 
0313   // Data access
0314 
0315   T& operator[](size_t i) { return data_ptr()[i]; }
0316 
0317   constexpr const T& operator[](size_t i) const { return const_data_ptr()[i]; }
0318 
0319   T& front() { return data_ptr()[0]; }
0320 
0321   constexpr const T& front() const { return const_data_ptr()[0]; }
0322 
0323   T& back() { return data_ptr()[storage_.size_ - 1]; }
0324 
0325   constexpr const T& back() const { return const_data_ptr()[storage_.size_ - 1]; }
0326 
0327   T* data() { return data_ptr(); }
0328 
0329   constexpr const T* data() const { return const_data_ptr(); }
0330 
0331   // Iterators
0332 
0333   iterator begin() { return iterator(data_ptr()); }
0334 
0335   constexpr const_iterator begin() const { return const_iterator(const_data_ptr()); }
0336 
0337   constexpr const_iterator cbegin() const { return const_iterator(const_data_ptr()); }
0338 
0339   iterator end() { return iterator(data_ptr() + storage_.size_); }
0340 
0341   constexpr const_iterator end() const {
0342     return const_iterator(const_data_ptr() + storage_.size_);
0343   }
0344 
0345   constexpr const_iterator cend() const {
0346     return const_iterator(const_data_ptr() + storage_.size_);
0347   }
0348 
0349   reverse_iterator rbegin() { return reverse_iterator(end()); }
0350 
0351   constexpr const_reverse_iterator rbegin() const {
0352     return const_reverse_iterator(end());
0353   }
0354 
0355   constexpr const_reverse_iterator crbegin() const {
0356     return const_reverse_iterator(end());
0357   }
0358 
0359   reverse_iterator rend() { return reverse_iterator(begin()); }
0360 
0361   constexpr const_reverse_iterator rend() const {
0362     return const_reverse_iterator(begin());
0363   }
0364 
0365   constexpr const_reverse_iterator crend() const {
0366     return const_reverse_iterator(begin());
0367   }
0368 
0369   // Mutations
0370 
0371   void reserve(size_t n) { storage_.reserve(n); }
0372 
0373   void clear() { storage_.clear(); }
0374 
0375   void push_back(const T& value) {
0376     storage_.bump_size(1);
0377     storage_.storage_ptr()[storage_.size_ - 1].construct(value);
0378   }
0379 
0380   void push_back(T&& value) {
0381     storage_.bump_size(1);
0382     storage_.storage_ptr()[storage_.size_ - 1].construct(std::move(value));
0383   }
0384 
0385   template <typename... Args>
0386   void emplace_back(Args&&... args) {
0387     storage_.bump_size(1);
0388     storage_.storage_ptr()[storage_.size_ - 1].construct(std::forward<Args>(args)...);
0389   }
0390 
0391   template <typename InputIt>
0392   iterator insert(const_iterator insert_at, InputIt first, InputIt last) {
0393     const size_t n = storage_.size_;
0394     const size_t it_size = static_cast<size_t>(last - first);  // XXX might be O(n)?
0395     const size_t pos = static_cast<size_t>(insert_at - const_data_ptr());
0396     storage_.bump_size(it_size);
0397     auto* p = storage_.storage_ptr();
0398     if (it_size == 0) {
0399       return p[pos].get();
0400     }
0401     const size_t end_pos = pos + it_size;
0402 
0403     // Move [pos; n) to [end_pos; end_pos + n - pos)
0404     size_t i = n;
0405     size_t j = end_pos + n - pos;
0406     while (j > std::max(n, end_pos)) {
0407       p[--j].move_construct(&p[--i]);
0408     }
0409     while (j > end_pos) {
0410       p[--j].move_assign(&p[--i]);
0411     }
0412     assert(j == end_pos);
0413     // Copy [first; last) to [pos; end_pos)
0414     j = pos;
0415     while (j < std::min(n, end_pos)) {
0416       p[j++].assign(*first++);
0417     }
0418     while (j < end_pos) {
0419       p[j++].construct(*first++);
0420     }
0421     assert(first == last);
0422     return p[pos].get();
0423   }
0424 
0425   void resize(size_t n) {
0426     const size_t old_size = storage_.size_;
0427     if (n > storage_.size_) {
0428       storage_.bump_size(n - old_size);
0429       auto* p = storage_.storage_ptr();
0430       for (size_t i = old_size; i < n; ++i) {
0431         p[i].construct(T{});
0432       }
0433     } else {
0434       auto* p = storage_.storage_ptr();
0435       for (size_t i = n; i < old_size; ++i) {
0436         p[i].destroy();
0437       }
0438       storage_.reduce_size(old_size - n);
0439     }
0440   }
0441 
0442   void resize(size_t n, const T& value) {
0443     const size_t old_size = storage_.size_;
0444     if (n > storage_.size_) {
0445       storage_.bump_size(n - old_size);
0446       auto* p = storage_.storage_ptr();
0447       for (size_t i = old_size; i < n; ++i) {
0448         p[i].construct(value);
0449       }
0450     } else {
0451       auto* p = storage_.storage_ptr();
0452       for (size_t i = n; i < old_size; ++i) {
0453         p[i].destroy();
0454       }
0455       storage_.reduce_size(old_size - n);
0456     }
0457   }
0458 
0459  private:
0460   template <typename InputIt>
0461   void init_by_copying(size_t n, InputIt src) {
0462     storage_.bump_size(n);
0463     auto* dest = storage_.storage_ptr();
0464     for (size_t i = 0; i < n; ++i, ++src) {
0465       dest[i].construct(*src);
0466     }
0467   }
0468 
0469   template <typename InputIt>
0470   void init_by_moving(size_t n, InputIt src) {
0471     init_by_copying(n, std::make_move_iterator(src));
0472   }
0473 
0474   template <typename InputIt>
0475   void assign_by_copying(size_t n, InputIt src) {
0476     const size_t old_size = storage_.size_;
0477     if (n > old_size) {
0478       storage_.bump_size(n - old_size);
0479       auto* dest = storage_.storage_ptr();
0480       for (size_t i = 0; i < old_size; ++i, ++src) {
0481         dest[i].assign(*src);
0482       }
0483       for (size_t i = old_size; i < n; ++i, ++src) {
0484         dest[i].construct(*src);
0485       }
0486     } else {
0487       auto* dest = storage_.storage_ptr();
0488       for (size_t i = 0; i < n; ++i, ++src) {
0489         dest[i].assign(*src);
0490       }
0491       for (size_t i = n; i < old_size; ++i) {
0492         dest[i].destroy();
0493       }
0494       storage_.reduce_size(old_size - n);
0495     }
0496   }
0497 
0498   template <typename InputIt>
0499   void assign_by_moving(size_t n, InputIt src) {
0500     assign_by_copying(n, std::make_move_iterator(src));
0501   }
0502 };
0503 
0504 template <typename T, size_t N>
0505 using StaticVector = StaticVectorImpl<T, N, StaticVectorStorage<T, N>>;
0506 
0507 template <typename T, size_t N>
0508 using SmallVector = StaticVectorImpl<T, N, SmallVectorStorage<T, N>>;
0509 
0510 }  // namespace internal
0511 }  // namespace arrow