2#include <unordered_map>
10template<
typename Expected,
typename Actual>
11concept UniversalType = std::convertible_to<std::remove_cvref_t<Expected>, std::remove_cvref_t<Actual>>;
13template<
typename Derived,
typename MapType,
typename InverseMapType>
14class AbstractBidirectionalMap {
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");
24 InverseMapType inverse;
26 constexpr void update(value_type && value)
noexcept {
27 static_cast<Derived*
>(
this)->updateImpl(std::forward<
decltype(value)>(value));
31 constexpr AbstractBidirectionalMap()=
default;
33 AbstractBidirectionalMap(std::initializer_list<value_type_non_const> init){
34 for(
auto && value :init){
35 insert(std::move(value));
39 constexpr auto begin() noexcept {
43 constexpr auto end() noexcept {
47 constexpr auto cbegin() const noexcept {
51 constexpr auto cend() const noexcept {
55 constexpr auto inverseBegin() noexcept {
56 return inverse.begin();
59 constexpr auto inverseEnd() noexcept {
63 constexpr auto cInverseBegin() const noexcept {
64 return inverse.cbegin();
67 constexpr auto cInverseEnd() const noexcept {
68 return inverse.cend();
71 constexpr bool empty() const noexcept {
75 constexpr size_t size() const noexcept {
79 constexpr bool containsFrom(
const from_type & key)
const noexcept {
80 return map.contains(key);
83 constexpr bool containsTo(
const to_type & key)
const noexcept {
84 return inverse.contains(key);
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>)
92 if constexpr(UniversalType<T, from_type>) {
93 return containsFrom(key);
95 return containsTo(key);
99 constexpr void insert(UniversalType<value_type>
auto && value)
noexcept {
100 update(std::forward<
decltype(value)>(value));
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)});
107 constexpr bool try_insert(UniversalType<value_type>
auto && value)
noexcept {
108 if(contains(value.first) || containsTo(value.second))
110 insert(std::forward<
decltype(value)>(value));
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)});
118 constexpr bool eraseFrom(
const from_type & fromKey)
noexcept {
119 if(not map.contains(fromKey))
121 auto [begin,end] = map.equal_range(fromKey);
122 for(
auto it = begin; it != end; ++it) {
123 inverse.erase(it->second);
129 constexpr bool eraseTo(
const to_type & toKey)
noexcept {
130 if(not inverse.contains(toKey))
132 auto [begin,end] = inverse.equal_range(toKey);
133 for(
auto it = begin; it != end; ++it) {
134 map.erase(it->second);
136 inverse.erase(toKey);
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>)
145 if constexpr(UniversalType<T, from_type>) {
146 return eraseFrom(key);
152 constexpr void clear() noexcept {
157 ~AbstractBidirectionalMap() =
default;
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>> {
171 using Base = __impl::AbstractBidirectionalMap<BidirectionalHashMap<from_type,to_type>, std::unordered_map<from_type,to_type>, std::unordered_map<to_type,from_type>>;
174 constexpr void updateImpl(
typename Base::value_type && value)
noexcept {
175 if(this->map.contains(value.first)){
176 this->eraseFrom(value.first);
178 if(this->inverse.contains(value.second)){
179 this->eraseTo(value.second);
182 this->map.insert(std::forward<
decltype(value)>(value));
192 constexpr std::optional<to_type>
getTo(
const from_type & key)
const noexcept {
193 if(not this->map.contains(key))
195 return this->map.at(key);
198 constexpr std::optional<from_type>
getFrom(
const to_type & key)
const noexcept {
199 if(not this->inverse.contains(key))
201 return this->inverse.at(key);
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>)
209 if constexpr(__impl::UniversalType<T, from_type>) {
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>> {
227 using Base = __impl::AbstractBidirectionalMap<BidirectionalMultiHashMap<from_type,to_type>, std::unordered_multimap<from_type,to_type>, std::unordered_multimap<to_type,from_type>>;
230 constexpr void updateImpl(
typename Base::value_type && value)
noexcept {
232 this->map.insert(std::forward<
decltype(value)>(value));
251 constexpr auto getTo(
const from_type & key)
const noexcept {
252 auto [begin,end] = this->map.equal_range(key);
256 constexpr auto getFrom(
const to_type & key)
const noexcept {
257 auto [begin,end] = this->inverse.equal_range(key);
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>)
266 if constexpr(__impl::UniversalType<T, from_type>) {
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