Jlm
Loading...
Searching...
No Matches
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
13namespace jlm::util
14{
21template<typename K, typename V>
23{
24 using ForwardMapType = std::unordered_map<K, V>;
25 using ReverseMapType = std::unordered_map<V, K>;
26
27public:
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 *;
38
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_(),
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
124 operator=(const BijectiveMap & other) = default;
125
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
364 RemoveKeysWhere(const F & match)
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
381 RemoveValuesWhere(const F & match)
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
412private:
415};
416
417}
418
419#endif // JLM_UTIL_BIJECTIVE_MAP_HPP
ForwardMapType::const_iterator It_
bool operator!=(const ConstIterator &other) const
const ItemType * operator->() const
std::forward_iterator_tag iterator_category
ConstIterator(const typename ForwardMapType::const_iterator &it)
bool operator==(const ConstIterator &other) const
~BijectiveMap() noexcept=default
bool operator!=(const BijectiveMap &other) const noexcept
size_t RemoveValuesWhere(const F &match)
std::unordered_map< V, K > ReverseMapType
bool RemoveKey(const K &key)
size_t RemoveWhere(const F &match)
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
BijectiveMap & operator=(BijectiveMap &&other)=default
bool operator==(const BijectiveMap &other) const noexcept
ConstIterator end() const noexcept
const V & LookupKey(const K &key) const
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
const K & LookupValue(const V &value) const
bool Insert(const K &key, const V &value)
bool HasKey(const K &key) const noexcept
BijectiveMap(std::initializer_list< ItemType > init)
BijectiveMap & operator=(const BijectiveMap &other)=default
bool HasValue(const V &value) const noexcept
#define JLM_ASSERT(x)
Definition common.hpp:16