/******************************************************************************/ /* SETS - INLINE CODE *********************************************************/ /******************************************************************************/ #ifndef _H_EBCL_INLINE_SETS #define _H_EBCL_INLINE_SETS #include namespace ebcl { /*= SET IMPLEMENTATION - FULLY DYNAMIC ARRAY =================================*/ template< typename Type , uint32_t Growth > class T_SetImplementation< Type , ArrayBacked< 0 , Growth > > { private: T_Array< Type > data_; public: template< uint32_t G = Growth , typename std::enable_if_t< G == 0 , int > = 0 > T_SetImplementation( ) noexcept; template< uint32_t G = Growth , typename std::enable_if_t< G != 0 , int > = 0 > T_SetImplementation( ) noexcept; uint32_t size( ) const noexcept; int32_t indexOf( Type const& item ) const noexcept; Type const* access( uint32_t item ) const noexcept; bool add( Type const& item ) noexcept; bool add( Type&& item ) noexcept; bool remove( Type const& item ) noexcept; void free( ) noexcept; void clear( ) noexcept; }; /*----------------------------------------------------------------------------*/ #define M_TMPL_ template< typename Type , uint32_t Growth > #define M_TYPE_ T_SetImplementation< Type , ArrayBacked< 0 , Growth > > M_TMPL_ template< uint32_t G , typename std::enable_if_t< G == 0 , int > > M_TYPE_::T_SetImplementation( ) noexcept : data_( ) { } M_TMPL_ template< uint32_t G , typename std::enable_if_t< G != 0 , int > > M_TYPE_::T_SetImplementation( ) noexcept : data_( Growth ) { } /*----------------------------------------------------------------------------*/ M_TMPL_ uint32_t M_TYPE_::size( ) const noexcept { return data_.size( ); } M_TMPL_ int32_t M_TYPE_::indexOf( Type const& item ) const noexcept { return data_.indexOf( item ); } M_TMPL_ Type const* M_TYPE_::access( const uint32_t item ) const noexcept { return &data_[ item ]; } /*----------------------------------------------------------------------------*/ M_TMPL_ bool M_TYPE_::add( Type const& item ) noexcept { const auto ok( indexOf( item ) == -1 ); if ( ok ) { data_.add( item ); } return ok; } M_TMPL_ bool M_TYPE_::add( Type&& item ) noexcept { const auto ok( indexOf( item ) == -1 ); if ( ok ) { data_.add( std::move( item ) ); } return ok; } M_TMPL_ bool M_TYPE_::remove( Type const& item ) noexcept { const auto index( indexOf( item ) ); if ( index >= 0 ) { data_.removeSwap( index ); } return index >= 0; } /*----------------------------------------------------------------------------*/ M_TMPL_ void M_TYPE_::free( ) noexcept { data_.free( ); } M_TMPL_ void M_TYPE_::clear( ) noexcept { data_.clear( ); } #undef M_TMPL_ #undef M_TYPE_ /*= SET IMPLEMENTATION - AUTOMATIC ARRAY =====================================*/ template< typename Type , uint32_t InPlace , uint32_t Growth > class T_SetImplementation< Type , ArrayBacked< InPlace , Growth > > { private: T_AutoArray< Type , InPlace , Growth == 0 ? ( InPlace * 4 ) : Growth > data_; public: uint32_t size( ) const noexcept; int32_t indexOf( Type const& item ) const noexcept; Type const* access( uint32_t item ) const noexcept; bool add( Type const& item ) noexcept; bool add( Type&& item ) noexcept; bool remove( Type const& item ) noexcept; void free( ) noexcept; void clear( ) noexcept; }; /*----------------------------------------------------------------------------*/ #define M_TMPL_ template< typename Type , uint32_t ISize , uint32_t Growth > #define M_TYPE_ T_SetImplementation< Type , ArrayBacked< ISize , Growth > > M_TMPL_ uint32_t M_TYPE_::size( ) const noexcept { return data_.size( ); } M_TMPL_ int32_t M_TYPE_::indexOf( Type const& item ) const noexcept { return data_.indexOf( item ); } M_TMPL_ Type const* M_TYPE_::access( const uint32_t item ) const noexcept { return &data_[ item ]; } /*----------------------------------------------------------------------------*/ M_TMPL_ bool M_TYPE_::add( Type const& item ) noexcept { const auto ok( indexOf( item ) == -1 ); if ( ok ) { data_.add( item ); } return ok; } M_TMPL_ bool M_TYPE_::add( Type&& item ) noexcept { const auto ok( indexOf( item ) == -1 ); if ( ok ) { data_.add( std::move( item ) ); } return ok; } M_TMPL_ bool M_TYPE_::remove( Type const& item ) noexcept { const auto index( indexOf( item ) ); if ( index >= 0 ) { data_.removeSwap( index ); } return index >= 0; } /*----------------------------------------------------------------------------*/ M_TMPL_ void M_TYPE_::free( ) noexcept { data_.free( ); } M_TMPL_ void M_TYPE_::clear( ) noexcept { data_.clear( ); } #undef M_TMPL_ #undef M_TYPE_ /*= SET IMPLEMENTATION - INDEX ===============================================*/ template< typename Type , uint32_t InitialSize , uint32_t HashSize , uint32_t Growth > class T_SetImplementation< Type , IndexBacked< InitialSize , HashSize , Growth > > { static_assert( InitialSize > 0 , "invalid initial size" ); static_assert( HashSize > 0 , "invalid hash array size" ); static_assert( Growth > 0 , "invalid growth" ); private: T_HashIndex index_{ HashSize , InitialSize , Growth }; T_Array< Type > items_{ Growth }; public: uint32_t size( ) const noexcept; int32_t indexOf( Type const& item ) const noexcept; Type const* access( uint32_t item ) const noexcept; bool add( Type const& item ) noexcept; bool add( Type&& item ) noexcept; bool remove( Type const& item ) noexcept; void free( ) noexcept; void clear( ) noexcept; private: uint32_t find( Type const& k , const uint32_t hash ) const noexcept; }; /*----------------------------------------------------------------------------*/ #define M_TMPL_ template< typename Type , uint32_t ISize , uint32_t HSize , uint32_t Growth > #define M_TYPE_ T_SetImplementation< Type , IndexBacked< ISize , HSize , Growth > > M_TMPL_ uint32_t M_TYPE_::size( ) const noexcept { return items_.size( ); } M_TMPL_ int32_t M_TYPE_::indexOf( Type const& item ) const noexcept { const auto idx{ find( item , ComputeHash( item ) ) }; return idx == T_HashIndex::INVALID_INDEX ? -1 : int32_t( idx ); } M_TMPL_ Type const* M_TYPE_::access( const uint32_t item ) const noexcept { return &items_[ item ]; } /*----------------------------------------------------------------------------*/ M_TMPL_ bool M_TYPE_::add( Type const& item ) noexcept { const auto hash{ ComputeHash( item ) }; const auto idx{ find( item , hash ) }; if ( idx == T_HashIndex::INVALID_INDEX ) { index_.add( hash ); items_.add( item ); } return idx == T_HashIndex::INVALID_INDEX; } M_TMPL_ bool M_TYPE_::add( Type&& item ) noexcept { const auto hash{ ComputeHash( item ) }; const auto idx{ find( item , hash ) }; if ( idx == T_HashIndex::INVALID_INDEX ) { index_.add( hash ); items_.add( std::move( item ) ); } return idx == T_HashIndex::INVALID_INDEX; } M_TMPL_ bool M_TYPE_::remove( Type const& item ) noexcept { const auto hash{ ComputeHash( item ) }; const auto idx{ find( item , hash ) }; if ( idx != T_HashIndex::INVALID_INDEX ) { items_.removeSwap( idx ); index_.remove( idx ); } return idx != T_HashIndex::INVALID_INDEX; } /*----------------------------------------------------------------------------*/ M_TMPL_ void M_TYPE_::free( ) noexcept { index_.free( ); items_.free( ); } M_TMPL_ void M_TYPE_::clear( ) noexcept { index_.clear( ); items_.clear( ); } /*----------------------------------------------------------------------------*/ M_TMPL_ uint32_t M_TYPE_::find( Type const& k , const uint32_t hash ) const noexcept { uint32_t idx = index_.first( hash ); while ( idx != T_HashIndex::INVALID_INDEX ) { // XXX use a match function? // if ( match_( keys_[ idx ] , k ) ) { // break; // } if ( items_[ idx ] == k ) { break; } idx = index_.next( idx ); } return idx; } #undef M_TMPL_ #undef M_TYPE_ /*= COMMON HANDLER ===========================================================*/ // In-place version template< typename Type , typename ImplTag > void T_SetHelper::T_InPlaceHandler< Type , ImplTag >::shdl( const E_Operation operation , void* const wArg , void const* const rArg , void* const output ) { using T_Impl_ = T_SetImplementation< Type , ImplTag >; switch ( operation ) { case INIT: ::new ((char*)output) T_Impl_( ); break; case INIT_COPY: ::new ((char*)output) T_Impl_( *(T_Impl_ const*)rArg ); break; case INIT_MOVE: ::new ((char*)output) T_Impl_( std::move( *(T_Impl_*)wArg ) ); break; case DESTROY: ((T_Impl_*)wArg)->~T_Impl_( ); break; //------------------------------------------------------------------ case SIZE: *((uint32_t*) output) = ((T_Impl_ const*)rArg)->size( ); break; case INDEX_OF: *((uint32_t*) output) = ((T_Impl_ const*)wArg)->indexOf( *(Type const*) rArg ); break; case ACCESS: *((Type const**) output) = ((T_Impl_ const*)rArg)->access( *(uint32_t const*) wArg ); break; //------------------------------------------------------------------ case ADD_COPY: *((bool*)output) = ((T_Impl_*)wArg)->add( *(Type const*) rArg ); break; case ADD_MOVE: *((bool*)output) = ((T_Impl_*)wArg)->add( std::move( *const_cast< Type* >( (Type const*) rArg ) ) ); break; case REMOVE: *((bool*)output) = ((T_Impl_*)wArg)->remove( *((Type const*) rArg) ); break; //------------------------------------------------------------------ case FREE: ((T_Impl_*)wArg)->free( ); break; case CLEAR: ((T_Impl_*)wArg)->clear( ); break; } } /*----------------------------------------------------------------------------*/ // Heap-allocated implementation template< typename Type , typename ImplTag > void T_SetHelper::T_HeapHandler< Type , ImplTag >::shdl( E_Operation operation , void* wArg , void const* rArg , void* output ) { using T_Impl_ = T_SetImplementation< Type , ImplTag >; switch ( operation ) { case INIT: *(T_Impl_**)output = ::new T_Impl_( ); break; case INIT_COPY: *(T_Impl_**)output = ::new T_Impl_( **(T_Impl_ const**)rArg ); break; case INIT_MOVE: *(T_Impl_**)output = ::new T_Impl_( std::move( **(T_Impl_**)wArg ) ); break; case DESTROY: delete *(T_Impl_**)wArg; break; //------------------------------------------------------------------ case SIZE: *((uint32_t*) output) = (*(T_Impl_ const**)rArg)->size( ); break; case INDEX_OF: *((uint32_t*) output) = (*(T_Impl_ const**)wArg)->indexOf( *(Type const*) rArg ); break; case ACCESS: *((Type const**) output) = (*(T_Impl_ const**)rArg)->access( *(uint32_t const*) wArg ); break; //------------------------------------------------------------------ case ADD_COPY: *((bool*)output) = (*(T_Impl_**)wArg)->add( *(Type const*) rArg ); break; case ADD_MOVE: *((bool*)output) = (*(T_Impl_**)wArg)->add( std::move( *const_cast< Type* >( (Type const*) rArg ) ) ); break; case REMOVE: *((bool*)output) = (*(T_Impl_**)wArg)->remove( *((Type const*) rArg) ); break; //------------------------------------------------------------------ case FREE: (*(T_Impl_**)wArg)->free( ); break; case CLEAR: (*(T_Impl_**)wArg)->clear( ); break; } } /*= T_Set ====================================================================*/ template< typename Type > T_Set< Type >::T_Set( ) noexcept : T_Set( UseTag< T_SetHelper::DefaultImplementation >( ) ) { } template< typename Type > template< typename Tag > T_Set< Type >::T_Set( const UseTag< Tag > ) noexcept : handler_( T_SetHelper::T_Handler< Type , Tag >::shdl ) { handler_( T_SetHelper::INIT , nullptr , nullptr , &storage_ ); } /*----------------------------------------------------------------------------*/ template< typename Type > T_Set< Type >::T_Set( T_Set const& other ) noexcept : handler_( other.handler_ ) { handler_( T_SetHelper::INIT_COPY , nullptr , &other.storage_ , &storage_ ); } template< typename Type > T_Set< Type >& T_Set< Type >::operator =( T_Set const& other ) noexcept { handler_( T_SetHelper::DESTROY , &storage_ , nullptr , nullptr ); handler_ = other.handler_; handler_( T_SetHelper::INIT_COPY , nullptr , &other.storage_ , &storage_ ); return *this; } /*----------------------------------------------------------------------------*/ template< typename Type > T_Set< Type >::T_Set( T_Set&& other ) noexcept : handler_( other.handler_ ) { handler_( T_SetHelper::INIT_MOVE , &other.storage_ , nullptr , &storage_ ); } template< typename Type > T_Set< Type >& T_Set< Type >::operator =( T_Set&& other ) noexcept { handler_( T_SetHelper::DESTROY , &storage_ , nullptr , nullptr ); handler_ = other.handler_; handler_( T_SetHelper::INIT_MOVE , &other.storage_ , nullptr , &storage_ ); return *this; } /*----------------------------------------------------------------------------*/ template< typename Type > T_Set< Type >::~T_Set( ) { handler_( T_SetHelper::DESTROY , &storage_ , nullptr , nullptr ); } /*----------------------------------------------------------------------------*/ template< typename Type > uint32_t T_Set< Type >::size( ) const noexcept { uint32_t r; handler_( T_SetHelper::SIZE , nullptr , &storage_ , &r ); return r; } template< typename Type > bool T_Set< Type >::contains( Type const& item ) const noexcept { return indexOf( item ) >= 0; } template< typename Type > int32_t T_Set< Type >::indexOf( Type const& item ) const noexcept { int32_t r; handler_( T_SetHelper::INDEX_OF , const_cast< decltype( storage_ )* >( &storage_ ) , &item , &r ); return r; } template< typename Type > Type const& T_Set< Type >::operator[]( uint32_t index ) const noexcept { Type* ptr; handler_( T_SetHelper::ACCESS , &index , &storage_ , &ptr ); return *ptr; } /*----------------------------------------------------------------------------*/ template< typename Type > bool T_Set< Type >::add( Type const& item ) noexcept { bool r; handler_( T_SetHelper::ADD_COPY , &storage_ , &item , &r ); return r; } template< typename Type > bool T_Set< Type >::add( Type&& item ) noexcept { bool r; handler_( T_SetHelper::ADD_MOVE , &storage_ , &item , &r ); return r; } template< typename Type > bool T_Set< Type >::remove( Type const& item ) noexcept { bool r; handler_( T_SetHelper::REMOVE , &storage_ , &item , &r ); return r; } /*----------------------------------------------------------------------------*/ template< typename Type > void T_Set< Type >::free( ) noexcept { handler_( T_SetHelper::FREE , &storage_ , nullptr , nullptr ); } template< typename Type > void T_Set< Type >::clear( ) noexcept { handler_( T_SetHelper::CLEAR , &storage_ , nullptr , nullptr ); } } #endif // _H_EBCL_INLINE_SETS