/******************************************************************************/ /* HASH INDEX *****************************************************************/ /******************************************************************************/ #pragma once #include #include namespace lw { /* * This is based on http://glampert.com/2016/05-04/dissecting-idhashindex, * which explains how the hash tables in idTech4 work. Not looking at the code * to avoid GPL-related issues, so my implementation will probably suck. * * Unlike the original thing, this version considers that: * - all additions are made at the end of the array (and therefore at the * end of the index), * - erasing is done by swapping the element being erased and the last * element of the index. * * It also keeps track of the hash key for a given index in order to make * erasing easier. */ class T_HashIndex { public: static constexpr uint32_t INVALID_INDEX = 0xffffffff; static constexpr uint32_t DEFAULT_SIZE = 1024; static constexpr uint32_t DEFAULT_GROWTH = 1024; private: static uint32_t invalidIndex_; uint32_t hashSize_; uint32_t* hash_; uint32_t indexSize_; uint32_t indexGrowth_; uint32_t indexUsed_; uint32_t* index_; uint32_t* indexReverse_; uint32_t hashMask_; uint32_t lookupMask_; void enlargeIndex( uint32_t needed ); void allocateIfNecessary( ); public: T_HashIndex( ) noexcept; T_HashIndex( uint32_t hashSize , uint32_t indexSize , uint32_t growth = DEFAULT_GROWTH ) noexcept; T_HashIndex( T_HashIndex const& source ); T_HashIndex( T_HashIndex&& source ) noexcept; ~T_HashIndex( ); T_HashIndex& operator =( T_HashIndex const& other ); T_HashIndex& operator =( T_HashIndex&& other ) noexcept; friend void swap( T_HashIndex& lhs , T_HashIndex& rhs ) noexcept; void free( ); void clear( ); void add( uint32_t key ); void remove( uint32_t index ); uint32_t first( uint32_t key ) const; uint32_t next( uint32_t index ) const; }; M_CLASS_POINTERS( HashIndex ); void swap( T_HashIndex& lhs , T_HashIndex& rhs ) noexcept; } // namespace #include