/* SPDX-FileCopyrightText: 2023 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include "BLI_vector.hh" namespace blender { /** * A VectorList is a vector of vectors. * * VectorList can be used when: * * 1) Don't know up front the number of elements that will be added to the list. Use array or * vector.reserve when known up front. * * 2) Number of reads/writes doesn't require sequential access * of the whole list. A vector ensures memory is sequential which is fast when reading, writing can * have overhead when the reserved memory is full. * * When a VectorList reserved memory is full it will allocate memory for the new items, breaking * the sequential access. Within each allocated memory block the elements are ordered sequentially. */ template class VectorList { public: using UsedVector = Vector; private: /** * Contains the individual vectors. There must always be at least one vector */ Vector vectors_; public: VectorList() { this->append_vector(); } void append(const T &value) { this->append_as(value); } void append(T &&value) { this->append_as(std::move(value)); } template void append_as(ForwardT &&value) { UsedVector &vector = this->ensure_space_for_one(); vector.append_unchecked_as(std::forward(value)); } UsedVector *begin() { return vectors_.begin(); } UsedVector *end() { return vectors_.end(); } const UsedVector *begin() const { return vectors_.begin(); } const UsedVector *end() const { return vectors_.end(); } T &last() { return vectors_.last().last(); } int64_t size() const { int64_t result = 0; for (const UsedVector &vector : *this) { result += vector.size(); } return result; } private: UsedVector &ensure_space_for_one() { UsedVector &vector = vectors_.last(); if (LIKELY(!vector.is_at_capacity())) { return vector; } this->append_vector(); return vectors_.last(); } void append_vector() { const int64_t new_vector_capacity = this->get_next_vector_capacity(); vectors_.append({}); vectors_.last().reserve(new_vector_capacity); } int64_t get_next_vector_capacity() { if (vectors_.is_empty()) { return CapacityStart; } return std::min(vectors_.last().capacity() * 2, CapacitySoftLimit); } }; } // namespace blender