| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- // 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/MemoryPool.h>
- #include <AnKi/Util/Functions.h>
- #include <AnKi/Util/BitSet.h>
- #include <AnKi/Util/DynamicArray.h>
- namespace anki {
- /// @addtogroup util_containers
- /// @{
- /// Config options for a BlockArray.
- template<U32 kElementCountPerBlock>
- class BlockArrayConfig
- {
- public:
- static constexpr U32 getElementCountPerBlock()
- {
- return kElementCountPerBlock;
- }
- };
- /// Config options for a BlockArray.
- class BlockArrayDefaultConfig : public BlockArrayConfig<64>
- {
- };
- /// BlockArray iterator.
- template<typename TValuePointer, typename TValueReference, typename TBlockArrayPtr>
- class BlockArrayIterator
- {
- template<typename, typename, typename>
- friend class BlockArray;
- template<typename, typename, typename>
- friend class BlockArrayIterator;
- public:
- /// Default constructor.
- BlockArrayIterator()
- : m_array(nullptr)
- , m_elementIdx(kMaxU32)
- {
- }
- /// Copy.
- BlockArrayIterator(const BlockArrayIterator& b)
- : m_array(b.m_array)
- , m_elementIdx(b.m_elementIdx)
- {
- }
- /// Allow conversion from iterator to const iterator.
- template<typename YValuePointer, typename YValueReference, typename YBlockArrayPtr>
- BlockArrayIterator(const BlockArrayIterator<YValuePointer, YValueReference, YBlockArrayPtr>& b)
- : m_array(b.m_array)
- , m_elementIdx(b.m_elementIdx)
- {
- }
- BlockArrayIterator(TBlockArrayPtr arr, U32 idx)
- : m_array(arr)
- , m_elementIdx(idx)
- {
- }
- BlockArrayIterator& operator=(const BlockArrayIterator& b)
- {
- m_array = b.m_array;
- m_elementIdx = b.m_elementIdx;
- return *this;
- }
- TValueReference operator*() const
- {
- check();
- return (*m_array)[m_elementIdx];
- }
- TValuePointer operator->() const
- {
- check();
- return &(*m_array)[m_elementIdx];
- }
- BlockArrayIterator& operator++()
- {
- check();
- m_elementIdx = m_array->getNextElementIndex(m_elementIdx);
- return *this;
- }
- BlockArrayIterator operator++(int)
- {
- check();
- BlockArrayIterator out = *this;
- ++(*this);
- return out;
- }
- Bool operator==(const BlockArrayIterator& b) const
- {
- ANKI_ASSERT(m_array == b.m_array);
- return m_elementIdx == b.m_elementIdx;
- }
- Bool operator!=(const BlockArrayIterator& b) const
- {
- return !(*this == b);
- }
- /// Returns the imaginary index inside the BlockArray.
- U32 getArrayIndex() const
- {
- check();
- return m_elementIdx;
- }
- private:
- TBlockArrayPtr m_array;
- U32 m_elementIdx;
- void check() const
- {
- ANKI_ASSERT(m_array);
- ANKI_ASSERT(m_array->indexExists(m_elementIdx));
- }
- };
- /// It's a type of dynamic array that unlike DynamicArray doesn't move elements around when it shrinks or grows the storage.
- template<typename T, typename TMemoryPool = SingletonMemoryPoolWrapper<DefaultMemoryPool>, typename TConfig = BlockArrayDefaultConfig>
- class BlockArray
- {
- template<typename, typename, typename>
- friend class BlockArrayIterator;
- public:
- // Typedefs
- using Config = TConfig;
- using Value = T;
- using Iterator = BlockArrayIterator<T*, T&, BlockArray*>;
- using ConstIterator = BlockArrayIterator<const T*, const T&, const BlockArray*>;
- using Reference = Value&;
- using ConstReference = const Value&;
- static constexpr U32 kElementCountPerBlock = TConfig::getElementCountPerBlock();
- BlockArray(const TMemoryPool& pool = TMemoryPool())
- : m_blockStorages(pool)
- , m_blockMetadatas(pool)
- {
- }
- /// Copy.
- BlockArray(const BlockArray& b)
- {
- *this = b;
- }
- /// Move.
- BlockArray(BlockArray&& b)
- {
- *this = std::move(b);
- }
- /// Destroy.
- ~BlockArray()
- {
- destroy();
- }
- /// Copy.
- BlockArray& operator=(const BlockArray& b);
- /// Move operator.
- BlockArray& operator=(BlockArray&& b)
- {
- destroy();
- m_blockStorages = std::move(b.m_blockStorages);
- m_blockMetadatas = std::move(b.m_blockMetadatas);
- m_elementCount = b.m_elementCount;
- b.m_elementCount = 0;
- m_firstIndex = b.m_firstIndex;
- b.m_firstIndex = 0;
- m_endIndex = b.m_endIndex;
- b.m_endIndex = 0;
- return *this;
- }
- ConstReference operator[](U32 idx) const
- {
- const U32 blockIdx = idx / kElementCountPerBlock;
- const U32 localIdx = idx % kElementCountPerBlock;
- ANKI_ASSERT(blockIdx < m_blockMetadatas.getSize());
- ANKI_ASSERT(m_blockStorages[blockIdx] != nullptr);
- ANKI_ASSERT(m_blockMetadatas[blockIdx].m_elementsInUseMask.get(localIdx) == true);
- return *reinterpret_cast<Value*>(&m_blockStorages[blockIdx]->m_storage[localIdx * sizeof(Value)]);
- }
- Reference operator[](U32 idx)
- {
- const auto& constSelf = *this;
- return const_cast<Reference>(constSelf[idx]);
- }
- /// Get begin.
- Iterator getBegin()
- {
- return Iterator(this, m_firstIndex);
- }
- /// Get begin.
- ConstIterator getBegin() const
- {
- return ConstIterator(this, m_firstIndex);
- }
- /// Get end.
- Iterator getEnd()
- {
- return Iterator(this, m_endIndex);
- }
- /// Get end.
- ConstIterator getEnd() const
- {
- return ConstIterator(this, m_endIndex);
- }
- /// 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();
- }
- U32 getSize() const
- {
- return m_elementCount;
- }
- Bool isEmpty() const
- {
- return m_elementCount == 0;
- }
- /// Destroy the array and free its elements.
- void destroy();
- /// Emplace somewhere in some block.
- template<typename... TArgs>
- Iterator emplace(TArgs&&... args);
- /// Removes one element.
- /// @param at Points to the position of the element to remove.
- void erase(Iterator idx);
- /// Removes one element.
- /// @param at Points to the position of the element to remove.
- void erase(U32 index)
- {
- erase(indexToIterator(index));
- }
- Iterator indexToIterator(U32 idx)
- {
- ANKI_ASSERT(indexExists(idx));
- return Iterator(this, idx);
- }
- ConstIterator indexToIterator(U32 idx) const
- {
- ANKI_ASSERT(indexExists(idx));
- return ConstIterator(this, idx);
- }
- Bool indexExists(U32 idx) const
- {
- const U32 localIdx = idx % kElementCountPerBlock;
- const U32 blockIdx = idx / kElementCountPerBlock;
- return blockIdx < m_blockMetadatas.getSize() && m_blockMetadatas[blockIdx].m_elementsInUseMask.get(localIdx) == true;
- }
- TMemoryPool& getMemoryPool()
- {
- return m_blockStorages.getMemoryPool();
- }
- void validate() const;
- private:
- class alignas(alignof(T)) BlockStorage
- {
- public:
- U8 m_storage[sizeof(T) * kElementCountPerBlock];
- };
- using Mask = BitSet<kElementCountPerBlock, U64>;
- class BlockMetadata
- {
- public:
- Mask m_elementsInUseMask{false};
- BlockMetadata() = default;
- BlockMetadata(Bool set)
- : m_elementsInUseMask(set)
- {
- }
- };
- DynamicArray<BlockStorage*, TMemoryPool> m_blockStorages;
- DynamicArray<BlockMetadata, TMemoryPool> m_blockMetadatas;
- U32 m_elementCount = 0;
- U32 m_firstIndex = 0;
- U32 m_endIndex = 0; ///< The index after the last.
- U32 getFirstElementIndex() const
- {
- for(U32 blockIdx = 0; blockIdx < m_blockMetadatas.getSize(); ++blockIdx)
- {
- U32 localIdx;
- if((localIdx = m_blockMetadatas[blockIdx].m_elementsInUseMask.getLeastSignificantBit()) != kMaxU32)
- {
- return localIdx + blockIdx * kElementCountPerBlock;
- }
- }
- ANKI_ASSERT(0);
- return 0;
- }
- U32 getLastElementIndex() const
- {
- U32 blockIdx = m_blockMetadatas.getSize();
- while(blockIdx--)
- {
- U32 localIdx;
- if((localIdx = m_blockMetadatas[blockIdx].m_elementsInUseMask.getMostSignificantBit()) != kMaxU32)
- {
- return localIdx + blockIdx * kElementCountPerBlock;
- }
- }
- ANKI_ASSERT(0);
- return 0;
- }
- U32 getNextElementIndex(U32 crnt) const;
- };
- /// @}
- } // end namespace anki
- #include <AnKi/Util/BlockArray.inl.h>
|