Advertisement
sp2danny

refmap.hpp

Nov 16th, 2015
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.15 KB | None | 0 0
  1. #include <map>
  2. #include <functional>
  3. #include <iterator>
  4. #include <exception>
  5. #include <stdexcept>
  6.  
  7. // class refmap
  8. //   parameters:
  9. //     Key - the key type, must be indexable according to underlying containers requirements
  10. //     Val - the unqualified contained type
  11. //     Underlying - an associative unique-key container, such as std::map or std::unordered_map
  12.  
  13. template<
  14.     typename Key,
  15.     typename Val,
  16.     template<typename ...> class Underlying = std::map
  17. >
  18. class refmap
  19. {
  20. public:
  21.     typedef Key key_type;                               // the key type used for lookup
  22.     typedef std::reference_wrapper<Val> mapped_type;    // underlying container uses this
  23.     typedef Val& value_reference;
  24.     typedef const Val& const_value_reference;
  25.  
  26.     typedef Underlying< key_type, mapped_type > underlying;
  27.  
  28.     typedef typename underlying::iterator iterator;
  29.     typedef typename underlying::const_iterator const_iterator;
  30.     typedef typename underlying::value_type value_type;
  31.     typedef typename underlying::size_type size_type;
  32.     typedef typename underlying::reference reference;
  33.     typedef typename underlying::const_reference const_reference;
  34.    
  35.     typedef std::pair<iterator,bool> insert_result;
  36.  
  37.     refmap() = default; // all 5 are default generated
  38.  
  39.     // subscript is used for lookup only
  40.     // UB if key non-existent
  41.     value_reference operator[]( const Key& key ) { return at(key); }
  42.     const_value_reference operator[]( const Key& key ) const { return at(key); }
  43.  
  44.     // subscript is used for lookup only
  45.     // throws if key non-existent
  46.     value_reference at( const Key& key );
  47.     const_value_reference at( const Key& key ) const;
  48.  
  49.     // binds (or rebinds) a reference to the key
  50.     // operator() an alias for bind
  51.     // can be chained
  52.     refmap& bind( const Key& key, Val& val, bool rebind = true );
  53.     refmap& operator() ( const Key& key, Val& val, bool rebind = true ) { return bind(key,val,rebind); }
  54.  
  55.     // the rest works as can be expected from underlying container
  56.     template<typename... Args>
  57.     auto insert( Args&&... args ) -> insert_result { return data_.insert( std::forward<Args>(args)... ); }
  58.  
  59.     template<typename... Args>
  60.     auto emplace( Args&&... args ) -> insert_result { return data_.emplace( std::forward<Args>(args)... ); }
  61.  
  62.     template<typename... Args>
  63.     insert_result try_emplace(const key_type& k, Args&&... args);
  64.  
  65.     template<typename... Args>
  66.     insert_result try_emplace(key_type&& k, Args&&... args);
  67.  
  68.     iterator find( const key_type& key ) { return { data_.find(key) }; }
  69.  
  70.     size_type count( const key_type& key ) const { return data_.count(key); }
  71.     size_type size() const noexcept { return data_.size(); }
  72.     bool empty() const noexcept { return data_.empty(); }
  73.     void clear() { data_.clear(); }
  74.  
  75.     size_type max_size() const noexcept { return data_.max_size(); }
  76.  
  77.     iterator erase( iterator itr ) { return data_.erase(itr); }
  78.  
  79.     auto equal_range( const key_type& key ) -> std::pair<iterator,iterator> { return data_.equal_range(key); }
  80.  
  81.     insert_result insert_or_assign( const key_type& key, value_reference val );
  82.  
  83.     iterator begin() { return data_.begin(); }
  84.     iterator end()   { return data_.end();   }
  85.  
  86.     const_iterator begin()  const { return data_.cbegin(); }
  87.     const_iterator end()    const { return data_.cend();   }
  88.     const_iterator cbegin() const { return data_.cbegin(); }
  89.     const_iterator cend()   const { return data_.cend();   }
  90.  
  91.     void swap( refmap&  other ) noexcept { data_.swap(other.data_); }
  92.     void swap( refmap&& other ) noexcept { swap(other); }
  93.  
  94.     // bool operator==( const refmap& other ) const { return data_ == other.data_; }
  95.     // bool operator!=( const refmap& other ) const { return data_ != other.data_; }
  96.  
  97.     struct key_not_found_error : std::out_of_range
  98.     {
  99.         key_not_found_error() : std::out_of_range("key not found") {}
  100.     };
  101.     struct key_already_exists_error : std::logic_error
  102.     {
  103.         key_already_exists_error() : std::logic_error("key already exists") {}
  104.     };
  105.  
  106.     underlying& data() noexcept { return data_; }
  107.  
  108. private:
  109.     underlying data_;
  110. };
  111.  
  112. template< typename Key, typename Val, template<typename ...> class Underlying >
  113. auto refmap<Key,Val,Underlying>::at( const Key& key ) -> value_reference
  114. {
  115.     auto itr = data_.find(key);
  116.     if(itr==data_.end()) throw key_not_found_error{};
  117.     return itr->second;
  118. }
  119.  
  120. template< typename Key, typename Val, template<typename ...> class Underlying >
  121. auto refmap<Key,Val,Underlying>::at( const Key& key ) const -> const_value_reference
  122. {
  123.     auto itr = data_.find(key);
  124.     if(itr==data_.end()) throw key_not_found_error{};
  125.     return itr->second;
  126. }
  127.  
  128. template< typename Key, typename Val, template<typename ...> class Underlying >
  129. auto refmap<Key,Val,Underlying>::bind( const Key& key, Val& val, bool rebind ) -> refmap&
  130. {
  131.     auto itr = data_.find(key);
  132.     if( itr != data_.end() )
  133.     {
  134.         if(rebind)
  135.             itr->second = val;
  136.         else
  137.             throw key_already_exists_error{};
  138.     } else {
  139.         data_.insert( value_type(key,std::ref(val)) );
  140.     }
  141.     return *this;
  142. }
  143.  
  144. template< typename Key, typename Val, template<typename ...> class Underlying >
  145. auto refmap<Key,Val,Underlying>::insert_or_assign( const key_type& key, value_reference val ) -> insert_result
  146. {
  147.     auto itr = data_.find(key);
  148.     if( itr != data_.end() )
  149.     {
  150.         itr->second = val;
  151.         return { itr, false };
  152.     } else {
  153.         return data_.insert( value_type(key,std::ref(val)) );
  154.     }
  155. }
  156.  
  157. template< typename Key, typename Val, template<typename ...> class Underlying >
  158. template<typename... Args>
  159. auto refmap<Key,Val,Underlying>::try_emplace(const key_type& key, Args&&... args) -> insert_result
  160. {
  161.     auto itr = data_.find(key);
  162.     if( itr != data_.end() )
  163.         return { itr, false };
  164.     return data_.emplace( std::piecewise_construct, std::tuple<const key_type&>(key), std::tuple<Args&&...>( std::forward<Args>(args)... ) );
  165. }
  166.  
  167. template< typename Key, typename Val, template<typename ...> class Underlying >
  168. template<typename... Args>
  169. auto refmap<Key,Val,Underlying>::try_emplace(key_type&& key, Args&&... args) -> insert_result
  170. {
  171.     auto itr = data_.find(key);
  172.     if( itr != data_.end() )
  173.         return { itr, false };
  174.     return data_.emplace( std::piecewise_construct, std::tuple<key_type&&>(std::move(key)), std::tuple<Args&&...>( std::forward<Args>(args)... ) );
  175. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement