/** \file G3D/SmallArray.h \created 2009-04-26 \edited 2012-07-23 Copyright 2000-2012, Morgan McGuire, http://graphics.cs.williams.edu All rights reserved. */ #ifndef G3D_SmallArray_h #define G3D_SmallArray_h #include "G3D/platform.h" #include "G3D/Array.h" #include "G3D/MemoryManager.h" namespace G3D { /** Embeds \a N elements to reduce allocation time and increase memory coherence when working with arrays of arrays. Offers a limited subset of the functionality of G3D::Array.*/ template class SmallArray { private: int m_size; /** First N elements */ T m_embedded[N]; /** Remaining elements */ Array m_rest; public: SmallArray() : m_size(0) {} inline int size() const { return m_size; } void resize(int n, bool shrinkIfNecessary = true) { m_rest.resize(std::max(0, n - N), shrinkIfNecessary); m_size = n; } void clear(bool shrinkIfNecessary = true) { resize(0, shrinkIfNecessary); } void clearAndSetMemoryManager(MemoryManager::Ref& m) { clear(); m_rest.clearAndSetMemoryManager(m); } inline T& operator[](int i) { debugAssert(i < m_size && i >= 0); if (i < N) { return m_embedded[i]; } else { return m_rest[i - N]; } } inline const T& operator[](int i) const { debugAssert(i < m_size && i >= 0); if (i < N) { return m_embedded[i]; } else { return m_rest[i - N]; } } inline void push(const T& v) { ++m_size; if (m_size <= N) { m_embedded[m_size - 1] = v; } else { m_rest.append(v); } } inline void append(const T& v) { push(v); } inline void append(const T& v, const T& v2) { push(v); push(v2); } inline void append(const T& v, const T& v2, const T& v3) { push(v); push(v2); push(v3); } inline void append(const T& v, const T& v2, const T& v3, const T& v4) { push(v); push(v2); push(v3); push(v4); } /** Find the index of \a v or -1 if not found */ int findIndex(const T& v) { for (int i = 0; i < N; ++i) { if (m_embedded[i] == v) { return i; } } return m_rest.findIndex(v) + N; } void fastRemove(int i, bool shrinkIfNecessary = false) { debugAssert(i < m_size && i >= 0); if (i < N) { if (m_size <= N) { // Exclusively embedded m_embedded[i] = m_embedded[m_size - 1]; } else { // Move one down from the rest array m_embedded[i] = m_rest.pop(); } } else { // Removing from the rest array m_rest.fastRemove(i - N, shrinkIfNecessary); } --m_size; } T pop() { debugAssert(m_size > 0); if (m_size <= N) { // Popping from embedded, don't need a temporary --m_size; return m_embedded[m_size]; } else { // Popping from rest --m_size; return m_rest.pop(); } } inline void popDiscard() { debugAssert(m_size > 0); if (m_size > N) { m_rest.popDiscard(); } --m_size; } inline T& next() { ++m_size; if (m_size <= N) { return m_embedded[m_size - 1]; } else { return m_rest.next(); } } bool contains(const T& value) const { for (int i = std::min(m_size, N) - 1; i >= 0; --i) { if (m_embedded[i] == value) { return true; } } return m_rest.contains(value); } template SmallArray& operator=(const Array& src) { resize(src.size()); for (int i = 0; i < src.size(); ++i) { (*this)[i] = src[i]; } return *this; } inline const T& last() const { return (*this)[size() - 1]; } inline T& last() { return (*this)[size() - 1]; } }; } #endif