#ifndef DMSDK_ARRAY_H
#define DMSDK_ARRAY_H
#include <assert.h>
#include <stdint.h>
#include <string.h>
namespace dmArrayUtil
{
void SetCapacity(uint32_t capacity, uint32_t type_size, uintptr_t* first, uintptr_t* last, uintptr_t* end);
};
template <typename T, size_t N>
char (&ArraySizeHelper(T (&a)[N]))[N];
#define DM_ARRAY_SIZE(A) (sizeof(ArraySizeHelper(A)))
template <typename T>
class dmArray
{
public:
dmArray();
dmArray(T* user_array, uint32_t size, uint32_t capacity);
~dmArray();
T* Begin();
const T* Begin() const;
T* End();
const T* End() const;
T& Front();
const T& Front() const;
T& Back();
const T& Back() const;
uint32_t Size() const;
uint32_t Capacity() const;
bool Full() const;
bool Empty() const;
uint32_t Remaining() const;
T& operator[](uint32_t i);
const T& operator[](uint32_t i) const;
void SetCapacity(uint32_t capacity);
void OffsetCapacity(int32_t offset);
void SetSize(uint32_t size);
T& EraseSwap(uint32_t index);
T& EraseSwapRef(T& element);
void Push(const T& element);
void PushArray(const T* array, uint32_t count);
void Pop();
void Swap(dmArray<T>& rhs);
void Map(void (*fn)(T* value, void* ctx), void* ctx);
private:
T *m_Front, *m_End;
T *m_Back;
uint16_t m_UserAllocated : 1;
dmArray(const dmArray<T>&) {}
void operator =(const dmArray<T>&) {}
void operator ==(const dmArray<T>&) {}
};
template <typename T>
dmArray<T>::dmArray()
{
memset(this, 0, sizeof(*this));
}
template <typename T>
dmArray<T>::dmArray(T *user_array, uint32_t size, uint32_t capacity)
{
assert(user_array != 0);
assert(size <= capacity);
m_Front = user_array;
m_End = user_array + size;
m_Back = user_array + capacity;
m_UserAllocated = 1;
}
template <typename T>
dmArray<T>::~dmArray()
{
if (!m_UserAllocated && m_Front)
{
delete[] (uint8_t*) m_Front;
}
}
template <typename T>
T* dmArray<T>::Begin()
{
return m_Front;
}
template <typename T>
const T* dmArray<T>::Begin() const
{
return m_Front;
}
template <typename T>
T* dmArray<T>::End()
{
return m_End;
}
template <typename T>
const T* dmArray<T>::End() const
{
return m_End;
}
template <typename T>
T& dmArray<T>::Front()
{
assert(Size() > 0);
return m_Front[0];
}
template <typename T>
const T& dmArray<T>::Front() const
{
assert(Size() > 0);
return m_Front[0];
}
template <typename T>
T& dmArray<T>::Back()
{
assert(Size() > 0);
return m_End[-1];
}
template <typename T>
const T& dmArray<T>::Back() const
{
assert(Size() > 0);
return m_End[-1];
}
template <typename T>
uint32_t dmArray<T>::Size() const
{
return (uint32_t)(uintptr_t)(m_End - m_Front);
}
template <typename T>
uint32_t dmArray<T>::Capacity() const
{
return (uint32_t)(uintptr_t)(m_Back - m_Front);
}
template <typename T>
bool dmArray<T>::Full() const
{
return m_End == m_Back;
}
template <typename T>
bool dmArray<T>::Empty() const
{
return m_End == m_Front;
}
template <typename T>
uint32_t dmArray<T>::Remaining() const
{
return (uint32_t)(uintptr_t)(m_Back - m_End);
}
template <typename T>
T& dmArray<T>::operator[](uint32_t i)
{
assert(i < Size());
return m_Front[i];
}
template <typename T>
const T& dmArray<T>::operator[](uint32_t i) const
{
assert(i < Size());
return m_Front[i];
}
template <typename T>
void dmArray<T>::SetCapacity(uint32_t capacity)
{
assert(!m_UserAllocated && "SetCapacity is not allowed for user-allocated arrays");
dmArrayUtil::SetCapacity(capacity, sizeof(T), (uintptr_t*)&m_Front, (uintptr_t*)&m_Back, (uintptr_t*)&m_End);
}
template <typename T>
void dmArray<T>::OffsetCapacity(int32_t offset)
{
SetCapacity((uint32_t)((int32_t)Capacity()) + offset);
}
template <typename T>
void dmArray<T>::SetSize(uint32_t size)
{
assert(size <= Capacity());
m_End = m_Front + size;
}
template <typename T>
T& dmArray<T>::EraseSwap(uint32_t index)
{
assert(index < Size());
m_Front[index] = *(m_End - 1);
m_End--;
assert(m_End >= m_Front);
return m_Front[index];
}
template <typename T>
T& dmArray<T>::EraseSwapRef(T& element)
{
assert(&element >= m_Front && &element < m_End);
element = *(m_End - 1);
m_End--;
assert(m_End >= m_Front);
return element;
}
template <typename T>
void dmArray<T>::Push(const T& element)
{
assert(Capacity() - Size() > 0);
*m_End++ = element;
}
template <typename T>
void dmArray<T>::PushArray(const T* array, uint32_t count)
{
assert(Capacity() - Size() >= count);
memcpy(m_End, array, sizeof(T) * count);
m_End += count;
}
template <typename T>
void dmArray<T>::Pop()
{
assert(Size() > 0);
m_End--;
}
#define SWAP(type, lhs, rhs)\
{\
type tmp = rhs;\
rhs = lhs;\
lhs = tmp;\
}
template <typename T>
void dmArray<T>::Swap(dmArray<T>& rhs)
{
SWAP(T*, m_Front, rhs.m_Front);
SWAP(T*, m_End, rhs.m_End);
SWAP(T*, m_Back, rhs.m_Back);
SWAP(uint16_t, m_UserAllocated, rhs.m_UserAllocated);
}
#undef SWAP
template <typename T>
void dmArray<T>::Map(void (*fn)(T* value, void* ctx), void* ctx)
{
for (uint32_t i = 0; i < Size(); ++i)
{
fn(&m_Front[i], ctx);
}
}
#endif