bimap.h
Go to the documentation of this file.
1 /*
2  * This file is part of the alglib project.
3  *
4  * (c) Divyanshu Kakwani <divkakwani@gmail.com>
5  *
6  * For the full copyright and license information, please view the LICENSE file
7  * that was distributed with this source code.
8  */
9 
10 #pragma once
11 
12 #include <map>
13 #include <vector>
14 #include <stdexcept>
15 #include <boost/iterator/transform_iterator.hpp>
16 
17 namespace alglib {
18 namespace bimap {
19 
20 /*
21  * \brief Data structure to hold bijective mappings
22  *
23  * Every element in the domain and the codomain must be distinct.
24  */
25 template<typename type1, typename type2>
26 class bimap {
27 
28  private:
29 
30 
31  /* All the elements in the domain are put into `domain` where each of the element
32  * is given a distinct int. Same goes with the elements of codomain.
33  */
34  std::map<type1, int> domain;
35  std::map<type2, int> codomain;
36 
37  /* Upon every insertion, a new entry is made in `directory` which stores a pair of iterators,
38  * one referring to the element inserted in domain, the other to the element inserted in the
39  * codomain against the integer assigned to them.
40  */
41  typedef std::pair<typename std::map<type1, int>::iterator,
42  typename std::map<type2, int>::iterator>
43  dir_entry;
44 
45  std::map<int, dir_entry> directory; // An indirection
46 
47  /* total elements in domain/codomain */
48  int dir_entries;
49 
50  template<typename T>
51  struct select1st : public std::unary_function<T, typename T::first_type> {
52  typename T::first_type operator()(const T& p) const { return p.first; };
53  };
54 
55  select1st<std::pair<type1, int>> get_domain_elt;
56  select1st<std::pair<type2, int>> get_codomain_elt;
57 
58  public:
59 
60  /* typedefs */
61  typedef type1 domain_type;
62  typedef type2 codomain_type;
63  typedef boost::transform_iterator<select1st<std::pair<domain_type, int>>,
64  typename std::map<domain_type, int>::const_iterator>
66  typedef boost::transform_iterator<select1st<std::pair<codomain_type, int>>,
67  typename std::map<codomain_type, int>::const_iterator>
69 
70 
71  /* ctors */
72  bimap();
73  bimap(const bimap&) = default;
74  bimap(bimap&&);
75 
76  void insert(const type1& elt1, const type2& elt2);
77 
78  const codomain_type& get_image(const domain_type& elt) const;
79  const domain_type& get_preimage(const codomain_type& elt) const;
80 
81  void remove_domain_elt(const domain_type& elt);
82  void remove_codomain_elt(const codomain_type& elt);
83 
84  /* Iterator-returning methods */
89 };
90 
91 template<typename type1, typename type2>
93  dir_entries = 0;
94 }
95 
96 /* Move-constructor */
97 template<typename type1, typename type2>
98 bimap<type1, type2>::bimap(bimap&& b) : domain(std::move(b.domain)),
99  codomain(std::move(b.codomain)),
100  directory(std::move(b.directory)),
101  dir_entries(b.dir_entries) {}
102 
103 template<typename type1, typename type2>
104 void bimap<type1, type2>::insert(const type1& elt1, const type2& elt2) {
105 
106  auto ret1 = domain.insert(std::make_pair(elt1, dir_entries));
107  auto ret2 = codomain.insert(std::make_pair(elt2, dir_entries));
108 
109  // check if elt1 or elt2 already existed
110  if(!ret1.second or !ret2.second)
111  throw std::domain_error("Either or both of the element already exists");
112 
113  // record it in the directory
114  directory[dir_entries] = std::make_pair(ret1.first, ret2.first);
115 
116  ++dir_entries;
117 }
118 
119 template<typename type1, typename type2>
120 const type2& bimap<type1, type2>::get_image(const type1& elt) const {
121 
122  auto it = domain.find(elt);
123  if(it == domain.end())
124  throw std::out_of_range("The key doesn't exist");
125 
126  return (directory.at(it->second).second)->first;
127 }
128 
129 template<typename type1, typename type2>
130 const type1& bimap<type1, type2>::get_preimage(const type2& elt) const {
131 
132  auto it = codomain.find(elt);
133  if(it == codomain.end())
134  throw std::out_of_range("The key doesn't exist");
135 
136  return (directory.at(it->second).first)->first;
137 }
138 
139 
140 template<typename type1, typename type2>
142 
143  auto domain_it = domain.find(elt);
144  if(domain_it == domain.end())
145  throw std::out_of_range("element doesn't exist");
146 
147  auto dir_entry = *directory[domain_it->second];
148  auto it_pair = dir_entry->second;
149 
150  // Now erase the domain and codomain entry
151  domain.erase(it_pair->first);
152  codomain.erase(it_pair->second);
153 
154  // finally, delete the directory entry)
155  directory.erase(dir_entry);
156 }
157 
158 
159 template<typename type1, typename type2>
161 
162  auto codomain_it = codomain.find(elt);
163  if(codomain_it == codomain.end())
164  throw std::out_of_range("element doesn't exist");
165 
166  auto dir_entry = *directory[codomain_it->second];
167  auto it_pair = dir_entry->second;
168 
169  // Now erase the domain and codomain entry
170  domain.erase(it_pair->first);
171  codomain.erase(it_pair->second);
172 
173  // finally, delete the directory entry)
174  directory.erase(dir_entry);
175 }
176 
177 
178 /* Iterator-returning functions start here */
179 
180 template<typename type1, typename type2>
183  return boost::make_transform_iterator(domain.begin(), get_domain_elt);
184 }
185 
186 template<typename type1, typename type2>
189  return boost::make_transform_iterator(domain.end(), get_domain_elt);
190 }
191 
192 template<typename type1, typename type2>
195  return boost::make_transform_iterator(codomain.begin(), get_codomain_elt);
196 }
197 
198 template<typename type1, typename type2>
201  return boost::make_transform_iterator(codomain.end(), get_codomain_elt);
202 }
203 
204 
205 } // end bimap namespace
206 } // end alglib namespace
207 
boost::transform_iterator< select1st< std::pair< domain_type, int > >, typename std::map< domain_type, int >::const_iterator > domain_iterator
Definition: bimap.h:65
boost::transform_iterator< select1st< std::pair< codomain_type, int > >, typename std::map< codomain_type, int >::const_iterator > codomain_iterator
Definition: bimap.h:68
bimap()
Definition: bimap.h:92
Definition: bimap.h:17
type2 codomain_type
Definition: bimap.h:62
codomain_iterator codomain_begin() const
Definition: bimap.h:194
void insert(const type1 &elt1, const type2 &elt2)
Definition: bimap.h:104
void remove_domain_elt(const domain_type &elt)
Definition: bimap.h:141
const codomain_type & get_image(const domain_type &elt) const
Definition: bimap.h:120
domain_iterator domain_end() const
Definition: bimap.h:188
codomain_iterator codomain_end() const
Definition: bimap.h:200
void remove_codomain_elt(const codomain_type &elt)
Definition: bimap.h:160
const domain_type & get_preimage(const codomain_type &elt) const
Definition: bimap.h:130
type1 domain_type
Definition: bimap.h:61
Definition: bimap.h:26
domain_iterator domain_begin() const
Definition: bimap.h:182