// // Lol Engine // // Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net> // This program is free software; you can redistribute it and/or // modify it under the terms of the Do What The Fuck You Want To // Public License, Version 2, as published by Sam Hocevar. See // http://sam.zoy.org/projects/COPYING.WTFPL for more details. // // // The Array class // --------------- // A very simple Array class not unlike the std::vector, with some nice // additional features, eg. Array<int,float> for automatic arrays of structs. // #if !defined __LOL_ARRAY_H__ #define __LOL_ARRAY_H__ #include <new> #include <stdint.h> namespace lol { /* * The base array type. * * Contains an m_data memory array of Elements, of which only the first * m_count are allocated. The rest is uninitialised memory. */ template<typename T, typename ARRAY> class ArrayBase { public: typedef T Element; inline ArrayBase() : m_data(0), m_count(0), m_reserved(0) { } inline ~ArrayBase() { for (int i = 0; i < m_count; i++) m_data[i].~Element(); delete[] reinterpret_cast<uint8_t *>(m_data); } ArrayBase(ArrayBase const& that) : m_data(0), m_count(0), m_reserved(0) { /* Reserve the exact number of values instead of what the other * array had reserved. Just a method for not wasting too much. */ Reserve(that.m_count); for (int i = 0; i < that.m_count; i++) new(&m_data[i]) Element(that[i]); m_count = that.m_count; } ArrayBase& operator=(ArrayBase const& that) { if ((uintptr_t)this != (uintptr_t)&that) { if (m_reserved < that.m_count) { /* If not enough space, reserve memory and use placement * new directly for all elements. */ Reserve(that.m_count); for (int i = 0; i < that.m_count; i++) new(&m_data[i]) Element(that[i]); } else { /* If enough space, overwrite the common elements, then * use placement new for the elements in the other array * that we do not have, and finally destroy the remaining * elements. */ for (int i = 0; i < m_count && i < that.m_count; i++) m_data[i] = Element(that[i]); for (int i = m_count; i < that.m_count; i++) new(&m_data[i]) Element(that[i]); for (int i = that.m_count; i < m_count; i++) m_data[i].~Element(); } m_count = that.m_count; } return *this; } ArrayBase& operator+=(ARRAY const &that) { int todo = that.m_count; Reserve(m_count + that.m_count); for (int i = 0; i < todo; i++) *this << that[i]; return *this; } ARRAY operator+(ARRAY const &that) const { /* FIXME: upon return, this makes a copy of the temporary object; * use either C++11 move semantics, or add a special flag to the * object indicating we're a temporary about to be destroyed */ ARRAY ret; ret.Reserve(m_count + that.m_count); for (int i = 0; i < m_count; i++) ret << (*this)[i]; for (int i = 0; i < that.m_count; i++) ret << that[i]; return ret; } inline Element& operator[](int n) { return m_data[n]; } inline Element const& operator[](int n) const { return m_data[n]; } inline Element& Last() { return m_data[m_count - 1]; } inline Element const& Last() const { return m_data[m_count - 1]; } inline ArrayBase& operator<<(T const &x) { if (m_count >= m_reserved) { T tmp = x; Reserve(m_count * 13 / 8 + 8); new (&m_data[m_count++]) Element(tmp); } else { new (&m_data[m_count++]) Element(x); } return *this; } inline void Push(T const &x) { *this << x; } inline void Pop() { Remove(m_count - 1, 1); } void Remove(int pos, int todelete = 1) { for (int i = pos; i + todelete < m_count; i++) m_data[i] = m_data[i + todelete]; for (int i = m_count - todelete; i < m_count; i++) m_data[i].~Element(); m_count -= todelete; } inline void Empty() { Remove(0, m_count); } void Reserve(int toreserve) { if (toreserve <= (int)m_reserved) return; Element *tmp = reinterpret_cast<Element *> (new uint8_t [sizeof(Element) * toreserve]); for (int i = 0; i < m_count; i++) { new(&tmp[i]) Element(m_data[i]); m_data[i].~Element(); } if (m_data) delete[] reinterpret_cast<uint8_t *>(m_data); m_data = tmp; m_reserved = toreserve; } inline int Count() const { return m_count; } inline int Bytes() const { return m_count * sizeof(Element); } protected: Element *m_data; int m_count, m_reserved; }; /* * Element types */ template<typename T1, typename T2, typename T3 = void, typename T4 = void, typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void> class ArrayElement { public: T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7; T8 m8; }; template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> class ArrayElement<T1, T2, T3, T4, T5, T6, T7, void> { public: T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7; }; template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> class ArrayElement<T1, T2, T3, T4, T5, T6, void, void> { public: T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; }; template<typename T1, typename T2, typename T3, typename T4, typename T5> class ArrayElement<T1, T2, T3, T4, T5, void, void, void> { public: T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; }; template<typename T1, typename T2, typename T3, typename T4> class ArrayElement<T1, T2, T3, T4, void, void, void, void> { public: T1 m1; T2 m2; T3 m3; T4 m4; }; template<typename T1, typename T2, typename T3> class ArrayElement<T1, T2, T3, void, void, void, void, void> { public: T1 m1; T2 m2; T3 m3; }; template<typename T1, typename T2> class ArrayElement<T1, T2, void, void, void, void, void, void> { public: T1 m1; T2 m2; }; /* * Array specialisations implementing specific setters */ template<typename T1, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void> class Array : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, T8>, Array<T1, T2, T3, T4, T5, T6, T7, T8> > { public: inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4, T5 const &m5, T6 const &m6, T7 const &m7, T8 const &m8) { if (this->m_count >= this->m_reserved) { T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4; T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7; T8 tmp8 = m8; Reserve(this->m_count * 13 / 8 + 8); this->m_data[this->m_count].m1 = tmp1; this->m_data[this->m_count].m2 = tmp2; this->m_data[this->m_count].m3 = tmp3; this->m_data[this->m_count].m4 = tmp4; this->m_data[this->m_count].m5 = tmp5; this->m_data[this->m_count].m6 = tmp6; this->m_data[this->m_count].m7 = tmp7; this->m_data[this->m_count].m8 = tmp8; } else { this->m_data[this->m_count].m1 = m1; this->m_data[this->m_count].m2 = m2; this->m_data[this->m_count].m3 = m3; this->m_data[this->m_count].m4 = m4; this->m_data[this->m_count].m5 = m5; this->m_data[this->m_count].m6 = m6; this->m_data[this->m_count].m7 = m7; this->m_data[this->m_count].m8 = m8; } ++this->m_count; } }; template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> class Array<T1, T2, T3, T4, T5, T6, T7, void> : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>, Array<T1, T2, T3, T4, T5, T6, T7> > { public: inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4, T5 const &m5, T6 const &m6, T7 const &m7) { if (this->m_count >= this->m_reserved) { T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4; T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7; Reserve(this->m_count * 13 / 8 + 8); this->m_data[this->m_count].m1 = tmp1; this->m_data[this->m_count].m2 = tmp2; this->m_data[this->m_count].m3 = tmp3; this->m_data[this->m_count].m4 = tmp4; this->m_data[this->m_count].m5 = tmp5; this->m_data[this->m_count].m6 = tmp6; this->m_data[this->m_count].m7 = tmp7; } else { this->m_data[this->m_count].m1 = m1; this->m_data[this->m_count].m2 = m2; this->m_data[this->m_count].m3 = m3; this->m_data[this->m_count].m4 = m4; this->m_data[this->m_count].m5 = m5; this->m_data[this->m_count].m6 = m6; this->m_data[this->m_count].m7 = m7; } ++this->m_count; } }; template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> class Array<T1, T2, T3, T4, T5, T6, void, void> : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, void, void>, Array<T1, T2, T3, T4, T5, T6> > { public: inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4, T5 const &m5, T6 const &m6) { if (this->m_count >= this->m_reserved) { T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4; T5 tmp5 = m5; T6 tmp6 = m6; Reserve(this->m_count * 13 / 8 + 8); this->m_data[this->m_count].m1 = tmp1; this->m_data[this->m_count].m2 = tmp2; this->m_data[this->m_count].m3 = tmp3; this->m_data[this->m_count].m4 = tmp4; this->m_data[this->m_count].m5 = tmp5; this->m_data[this->m_count].m6 = tmp6; } else { this->m_data[this->m_count].m1 = m1; this->m_data[this->m_count].m2 = m2; this->m_data[this->m_count].m3 = m3; this->m_data[this->m_count].m4 = m4; this->m_data[this->m_count].m5 = m5; this->m_data[this->m_count].m6 = m6; } ++this->m_count; } }; template<typename T1, typename T2, typename T3, typename T4, typename T5> class Array<T1, T2, T3, T4, T5, void, void, void> : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, void, void, void>, Array<T1, T2, T3, T4, T5> > { public: inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4, T5 const &m5) { if (this->m_count >= this->m_reserved) { T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4; T5 tmp5 = m5; Reserve(this->m_count * 13 / 8 + 8); this->m_data[this->m_count].m1 = tmp1; this->m_data[this->m_count].m2 = tmp2; this->m_data[this->m_count].m3 = tmp3; this->m_data[this->m_count].m4 = tmp4; this->m_data[this->m_count].m5 = tmp5; } else { this->m_data[this->m_count].m1 = m1; this->m_data[this->m_count].m2 = m2; this->m_data[this->m_count].m3 = m3; this->m_data[this->m_count].m4 = m4; this->m_data[this->m_count].m5 = m5; } ++this->m_count; } }; template<typename T1, typename T2, typename T3, typename T4> class Array<T1, T2, T3, T4, void, void, void, void> : public ArrayBase<ArrayElement<T1, T2, T3, T4, void, void, void, void>, Array<T1, T2, T3, T4> > { public: inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4) { if (this->m_count >= this->m_reserved) { T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4; Reserve(this->m_count * 13 / 8 + 8); this->m_data[this->m_count].m1 = tmp1; this->m_data[this->m_count].m2 = tmp2; this->m_data[this->m_count].m3 = tmp3; this->m_data[this->m_count].m4 = tmp4; } else { this->m_data[this->m_count].m1 = m1; this->m_data[this->m_count].m2 = m2; this->m_data[this->m_count].m3 = m3; this->m_data[this->m_count].m4 = m4; } ++this->m_count; } }; template<typename T1, typename T2, typename T3> class Array<T1, T2, T3, void, void, void, void, void> : public ArrayBase<ArrayElement<T1, T2, T3, void, void, void, void, void>, Array<T1, T2, T3> > { public: inline void Push(T1 const &m1, T2 const &m2, T3 const &m3) { if (this->m_count >= this->m_reserved) { T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; Reserve(this->m_count * 13 / 8 + 8); this->m_data[this->m_count].m1 = tmp1; this->m_data[this->m_count].m2 = tmp2; this->m_data[this->m_count].m3 = tmp3; } else { this->m_data[this->m_count].m1 = m1; this->m_data[this->m_count].m2 = m2; this->m_data[this->m_count].m3 = m3; } ++this->m_count; } }; template<typename T1, typename T2> class Array<T1, T2, void, void, void, void, void, void> : public ArrayBase<ArrayElement<T1, T2, void, void, void, void, void, void>, Array<T1, T2> > { public: inline void Push(T1 const &m1, T2 const &m2) { if (this->m_count >= this->m_reserved) { T1 tmp1 = m1; T2 tmp2 = m2; Reserve(this->m_count * 13 / 8 + 8); this->m_data[this->m_count].m1 = tmp1; this->m_data[this->m_count].m2 = tmp2; } else { this->m_data[this->m_count].m1 = m1; this->m_data[this->m_count].m2 = m2; } ++this->m_count; } }; template<typename T> class Array<T, void, void, void, void, void, void, void> : public ArrayBase<T, Array<T> > { }; } /* namespace lol */ #endif // __LOL_ARRAY_H__