| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #pragma once
- #include <AnKi/Util/StdTypes.h>
- #include <AnKi/Util/Assert.h>
- #include <AnKi/Util/Array.h>
- #include <utility>
- namespace anki {
- /// @addtogroup util_containers
- /// @{
- /// Sparse array iterator.
- template<typename TValuePointer, typename TValueReference, typename TSparseArrayPtr>
- class SparseArrayIterator
- {
- template<typename, typename, typename>
- friend class SparseArray;
- public:
- using Index = typename RemovePointer<TSparseArrayPtr>::Type::Index;
- /// Default constructor.
- SparseArrayIterator()
- : m_array(nullptr)
- , m_elementIdx(getMaxNumericLimit<Index>())
- #if ANKI_EXTRA_CHECKS
- , m_iteratorVer(kMaxU32)
- #endif
- {
- }
- /// Copy.
- SparseArrayIterator(const SparseArrayIterator& b)
- : m_array(b.m_array)
- , m_elementIdx(b.m_elementIdx)
- #if ANKI_EXTRA_CHECKS
- , m_iteratorVer(b.m_iteratorVer)
- #endif
- {
- }
- /// Allow conversion from iterator to const iterator.
- template<typename YValuePointer, typename YValueReference, typename YSparseArrayPtr>
- SparseArrayIterator(const SparseArrayIterator<YValuePointer, YValueReference, YSparseArrayPtr>& b)
- : m_array(b.m_array)
- , m_elementIdx(b.m_elementIdx)
- #if ANKI_EXTRA_CHECKS
- , m_iteratorVer(b.m_iteratorVer)
- #endif
- {
- }
- SparseArrayIterator(TSparseArrayPtr arr, Index modIdx
- #if ANKI_EXTRA_CHECKS
- ,
- U32 ver
- #endif
- )
- : m_array(arr)
- , m_elementIdx(modIdx)
- #if ANKI_EXTRA_CHECKS
- , m_iteratorVer(ver)
- #endif
- {
- ANKI_ASSERT(arr);
- }
- SparseArrayIterator& operator=(const SparseArrayIterator& b)
- {
- m_array = b.m_array;
- m_elementIdx = b.m_elementIdx;
- #if ANKI_EXTRA_CHECKS
- m_iteratorVer = b.m_iteratorVer;
- #endif
- return *this;
- }
- TValueReference operator*() const
- {
- check();
- return m_array->m_elements[m_elementIdx];
- }
- TValuePointer operator->() const
- {
- check();
- return &m_array->m_elements[m_elementIdx];
- }
- SparseArrayIterator& operator++()
- {
- check();
- m_elementIdx = m_array->iterate(m_elementIdx, 1);
- return *this;
- }
- SparseArrayIterator operator++(int)
- {
- check();
- SparseArrayIterator out = *this;
- ++(*this);
- return out;
- }
- SparseArrayIterator operator+(Index n) const
- {
- check();
- Index pos = m_array->iterate(m_elementIdx, n);
- return SparseArrayIterator(m_array, pos);
- }
- SparseArrayIterator& operator+=(Index n)
- {
- check();
- m_elementIdx = m_array->iterate(m_elementIdx, n);
- return *this;
- }
- Bool operator==(const SparseArrayIterator& b) const
- {
- ANKI_ASSERT(m_array == b.m_array);
- ANKI_ASSERT(m_iteratorVer == b.m_iteratorVer);
- return m_elementIdx == b.m_elementIdx;
- }
- Bool operator!=(const SparseArrayIterator& b) const
- {
- return !(*this == b);
- }
- Index getKey() const
- {
- check();
- return m_elementIdx;
- }
- private:
- TSparseArrayPtr m_array;
- Index m_elementIdx;
- #if ANKI_EXTRA_CHECKS
- U32 m_iteratorVer; ///< See SparseArray::m_iteratorVer.
- #endif
- void check() const
- {
- ANKI_ASSERT(m_array);
- ANKI_ASSERT(m_elementIdx != getMaxNumericLimit<Index>());
- ANKI_ASSERT(m_array->m_metadata[m_elementIdx].m_alive);
- ANKI_ASSERT(m_array->m_iteratorVer == m_iteratorVer);
- }
- };
- /// Contains the default configuration for SparseArray.
- /// @memberof SparseArray
- class SparseArrayDefaultConfig
- {
- public:
- /// Indicates the max size of the sparse indices it can accept. Can be U32 or U64.
- using Index = U32;
- /// The initial storage size of the array.
- static constexpr Index getInitialStorageSize()
- {
- return 64;
- }
- /// The number of linear probes.
- static constexpr U32 getLinearProbingCount()
- {
- return 8;
- }
- /// Load factor. If storage is loaded more than getMaxLoadFactor() then increase it.
- static constexpr F32 getMaxLoadFactor()
- {
- return 0.8f;
- }
- };
- /// Sparse array.
- /// @tparam T The type of the valut it will hold.
- /// @tparam TConfig A class that has configuration required by the SparseArray. See SparseArrayDefaultConfig for
- /// details.
- template<typename T, typename TMemoryPool = SingletonMemoryPoolWrapper<DefaultMemoryPool>, typename TConfig = SparseArrayDefaultConfig>
- class SparseArray
- {
- template<typename, typename, typename>
- friend class SparseArrayIterator;
- public:
- // Typedefs
- using Config = TConfig;
- using Value = T;
- using Iterator = SparseArrayIterator<T*, T&, SparseArray*>;
- using ConstIterator = SparseArrayIterator<const T*, const T&, const SparseArray*>;
- using Index = typename Config::Index;
- SparseArray(const TMemoryPool& pool = TMemoryPool())
- : m_pool(pool)
- {
- }
- SparseArray(const Config& config, const TMemoryPool& pool = TMemoryPool())
- : m_pool(pool)
- , m_config(config)
- {
- }
- /// Copy.
- SparseArray(const SparseArray& b)
- {
- *this = b;
- }
- /// Move.
- SparseArray(SparseArray&& b)
- {
- *this = std::move(b);
- }
- /// Destroy.
- ~SparseArray()
- {
- destroy();
- }
- /// Copy.
- SparseArray& operator=(const SparseArray& b);
- /// Move operator.
- SparseArray& operator=(SparseArray&& b)
- {
- destroy();
- m_elements = b.m_elements;
- m_metadata = b.m_metadata;
- m_elementCount = b.m_elementCount;
- m_capacity = b.m_capacity;
- m_config = std::move(b.m_config);
- invalidateIterators();
- b.resetMembers();
- return *this;
- }
- /// Get begin.
- Iterator getBegin()
- {
- return Iterator(this, findFirstAlive()
- #if ANKI_EXTRA_CHECKS
- ,
- m_iteratorVer
- #endif
- );
- }
- /// Get begin.
- ConstIterator getBegin() const
- {
- return ConstIterator(this, findFirstAlive()
- #if ANKI_EXTRA_CHECKS
- ,
- m_iteratorVer
- #endif
- );
- }
- /// Get end.
- Iterator getEnd()
- {
- return Iterator(this, getMaxNumericLimit<Index>()
- #if ANKI_EXTRA_CHECKS
- ,
- m_iteratorVer
- #endif
- );
- }
- /// Get end.
- ConstIterator getEnd() const
- {
- return ConstIterator(this, getMaxNumericLimit<Index>()
- #if ANKI_EXTRA_CHECKS
- ,
- m_iteratorVer
- #endif
- );
- }
- /// Get begin.
- Iterator begin()
- {
- return getBegin();
- }
- /// Get begin.
- ConstIterator begin() const
- {
- return getBegin();
- }
- /// Get end.
- Iterator end()
- {
- return getEnd();
- }
- /// Get end.
- ConstIterator end() const
- {
- return getEnd();
- }
- /// Get the number of elements in the array.
- PtrSize getSize() const
- {
- return m_elementCount;
- }
- /// Return true if it's empty and false otherwise.
- Bool isEmpty() const
- {
- return m_elementCount == 0;
- }
- /// Destroy the array and free its elements.
- void destroy();
- /// Set a value to an index.
- template<typename... TArgs>
- Iterator emplace(Index idx, TArgs&&... args);
- /// Get an iterator.
- Iterator find(Index idx)
- {
- return Iterator(this, findInternal(idx)
- #if ANKI_EXTRA_CHECKS
- ,
- m_iteratorVer
- #endif
- );
- }
- /// Get an iterator.
- ConstIterator find(Index idx) const
- {
- return ConstIterator(this, findInternal(idx)
- #if ANKI_EXTRA_CHECKS
- ,
- m_iteratorVer
- #endif
- );
- }
- /// Remove an element.
- void erase(Iterator it);
- /// Check the validity of the array.
- void validate() const;
- const Config& getConfig() const
- {
- return m_config;
- }
- protected:
- /// Element metadata.
- class Metadata
- {
- public:
- Index m_idx;
- Bool m_alive;
- };
- TMemoryPool m_pool;
- Value* m_elements = nullptr;
- Metadata* m_metadata = nullptr;
- Index m_elementCount = 0;
- Index m_capacity = 0;
- Config m_config;
- #if ANKI_EXTRA_CHECKS
- /// Iterators version. Used to check if iterators point to the newest storage. Needs to be changed whenever we need
- /// to invalidate iterators.
- U32 m_iteratorVer = 0;
- #endif
- /// Wrap an index.
- Index mod(const Index idx) const
- {
- ANKI_ASSERT(m_capacity > 0);
- ANKI_ASSERT(isPowerOfTwo(m_capacity));
- return idx & (m_capacity - 1);
- }
- /// Wrap an index.
- static Index mod(const Index idx, Index capacity)
- {
- ANKI_ASSERT(capacity > 0);
- ANKI_ASSERT(isPowerOfTwo(capacity));
- return idx & (capacity - 1);
- }
- F32 calcLoadFactor() const
- {
- ANKI_ASSERT(m_elementCount <= m_capacity);
- ANKI_ASSERT(m_capacity > 0);
- return F32(m_elementCount) / F32(m_capacity);
- }
- /// Insert a value. This method will move the val to a new place.
- /// @return One if the idx was a new element or zero if the idx was there already.
- Index insert(Index idx, Value& val);
- /// Grow the storage and re-insert.
- void grow();
- /// Compute the distance between a desired position and the current one. This method does a trick with capacity to
- /// account for wrapped positions.
- Index distanceFromDesired(const Index crntPos, const Index desiredPos) const
- {
- return mod(crntPos + m_capacity - desiredPos);
- }
- /// Find the first alive element.
- Index findFirstAlive() const
- {
- if(m_elementCount == 0)
- {
- return getMaxNumericLimit<Index>();
- }
- for(Index i = 0; i < m_capacity; ++i)
- {
- if(m_metadata[i].m_alive)
- {
- return i;
- }
- }
- ANKI_ASSERT(0);
- return getMaxNumericLimit<Index>();
- }
- /// Find an element and return its position inside m_elements.
- Index findInternal(Index idx) const;
- /// Reset the class.
- void resetMembers()
- {
- m_elements = nullptr;
- m_metadata = nullptr;
- m_elementCount = 0;
- m_capacity = 0;
- invalidateIterators();
- }
- /// Iterate a number of elements.
- Index iterate(Index pos, Index n) const
- {
- ANKI_ASSERT(pos < m_capacity);
- ANKI_ASSERT(n > 0);
- ANKI_ASSERT(m_metadata[pos].m_alive);
- while(n > 0 && ++pos < m_capacity)
- {
- ANKI_ASSERT(m_metadata[pos].m_alive == 1 || m_metadata[pos].m_alive == 0);
- n -= Index(m_metadata[pos].m_alive);
- }
- return (pos >= m_capacity) ? getMaxNumericLimit<Index>() : pos;
- }
- template<typename... TArgs>
- void emplaceInternal(Index idx, TArgs&&... args);
- void destroyElement(Value& v)
- {
- v.~Value();
- #if ANKI_EXTRA_CHECKS
- memset(&v, 0xC, sizeof(v));
- #endif
- }
- void invalidateIterators()
- {
- #if ANKI_EXTRA_CHECKS
- ++m_iteratorVer;
- #endif
- }
- F32 getMaxLoadFactor() const
- {
- const F32 f = m_config.getMaxLoadFactor();
- ANKI_ASSERT(f > 0.0f && f < 1.0f);
- return f;
- }
- U32 getLinearProbingCount() const
- {
- const U32 o = m_config.getLinearProbingCount();
- ANKI_ASSERT(o > 0);
- return o;
- }
- Index getInitialStorageSize() const
- {
- const Index o = m_config.getInitialStorageSize();
- ANKI_ASSERT(o > 0);
- return o;
- }
- };
- /// @}
- } // end namespace anki
- #include <AnKi/Util/SparseArray.inl.h>
|