tornavis/source/blender/blenlib/BLI_array_cxx.h

235 lines
4.6 KiB
C++

/*
* 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_ARRAY_CXX_H__
#define __BLI_ARRAY_CXX_H__
/** \file
* \ingroup bli
*
* This is a container that contains a fixed size array. Note however, the size of the array is not
* a template argument. Instead it can be specified at the construction time.
*/
#include "BLI_utildefines.h"
#include "BLI_allocator.h"
#include "BLI_array_ref.h"
#include "BLI_memory_utils_cxx.h"
#include "BLI_index_range.h"
namespace BLI {
template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Array {
private:
T *m_data;
uint m_size;
Allocator m_allocator;
AlignedBuffer<sizeof(T) * N, alignof(T)> m_inline_storage;
public:
Array()
{
m_data = this->inline_storage();
m_size = 0;
}
Array(ArrayRef<T> values)
{
m_size = values.size();
m_data = this->get_buffer_for_size(values.size());
uninitialized_copy_n(values.begin(), m_size, m_data);
}
Array(const std::initializer_list<T> &values) : Array(ArrayRef<T>(values))
{
}
explicit Array(uint size)
{
m_size = size;
m_data = this->get_buffer_for_size(size);
for (uint i = 0; i < m_size; i++) {
new (m_data + i) T();
}
}
Array(uint size, const T &value)
{
m_size = size;
m_data = this->get_buffer_for_size(size);
uninitialized_fill_n(m_data, m_size, value);
}
Array(const Array &other)
{
m_size = other.size();
m_allocator = other.m_allocator;
m_data = this->get_buffer_for_size(other.size());
copy_n(other.begin(), m_size, m_data);
}
Array(Array &&other) noexcept
{
m_size = other.m_size;
m_allocator = other.m_allocator;
if (!other.uses_inline_storage()) {
m_data = other.m_data;
}
else {
m_data = this->get_buffer_for_size(m_size);
uninitialized_relocate_n(other.m_data, m_size, m_data);
}
other.m_data = other.inline_storage();
other.m_size = 0;
}
~Array()
{
destruct_n(m_data, m_size);
if (!this->uses_inline_storage()) {
m_allocator.deallocate((void *)m_data);
}
}
Array &operator=(const Array &other)
{
if (this == &other) {
return *this;
}
this->~Array();
new (this) Array(other);
return *this;
}
Array &operator=(Array &&other)
{
if (this == &other) {
return *this;
}
this->~Array();
new (this) Array(std::move(other));
return *this;
}
operator ArrayRef<T>() const
{
return ArrayRef<T>(m_data, m_size);
}
operator MutableArrayRef<T>()
{
return MutableArrayRef<T>(m_data, m_size);
}
ArrayRef<T> as_ref() const
{
return *this;
}
MutableArrayRef<T> as_mutable_ref()
{
return *this;
}
T &operator[](uint index)
{
BLI_assert(index < m_size);
return m_data[index];
}
const T &operator[](uint index) const
{
BLI_assert(index < m_size);
return m_data[index];
}
uint size() const
{
return m_size;
}
void fill(const T &value)
{
MutableArrayRef<T>(*this).fill(value);
}
void fill_indices(ArrayRef<uint> indices, const T &value)
{
MutableArrayRef<T>(*this).fill_indices(indices, value);
}
const T *begin() const
{
return m_data;
}
const T *end() const
{
return m_data + m_size;
}
T *begin()
{
return m_data;
}
T *end()
{
return m_data + m_size;
}
IndexRange index_range() const
{
return IndexRange(m_size);
}
private:
T *get_buffer_for_size(uint size)
{
if (size <= N) {
return this->inline_storage();
}
else {
return this->allocate(size);
}
}
T *inline_storage() const
{
return (T *)m_inline_storage.ptr();
}
T *allocate(uint size)
{
return (T *)m_allocator.allocate_aligned(
size * sizeof(T), std::alignment_of<T>::value, __func__);
}
bool uses_inline_storage() const
{
return m_data == this->inline_storage();
}
};
} // namespace BLI
#endif /* __BLI_ARRAY_CXX_H__ */