Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2020-04-21 18:31:56 +0300
committerJacques Lucke <jacques@blender.org>2020-04-21 18:31:56 +0300
commit3059353b38ed1fc432cce584afad5bef3b7f2227 (patch)
tree7b0fe042cccc6a3372ecb379e2d1725dea6515a9 /source/blender/blenlib/BLI_vector.h
parent0e52b91f97bcb800dc4f07f93f7f07e1cf9cab1c (diff)
BLI: Use .hh extension for C++ headers in blenlib
Diffstat (limited to 'source/blender/blenlib/BLI_vector.h')
-rw-r--r--source/blender/blenlib/BLI_vector.h668
1 files changed, 0 insertions, 668 deletions
diff --git a/source/blender/blenlib/BLI_vector.h b/source/blender/blenlib/BLI_vector.h
deleted file mode 100644
index 6a708759d0e..00000000000
--- a/source/blender/blenlib/BLI_vector.h
+++ /dev/null
@@ -1,668 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef __BLI_VECTOR_H__
-#define __BLI_VECTOR_H__
-
-/** \file
- * \ingroup bli
- *
- * This vector wraps a dynamically sized array of a specific type. It supports small object
- * optimization. That means, when the vector only contains a few elements, no memory allocation is
- * performed. Instead, those elements are stored directly in the vector.
- */
-
-#include <algorithm>
-#include <cstdlib>
-#include <cstring>
-#include <iostream>
-#include <memory>
-
-#include "BLI_allocator.h"
-#include "BLI_array_ref.h"
-#include "BLI_index_range.h"
-#include "BLI_listbase_wrapper.h"
-#include "BLI_math_base.h"
-#include "BLI_memory_utils_cxx.h"
-#include "BLI_utildefines.h"
-
-#include "MEM_guardedalloc.h"
-
-namespace BLI {
-
-template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Vector {
- private:
- T *m_begin;
- T *m_end;
- T *m_capacity_end;
- Allocator m_allocator;
- AlignedBuffer<sizeof(T) * N, alignof(T)> m_small_buffer;
-
-#ifndef NDEBUG
- /* Storing size in debug builds, because it makes debugging much easier sometimes. */
- uint m_debug_size;
-# define UPDATE_VECTOR_SIZE(ptr) (ptr)->m_debug_size = (uint)((ptr)->m_end - (ptr)->m_begin)
-#else
-# define UPDATE_VECTOR_SIZE(ptr) ((void)0)
-#endif
-
- template<typename OtherT, uint OtherN, typename OtherAllocator> friend class Vector;
-
- public:
- /**
- * Create an empty vector.
- * This does not do any memory allocation.
- */
- Vector()
- {
- m_begin = this->small_buffer();
- m_end = m_begin;
- m_capacity_end = m_begin + N;
- UPDATE_VECTOR_SIZE(this);
- }
-
- /**
- * Create a vector with a specific size.
- * The elements will be default initialized.
- */
- explicit Vector(uint size) : Vector()
- {
- this->reserve(size);
- this->increase_size_unchecked(size);
- for (T *current = m_begin; current != m_end; current++) {
- new (current) T();
- }
- }
-
- /**
- * Create a vector filled with a specific value.
- */
- Vector(uint size, const T &value) : Vector()
- {
- this->reserve(size);
- this->increase_size_unchecked(size);
- BLI::uninitialized_fill_n(m_begin, size, value);
- }
-
- /**
- * Create a vector from an initializer list.
- */
- Vector(std::initializer_list<T> values) : Vector(ArrayRef<T>(values))
- {
- }
-
- /**
- * Create a vector from an array ref.
- */
- Vector(ArrayRef<T> values) : Vector()
- {
- this->reserve(values.size());
- this->increase_size_unchecked(values.size());
- BLI::uninitialized_copy_n(values.begin(), values.size(), this->begin());
- }
-
- /**
- * Create a vector from any container. It must be possible to use the container in a range-for
- * loop.
- */
- template<typename ContainerT> static Vector FromContainer(const ContainerT &container)
- {
- Vector vector;
- for (const auto &value : container) {
- vector.append(value);
- }
- return vector;
- }
-
- /**
- * Create a vector from a ListBase.
- */
- Vector(ListBase &values, bool intrusive_next_and_prev_pointers) : Vector()
- {
- BLI_assert(intrusive_next_and_prev_pointers);
- if (intrusive_next_and_prev_pointers) {
- for (T value : IntrusiveListBaseWrapper<typename std::remove_pointer<T>::type>(values)) {
- this->append(value);
- }
- }
- }
-
- /**
- * Create a copy of another vector.
- * The other vector will not be changed.
- * If the other vector has less than N elements, no allocation will be made.
- */
- Vector(const Vector &other) : m_allocator(other.m_allocator)
- {
- this->init_copy_from_other_vector(other);
- }
-
- template<uint OtherN>
- Vector(const Vector<T, OtherN, Allocator> &other) : m_allocator(other.m_allocator)
- {
- this->init_copy_from_other_vector(other);
- }
-
- /**
- * Steal the elements from another vector.
- * This does not do an allocation.
- * The other vector will have zero elements afterwards.
- */
- template<uint OtherN>
- Vector(Vector<T, OtherN, Allocator> &&other) noexcept : m_allocator(other.m_allocator)
- {
- uint size = other.size();
-
- if (other.is_small()) {
- if (size <= N) {
- /* Copy between inline buffers. */
- m_begin = this->small_buffer();
- m_end = m_begin + size;
- m_capacity_end = m_begin + N;
- uninitialized_relocate_n(other.m_begin, size, m_begin);
- }
- else {
- /* Copy from inline buffer to newly allocated buffer. */
- uint capacity = size;
- m_begin = (T *)m_allocator.allocate_aligned(
- sizeof(T) * capacity, std::alignment_of<T>::value, __func__);
- m_end = m_begin + size;
- m_capacity_end = m_begin + capacity;
- uninitialized_relocate_n(other.m_begin, size, m_begin);
- }
- }
- else {
- /* Steal the pointer. */
- m_begin = other.m_begin;
- m_end = other.m_end;
- m_capacity_end = other.m_capacity_end;
- }
-
- other.m_begin = other.small_buffer();
- other.m_end = other.m_begin;
- other.m_capacity_end = other.m_begin + OtherN;
- UPDATE_VECTOR_SIZE(this);
- UPDATE_VECTOR_SIZE(&other);
- }
-
- ~Vector()
- {
- destruct_n(m_begin, this->size());
- if (!this->is_small()) {
- m_allocator.deallocate(m_begin);
- }
- }
-
- operator ArrayRef<T>() const
- {
- return ArrayRef<T>(m_begin, this->size());
- }
-
- operator MutableArrayRef<T>()
- {
- return MutableArrayRef<T>(m_begin, this->size());
- }
-
- ArrayRef<T> as_ref() const
- {
- return *this;
- }
-
- MutableArrayRef<T> as_mutable_ref()
- {
- return *this;
- }
-
- Vector &operator=(const Vector &other)
- {
- if (this == &other) {
- return *this;
- }
-
- this->~Vector();
- new (this) Vector(other);
-
- return *this;
- }
-
- Vector &operator=(Vector &&other)
- {
- if (this == &other) {
- return *this;
- }
-
- /* This can fail, when the vector is used to build a recursive data structure.
- See https://youtu.be/7Qgd9B1KuMQ?t=840. */
- this->~Vector();
- new (this) Vector(std::move(other));
-
- return *this;
- }
-
- /**
- * Make sure that enough memory is allocated to hold size elements.
- * This won't necessarily make an allocation when size is small.
- * The actual size of the vector does not change.
- */
- void reserve(uint size)
- {
- this->grow(size);
- }
-
- /**
- * Afterwards the vector has 0 elements, but will still have
- * memory to be refilled again.
- */
- void clear()
- {
- destruct_n(m_begin, this->size());
- m_end = m_begin;
- UPDATE_VECTOR_SIZE(this);
- }
-
- /**
- * Afterwards the vector has 0 elements and any allocated memory
- * will be freed.
- */
- void clear_and_make_small()
- {
- destruct_n(m_begin, this->size());
- if (!this->is_small()) {
- m_allocator.deallocate(m_begin);
- }
-
- m_begin = this->small_buffer();
- m_end = m_begin;
- m_capacity_end = m_begin + N;
- UPDATE_VECTOR_SIZE(this);
- }
-
- /**
- * Insert a new element at the end of the vector.
- * This might cause a reallocation with the capacity is exceeded.
- */
- void append(const T &value)
- {
- this->ensure_space_for_one();
- this->append_unchecked(value);
- }
-
- void append(T &&value)
- {
- this->ensure_space_for_one();
- this->append_unchecked(std::move(value));
- }
-
- uint append_and_get_index(const T &value)
- {
- uint index = this->size();
- this->append(value);
- return index;
- }
-
- void append_non_duplicates(const T &value)
- {
- if (!this->contains(value)) {
- this->append(value);
- }
- }
-
- void append_unchecked(const T &value)
- {
- BLI_assert(m_end < m_capacity_end);
- new (m_end) T(value);
- m_end++;
- UPDATE_VECTOR_SIZE(this);
- }
-
- void append_unchecked(T &&value)
- {
- BLI_assert(m_end < m_capacity_end);
- new (m_end) T(std::move(value));
- m_end++;
- UPDATE_VECTOR_SIZE(this);
- }
-
- /**
- * Insert the same element n times at the end of the vector.
- * This might result in a reallocation internally.
- */
- void append_n_times(const T &value, uint n)
- {
- this->reserve(this->size() + n);
- BLI::uninitialized_fill_n(m_end, n, value);
- this->increase_size_unchecked(n);
- }
-
- void increase_size_unchecked(uint n)
- {
- BLI_assert(m_end + n <= m_capacity_end);
- m_end += n;
- UPDATE_VECTOR_SIZE(this);
- }
-
- /**
- * Copy the elements of another array to the end of this vector.
- */
- void extend(ArrayRef<T> array)
- {
- this->extend(array.begin(), array.size());
- }
-
- void extend(const T *start, uint amount)
- {
- this->reserve(this->size() + amount);
- this->extend_unchecked(start, amount);
- }
-
- void extend_non_duplicates(ArrayRef<T> array)
- {
- for (const T &value : array) {
- this->append_non_duplicates(value);
- }
- }
-
- void extend_unchecked(ArrayRef<T> array)
- {
- this->extend_unchecked(array.begin(), array.size());
- }
-
- void extend_unchecked(const T *start, uint amount)
- {
- BLI_assert(m_begin + amount <= m_capacity_end);
- BLI::uninitialized_copy_n(start, amount, m_end);
- m_end += amount;
- UPDATE_VECTOR_SIZE(this);
- }
-
- /**
- * Return a reference to the last element in the vector.
- * This will assert when the vector is empty.
- */
- const T &last() const
- {
- BLI_assert(this->size() > 0);
- return *(m_end - 1);
- }
-
- T &last()
- {
- BLI_assert(this->size() > 0);
- return *(m_end - 1);
- }
-
- /**
- * Replace every element with a new value.
- */
- void fill(const T &value)
- {
- std::fill(m_begin, m_end, value);
- }
-
- void fill_indices(ArrayRef<uint> indices, const T &value)
- {
- MutableArrayRef<T>(*this).fill_indices(indices, value);
- }
-
- /**
- * Return how many values are currently stored in the vector.
- */
- uint size() const
- {
- BLI_assert(m_debug_size == (uint)(m_end - m_begin));
- return (uint)(m_end - m_begin);
- }
-
- /**
- * Returns true when the vector contains no elements, otherwise false.
- */
- bool empty() const
- {
- return m_begin == m_end;
- }
-
- /**
- * Deconstructs the last element and decreases the size by one.
- * This will assert when the vector is empty.
- */
- void remove_last()
- {
- BLI_assert(!this->empty());
- m_end--;
- destruct(m_end);
- UPDATE_VECTOR_SIZE(this);
- }
-
- /**
- * Remove the last element from the vector and return it.
- */
- T pop_last()
- {
- BLI_assert(!this->empty());
- m_end--;
- T value = std::move(*m_end);
- destruct(m_end);
- UPDATE_VECTOR_SIZE(this);
- return value;
- }
-
- /**
- * Delete any element in the vector.
- * The empty space will be filled by the previously last element.
- */
- void remove_and_reorder(uint index)
- {
- BLI_assert(index < this->size());
- T *element_to_remove = m_begin + index;
- m_end--;
- if (element_to_remove < m_end) {
- *element_to_remove = std::move(*m_end);
- }
- destruct(m_end);
- UPDATE_VECTOR_SIZE(this);
- }
-
- void remove_first_occurrence_and_reorder(const T &value)
- {
- uint index = this->index(value);
- this->remove_and_reorder((uint)index);
- }
-
- /**
- * Do a linear search to find the value in the vector.
- * When found, return the first index, otherwise return -1.
- */
- int index_try(const T &value) const
- {
- for (T *current = m_begin; current != m_end; current++) {
- if (*current == value) {
- return current - m_begin;
- }
- }
- return -1;
- }
-
- /**
- * Do a linear search to find the value in the vector.
- * When found, return the first index, otherwise fail.
- */
- uint index(const T &value) const
- {
- int index = this->index_try(value);
- BLI_assert(index >= 0);
- return (uint)index;
- }
-
- /**
- * Do a linear search to see of the value is in the vector.
- * Return true when it exists, otherwise false.
- */
- bool contains(const T &value) const
- {
- return this->index_try(value) != -1;
- }
-
- /**
- * Compare vectors element-wise.
- * Return true when they have the same length and all elements
- * compare equal, otherwise false.
- */
- static bool all_equal(const Vector &a, const Vector &b)
- {
- if (a.size() != b.size()) {
- return false;
- }
- for (uint i = 0; i < a.size(); i++) {
- if (a[i] != b[i]) {
- return false;
- }
- }
- return true;
- }
-
- const T &operator[](uint index) const
- {
- BLI_assert(index < this->size());
- return m_begin[index];
- }
-
- T &operator[](uint index)
- {
- BLI_assert(index < this->size());
- return m_begin[index];
- }
-
- T *begin()
- {
- return m_begin;
- }
- T *end()
- {
- return m_end;
- }
-
- const T *begin() const
- {
- return m_begin;
- }
- const T *end() const
- {
- return m_end;
- }
-
- /**
- * Get the current capacity of the vector.
- */
- uint capacity() const
- {
- return (uint)(m_capacity_end - m_begin);
- }
-
- IndexRange index_range() const
- {
- return IndexRange(this->size());
- }
-
- void print_stats() const
- {
- std::cout << "Small Vector at " << (void *)this << ":" << std::endl;
- std::cout << " Elements: " << this->size() << std::endl;
- std::cout << " Capacity: " << (m_capacity_end - m_begin) << std::endl;
- std::cout << " Small Elements: " << N << " Size on Stack: " << sizeof(*this) << std::endl;
- }
-
- private:
- T *small_buffer() const
- {
- return (T *)m_small_buffer.ptr();
- }
-
- bool is_small() const
- {
- return m_begin == this->small_buffer();
- }
-
- void ensure_space_for_one()
- {
- if (UNLIKELY(m_end >= m_capacity_end)) {
- this->grow(std::max(this->size() * 2, (uint)1));
- }
- }
-
- BLI_NOINLINE void grow(uint min_capacity)
- {
- if (this->capacity() >= min_capacity) {
- return;
- }
-
- /* Round up to the next power of two. Otherwise consecutive calls to grow can cause a
- * reallocation every time even though the min_capacity only increments. */
- min_capacity = power_of_2_max_u(min_capacity);
-
- uint size = this->size();
-
- T *new_array = (T *)m_allocator.allocate_aligned(
- min_capacity * (uint)sizeof(T), std::alignment_of<T>::value, "grow BLI::Vector");
- uninitialized_relocate_n(m_begin, size, new_array);
-
- if (!this->is_small()) {
- m_allocator.deallocate(m_begin);
- }
-
- m_begin = new_array;
- m_end = m_begin + size;
- m_capacity_end = m_begin + min_capacity;
- }
-
- /**
- * Initialize all properties, except for m_allocator, which has to be initialized beforehand.
- */
- template<uint OtherN> void init_copy_from_other_vector(const Vector<T, OtherN, Allocator> &other)
- {
- m_allocator = other.m_allocator;
-
- uint size = other.size();
- uint capacity = size;
-
- if (size <= N) {
- m_begin = this->small_buffer();
- capacity = N;
- }
- else {
- m_begin = (T *)m_allocator.allocate_aligned(
- sizeof(T) * size, std::alignment_of<T>::value, __func__);
- capacity = size;
- }
-
- m_end = m_begin + size;
- m_capacity_end = m_begin + capacity;
-
- uninitialized_copy(other.begin(), other.end(), m_begin);
- UPDATE_VECTOR_SIZE(this);
- }
-};
-
-#undef UPDATE_VECTOR_SIZE
-
-/**
- * Use when the vector is used in the local scope of a function. It has a larger inline storage by
- * default to make allocations less likely.
- */
-template<typename T, uint N = 20> using ScopedVector = Vector<T, N, GuardedAllocator>;
-
-} /* namespace BLI */
-
-#endif /* __BLI_VECTOR_H__ */