forked from chipsalliance/verible
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bijective_map.h
147 lines (126 loc) · 5.43 KB
/
bijective_map.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright 2017-2020 The Verible Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef VERIBLE_COMMON_UTIL_BIJECTIVE_MAP_H_
#define VERIBLE_COMMON_UTIL_BIJECTIVE_MAP_H_
#include <functional>
#include <initializer_list>
#include <map>
#include <utility>
#include "common/util/forward.h"
#include "common/util/logging.h"
namespace verible {
// 1-to-1 key-value map that maintains bijectiveness as an invariant.
// Both keys and values are stored once, and internal cross-reference
// maps point to each other's keys.
// Using std::map internally because it provides stable iterators
// across insertion/deletion operations.
template <class K, class V, class KComp = std::less<K>,
class VComp = std::less<V>>
class BijectiveMap {
// Map of keys to values (by pointer).
// Would really rather have value_type be a reverse_map_type::const_iterator
// but cannot due to mutually recursive template type.
typedef std::map<K, const V*, KComp> forward_map_type;
// Map of values to keys (by pointer).
// Would really rather have value_type be a forward_map_type::const_iterator
// but cannot due to mutually recursive template type.
typedef std::map<V, const K*, VComp> reverse_map_type;
public:
BijectiveMap() = default;
// Initializes from a pair of iterators (to key-value pairs).
// Duplicate key or value entries will result in a fatal error.
template <class Iter>
BijectiveMap(Iter begin, Iter end) {
for (; begin != end; ++begin) {
CHECK(insert(*begin)) << "duplicate key or value: (" << begin->first
<< ", " << begin->second << ')';
}
}
// Initializes from a list of pairs.
// Duplicate key or value entries will result in a fatal error.
BijectiveMap(std::initializer_list<std::pair<K, V>> pairs)
: BijectiveMap(pairs.begin(), pairs.end()) {}
// Returns number of keys, which is same as number of values.
size_t size() const { return forward_map.size(); }
bool empty() const { return forward_map.empty(); }
// read-only direct access to internal maps
const forward_map_type& forward_view() const { return forward_map; }
const reverse_map_type& reverse_view() const { return reverse_map; }
// Lookup value given key. Returns nullptr if not found.
template <typename ConvertibleToKey>
const V* find_forward(const ConvertibleToKey& k) const {
const auto found = forward_map.find(k);
return found == forward_map.end() ? nullptr : found->second;
}
// Lookup key given value. Returns nullptr if not found.
template <typename ConvertibleToValue>
const K* find_reverse(const ConvertibleToValue& v) const {
const auto found = reverse_map.find(v);
return found == reverse_map.end() ? nullptr : found->second;
}
// Returns true if successfully inserted new pair.
bool insert(const std::pair<K, V>& p) { return insert(p.first, p.second); }
// Establishes 1-1 association between key and value.
// Returns true if successfully inserted new pair.
bool insert(const K& k, const V& v) {
const auto fwd_p = forward_map.insert(std::make_pair(k, nullptr));
const auto rev_p = reverse_map.insert(std::make_pair(v, nullptr));
if (fwd_p.second && rev_p.second) {
// cross-link
// pointers are guaranteed to be stable across non-destructive map
// mutations.
fwd_p.first->second = &rev_p.first->first;
rev_p.first->second = &fwd_p.first->first;
return true;
} else { // either key or value already existed in respective set
// undo any insertions
if (fwd_p.second) {
forward_map.erase(fwd_p.first);
}
if (rev_p.second) {
reverse_map.erase(rev_p.first);
}
return false;
}
}
// function f is a (lazy) value generator that is invoked only when the key
// insertion succeeds. Retries value insertion (calling generator) until
// success. If the range of values generated is small, this could result
// in more frequent retries. Use cases for this include randomizing generated
// values, or using secondary hashes to avoid collisions.
const V* insert_using_value_generator(const K& k, std::function<V()> f) {
const auto fwd_p = forward_map.insert(std::make_pair(k, nullptr));
if (!fwd_p.second) return fwd_p.first->second; // key entry aleady exists
do {
const auto rev_p = reverse_map.insert(std::make_pair(f(), nullptr));
if (rev_p.second) { // successful value insertion
// cross-link
fwd_p.first->second = &rev_p.first->first;
rev_p.first->second = &fwd_p.first->first;
return fwd_p.first->second;
}
} while (true);
// never reached
return nullptr;
}
// TODO(fangism): erase()
private:
// Internal storage of keys, and pointers to values
forward_map_type forward_map;
// Internal storage of values, and pointers to keys
reverse_map_type reverse_map;
};
// TODO(fangism): forward and reverse view adaptors
} // namespace verible
#endif // VERIBLE_COMMON_UTIL_BIJECTIVE_MAP_H_