Apollo 10.0
自动驾驶开放平台
atomic_hash_map.h
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
17#ifndef CYBER_BASE_ATOMIC_HASH_MAP_H_
18#define CYBER_BASE_ATOMIC_HASH_MAP_H_
19
20#include <atomic>
21#include <cstdint>
22#include <type_traits>
23#include <utility>
24
25namespace apollo {
26namespace cyber {
27namespace base {
36template <typename K, typename V, std::size_t TableSize = 128,
37 typename std::enable_if<std::is_integral<K>::value &&
38 (TableSize & (TableSize - 1)) == 0,
39 int>::type = 0>
41 public:
42 AtomicHashMap() : capacity_(TableSize), mode_num_(capacity_ - 1) {}
43 AtomicHashMap(const AtomicHashMap &other) = delete;
44 AtomicHashMap &operator=(const AtomicHashMap &other) = delete;
45
46 bool Has(K key) {
47 uint64_t index = key & mode_num_;
48 return table_[index].Has(key);
49 }
50
51 bool Get(K key, V **value) {
52 uint64_t index = key & mode_num_;
53 return table_[index].Get(key, value);
54 }
55
56 bool Get(K key, V *value) {
57 uint64_t index = key & mode_num_;
58 V *val = nullptr;
59 bool res = table_[index].Get(key, &val);
60 if (res) {
61 *value = *val;
62 }
63 return res;
64 }
65
66 void Set(K key) {
67 uint64_t index = key & mode_num_;
68 table_[index].Insert(key);
69 }
70
71 void Set(K key, const V &value) {
72 uint64_t index = key & mode_num_;
73 table_[index].Insert(key, value);
74 }
75
76 void Set(K key, V &&value) {
77 uint64_t index = key & mode_num_;
78 table_[index].Insert(key, std::forward<V>(value));
79 }
80
81 private:
82 struct Entry {
83 Entry() {}
84 explicit Entry(K key) : key(key) {
85 value_ptr.store(new V(), std::memory_order_release);
86 }
87 Entry(K key, const V &value) : key(key) {
88 value_ptr.store(new V(value), std::memory_order_release);
89 }
90 Entry(K key, V &&value) : key(key) {
91 value_ptr.store(new V(std::forward<V>(value)), std::memory_order_release);
92 }
93 ~Entry() { delete value_ptr.load(std::memory_order_acquire); }
94
95 K key = 0;
96 std::atomic<V *> value_ptr = {nullptr};
97 std::atomic<Entry *> next = {nullptr};
98 };
99
100 class Bucket {
101 public:
102 Bucket() : head_(new Entry()) {}
103 ~Bucket() {
104 Entry *ite = head_;
105 while (ite) {
106 auto tmp = ite->next.load(std::memory_order_acquire);
107 delete ite;
108 ite = tmp;
109 }
110 }
111
112 bool Has(K key) {
113 Entry *m_target = head_->next.load(std::memory_order_acquire);
114 while (Entry *target = m_target) {
115 if (target->key < key) {
116 m_target = target->next.load(std::memory_order_acquire);
117 continue;
118 } else {
119 return target->key == key;
120 }
121 }
122 return false;
123 }
124
125 bool Find(K key, Entry **prev_ptr, Entry **target_ptr) {
126 Entry *prev = head_;
127 Entry *m_target = head_->next.load(std::memory_order_acquire);
128 while (Entry *target = m_target) {
129 if (target->key == key) {
130 *prev_ptr = prev;
131 *target_ptr = target;
132 return true;
133 } else if (target->key > key) {
134 *prev_ptr = prev;
135 *target_ptr = target;
136 return false;
137 } else {
138 prev = target;
139 m_target = target->next.load(std::memory_order_acquire);
140 }
141 }
142 *prev_ptr = prev;
143 *target_ptr = nullptr;
144 return false;
145 }
146
147 void Insert(K key, const V &value) {
148 Entry *prev = nullptr;
149 Entry *target = nullptr;
150 Entry *new_entry = nullptr;
151 V *new_value = nullptr;
152 while (true) {
153 if (Find(key, &prev, &target)) {
154 // key exists, update value
155 if (!new_value) {
156 new_value = new V(value);
157 }
158 auto old_val_ptr = target->value_ptr.load(std::memory_order_acquire);
159 if (target->value_ptr.compare_exchange_strong(
160 old_val_ptr, new_value, std::memory_order_acq_rel,
161 std::memory_order_relaxed)) {
162 delete old_val_ptr;
163 if (new_entry) {
164 delete new_entry;
165 new_entry = nullptr;
166 }
167 return;
168 }
169 continue;
170 } else {
171 if (!new_entry) {
172 new_entry = new Entry(key, value);
173 }
174 new_entry->next.store(target, std::memory_order_release);
175 if (prev->next.compare_exchange_strong(target, new_entry,
176 std::memory_order_acq_rel,
177 std::memory_order_relaxed)) {
178 // Insert success
179 if (new_value) {
180 delete new_value;
181 new_value = nullptr;
182 }
183 return;
184 }
185 // another entry has been inserted, retry
186 }
187 }
188 }
189
190 void Insert(K key, V &&value) {
191 Entry *prev = nullptr;
192 Entry *target = nullptr;
193 Entry *new_entry = nullptr;
194 V *new_value = nullptr;
195 while (true) {
196 if (Find(key, &prev, &target)) {
197 // key exists, update value
198 if (!new_value) {
199 new_value = new V(std::forward<V>(value));
200 }
201 auto old_val_ptr = target->value_ptr.load(std::memory_order_acquire);
202 if (target->value_ptr.compare_exchange_strong(
203 old_val_ptr, new_value, std::memory_order_acq_rel,
204 std::memory_order_relaxed)) {
205 delete old_val_ptr;
206 if (new_entry) {
207 delete new_entry;
208 new_entry = nullptr;
209 }
210 return;
211 }
212 continue;
213 } else {
214 if (!new_entry) {
215 new_entry = new Entry(key, value);
216 }
217 new_entry->next.store(target, std::memory_order_release);
218 if (prev->next.compare_exchange_strong(target, new_entry,
219 std::memory_order_acq_rel,
220 std::memory_order_relaxed)) {
221 // Insert success
222 if (new_value) {
223 delete new_value;
224 new_value = nullptr;
225 }
226 return;
227 }
228 // another entry has been inserted, retry
229 }
230 }
231 }
232
233 void Insert(K key) {
234 Entry *prev = nullptr;
235 Entry *target = nullptr;
236 Entry *new_entry = nullptr;
237 V *new_value = nullptr;
238 while (true) {
239 if (Find(key, &prev, &target)) {
240 // key exists, update value
241 if (!new_value) {
242 new_value = new V();
243 }
244 auto old_val_ptr = target->value_ptr.load(std::memory_order_acquire);
245 if (target->value_ptr.compare_exchange_strong(
246 old_val_ptr, new_value, std::memory_order_acq_rel,
247 std::memory_order_relaxed)) {
248 delete old_val_ptr;
249 if (new_entry) {
250 delete new_entry;
251 new_entry = nullptr;
252 }
253 return;
254 }
255 continue;
256 } else {
257 if (!new_entry) {
258 new_entry = new Entry(key);
259 }
260 new_entry->next.store(target, std::memory_order_release);
261 if (prev->next.compare_exchange_strong(target, new_entry,
262 std::memory_order_acq_rel,
263 std::memory_order_relaxed)) {
264 // Insert success
265 if (new_value) {
266 delete new_value;
267 new_value = nullptr;
268 }
269 return;
270 }
271 // another entry has been inserted, retry
272 }
273 }
274 }
275
276 bool Get(K key, V **value) {
277 Entry *prev = nullptr;
278 Entry *target = nullptr;
279 if (Find(key, &prev, &target)) {
280 *value = target->value_ptr.load(std::memory_order_acquire);
281 return true;
282 }
283 return false;
284 }
285
286 Entry *head_;
287 };
288
289 private:
290 Bucket table_[TableSize];
291 uint64_t capacity_;
292 uint64_t mode_num_;
293};
294
295} // namespace base
296} // namespace cyber
297} // namespace apollo
298
299#endif // CYBER_BASE_ATOMIC_HASH_MAP_H_
A implementation of lock-free fixed size hash map
AtomicHashMap & operator=(const AtomicHashMap &other)=delete
void Set(K key, const V &value)
AtomicHashMap(const AtomicHashMap &other)=delete
class register implement
Definition arena_queue.h:37