Orange/include/Orange/Core/SmallVector.h

149 lines
3.3 KiB
C++

#pragma once
#include <Orange/Core/AlignedStorage.h>
namespace orange
{
template <typename T, size_t N>
class SmallVector
{
public:
SmallVector() {}
SmallVector(size_t size) { Resize(size); }
SmallVector (const SmallVector&) = delete;
SmallVector& operator = (const SmallVector&) = delete;
~SmallVector()
{
for (size_t i = 0; i < m_size; i++)
Ptr(i)->~T();
if (m_capacity > N)
delete[] u.m_ptr;
}
size_t Size() const
{
return m_size;
}
void Reserve(size_t n)
{
n = PickCapacity(n);
if (n <= m_capacity)
return;
Storage* data = new Storage[n];
for (size_t i = 0; i < m_size; i++)
{
new (&data[i]) T(Move(*Ptr(i)));
Ptr(i)->~T();
}
if (m_capacity > N)
delete[] u.m_ptr;
m_capacity = n;
u.m_ptr = data;
}
const T* Data() const { return Ptr(0); }
T* Data() { return Ptr(0); }
void Resize(size_t n)
{
Reserve(n);
for (size_t i = n; i < m_size; i++)
Ptr(i)->~T();
for (size_t i = m_size; i < n; i++)
new (Ptr(i)) T();
}
void PushBack(const T& object)
{
Reserve(m_size + 1);
new (Ptr(m_size++)) T(object);
}
void PushBack(T&& object)
{
Reserve(m_size + 1);
new (Ptr(m_size++)) T(Move(object));
}
template<typename... Args>
void EmplaceBack(Args... args)
{
Reserve(m_size + 1);
new (Ptr(m_size++)) T(Forward<Args>(args)...);
}
void Erase(size_t idx)
{
Ptr(idx)->~T();
for (size_t i = idx; i < m_size - 1; i++)
{
new (Ptr(i)) T(Move(*Ptr(i + 1)));
Ptr(i + 1)->~T();
}
}
void PopBack()
{
Ptr(--m_size)->~T();
}
T& operator [] (size_t idx) { return *Ptr(idx); }
const T& operator [] (size_t idx) const { return *Ptr(idx); }
T& front() { return *Ptr(0); }
const T& front() const { return *Ptr(0); }
T& back() { return *Ptr(m_size - 1); }
const T& back() const { return *Ptr(m_size - 1); }
private:
using Storage = AlignedStorage<sizeof(T), alignof(T)>;
size_t m_capacity = N;
size_t m_size = 0;
union
{
Storage* m_ptr;
Storage m_data[sizeof(T) * N];
} u;
size_t PickCapacity(size_t n) {
size_t capacity = m_capacity;
while (capacity < n)
capacity *= 2;
return capacity;
}
T* Ptr(size_t idx) {
return m_capacity == N
? reinterpret_cast<T*>(&u.m_data[idx])
: reinterpret_cast<T*>(&u.m_ptr[idx]);
}
const T* Ptr(size_t idx) const
{
return m_capacity == N
? reinterpret_cast<const T*>(&u.m_data[idx])
: reinterpret_cast<const T*>(&u.m_ptr[idx]);
}
};
}