Fishnet 2.0.1
Framework for Graph-Based Analysis of GIS Vector Data
Loading...
Searching...
No Matches
BidirectionalMap.hpp
Go to the documentation of this file.
1#pragma once
2#include <unordered_map>
3#include <type_traits>
5
6namespace fishnet::util {
7
8namespace __impl{
9
10template<typename Expected, typename Actual>
11concept UniversalType = std::convertible_to<std::remove_cvref_t<Expected>, std::remove_cvref_t<Actual>>;
12
13template<typename Derived, typename MapType, typename InverseMapType>
14class AbstractBidirectionalMap {
15public:
16 using value_type = std::pair<const typename MapType::key_type, const typename MapType::mapped_type>;
17 using value_type_non_const = std::pair<typename MapType::key_type, typename MapType::mapped_type>;
18 using inverse_value_type = std::pair<const typename InverseMapType::key_type, const typename InverseMapType::mapped_type>;
19 using from_type = typename MapType::key_type;
20 using to_type = typename MapType::mapped_type;
21 static_assert(std::is_same_v<from_type, typename InverseMapType::mapped_type> && std::is_same_v<to_type, typename InverseMapType::key_type>, "Map and inverse map types are not consistent");
22protected:
23 MapType map;
24 InverseMapType inverse;
25
26 constexpr void update(value_type && value) noexcept {
27 static_cast<Derived*>(this)->updateImpl(std::forward<decltype(value)>(value));
28 }
29public:
30
31 constexpr AbstractBidirectionalMap()=default;
32
33 AbstractBidirectionalMap(std::initializer_list<value_type_non_const> init){
34 for(auto && value :init){
35 insert(std::move(value));
36 }
37 }
38
39 constexpr auto begin() noexcept {
40 return map.begin();
41 }
42
43 constexpr auto end() noexcept {
44 return map.end();
45 }
46
47 constexpr auto cbegin() const noexcept {
48 return map.cbegin();
49 }
50
51 constexpr auto cend() const noexcept {
52 return map.cend();
53 }
54
55 constexpr auto inverseBegin() noexcept {
56 return inverse.begin();
57 }
58
59 constexpr auto inverseEnd() noexcept {
60 return inverse.end();
61 }
62
63 constexpr auto cInverseBegin() const noexcept {
64 return inverse.cbegin();
65 }
66
67 constexpr auto cInverseEnd() const noexcept {
68 return inverse.cend();
69 }
70
71 constexpr bool empty() const noexcept {
72 return map.empty();
73 }
74
75 constexpr size_t size() const noexcept {
76 return map.size();
77 }
78
79 constexpr bool containsFrom(const from_type & key) const noexcept {
80 return map.contains(key);
81 }
82
83 constexpr bool containsTo(const to_type & key) const noexcept {
84 return inverse.contains(key);
85 }
86
87 template<typename T>
88 constexpr bool contains(const T & key) const noexcept
89 requires(UniversalType<T, from_type> || UniversalType<T, to_type>)
90 && (not std::convertible_to<from_type,to_type>)
91 {
92 if constexpr(UniversalType<T, from_type>) {
93 return containsFrom(key);
94 } else {
95 return containsTo(key);
96 }
97 }
98
99 constexpr void insert(UniversalType<value_type> auto && value) noexcept {
100 update(std::forward<decltype(value)>(value));
101 }
102
103 constexpr void insert(UniversalType<from_type> auto && fromKey, UniversalType<to_type> auto && toKey) noexcept {
104 insert(value_type{std::forward<decltype(fromKey)>(fromKey), std::forward<decltype(toKey)>(toKey)});
105 }
106
107 constexpr bool try_insert(UniversalType<value_type> auto && value) noexcept {
108 if(contains(value.first) || containsTo(value.second))
109 return false;
110 insert(std::forward<decltype(value)>(value));
111 return true;
112 }
113
114 constexpr bool try_insert(UniversalType<from_type> auto && fromKey, UniversalType<to_type> auto && toKey) noexcept {
115 return try_insert(value_type{std::forward<decltype(fromKey)>(fromKey), std::forward<decltype(toKey)>(toKey)});
116 }
117
118 constexpr bool eraseFrom(const from_type & fromKey) noexcept {
119 if(not map.contains(fromKey))
120 return false;
121 auto [begin,end] = map.equal_range(fromKey);
122 for(auto it = begin; it != end; ++it) {
123 inverse.erase(it->second);
124 }
125 map.erase(fromKey);
126 return true;
127 }
128
129 constexpr bool eraseTo(const to_type & toKey) noexcept {
130 if(not inverse.contains(toKey))
131 return false;
132 auto [begin,end] = inverse.equal_range(toKey);
133 for(auto it = begin; it != end; ++it) {
134 map.erase(it->second);
135 }
136 inverse.erase(toKey);
137 return true;
138 }
139
140 template<typename T>
141 constexpr bool erase(const T & key) noexcept
142 requires(UniversalType<T, from_type> || UniversalType<T, to_type>)
143 && (not std::convertible_to<from_type,to_type>)
144 {
145 if constexpr(UniversalType<T, from_type>) {
146 return eraseFrom(key);
147 } else {
148 return eraseTo(key);
149 }
150 }
151
152 constexpr void clear() noexcept {
153 map.clear();
154 inverse.clear();
155 }
156
157 ~AbstractBidirectionalMap() = default;
158};
159
160}
161
168template<Mapable from_type, Mapable to_type>
169class BidirectionalHashMap: public __impl::AbstractBidirectionalMap<BidirectionalHashMap<from_type,to_type>, std::unordered_map<from_type,to_type>, std::unordered_map<to_type,from_type>> {
170private:
171 using Base = __impl::AbstractBidirectionalMap<BidirectionalHashMap<from_type,to_type>, std::unordered_map<from_type,to_type>, std::unordered_map<to_type,from_type>>;
172 friend Base;
173
174 constexpr void updateImpl(typename Base::value_type && value) noexcept {
175 if(this->map.contains(value.first)){
176 this->eraseFrom(value.first);
177 }
178 if(this->inverse.contains(value.second)){
179 this->eraseTo(value.second);
180 }
181 this->inverse.insert(inverse_value_type{value.second,value.first});
182 this->map.insert(std::forward<decltype(value)>(value));
183 }
184public:
185 using value_type = typename Base::value_type;
186 using inverse_value_type = typename Base::inverse_value_type;
187
188 BidirectionalHashMap(std::initializer_list<typename Base::value_type_non_const> init):Base(std::move(init)) {}
189
190 constexpr BidirectionalHashMap()=default;
191
192 constexpr std::optional<to_type> getTo(const from_type & key) const noexcept {
193 if(not this->map.contains(key))
194 return std::nullopt;
195 return this->map.at(key);
196 }
197
198 constexpr std::optional<from_type> getFrom(const to_type & key) const noexcept {
199 if(not this->inverse.contains(key))
200 return std::nullopt;
201 return this->inverse.at(key);
202 }
203
204 template<typename T>
205 constexpr auto get(const T & key) const noexcept
206 requires(__impl::UniversalType<T, from_type> || __impl::UniversalType<T, to_type>)
207 && (not std::convertible_to<from_type,to_type>)
208 {
209 if constexpr(__impl::UniversalType<T, from_type>) {
210 return getTo(key);
211 } else {
212 return getFrom(key);
213 }
214 }
215};
216
217
224template<Mapable from_type, Mapable to_type>
225class BidirectionalMultiHashMap: public __impl::AbstractBidirectionalMap<BidirectionalMultiHashMap<from_type,to_type>, std::unordered_multimap<from_type,to_type>, std::unordered_multimap<to_type,from_type>> {
226private:
227 using Base = __impl::AbstractBidirectionalMap<BidirectionalMultiHashMap<from_type,to_type>, std::unordered_multimap<from_type,to_type>, std::unordered_multimap<to_type,from_type>>;
228 friend Base;
229
230 constexpr void updateImpl(typename Base::value_type && value) noexcept {
231 this->inverse.insert(inverse_value_type{value.second,value.first});
232 this->map.insert(std::forward<decltype(value)>(value));
233 }
234
235public:
236 using value_type = typename Base::value_type;
237 using inverse_value_type = typename Base::inverse_value_type;
238
239 BidirectionalMultiHashMap(std::initializer_list<typename Base::value_type_non_const> init):Base(std::move(init)) {}
240
241 constexpr BidirectionalMultiHashMap()=default;
242
243 constexpr auto keySet() const noexcept {
244 return fishnet::util::toUnorderedSet(this->map | std::views::keys);
245 }
246
247 constexpr auto inverseKeySet() const noexcept {
248 return fishnet::util::toUnorderedSet(this->inverse | std::views::keys);
249 }
250
251 constexpr auto getTo(const from_type & key) const noexcept {
252 auto [begin,end] = this->map.equal_range(key);
253 return fishnet::util::toVector(std::ranges::subrange(begin,end) | std::views::values);
254 }
255
256 constexpr auto getFrom(const to_type & key) const noexcept {
257 auto [begin,end] = this->inverse.equal_range(key);
258 return fishnet::util::toVector(std::ranges::subrange(begin,end) | std::views::values);
259 }
260
261 template<typename T>
262 constexpr auto get(const T & key) const noexcept
263 requires(__impl::UniversalType<T, from_type> || __impl::UniversalType<T, to_type>)
264 && (not std::convertible_to<from_type,to_type>)
265 {
266 if constexpr(__impl::UniversalType<T, from_type>) {
267 return getTo(key);
268 } else {
269 return getFrom(key);
270 }
271 }
272};
273} // namespace fishnet::util
Bidirectional Hash Map. Behaves like a regular map, but also implements fast reversed look-up in trad...
Definition BidirectionalMap.hpp:169
constexpr std::optional< from_type > getFrom(const to_type &key) const noexcept
Definition BidirectionalMap.hpp:198
BidirectionalHashMap(std::initializer_list< typename Base::value_type_non_const > init)
Definition BidirectionalMap.hpp:188
constexpr BidirectionalHashMap()=default
constexpr auto get(const T &key) const noexcept
Definition BidirectionalMap.hpp:205
constexpr std::optional< to_type > getTo(const from_type &key) const noexcept
Definition BidirectionalMap.hpp:192
typename Base::inverse_value_type inverse_value_type
Definition BidirectionalMap.hpp:186
typename Base::value_type value_type
Definition BidirectionalMap.hpp:185
Bidirectional Hash MultiMap. Behaves like a regular multimap, but also implements fast reversed look-...
Definition BidirectionalMap.hpp:225
constexpr auto get(const T &key) const noexcept
Definition BidirectionalMap.hpp:262
typename Base::value_type value_type
Definition BidirectionalMap.hpp:236
constexpr auto keySet() const noexcept
Definition BidirectionalMap.hpp:243
constexpr auto getFrom(const to_type &key) const noexcept
Definition BidirectionalMap.hpp:256
BidirectionalMultiHashMap(std::initializer_list< typename Base::value_type_non_const > init)
Definition BidirectionalMap.hpp:239
constexpr auto getTo(const from_type &key) const noexcept
Definition BidirectionalMap.hpp:251
typename Base::inverse_value_type inverse_value_type
Definition BidirectionalMap.hpp:237
constexpr BidirectionalMultiHashMap()=default
constexpr auto inverseKeySet() const noexcept
Definition BidirectionalMap.hpp:247
VectorLayer< G > empty(const OGRSpatialReference &spatialReference)
Creates an empty VectorLayer with the given spatial reference.
Definition VectorIO.hpp:65
Definition AlternativeKeyMap.hpp:4
constexpr auto toUnorderedSet(R &&range)
Definition CollectionConcepts.hpp:73
constexpr size_t size(std::ranges::range auto &&range) noexcept
Definition CollectionConcepts.hpp:50
constexpr auto toVector(R &&range)
Definition CollectionConcepts.hpp:64
STL namespace.