Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <map>
- #include <functional>
- #include <iterator>
- #include <exception>
- #include <stdexcept>
- // class refmap
- // parameters:
- // Key - the key type, must be indexable according to underlying containers requirements
- // Val - the unqualified contained type
- // Underlying - an associative unique-key container, such as std::map or std::unordered_map
- template<
- typename Key,
- typename Val,
- template<typename ...> class Underlying = std::map
- >
- class refmap
- {
- public:
- typedef Key key_type; // the key type used for lookup
- typedef std::reference_wrapper<Val> mapped_type; // underlying container uses this
- typedef Val& value_reference;
- typedef const Val& const_value_reference;
- typedef Underlying< key_type, mapped_type > underlying;
- typedef typename underlying::iterator iterator;
- typedef typename underlying::const_iterator const_iterator;
- typedef typename underlying::value_type value_type;
- typedef typename underlying::size_type size_type;
- typedef typename underlying::reference reference;
- typedef typename underlying::const_reference const_reference;
- typedef std::pair<iterator,bool> insert_result;
- refmap() = default; // all 5 are default generated
- // subscript is used for lookup only
- // UB if key non-existent
- value_reference operator[]( const Key& key ) { return at(key); }
- const_value_reference operator[]( const Key& key ) const { return at(key); }
- // subscript is used for lookup only
- // throws if key non-existent
- value_reference at( const Key& key );
- const_value_reference at( const Key& key ) const;
- // binds (or rebinds) a reference to the key
- // operator() an alias for bind
- // can be chained
- refmap& bind( const Key& key, Val& val, bool rebind = true );
- refmap& operator() ( const Key& key, Val& val, bool rebind = true ) { return bind(key,val,rebind); }
- // the rest works as can be expected from underlying container
- template<typename... Args>
- auto insert( Args&&... args ) -> insert_result { return data_.insert( std::forward<Args>(args)... ); }
- template<typename... Args>
- auto emplace( Args&&... args ) -> insert_result { return data_.emplace( std::forward<Args>(args)... ); }
- template<typename... Args>
- insert_result try_emplace(const key_type& k, Args&&... args);
- template<typename... Args>
- insert_result try_emplace(key_type&& k, Args&&... args);
- iterator find( const key_type& key ) { return { data_.find(key) }; }
- size_type count( const key_type& key ) const { return data_.count(key); }
- size_type size() const noexcept { return data_.size(); }
- bool empty() const noexcept { return data_.empty(); }
- void clear() { data_.clear(); }
- size_type max_size() const noexcept { return data_.max_size(); }
- iterator erase( iterator itr ) { return data_.erase(itr); }
- auto equal_range( const key_type& key ) -> std::pair<iterator,iterator> { return data_.equal_range(key); }
- insert_result insert_or_assign( const key_type& key, value_reference val );
- iterator begin() { return data_.begin(); }
- iterator end() { return data_.end(); }
- const_iterator begin() const { return data_.cbegin(); }
- const_iterator end() const { return data_.cend(); }
- const_iterator cbegin() const { return data_.cbegin(); }
- const_iterator cend() const { return data_.cend(); }
- void swap( refmap& other ) noexcept { data_.swap(other.data_); }
- void swap( refmap&& other ) noexcept { swap(other); }
- // bool operator==( const refmap& other ) const { return data_ == other.data_; }
- // bool operator!=( const refmap& other ) const { return data_ != other.data_; }
- struct key_not_found_error : std::out_of_range
- {
- key_not_found_error() : std::out_of_range("key not found") {}
- };
- struct key_already_exists_error : std::logic_error
- {
- key_already_exists_error() : std::logic_error("key already exists") {}
- };
- underlying& data() noexcept { return data_; }
- private:
- underlying data_;
- };
- template< typename Key, typename Val, template<typename ...> class Underlying >
- auto refmap<Key,Val,Underlying>::at( const Key& key ) -> value_reference
- {
- auto itr = data_.find(key);
- if(itr==data_.end()) throw key_not_found_error{};
- return itr->second;
- }
- template< typename Key, typename Val, template<typename ...> class Underlying >
- auto refmap<Key,Val,Underlying>::at( const Key& key ) const -> const_value_reference
- {
- auto itr = data_.find(key);
- if(itr==data_.end()) throw key_not_found_error{};
- return itr->second;
- }
- template< typename Key, typename Val, template<typename ...> class Underlying >
- auto refmap<Key,Val,Underlying>::bind( const Key& key, Val& val, bool rebind ) -> refmap&
- {
- auto itr = data_.find(key);
- if( itr != data_.end() )
- {
- if(rebind)
- itr->second = val;
- else
- throw key_already_exists_error{};
- } else {
- data_.insert( value_type(key,std::ref(val)) );
- }
- return *this;
- }
- template< typename Key, typename Val, template<typename ...> class Underlying >
- auto refmap<Key,Val,Underlying>::insert_or_assign( const key_type& key, value_reference val ) -> insert_result
- {
- auto itr = data_.find(key);
- if( itr != data_.end() )
- {
- itr->second = val;
- return { itr, false };
- } else {
- return data_.insert( value_type(key,std::ref(val)) );
- }
- }
- template< typename Key, typename Val, template<typename ...> class Underlying >
- template<typename... Args>
- auto refmap<Key,Val,Underlying>::try_emplace(const key_type& key, Args&&... args) -> insert_result
- {
- auto itr = data_.find(key);
- if( itr != data_.end() )
- return { itr, false };
- return data_.emplace( std::piecewise_construct, std::tuple<const key_type&>(key), std::tuple<Args&&...>( std::forward<Args>(args)... ) );
- }
- template< typename Key, typename Val, template<typename ...> class Underlying >
- template<typename... Args>
- auto refmap<Key,Val,Underlying>::try_emplace(key_type&& key, Args&&... args) -> insert_result
- {
- auto itr = data_.find(key);
- if( itr != data_.end() )
- return { itr, false };
- return data_.emplace( std::piecewise_construct, std::tuple<key_type&&>(std::move(key)), std::tuple<Args&&...>( std::forward<Args>(args)... ) );
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement