Jlm
BijectiveMap.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 HÃ¥vard Krogstie <krogstie.havard@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #ifndef JLM_UTIL_BIJECTIVE_MAP_HPP
7 #define JLM_UTIL_BIJECTIVE_MAP_HPP
8 
9 #include <jlm/util/common.hpp>
10 
11 #include <unordered_map>
12 
13 namespace jlm::util
14 {
21 template<typename K, typename V>
23 {
24  using ForwardMapType = std::unordered_map<K, V>;
25  using ReverseMapType = std::unordered_map<V, K>;
26 
27 public:
28  using ItemType = std::pair<const K, V>;
29 
30  class ConstIterator final
31  {
32  public:
33  using iterator_category = std::forward_iterator_tag;
35  using difference_type = std::ptrdiff_t;
36  using pointer = ItemType *;
37  using reference = ItemType &;
38 
39  friend BijectiveMap;
40 
41  ConstIterator() = default;
42 
43  explicit ConstIterator(const typename ForwardMapType::const_iterator & it)
44  : It_(it)
45  {}
46 
47  const ItemType &
48  operator*() const
49  {
50  return It_.operator*();
51  }
52 
53  const ItemType *
54  operator->() const
55  {
56  return It_.operator->();
57  }
58 
61  {
62  ++It_;
63  return *this;
64  }
65 
68  {
69  ConstIterator tmp = *this;
70  ++*this;
71  return tmp;
72  }
73 
74  bool
75  operator==(const ConstIterator & other) const
76  {
77  return It_ == other.It_;
78  }
79 
80  bool
81  operator!=(const ConstIterator & other) const
82  {
83  return !operator==(other);
84  }
85 
86  private:
87  typename ForwardMapType::const_iterator It_;
88  };
89 
90  ~BijectiveMap() noexcept = default;
91 
95  BijectiveMap() = default;
96 
97  BijectiveMap(const BijectiveMap & other) = default;
98 
99  BijectiveMap(BijectiveMap && other) noexcept = default;
100 
105  template<class InputIt>
106  explicit BijectiveMap(InputIt first, InputIt last)
107  : ForwardMap_(),
108  ReverseMap_()
109  {
110  for (auto it = first; it != last; ++it)
111  InsertOrThrow(it->first, it->second);
112  }
113 
119  BijectiveMap(std::initializer_list<ItemType> init)
120  : BijectiveMap(init.begin(), init.end())
121  {}
122 
123  BijectiveMap &
124  operator=(const BijectiveMap & other) = default;
125 
126  BijectiveMap &
127  operator=(BijectiveMap && other) = default;
128 
132  void
133  Clear() noexcept
134  {
135  ForwardMap_.clear();
136  ReverseMap_.clear();
137  }
138 
142  [[nodiscard]] std::size_t
143  Size() const noexcept
144  {
145  JLM_ASSERT(ForwardMap_.size() == ReverseMap_.size());
146  return ForwardMap_.size();
147  }
148 
156  bool
157  Insert(const K & key, const V & value)
158  {
159  if (HasKey(key) || HasValue(value))
160  return false;
161 
162  ForwardMap_.insert({ key, value });
163  ReverseMap_.insert({ value, key });
164  return true;
165  }
166 
174  template<typename IteratorType>
175  size_t
176  InsertPairs(IteratorType begin, IteratorType end)
177  {
178  static_assert(
179  std::is_base_of_v<std::forward_iterator_tag, typename IteratorType::iterator_category>);
180 
181  size_t inserted = 0;
182  while (begin != end)
183  {
184  if (Insert(begin->first, begin->second))
185  inserted++;
186  ++begin;
187  }
188 
189  return inserted;
190  }
191 
199  void
200  InsertOrThrow(const K & key, const V & value)
201  {
202  if (!Insert(key, value))
203  throw Error("Key or value were already present in the BijectiveMap");
204  }
205 
211  [[nodiscard]] bool
212  HasKey(const K & key) const noexcept
213  {
214  return ForwardMap_.count(key);
215  }
216 
222  [[nodiscard]] bool
223  HasValue(const V & value) const noexcept
224  {
225  return ReverseMap_.count(value);
226  }
227 
233  [[nodiscard]] const V &
234  LookupKey(const K & key) const
235  {
236  auto it = ForwardMap_.find(key);
237  if (it == ForwardMap_.end())
238  throw Error("Key not found in BijectiveMap");
239  return it->second;
240  }
241 
247  [[nodiscard]] const K &
248  LookupValue(const V & value) const
249  {
250  auto it = ReverseMap_.find(value);
251  if (it == ReverseMap_.end())
252  throw Error("Value not found in BijectiveMap");
253  return it->second;
254  }
255 
261  [[nodiscard]] ConstIterator
262  begin() const noexcept
263  {
264  return ConstIterator(ForwardMap_.cbegin());
265  }
266 
272  [[nodiscard]] ConstIterator
273  end() const noexcept
274  {
275  return ConstIterator(ForwardMap_.cend());
276  }
277 
285  ConstIterator
287  {
288  const size_t removed = ReverseMap_.erase(it->second);
289  JLM_ASSERT(removed == 1);
290  const auto nextForwardIt = ForwardMap_.erase(it.It_);
291  return ConstIterator(nextForwardIt);
292  }
293 
299  bool
300  RemoveKey(const K & key)
301  {
302  auto it = ForwardMap_.find(key);
303  if (it == ForwardMap_.end())
304  return false;
305 
306  Erase(ConstIterator(it));
307  return true;
308  }
309 
315  bool
316  RemoveValue(const V & value)
317  {
318  auto it = ReverseMap_.find(value);
319  if (it == ReverseMap_.end())
320  return false;
321 
322  auto removed = ForwardMap_.erase(it->second);
323  JLM_ASSERT(removed == 1);
324 
325  ReverseMap_.erase(it);
326  return true;
327  }
328 
335  template<typename F>
336  size_t
337  RemoveWhere(const F & match)
338  {
339  size_t removed = 0;
340  auto it = begin();
341  while (it != end())
342  {
343  if (match(it->first, it->second))
344  {
345  it = Erase(it);
346  removed++;
347  }
348  else
349  {
350  ++it;
351  }
352  }
353  return removed;
354  }
355 
362  template<typename F>
363  size_t
365  {
366  return RemoveWhere(
367  [&](const K & key, const V &)
368  {
369  return match(key);
370  });
371  }
372 
379  template<typename F>
380  size_t
382  {
383  return RemoveWhere(
384  [&](const K &, const V & value)
385  {
386  return match(value);
387  });
388  }
389 
395  [[nodiscard]] bool
396  operator==(const BijectiveMap & other) const noexcept
397  {
398  // We only need to compare forward maps, as reverse maps are uniquely defined by the forward map
399  return ForwardMap_ == other.ForwardMap_;
400  }
401 
406  [[nodiscard]] bool
407  operator!=(const BijectiveMap & other) const noexcept
408  {
409  return !operator==(other);
410  }
411 
412 private:
415 };
416 
417 }
418 
419 #endif // JLM_UTIL_BIJECTIVE_MAP_HPP
ForwardMapType::const_iterator It_
const ItemType & operator*() const
const ItemType * operator->() const
bool operator!=(const ConstIterator &other) const
std::forward_iterator_tag iterator_category
ConstIterator(const typename ForwardMapType::const_iterator &it)
bool operator==(const ConstIterator &other) const
~BijectiveMap() noexcept=default
const V & LookupKey(const K &key) const
bool operator!=(const BijectiveMap &other) const noexcept
const K & LookupValue(const V &value) const
size_t RemoveValuesWhere(const F &match)
std::unordered_map< V, K > ReverseMapType
bool RemoveKey(const K &key)
size_t RemoveWhere(const F &match)
BijectiveMap & operator=(const BijectiveMap &other)=default
BijectiveMap & operator=(BijectiveMap &&other)=default
ReverseMapType ReverseMap_
size_t InsertPairs(IteratorType begin, IteratorType end)
ConstIterator begin() const noexcept
std::size_t Size() const noexcept
ConstIterator Erase(ConstIterator it)
std::pair< const K, V > ItemType
ForwardMapType ForwardMap_
bool operator==(const BijectiveMap &other) const noexcept
ConstIterator end() const noexcept
size_t RemoveKeysWhere(const F &match)
bool RemoveValue(const V &value)
void InsertOrThrow(const K &key, const V &value)
std::unordered_map< K, V > ForwardMapType
bool Insert(const K &key, const V &value)
bool HasKey(const K &key) const noexcept
BijectiveMap(std::initializer_list< ItemType > init)
bool HasValue(const V &value) const noexcept
#define JLM_ASSERT(x)
Definition: common.hpp:16
jlm::rvsdg::Output * match(size_t nbits, const std::unordered_map< uint64_t, uint64_t > &mapping, uint64_t default_alternative, size_t nalternatives, jlm::rvsdg::Output *operand)
Definition: control.cpp:179