Program Listing for File Array.h¶
↰ Return to documentation for file (Source\Containers\Inc\Containers\Array.h
)
#pragma once
// for memcpy
#include <cassert>
#include <cstring>
#include "Memory/Allocator.h"
#include "Types.h"
namespace Azura {
namespace Containers {
template <typename Type, U32 MaxSize>
class Array {
public:
// TODO: Enable When NewDeleteAllocator is ready
// explicit Array(U32 maxSize);
explicit Array(Memory::Allocator& alloc);
~Array();
// Copy Ctor
Array(const Array& other);
// Move Ctor
Array(Array&& other) noexcept;
Array& operator=(const Array& other);
Array& operator=(Array&& other) noexcept;
void PushBack(const Type& data);
Type Pop();
int FindFirst(const Type& data);
void Remove(const Type& data);
bool IsEmpty() const;
void InsertAt(U32 idx, const Type& data);
Type& operator[](U32 idx);
Type& operator[](U32 idx) const;
Type* Data();
U32 GetSize() const {
return m_size;
}
U32 GetMaxSize() const {
return m_maxSize;
}
class Iterator {
public:
Iterator() = default;
~Iterator() = default;
Iterator(const Iterator& other) = default;
Iterator& operator=(const Iterator& other) = default;
using iterator_category = std::random_access_iterator_tag;
using value_type = Type;
using difference_type = int;
using pointer = Type*;
using reference = Type&;
Iterator(const Array* ptr, int index) : mPtr(ptr), mIndex(index) {}
Iterator(Iterator&& other) noexcept = default;
Iterator& operator=(Iterator&& other) noexcept = default;
// Pre Increment
Iterator& operator++() {
++mIndex;
return *this;
}
// Post Increment
Iterator operator++(int) {
Iterator copy(*this);
operator++();
return copy;
}
// Pre Decrement
Iterator& operator--() {
--mIndex;
return *this;
}
// Post Decrement
Iterator operator--(int) {
Iterator copy(*this);
operator--();
return copy;
}
bool operator==(const Iterator& rhs) {
return mPtr == rhs.mPtr && mIndex == rhs.mIndex;
}
bool operator!=(const Iterator& rhs) {
return !(*this == rhs);
}
bool operator<(const Iterator& rhs) {
assert(mPtr == rhs.mPtr);
return mIndex < rhs.mIndex;
}
bool operator<=(const Iterator& rhs) {
assert(mPtr == rhs.mPtr);
return mIndex <= rhs.mIndex;
}
bool operator>(const Iterator& rhs) {
assert(mPtr == rhs.mPtr);
return mIndex > rhs.mIndex;
}
bool operator>=(const Iterator& rhs) {
assert(mPtr == rhs.mPtr);
return mIndex >= rhs.mIndex;
}
Iterator operator+(const int& idx) {
return Iterator(mPtr, mIndex + idx);
}
Iterator& operator+=(const int& idx) {
mIndex += idx;
return *this;
}
Iterator operator-(const int& idx) {
assert(mIndex - idx > 0);
return Iterator(mPtr, mIndex - idx);
}
Iterator& operator-=(const int& idx) {
assert(mIndex - idx > 0);
mIndex -= idx;
return *this;
}
int operator-(const Iterator& rhs) {
assert(mPtr == rhs.mPtr);
return mIndex - rhs.mIndex;
}
friend int operator-(const Iterator& lhs, const Iterator& rhs) {
Iterator copy(lhs);
return copy - rhs;
}
// Element Accessors
Type& operator*() {
return mPtr->operator[](mIndex);
}
Type* operator->() {
return &mPtr->operator[](mIndex);
}
Type& operator[](const int& idx) {
return mPtr->operator[](mIndex + idx);
}
private:
const Array* mPtr{nullptr};
int mIndex{-1};
};
Iterator Begin() const;
Iterator End() const;
#ifdef BUILD_UNIT_TEST
Type* GetBackPtr() const {
return mBack;
};
Type* GetBasePtr() const {
return m_base;
};
#endif
private:
U32 m_size{0};
U32 m_maxSize{MaxSize};
Memory::Allocator& m_allocator;
Memory::UniqueArrayPtr<Type> m_base{nullptr};
};
// TODO: Enable When NewDeleteAllocator is ready
// template <typename Type>
// Array<Type, MaxSize>::Array(const U32 maxSize) : m_maxSize(maxSize), m_allocator(alloc),
// m_base(m_allocator->NewObjects<Type>(maxSize)) {}
template <typename Type, U32 MaxSize>
Array<Type, MaxSize>::Array(Memory::Allocator& alloc)
: m_allocator(alloc), m_base(m_allocator.RawNewArray<Type>(MaxSize)) {}
template <typename Type, U32 MaxSize>
Array<Type, MaxSize>::~Array() = default;
// TODO: error with non trivial types need something similar to typename
// std::enable_if<!std::is_fundamental<Type>::value>::type
template <typename Type, U32 MaxSize>
Array<Type, MaxSize>::Array(const Array& other)
: m_size(other.m_size), m_maxSize(other.m_maxSize), m_allocator(other.m_allocator) {
// Allocate Memory
m_base = m_allocator.RawNewArray<Type>(m_maxSize);
// Copy over Contents
std::memcpy(m_base.get(), other.m_base.get(), m_maxSize * sizeof(Type));
}
template <typename Type, U32 MaxSize>
Array<Type, MaxSize>::Array(Array&& other) noexcept
: m_size(std::move(other.m_size)),
m_maxSize(std::move(other.m_maxSize)),
m_allocator(other.m_allocator),
m_base(std::move(other.m_base)) {}
// TODO: error with non trivial types need something similar to typename
// std::enable_if<!std::is_fundamental<Type>::value>::type
template <typename Type, U32 MaxSize>
Array<Type, MaxSize>& Array<Type, MaxSize>::operator=(const Array& other) {
if (this == &other) {
return *this;
}
m_size = other.m_size;
m_maxSize = other.m_maxSize;
m_allocator = other.m_allocator;
// Allocate Memory
m_base = m_allocator.RawNewArray<Type>(m_maxSize);
// Copy over Contents
std::memcpy(m_base.get(), other.m_base.get(), m_maxSize * sizeof(Type));
return *this;
}
template <typename Type, U32 MaxSize>
Array<Type, MaxSize>& Array<Type, MaxSize>::operator=(Array&& other) noexcept {
if (this == &other) {
return *this;
}
m_size = std::move(other.m_size);
m_maxSize = std::move(other.m_maxSize);
m_allocator = other.m_allocator;
m_base = std::move(other.m_base);
return *this;
}
template <typename Type, U32 MaxSize>
void Array<Type, MaxSize>::PushBack(const Type& data) {
assert(m_size < m_maxSize);
m_base[m_size] = data;
++m_size;
}
template <typename Type, U32 MaxSize>
Type Array<Type, MaxSize>::Pop() {
assert(m_size > 0);
Type data = m_base[m_size - 1];
--m_size;
return data;
}
template <typename Type, U32 MaxSize>
int Array<Type, MaxSize>::FindFirst(const Type& data) {
int idx = -1;
for (U32 itr = 0; itr < m_size; ++itr) {
if (data == m_base[itr]) {
idx = itr;
break;
}
}
return idx;
}
template <typename Type, U32 MaxSize>
void Array<Type, MaxSize>::Remove(const Type& data) {
const int idx = FindFirst(data);
if (idx >= 0) {
for (U32 itr = idx + 1; itr < m_size; ++itr) {
m_base[itr - 1] = m_base[itr];
}
--m_size;
}
}
template <typename Type, U32 MaxSize>
bool Array<Type, MaxSize>::IsEmpty() const {
return m_size == 0;
}
template <typename Type, U32 MaxSize>
void Array<Type, MaxSize>::InsertAt(U32 idx, const Type& data) {
assert(idx >= 0 && idx <= m_size);
for (int itr = m_size; itr > idx; --itr) {
m_base[itr] = m_base[itr - 1];
}
m_base[idx] = data;
}
template <typename Type, U32 MaxSize>
Type& Array<Type, MaxSize>::operator[](const U32 idx) {
assert(idx < m_size);
return m_base[idx];
}
template <typename Type, U32 MaxSize>
Type& Array<Type, MaxSize>::operator[](const U32 idx) const {
assert(idx < m_size);
return m_base[idx];
}
template <typename Type, U32 MaxSize>
Type* Array<Type, MaxSize>::Data() {
return m_base.get();
}
template <typename Type, U32 MaxSize>
typename Array<Type, MaxSize>::Iterator Array<Type, MaxSize>::Begin() const {
return Iterator(this, 0);
}
template <typename Type, U32 MaxSize>
typename Array<Type, MaxSize>::Iterator Array<Type, MaxSize>::End() const {
return Iterator(this, m_size);
}
} // namespace Containers
} // namespace Azura