Radium Engine  1.5.0
BijectiveAssociation.hpp
1 #pragma once
2 
3 #include <Core/Utils/StdOptional.hpp>
4 
5 #include <algorithm>
6 #include <initializer_list>
7 #include <iostream>
8 #include <map>
9 
10 namespace Ra {
11 namespace Core {
12 namespace Utils {
13 
19 template <typename T1, typename T2>
21 {
22  public:
23  using key_type = T1;
24  using value_type = T2;
25  using key_to_value_map = std::map<key_type, value_type>;
26  using value_to_key_map = std::map<value_type, key_type>;
27 
31  explicit BijectiveAssociation( std::initializer_list<std::pair<key_type, value_type>> pairs );
32 
36  explicit BijectiveAssociation() = default;
37 
42  bool insert( std::pair<key_type, value_type> p );
43 
48  bool insert( key_type key, value_type value );
49 
63  void replace( std::pair<key_type, value_type> p );
64 
69  void replace( key_type key, value_type value );
70 
79  bool remove( std::pair<key_type, value_type> p );
80 
85  bool remove( key_type key, value_type value );
86 
91  value_type operator()( const key_type& key ) const;
92 
97  value_type value( const key_type& key ) const;
98 
104  optional<value_type> valueIfExists( const key_type& key ) const;
105 
110  key_type key( const value_type& value ) const;
111 
117  optional<key_type> keyIfExists( const value_type& value ) const;
118 
122  typename std::map<key_type, value_type>::const_iterator begin() const noexcept;
123 
125  typename std::map<key_type, value_type>::const_iterator cbegin() const noexcept;
126 
130  typename std::map<key_type, value_type>::const_iterator end() const noexcept;
131 
133  typename std::map<key_type, value_type>::const_iterator cend() const noexcept;
134 
138  size_t size() const;
139 
140  private:
141  key_to_value_map m_keyToValue;
142  value_to_key_map m_valueToKey;
143 };
144 
145 template <typename T1, typename T2>
147  std::initializer_list<std::pair<key_type, value_type>> pairs ) {
148  for ( auto& p : pairs ) {
149  m_valueToKey.insert( { p.second, p.first } );
150  m_keyToValue.insert( p );
151  }
152 }
153 
154 template <typename T1, typename T2>
155 bool BijectiveAssociation<T1, T2>::insert( std::pair<key_type, value_type> p ) {
156  auto [i1, r1] = m_valueToKey.insert( { p.second, p.first } );
157  if ( r1 ) {
158  auto [i2, r2] = m_keyToValue.insert( std::move( p ) );
159  return r2;
160  }
161  return false;
162 }
163 
164 template <typename T1, typename T2>
165 bool BijectiveAssociation<T1, T2>::insert( key_type key, value_type value ) {
166  return insert( { key, value } );
167 }
168 
169 template <typename T1, typename T2>
170 void BijectiveAssociation<T1, T2>::replace( key_type key, value_type value ) {
171  // clean previously set association
172  auto it1 = std::find_if(
173  m_keyToValue.begin(),
174  m_keyToValue.end(),
175  [&value]( const typename key_to_value_map::value_type& v ) { return value == v.second; } );
176 
177  if ( it1 != m_keyToValue.end() ) m_keyToValue.erase( it1 );
178 
179  auto it2 = std::find_if(
180  m_valueToKey.begin(),
181  m_valueToKey.end(),
182  [&key]( const typename value_to_key_map::value_type& v ) { return key == v.second; } );
183 
184  if ( it2 != m_valueToKey.end() ) m_valueToKey.erase( it2 );
185 
186  // set new association
187  m_keyToValue[key] = value;
188  m_valueToKey[value] = key;
189 }
190 template <typename T1, typename T2>
191 void BijectiveAssociation<T1, T2>::replace( std::pair<key_type, value_type> p ) {
192  replace( p.first, p.second );
193 }
194 
195 template <typename T1, typename T2>
196 bool BijectiveAssociation<T1, T2>::remove( key_type key, value_type value ) {
197  // clean previously set association
198  auto it1 = m_keyToValue.find( key );
199  auto it2 = m_valueToKey.find( value );
200  if ( it1 == m_keyToValue.end() || it2 == m_valueToKey.end() ) return false;
201 
202  if ( it1->second != value || it2->second != key ) return false;
203 
204  m_keyToValue.erase( it1 );
205  m_valueToKey.erase( it2 );
206  return true;
207 }
208 
209 template <typename T1, typename T2>
210 bool BijectiveAssociation<T1, T2>::remove( std::pair<key_type, value_type> p ) {
211  return remove( p.frist, p.second );
212 }
213 
214 template <typename T1, typename T2>
215 typename BijectiveAssociation<T1, T2>::value_type
216 BijectiveAssociation<T1, T2>::operator()( const key_type& k ) const {
217  return m_keyToValue.at( k );
218 }
219 
220 template <typename T1, typename T2>
221 typename BijectiveAssociation<T1, T2>::key_type
222 BijectiveAssociation<T1, T2>::key( const value_type& k ) const {
223  return m_valueToKey.at( k );
224 }
225 
226 template <typename T1, typename T2>
227 std::optional<typename BijectiveAssociation<T1, T2>::key_type>
228 BijectiveAssociation<T1, T2>::keyIfExists( const value_type& k ) const {
229  auto itr = m_valueToKey.find( k );
230  if ( itr == m_valueToKey.end() ) return {};
231  return itr->second;
232 }
233 
234 template <typename T1, typename T2>
235 typename BijectiveAssociation<T1, T2>::value_type
236 BijectiveAssociation<T1, T2>::value( const key_type& k ) const {
237  return m_keyToValue.at( k );
238 }
239 
240 template <typename T1, typename T2>
241 std::optional<typename BijectiveAssociation<T1, T2>::value_type>
243  auto itr = m_keyToValue.find( k );
244  if ( itr == m_keyToValue.end() ) return {};
245  return itr->second;
246 }
247 
248 template <typename T1, typename T2>
249 typename std::map<T1, T2>::const_iterator BijectiveAssociation<T1, T2>::cbegin() const noexcept {
250  return m_keyToValue.cbegin();
251 }
252 
253 template <typename T1, typename T2>
254 typename std::map<T1, T2>::const_iterator BijectiveAssociation<T1, T2>::cend() const noexcept {
255  return m_keyToValue.cend();
256 }
257 
258 template <typename T1, typename T2>
259 typename std::map<T1, T2>::const_iterator BijectiveAssociation<T1, T2>::begin() const noexcept {
260  return m_keyToValue.begin();
261 }
262 
263 template <typename T1, typename T2>
264 typename std::map<T1, T2>::const_iterator BijectiveAssociation<T1, T2>::end() const noexcept {
265  return m_keyToValue.end();
266 }
267 
268 template <typename T1, typename T2>
270  return m_keyToValue.size();
271 }
272 
273 } // namespace Utils
274 } // namespace Core
275 } // namespace Ra
Bijective association between two sets {keys} and {values} having the same cardinality....
value_type value(const key_type &key) const
Gets the value associated to key.
std::map< key_type, value_type >::const_iterator cend() const noexcept
Gets a const iterator at the end of the key to value map.
optional< value_type > valueIfExists(const key_type &key) const
Gets the value associated to key if it exists.
std::map< key_type, value_type >::const_iterator cbegin() const noexcept
Gets a const iterator at beginning of the key to value map.
value_type operator()(const key_type &key) const
Gets the value associated to the key.
bool remove(key_type key, value_type value)
Convenient alias for remove({key, value}).
bool remove(std::pair< key_type, value_type > p)
Remove a pair from the association.
std::map< key_type, value_type >::const_iterator begin() const noexcept
Gets a const iterator at beginning of the key to value map.
std::map< key_type, value_type >::const_iterator end() const noexcept
Gets a const iterator at the end of the key to value map.
void replace(std::pair< key_type, value_type > p)
bool insert(std::pair< key_type, value_type > p)
Insert a pair into the association.
bool insert(key_type key, value_type value)
Convenient alias for insert({key, value}).
size_t size() const
Gets the size of the association, i.e. the numer of <Key, Value> pairs.
BijectiveAssociation(std::initializer_list< std::pair< key_type, value_type >> pairs)
Constructor from { <T1, T2> } pairs.
BijectiveAssociation()=default
Creates an empty association.
void replace(key_type key, value_type value)
Convenient alias of replace({key, value}).
key_type key(const value_type &value) const
Gets the key associated to a value.
optional< key_type > keyIfExists(const value_type &value) const
Gets the key associated to value if it exists.
Definition: Cage.cpp:3