/******************************************************************************/ /* SETS ***********************************************************************/ /******************************************************************************/ #ifndef _H_EBCL_SETS #define _H_EBCL_SETS #include #include namespace ebcl { // FIXME move this to utilities \/ // Define a structure that can be used as a tag #define M_DEFINE_TAG( NAME ) \ struct NAME { } // Define a tag structure that can carry arguments #define M_DEFINE_TEMPLATE_TAG( NAME , ARGS... ) \ template< ARGS > \ M_DEFINE_TAG( NAME ) // A structure that can be used to carry a tag structure instance template< typename Tag > struct UseTag { const Tag tag; template< typename ... ArgTypes > constexpr UseTag( ArgTypes&&... args ) noexcept : tag( std::forward< ArgTypes >( args ) ... ) { } }; // Implementation of a set of type Type. The actual implementation is // determined by the ImplTag type template< typename Type , typename ImplTag > class T_SetImplementation; // ArrayBacked implementation tag. InPlace is the amount of items to // store in-place (0 will cause a fully dynamic array to be used) M_DEFINE_TEMPLATE_TAG( ArrayBacked , uint32_t InPlace , uint32_t Growth = 0 ); // IndexBacked implementation tag - the implementation will use a // T_HashIndex and an array. InitialSize and HashSize affect the index, // Growth affects both the index and the array. M_DEFINE_TEMPLATE_TAG( IndexBacked , uint32_t InitialSize = T_HashIndex::DEFAULT_SIZE , uint32_t HashSize = T_HashIndex::DEFAULT_SIZE , uint32_t Growth = T_HashIndex::DEFAULT_GROWTH ); // Templated horrors used by the main T_Set class. struct T_SetHelper { // Default implementation to use; also determines the in-place // storage size using DefaultImplementation = IndexBacked< >; // Default implementation class template< typename Type > using DefaultType = T_SetImplementation< Type , DefaultImplementation >; // --------------------------------------------------------------------- // In-place storage size template< typename Type > static constexpr auto DefaultSize{ sizeof( DefaultType< Type > ) }; // In-place storage alignment template< typename Type > static constexpr auto DefaultAlign{ alignof( DefaultType< Type > ) }; // --------------------------------------------------------------------- // Implementation handler operations enum E_Operation { // New instance; output = storage INIT , // Copy instance; output = storage, rArg = source INIT_COPY , // Move instance; output = storage, wArg = source INIT_MOVE , // Destroy instance; wArg = storage DESTROY , // Get size; rArg = storage, output = result SIZE , // Get index of element; wArg = storage, rArg = element, output = result INDEX_OF , // Access an element; wArg = index , rArg = storage, output = pointer ACCESS , // Add copy of element; wArg = storage, rArg = element, output = result ADD_COPY , // Move & add element; wArg = storage, rArg = element, output = result ADD_MOVE , // Delete element; wArg = storage, rArg = element, output = result REMOVE , // Free memory; wArg = storage FREE , // Clear contents; wArg = storage CLEAR , }; // Handler function type using F_Handler = std::function< void( E_Operation , void* , void const* , void* ) >; // --------------------------------------------------------------------- // Handler for in-place implementations template< typename Type , typename Impl > struct T_InPlaceHandler { static void shdl( E_Operation operation , void* wArg , void const* rArg , void* output ); }; // Handler for heap-allocated implementations template< typename Type , typename Impl > struct T_HeapHandler { static void shdl( E_Operation operation , void* wArg , void const* rArg , void* output ); }; // Use the in-place handler if the implementation data can fit into the // in-place storage; otherwise use the heap-allocated handler. template< typename Type , typename ImplTag , typename Impl = T_SetImplementation< Type , ImplTag > > using T_Handler = std::conditional_t< sizeof( Impl ) <= DefaultSize< Type > , T_InPlaceHandler< Type , ImplTag > , T_HeapHandler< Type , ImplTag > >; }; template< typename Type > class T_Set { private: // Storage area for the implementation's data std::aligned_storage_t< T_SetHelper::DefaultSize< Type > , T_SetHelper::DefaultAlign< Type > > storage_; // Handler T_SetHelper::F_Handler handler_; public: // Default constructor, using the default implementation T_Set( ) noexcept; // Create a set with a specific implementation template< typename Tag > T_Set( UseTag< Tag > impl ) noexcept; // Copy constructor / assignment T_Set( T_Set const& other ) noexcept; T_Set& operator =( T_Set const& other ) noexcept; // Move constructor / assignment T_Set( T_Set&& other ) noexcept; T_Set& operator =( T_Set&& other ) noexcept; ~T_Set( ); // --------------------------------------------------------------------- // Returns amount of elements uint32_t size( ) const noexcept; // Checks if item is in the set bool contains( Type const& item ) const noexcept; // Returns underlying index of item, or -1 if not in the set int32_t indexOf( Type const& item ) const noexcept; // Access an element using its underlying index Type const& operator[]( uint32_t index ) const noexcept; // --------------------------------------------------------------------- // Add copy of item, returns true if added bool add( Type const& item ) noexcept; // Add moved item, returns true if added bool add( Type&& item ) noexcept; // Remove item, returns true if removed bool remove( Type const& item ) noexcept; // --------------------------------------------------------------------- void clear( ) noexcept; void free( ) noexcept; }; } #endif // _H_EBCL_SETS // XXX #include #include "Sets-inline.hh"