#ifndef HGUARD_NETRUSH_VIEW_ANYVALUESET_HPP__ #define HGUARD_NETRUSH_VIEW_ANYVALUESET_HPP__ #include #include #include #include #include #include namespace netrush { namespace view { class AnyValueSet { public: template< class ValueType > void add( ValueType value ) { auto& flag_set = find_or_create_set(); flag_set.add( std::move(value) ); m_size_changed = true; } template< class ValueType > void remove( const ValueType& value ) { if( auto* flag_set = find_set() ) { flag_set->remove( std::forward( value ) ); m_size_changed = true; } } template< class ValueType, class KeyType > boost::optional find( const KeyType& key ) const { if( auto* flag_set = find_set() ) { return flag_set->find( key ); } return {}; } template< class ValueType > boost::optional find( const ValueType& value ) const { return find( value ); } template< class ValueType, class KeyType > bool contains( const KeyType& key ) const { if( auto* flag_set = find_set() ) { return flag_set->contains( key ); } return false; } template< class ValueType > bool contains( const ValueType& value ) const { return contains( value ); } void insert( const AnyValueSet& other ) { for( const auto& set_pair : other.m_set_index ) { if( auto flag_set = find_set( set_pair.first ) ) { flag_set->insert( *set_pair.second ); } else { m_set_index.emplace( set_pair.first, set_pair.second->clone() ); } } m_size_changed = true; } template< class ValueType > std::vector all() const { if( auto* flag_set = find_set() ) { return flag_set->values(); } return {}; } size_t size() const { if( m_size_changed ) { m_size_changed = false; compute_size(); } return m_size; } private: struct Set { virtual void insert( const Set& other ) = 0; virtual std::unique_ptr clone() = 0; virtual size_t size() const = 0; }; template< class T > class SetOf : public Set { boost::container::flat_set m_values; public: SetOf() = default; template< class Iterator > SetOf( Iterator&& it_begin, Iterator&& it_end ) : m_values( std::forward( it_begin ), std::forward( it_end ) ) {} /** Add a new value or replace an old one by the provided one. */ void add( T value ) { auto result = m_values.emplace( std::move( value ) ); if( !result.second ) // force overwriting if the value already exists *result.first = value; } void remove( T value ) { m_values.erase( std::move( value ) ); } template< class KeyType > boost::optional find( const KeyType& key ) const { for( const auto& value : m_values ) { if( value == key ) return value; } return {}; } template< class KeyType > bool contains( const KeyType& key ) const { for( const auto& value : m_values ) { if( value == key ) return true; } return false; } void insert( const Set& other ) override { const auto& specific_set = static_cast&>( other ); m_values.insert( begin( specific_set.m_values ), end( specific_set.m_values ) ); } std::unique_ptr clone() override { return std::make_unique>( begin( m_values ), end( m_values ) ); } size_t size() const override { return m_values.size(); } std::vector values() const { return { begin( m_values ), end( m_values ) }; } }; boost::container::flat_map> m_set_index; mutable bool m_size_changed = false; mutable size_t m_size = 0; Set* find_set( std::type_index type_id ) const { auto find_it = m_set_index.find( type_id ); if( find_it != end( m_set_index ) ) { auto& specific_set = *find_it->second; return &specific_set; } return nullptr; } template< class T > SetOf* find_set() const { return static_cast*>( find_set( typeid( T ) ) ); } template< class T > SetOf& find_or_create_set() { if( auto* specific_set = find_set() ) { return *specific_set; } auto position = m_set_index.emplace( typeid( T ), std::make_shared < SetOf < T >> ( ) ).first; return static_cast&>( *position->second ); } void compute_size() const { m_size = 0; for( const auto& set_pair : m_set_index ) { m_size += set_pair.second->size(); } } }; }} #endif