6 #ifndef XENIUM_HARRIS_MICHAEL_LIST_BASED_SET_HPP
7 #define XENIUM_HARRIS_MICHAEL_LIST_BASED_SET_HPP
9 #include <xenium/acquire_guard.hpp>
10 #include <xenium/backoff.hpp>
11 #include <xenium/parameter.hpp>
12 #include <xenium/policy.hpp>
39 template <
class Key,
class... Policies>
42 using value_type = Key;
43 using reclaimer = parameter::type_param_t<
policy::reclaimer, parameter::nil, Policies...>;
45 using compare = parameter::type_param_t<policy::compare, std::less<Key>, Policies...>;
47 template <
class... NewPolicies>
50 static_assert(parameter::is_set<reclaimer>::value,
"reclaimer policy must be specified");
71 template <
class... Args>
90 template <
class... Args>
103 bool erase(
const Key& key);
155 using concurrent_ptr =
typename reclaimer::template concurrent_ptr<node, 1>;
156 using marked_ptr =
typename concurrent_ptr::marked_ptr;
157 using guard_ptr =
typename concurrent_ptr::guard_ptr;
160 concurrent_ptr* prev;
165 bool find(
const Key& key, find_info& info, backoff& backoff);
183 template <
class Key,
class... Policies>
186 using iterator_category = std::forward_iterator_tag;
187 using value_type = Key;
188 using difference_type = std::ptrdiff_t;
189 using pointer =
const Key*;
190 using reference =
const Key&;
209 bool operator==(
const iterator& other)
const {
return info.cur.get() == other.info.cur.get(); }
210 bool operator!=(
const iterator& other)
const {
return !(*
this == other); }
211 reference operator*()
const noexcept {
return info.cur->key; }
212 pointer operator->()
const noexcept {
return &info.cur->key; }
232 info.cur.acquire(*start, std::memory_order_acquire);
236 explicit iterator(harris_michael_list_based_set& list, find_info&& info) : list(&list), info(std::move(info)) {}
238 harris_michael_list_based_set* list;
242 template <
class Key,
class... Policies>
243 struct harris_michael_list_based_set<Key, Policies...>::node : reclaimer::template enable_concurrent_ptr<node, 1> {
246 template <
class... Args>
247 explicit node(Args&&... args) : key(std::forward<Args>(args)...), next() {}
250 template <
class Key,
class... Policies>
252 assert(info.cur.get() !=
nullptr);
253 auto next = info.cur->next.load(std::memory_order_relaxed);
256 if (next.mark() == 0 && tmp_guard.acquire_if_equal(info.cur->next, next, std::memory_order_acquire)) {
257 info.prev = &info.cur->next;
258 info.save = std::move(info.cur);
259 info.cur = std::move(tmp_guard);
263 auto key = info.cur->key;
265 list->
find(key, info, backoff);
267 assert(info.prev == &list->head || info.cur.get() ==
nullptr ||
268 (info.save.get() !=
nullptr && &info.save->next == info.prev));
272 template <
class Key,
class... Policies>
279 template <
class Key,
class... Policies>
283 auto p = head.load(std::memory_order_acquire);
286 auto next = p->next.load(std::memory_order_acquire);
292 template <
class Key,
class... Policies>
294 assert((info.save ==
nullptr && info.prev == &head) || &info.save->next == info.prev);
295 concurrent_ptr* start = info.prev;
296 guard_ptr start_guard = info.save;
299 info.save = start_guard;
300 info.next = info.prev->load(std::memory_order_relaxed);
301 if (info.next.mark() != 0) {
310 if (!info.cur.acquire_if_equal(*info.prev, info.next, std::memory_order_acquire)) {
318 info.next = info.cur->next.load(std::memory_order_relaxed);
319 if (info.next.mark() != 0) {
323 info.next = info.cur->next.load(std::memory_order_acquire).get();
326 marked_ptr expected = info.cur.get();
330 if (!info.prev->compare_exchange_weak(
331 expected, info.next, std::memory_order_release, std::memory_order_relaxed)) {
337 if (info.prev->load(std::memory_order_relaxed) != info.cur.get()) {
341 const Key& ckey = info.cur->key;
343 if (!compare(ckey, key)) {
344 return !compare(key, ckey);
347 info.prev = &info.cur->next;
348 std::swap(info.save, info.cur);
353 template <
class Key,
class... Policies>
355 find_info info{&head};
357 return find(key, info, backoff);
360 template <
class Key,
class... Policies>
362 find_info info{&head};
364 if (find(key, info, backoff)) {
365 return iterator(*
this, std::move(info));
370 template <
class Key,
class... Policies>
371 template <
class... Args>
373 auto result = emplace_or_get(std::forward<Args>(args)...);
374 return result.second;
377 template <
class Key,
class... Policies>
378 template <
class... Args>
380 node* n =
new node(std::forward<Args>(args)...);
381 find_info info{&head};
384 if (find(n->key, info, backoff)) {
386 return {iterator(*
this, std::move(info)),
false};
390 marked_ptr expected = info.cur.get();
391 n->next.store(expected, std::memory_order_relaxed);
392 guard_ptr new_guard(n);
397 if (info.prev->compare_exchange_weak(expected, n, std::memory_order_release, std::memory_order_relaxed)) {
398 info.cur = std::move(new_guard);
399 return {iterator(*
this, std::move(info)),
true};
406 template <
class Key,
class... Policies>
409 find_info info{&head};
412 if (!find(key, info, backoff)) {
418 if (info.cur->next.compare_exchange_weak(
419 info.next, marked_ptr(info.next.get(), 1), std::memory_order_acquire, std::memory_order_relaxed)) {
426 assert(info.next.mark() == 0);
427 assert(info.cur.mark() == 0);
430 marked_ptr expected = info.cur;
434 if (info.prev->compare_exchange_weak(expected, info.next, std::memory_order_release, std::memory_order_relaxed)) {
438 find(key, info, backoff);
444 template <
class Key,
class... Policies>
448 auto next = pos.info.cur->next.load(std::memory_order_acquire);
449 while (next.mark() == 0) {
452 if (pos.info.cur->next.compare_exchange_weak(next, marked_ptr(next.get(), 1), std::memory_order_acquire)) {
459 guard_ptr next_guard(next.get());
460 assert(pos.info.cur.mark() == 0);
463 marked_ptr expected = pos.info.cur;
467 if (pos.info.prev->compare_exchange_weak(
468 expected, next_guard, std::memory_order_release, std::memory_order_relaxed)) {
469 pos.info.cur.reclaim();
470 pos.info.cur = std::move(next_guard);
473 Key key = pos.info.cur->key;
476 find(key, pos.info, backoff);
482 template <
class Key,
class... Policies>
487 template <
class Key,
class... Policies>