File indexing completed on 2025-01-18 10:12:45
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef __TBB_concurrent_skip_list_H
0018 #define __TBB_concurrent_skip_list_H
0019
0020 #if !defined(__TBB_concurrent_map_H) && !defined(__TBB_concurrent_set_H)
0021 #error Do not #include this internal file directly; use public TBB headers instead.
0022 #endif
0023
0024 #include "../tbb_config.h"
0025 #include "../tbb_stddef.h"
0026 #include "../tbb_allocator.h"
0027 #include "../spin_mutex.h"
0028 #include "../tbb_exception.h"
0029 #include "../enumerable_thread_specific.h"
0030 #include "_allocator_traits.h"
0031 #include "_template_helpers.h"
0032 #include "_node_handle_impl.h"
0033 #include <utility> // Need std::pair
0034 #include <functional>
0035 #include <initializer_list>
0036 #include <memory> // Need std::allocator_traits
0037 #include <atomic>
0038 #include <mutex>
0039 #include <vector>
0040 #include <array>
0041 #include <type_traits>
0042 #include <cstdlib>
0043 #include <random>
0044 #include <tuple>
0045
0046 #if _MSC_VER
0047 #pragma warning(disable: 4189)
0048 #pragma warning(disable: 4127)
0049 #endif
0050
0051 namespace tbb {
0052 namespace interface10 {
0053 namespace internal {
0054
0055 template <typename Value, typename Mutex>
0056 class skip_list_node {
0057
0058 public:
0059 using value_type = Value;
0060 using size_type = std::size_t;
0061 using reference = value_type & ;
0062 using const_reference = const value_type & ;
0063 using pointer = value_type * ;
0064 using const_pointer = const value_type *;
0065 using node_pointer = skip_list_node * ;
0066 using atomic_node_pointer = std::atomic<node_pointer>;
0067
0068 using mutex_type = Mutex;
0069 using lock_type = std::unique_lock<mutex_type>;
0070
0071 skip_list_node(size_type levels) : my_height(levels), my_fullyLinked(false) {
0072 for (size_type lev = 0; lev < my_height; ++lev)
0073 new(&my_next(lev)) atomic_node_pointer(nullptr);
0074 __TBB_ASSERT(height() == levels, "Wrong node height");
0075 }
0076
0077 ~skip_list_node() {
0078 for(size_type lev = 0; lev < my_height; ++lev)
0079 my_next(lev).~atomic();
0080 }
0081
0082 skip_list_node(const skip_list_node&) = delete;
0083
0084 skip_list_node(skip_list_node&&) = delete;
0085
0086 skip_list_node& operator=(const skip_list_node&) = delete;
0087
0088 pointer storage() {
0089 return reinterpret_cast<pointer>(&my_val);
0090 }
0091
0092 reference value() {
0093 return *storage();
0094 }
0095
0096 node_pointer next(size_type level) const {
0097 __TBB_ASSERT(level < height(), "Cannot get next on the level greater than height");
0098 return my_next(level).load(std::memory_order_acquire);
0099 }
0100
0101 void set_next(size_type level, node_pointer next) {
0102 __TBB_ASSERT(level < height(), "Cannot set next on the level greater than height");
0103
0104 my_next(level).store(next, std::memory_order_release);
0105 }
0106
0107
0108 size_type height() const {
0109 return my_height;
0110 }
0111
0112 bool fully_linked() const {
0113 return my_fullyLinked.load(std::memory_order_acquire);
0114 }
0115
0116 void mark_linked() {
0117 my_fullyLinked.store(true, std::memory_order_release);
0118 }
0119
0120 lock_type acquire() {
0121 return lock_type(my_mutex);
0122 }
0123
0124 private:
0125 using aligned_storage_type = typename std::aligned_storage<sizeof(value_type), alignof(value_type)>::type;
0126
0127 atomic_node_pointer& my_next(size_type level) {
0128 atomic_node_pointer* arr = reinterpret_cast<atomic_node_pointer*>(this + 1);
0129 return arr[level];
0130 }
0131
0132 const atomic_node_pointer& my_next(size_type level) const {
0133 const atomic_node_pointer* arr = reinterpret_cast<const atomic_node_pointer*>(this + 1);
0134 return arr[level];
0135 }
0136
0137 mutex_type my_mutex;
0138 aligned_storage_type my_val;
0139 size_type my_height;
0140 std::atomic_bool my_fullyLinked;
0141 };
0142
0143 template <typename NodeType, bool is_const>
0144 class skip_list_iterator {
0145 using node_type = NodeType;
0146 using node_ptr = node_type*;
0147 public:
0148 using iterator_category = std::forward_iterator_tag;
0149 using value_type = typename node_type::value_type;
0150 using difference_type = std::ptrdiff_t;
0151 using pointer = typename std::conditional<is_const, typename node_type::const_pointer,
0152 typename node_type::pointer>::type;
0153 using reference = typename std::conditional<is_const, typename node_type::const_reference,
0154 typename node_type::reference>::type;
0155
0156 skip_list_iterator() : my_node_ptr(nullptr) {}
0157
0158
0159
0160
0161
0162
0163
0164 skip_list_iterator(const skip_list_iterator<node_type, false>& other) : my_node_ptr(other.my_node_ptr) {}
0165
0166 skip_list_iterator& operator=(const skip_list_iterator<node_type, false>& other) {
0167 my_node_ptr = other.my_node_ptr;
0168 return *this;
0169 }
0170
0171 template <typename T = void, typename = typename std::enable_if<is_const, T>::type>
0172 skip_list_iterator(const skip_list_iterator<node_type, true>& other) : my_node_ptr(other.my_node_ptr) {}
0173
0174 reference operator*() const { return *(my_node_ptr->storage()); }
0175 pointer operator->() const { return &**this; }
0176
0177 skip_list_iterator& operator++() {
0178 __TBB_ASSERT(my_node_ptr != nullptr, NULL);
0179 my_node_ptr = my_node_ptr->next(0);
0180 return *this;
0181 }
0182
0183 skip_list_iterator operator++(int) {
0184 skip_list_iterator tmp = *this;
0185 ++*this;
0186 return tmp;
0187 }
0188
0189 private:
0190 skip_list_iterator(node_type* n) : my_node_ptr(n) {}
0191
0192 node_ptr my_node_ptr;
0193
0194 template <typename Traits>
0195 friend class concurrent_skip_list;
0196
0197 friend class skip_list_iterator<NodeType, true>;
0198
0199 friend class const_range;
0200 friend class range;
0201
0202 template <typename T, bool M, bool U>
0203 friend bool operator==(const skip_list_iterator<T, M>&, const skip_list_iterator<T, U>&);
0204
0205 template <typename T, bool M, bool U>
0206 friend bool operator!=(const skip_list_iterator<T, M>&, const skip_list_iterator<T, U>&);
0207 };
0208
0209 template <typename NodeType, bool is_const1, bool is_const2>
0210 bool operator==(const skip_list_iterator<NodeType, is_const1>& lhs, const skip_list_iterator<NodeType, is_const2>& rhs) {
0211 return lhs.my_node_ptr == rhs.my_node_ptr;
0212 }
0213
0214 template <typename NodeType, bool is_const1, bool is_const2>
0215 bool operator!=(const skip_list_iterator<NodeType, is_const1>& lhs, const skip_list_iterator<NodeType, is_const2>& rhs) {
0216 return lhs.my_node_ptr != rhs.my_node_ptr;
0217 }
0218
0219 template <typename Traits>
0220 class concurrent_skip_list {
0221 protected:
0222 using traits_type = Traits;
0223 using allocator_type = typename traits_type::allocator_type;
0224 using allocator_traits_type = std::allocator_traits<allocator_type>;
0225 using key_compare = typename traits_type::compare_type;
0226 using value_compare = typename traits_type::value_compare;
0227 using key_type = typename traits_type::key_type;
0228 using value_type = typename traits_type::value_type;
0229 using node_type = typename traits_type::node_type;
0230 using list_node_type = skip_list_node<value_type, typename traits_type::mutex_type>;
0231
0232 using iterator = skip_list_iterator<list_node_type, false>;
0233 using const_iterator = skip_list_iterator<list_node_type, true>;
0234 using reverse_iterator = std::reverse_iterator<iterator>;
0235 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
0236
0237 using reference = value_type&;
0238 using const_reference = const value_type&;
0239 using pointer = typename allocator_traits_type::pointer;
0240 using const_pointer = typename allocator_traits_type::const_pointer;
0241 using size_type = std::size_t;
0242 using difference_type = std::ptrdiff_t;
0243
0244 using random_level_generator_type = typename traits_type::random_level_generator_type;
0245 using node_allocator_type = typename std::allocator_traits<allocator_type>::template rebind_alloc<uint8_t>;
0246 using node_allocator_traits = typename std::allocator_traits<allocator_type>::template rebind_traits<uint8_t>;
0247 using node_ptr = list_node_type*;
0248
0249 static constexpr size_type MAX_LEVEL = traits_type::MAX_LEVEL;
0250
0251 using array_type = std::array<node_ptr, MAX_LEVEL>;
0252 using lock_array = std::array<typename list_node_type::lock_type, MAX_LEVEL>;
0253
0254 public:
0255 static bool const allow_multimapping = traits_type::allow_multimapping;
0256
0257
0258
0259
0260 concurrent_skip_list() : my_size(0) {
0261 create_dummy_head();
0262 }
0263
0264 explicit concurrent_skip_list(const key_compare& comp, const allocator_type& alloc = allocator_type())
0265 : my_node_allocator(alloc), my_compare(comp), my_size(0)
0266 {
0267 create_dummy_head();
0268 }
0269
0270 template<class InputIt>
0271 concurrent_skip_list(InputIt first, InputIt last, const key_compare& comp = key_compare(),
0272 const allocator_type& alloc = allocator_type())
0273 : my_node_allocator(alloc), my_compare(comp), my_size(0)
0274 {
0275 create_dummy_head();
0276 internal_copy(first, last);
0277 }
0278
0279
0280 concurrent_skip_list(const concurrent_skip_list& other)
0281 : my_node_allocator(node_allocator_traits::select_on_container_copy_construction(other.get_allocator())),
0282 my_compare(other.my_compare), my_rnd_generator(other.my_rnd_generator), my_size(0)
0283 {
0284 create_dummy_head();
0285 internal_copy(other);
0286 __TBB_ASSERT(my_size == other.my_size, "Wrong size of copy-constructed container");
0287 }
0288
0289 concurrent_skip_list(const concurrent_skip_list& other, const allocator_type& alloc)
0290 : my_node_allocator(alloc), my_compare(other.my_compare),
0291 my_rnd_generator(other.my_rnd_generator), my_size(0)
0292 {
0293 create_dummy_head();
0294 internal_copy(other);
0295 __TBB_ASSERT(my_size == other.my_size, "Wrong size of copy-constructed container");
0296 }
0297
0298 concurrent_skip_list(concurrent_skip_list&& other)
0299 : my_node_allocator(std::move(other.my_node_allocator)), my_compare(other.my_compare),
0300 my_rnd_generator(other.my_rnd_generator)
0301 {
0302 internal_move(std::move(other));
0303 }
0304
0305 concurrent_skip_list(concurrent_skip_list&& other, const allocator_type& alloc)
0306 : my_node_allocator(alloc), my_compare(other.my_compare),
0307 my_rnd_generator(other.my_rnd_generator)
0308 {
0309 if (alloc == other.get_allocator()) {
0310 internal_move(std::move(other));
0311 } else {
0312 my_size = 0;
0313 create_dummy_head();
0314 internal_copy(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
0315 }
0316 }
0317
0318 ~concurrent_skip_list() {
0319 clear();
0320 delete_dummy_head();
0321 }
0322
0323 concurrent_skip_list& operator=(const concurrent_skip_list& other) {
0324 if (this != &other) {
0325 using pocca_type = typename node_allocator_traits::propagate_on_container_copy_assignment;
0326 clear();
0327 tbb::internal::allocator_copy_assignment(my_node_allocator, other.my_node_allocator, pocca_type());
0328 my_compare = other.my_compare;
0329 my_rnd_generator = other.my_rnd_generator;
0330 internal_copy(other);
0331 }
0332 return *this;
0333 }
0334
0335 concurrent_skip_list& operator=(concurrent_skip_list&& other) {
0336 if (this != &other) {
0337 using pocma_type = typename node_allocator_traits::propagate_on_container_move_assignment;
0338 clear();
0339 my_compare = other.my_compare;
0340 my_rnd_generator = other.my_rnd_generator;
0341 internal_move_assign(std::move(other), pocma_type());
0342 }
0343 return *this;
0344 }
0345
0346 concurrent_skip_list& operator=(std::initializer_list<value_type> il)
0347 {
0348 clear();
0349 insert(il.begin(),il.end());
0350 return *this;
0351 }
0352
0353 std::pair<iterator, bool> insert(const value_type& value) {
0354 return internal_insert(value);
0355 }
0356
0357 std::pair<iterator, bool> insert(value_type&& value) {
0358 return internal_insert(std::move(value));
0359 }
0360
0361 iterator insert(const_iterator, const_reference value) {
0362
0363 return insert(value).first;
0364 }
0365
0366 iterator insert(const_iterator, value_type&& value) {
0367
0368 return insert(std::move(value)).first;
0369 }
0370
0371 template<typename InputIterator>
0372 void insert(InputIterator first, InputIterator last) {
0373 for (InputIterator it = first; it != last; ++it)
0374 insert(*it);
0375 }
0376
0377 void insert(std::initializer_list<value_type> init) {
0378 insert(init.begin(), init.end());
0379 }
0380
0381 std::pair<iterator, bool> insert(node_type&& nh) {
0382 if(!nh.empty()) {
0383 std::pair<iterator, bool> insert_result = internal_insert_node(nh.my_node);
0384 if(insert_result.second) {
0385 nh.deactivate();
0386 }
0387 return insert_result;
0388 }
0389 return std::pair<iterator, bool>(end(), false);
0390 }
0391
0392 iterator insert(const_iterator, node_type&& nh) {
0393
0394 return insert(std::move(nh)).first;
0395 }
0396
0397 template<typename... Args >
0398 std::pair<iterator, bool> emplace(Args&&... args) {
0399 return internal_insert(std::forward<Args>(args)...);
0400 }
0401
0402 template<typename... Args>
0403 iterator emplace_hint(const_iterator, Args&&... args) {
0404
0405 return emplace(std::forward<Args>(args)...).first;
0406 }
0407
0408 iterator unsafe_erase(iterator pos) {
0409 std::pair<node_ptr, node_ptr> extract_result = internal_extract(pos);
0410 if(extract_result.first) {
0411 delete_node(extract_result.first);
0412 return iterator(extract_result.second);
0413 }
0414 return end();
0415 }
0416
0417 iterator unsafe_erase(const_iterator pos) {
0418 return unsafe_erase(get_iterator(pos));
0419 }
0420
0421 template <typename K, typename = tbb::internal::is_transparent<key_compare, K>,
0422 typename = typename std::enable_if<!std::is_convertible<K, iterator>::value &&
0423 !std::is_convertible<K, const_iterator>::value>::type>
0424 size_type unsafe_erase(const K& key) {
0425 std::pair<iterator, iterator> range = equal_range(key);
0426 size_type sz = std::distance(range.first, range.second);
0427 unsafe_erase(range.first, range.second);
0428 return sz;
0429 }
0430
0431 iterator unsafe_erase(const_iterator first, const_iterator last) {
0432 while(first != last) {
0433 first = unsafe_erase(get_iterator(first));
0434 }
0435 return get_iterator(first);
0436 }
0437
0438 size_type unsafe_erase(const key_type& key) {
0439 std::pair<iterator, iterator> range = equal_range(key);
0440 size_type sz = std::distance(range.first, range.second);
0441 unsafe_erase(range.first, range.second);
0442 return sz;
0443 }
0444
0445 node_type unsafe_extract(const_iterator pos) {
0446 std::pair<node_ptr, node_ptr> extract_result = internal_extract(pos);
0447 return extract_result.first ? node_type(extract_result.first) : node_type();
0448 }
0449
0450 node_type unsafe_extract(const key_type& key) {
0451 return unsafe_extract(find(key));
0452 }
0453
0454 iterator lower_bound(const key_type& key) {
0455 return internal_get_bound(key, my_compare);
0456 }
0457
0458 const_iterator lower_bound(const key_type& key) const {
0459 return internal_get_bound(key, my_compare);
0460 }
0461
0462 template <typename K, typename = typename tbb::internal::is_transparent<key_compare, K> >
0463 iterator lower_bound(const K& key) {
0464 return internal_get_bound(key, my_compare);
0465 }
0466
0467 template <typename K, typename = typename tbb::internal::is_transparent<key_compare, K> >
0468 const_iterator lower_bound(const K& key) const {
0469 return internal_get_bound(key, my_compare);
0470 }
0471
0472 iterator upper_bound(const key_type& key) {
0473 return internal_get_bound(key, not_greater_compare(my_compare));
0474 }
0475
0476 const_iterator upper_bound(const key_type& key) const {
0477 return internal_get_bound(key, not_greater_compare(my_compare));
0478 }
0479
0480 template <typename K, typename = typename tbb::internal::is_transparent<key_compare, K> >
0481 iterator upper_bound(const K& key) {
0482 return internal_get_bound(key, not_greater_compare(my_compare));
0483 }
0484
0485 template <typename K, typename = typename tbb::internal::is_transparent<key_compare, K> >
0486 const_iterator upper_bound(const K& key) const {
0487 return internal_get_bound(key, not_greater_compare(my_compare));
0488 }
0489
0490 iterator find(const key_type& key) {
0491 return internal_find(key);
0492 }
0493
0494 const_iterator find(const key_type& key) const {
0495 return internal_find(key);
0496 }
0497
0498 template <typename K, typename = typename tbb::internal::is_transparent<key_compare, K> >
0499 iterator find(const K& key) {
0500 return internal_find(key);
0501 }
0502
0503 template <typename K, typename = typename tbb::internal::is_transparent<key_compare, K> >
0504 const_iterator find(const K& key) const {
0505 return internal_find(key);
0506 }
0507
0508 size_type count( const key_type& key ) const {
0509 return internal_count(key);
0510 }
0511
0512 template <typename K, typename = typename tbb::internal::is_transparent<key_compare, K> >
0513 size_type count(const K& key) const {
0514 return internal_count(key);
0515 }
0516
0517 bool contains(const key_type& key) const {
0518 return find(key) != end();
0519 }
0520
0521 template <typename K, typename = typename tbb::internal::is_transparent<key_compare, K> >
0522 bool contains(const K& key) const {
0523 return find(key) != end();
0524 }
0525
0526 void clear() noexcept {
0527 __TBB_ASSERT(dummy_head->height() > 0, NULL);
0528
0529 node_ptr current = dummy_head->next(0);
0530 while (current) {
0531 __TBB_ASSERT(current->height() > 0, NULL);
0532 node_ptr next = current->next(0);
0533 delete_node(current);
0534 current = next;
0535 }
0536
0537 my_size = 0;
0538 for (size_type i = 0; i < dummy_head->height(); ++i) {
0539 dummy_head->set_next(i, nullptr);
0540 }
0541 }
0542
0543 iterator begin() {
0544 return iterator(dummy_head->next(0));
0545 }
0546
0547 const_iterator begin() const {
0548 return const_iterator(dummy_head->next(0));
0549 }
0550
0551 const_iterator cbegin() const {
0552 return const_iterator(dummy_head->next(0));
0553 }
0554
0555 iterator end() {
0556 return iterator(nullptr);
0557 }
0558
0559 const_iterator end() const {
0560 return const_iterator(nullptr);
0561 }
0562
0563 const_iterator cend() const {
0564 return const_iterator(nullptr);
0565 }
0566
0567 size_type size() const {
0568 return my_size.load(std::memory_order_relaxed);
0569 }
0570
0571 size_type max_size() const {
0572 return my_node_allocator.max_size();
0573 }
0574
0575 bool empty() const {
0576 return 0 == size();
0577 }
0578
0579 allocator_type get_allocator() const {
0580 return my_node_allocator;
0581 }
0582
0583 void swap(concurrent_skip_list& other) {
0584 using std::swap;
0585 using pocs_type = typename node_allocator_traits::propagate_on_container_swap;
0586 tbb::internal::allocator_swap(my_node_allocator, other.my_node_allocator, pocs_type());
0587 swap(my_compare, other.my_compare);
0588 swap(my_rnd_generator, other.my_rnd_generator);
0589 swap(dummy_head, other.dummy_head);
0590
0591 size_type tmp = my_size;
0592 my_size.store(other.my_size);
0593 other.my_size.store(tmp);
0594 }
0595
0596 std::pair<iterator, iterator> equal_range(const key_type& key) {
0597 return std::pair<iterator, iterator>(lower_bound(key), upper_bound(key));
0598 }
0599
0600 std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
0601 return std::pair<const_iterator, const_iterator>(lower_bound(key), upper_bound(key));
0602 }
0603
0604 template <typename K, typename = typename tbb::internal::is_transparent<key_compare, K> >
0605 std::pair<iterator, iterator> equal_range(const K& key) {
0606 return std::pair<iterator, iterator>(lower_bound(key), upper_bound(key));
0607 }
0608
0609 template <typename K, typename = typename tbb::internal::is_transparent<key_compare, K> >
0610 std::pair<const_iterator, const_iterator> equal_range(const K& key) const {
0611 return std::pair<const_iterator, const_iterator>(lower_bound(key), upper_bound(key));
0612 }
0613
0614 key_compare key_comp() const { return my_compare; }
0615
0616 value_compare value_comp() const { return traits_type::value_comp(my_compare); }
0617
0618 class const_range_type : tbb::internal::no_assign {
0619 public:
0620 using size_type = typename concurrent_skip_list::size_type;
0621 using value_type = typename concurrent_skip_list::value_type;
0622 using iterator = typename concurrent_skip_list::const_iterator;
0623 private:
0624 const_iterator my_end;
0625 const_iterator my_begin;
0626 size_type my_level;
0627
0628 public:
0629
0630 bool empty() const {
0631 return my_begin.my_node_ptr->next(0) == my_end.my_node_ptr;
0632 }
0633
0634 bool is_divisible() const {
0635 return my_level != 0 ? my_begin.my_node_ptr->next(my_level - 1) != my_end.my_node_ptr : false;
0636 }
0637
0638 size_type size() const { return std::distance(my_begin, my_end);}
0639
0640 const_range_type( const_range_type& r, split)
0641 : my_end(r.my_end) {
0642 my_begin = iterator(r.my_begin.my_node_ptr->next(r.my_level - 1));
0643 my_level = my_begin.my_node_ptr->height();
0644 r.my_end = my_begin;
0645 }
0646
0647 const_range_type( const concurrent_skip_list& l)
0648 : my_end(l.end()), my_begin(l.begin()), my_level(my_begin.my_node_ptr->height() ) {}
0649
0650 iterator begin() const { return my_begin; }
0651 iterator end() const { return my_end; }
0652 size_t grainsize() const { return 1; }
0653
0654 };
0655
0656 class range_type : public const_range_type {
0657 public:
0658 using iterator = typename concurrent_skip_list::iterator;
0659
0660 range_type(range_type& r, split) : const_range_type(r, split()) {}
0661 range_type(const concurrent_skip_list& l) : const_range_type(l) {}
0662
0663 iterator begin() const {
0664 node_ptr node = const_range_type::begin().my_node_ptr;
0665 return iterator(node);
0666 }
0667
0668 iterator end() const {
0669 node_ptr node = const_range_type::end().my_node_ptr;
0670 return iterator(node); }
0671 };
0672
0673 range_type range() { return range_type(*this); }
0674 const_range_type range() const { return const_range_type(*this); }
0675
0676 private:
0677 void internal_move(concurrent_skip_list&& other) {
0678 dummy_head = other.dummy_head;
0679 other.dummy_head = nullptr;
0680 other.create_dummy_head();
0681
0682 my_size = other.my_size.load();
0683 other.my_size = 0;
0684 }
0685
0686 static const key_type& get_key(node_ptr n) {
0687 __TBB_ASSERT(n, NULL);
0688 return traits_type::get_key(n->value());
0689 }
0690
0691 template <typename K>
0692 iterator internal_find(const K& key) {
0693 iterator it = lower_bound(key);
0694 return (it == end() || my_compare(key, traits_type::get_key(*it))) ? end() : it;
0695 }
0696
0697 template <typename K>
0698 const_iterator internal_find(const K& key) const {
0699 const_iterator it = lower_bound(key);
0700 return (it == end() || my_compare(key, traits_type::get_key(*it))) ? end() : it;
0701 }
0702
0703 template <typename K>
0704 size_type internal_count( const K& key ) const {
0705 if (allow_multimapping) {
0706 std::pair<const_iterator, const_iterator> range = equal_range(key);
0707 return std::distance(range.first, range.second);
0708 }
0709 return (find(key) == end()) ? size_type(0) : size_type(1);
0710 }
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720
0721 template <typename K, typename pointer_type, typename comparator>
0722 pointer_type internal_find_position( size_type level, pointer_type& prev, const K& key,
0723 const comparator& cmp) const {
0724 __TBB_ASSERT(level < prev->height(), "Wrong level to find position");
0725 pointer_type curr = prev->next(level);
0726
0727 while (curr && cmp(get_key(curr), key)) {
0728 prev = curr;
0729 __TBB_ASSERT(level < prev->height(), NULL);
0730 curr = prev->next(level);
0731 }
0732
0733 return curr;
0734 }
0735
0736 template <typename comparator>
0737 void fill_prev_next_arrays(array_type& prev_nodes, array_type& next_nodes, node_ptr prev, const key_type& key,
0738 const comparator& cmp) {
0739 prev_nodes.fill(dummy_head);
0740 next_nodes.fill(nullptr);
0741
0742 for (size_type h = prev->height(); h > 0; --h) {
0743 node_ptr next = internal_find_position(h - 1, prev, key, cmp);
0744 prev_nodes[h - 1] = prev;
0745 next_nodes[h - 1] = next;
0746 }
0747 }
0748
0749 template <typename comparator>
0750 void fill_prev_next_by_ptr(array_type& prev_nodes, array_type& next_nodes, const_iterator it, const key_type& key,
0751 const comparator& cmp) {
0752 node_ptr prev = dummy_head;
0753 node_ptr erase_node = it.my_node_ptr;
0754 size_type node_height = erase_node->height();
0755
0756 for (size_type h = prev->height(); h >= node_height; --h) {
0757 internal_find_position(h - 1, prev, key, cmp);
0758 }
0759
0760 for (size_type h = node_height; h > 0; --h) {
0761 node_ptr curr = prev->next(h - 1);
0762 while (const_iterator(curr) != it) {
0763 prev = curr;
0764 curr = prev->next(h - 1);
0765 }
0766 prev_nodes[h - 1] = prev;
0767 }
0768
0769 std::fill(next_nodes.begin(), next_nodes.begin() + node_height, erase_node);
0770 }
0771
0772 template<typename... Args>
0773 std::pair<iterator, bool> internal_insert(Args&&... args) {
0774 node_ptr new_node = create_node(std::forward<Args>(args)...);
0775 std::pair<iterator, bool> insert_result = internal_insert_node(new_node);
0776 if(!insert_result.second) {
0777 delete_node(new_node);
0778 }
0779 return insert_result;
0780 }
0781
0782 std::pair<iterator, bool> internal_insert_node(node_ptr new_node) {
0783 array_type prev_nodes;
0784 array_type next_nodes;
0785 __TBB_ASSERT(dummy_head->height() >= new_node->height(), "Wrong height for new node");
0786
0787 do {
0788 if (allow_multimapping) {
0789 fill_prev_next_arrays(prev_nodes, next_nodes, dummy_head, get_key(new_node),
0790 not_greater_compare(my_compare));
0791 } else {
0792 fill_prev_next_arrays(prev_nodes, next_nodes, dummy_head, get_key(new_node), my_compare);
0793 }
0794
0795 node_ptr next = next_nodes[0];
0796 if (next && !allow_multimapping && !my_compare(get_key(new_node), get_key(next))) {
0797
0798 while (!next->fully_linked()) {
0799
0800 }
0801
0802 return std::pair<iterator, bool>(iterator(next), false);
0803 }
0804 __TBB_ASSERT(allow_multimapping || !next || my_compare(get_key(new_node), get_key(next)),
0805 "Wrong elements order");
0806
0807 } while (!try_insert_node(new_node, prev_nodes, next_nodes));
0808
0809 __TBB_ASSERT(new_node, NULL);
0810 return std::pair<iterator, bool>(iterator(new_node), true);
0811 }
0812
0813 bool try_insert_node(node_ptr new_node, array_type& prev_nodes, array_type& next_nodes) {
0814 __TBB_ASSERT(dummy_head->height() >= new_node->height(), NULL);
0815
0816 lock_array locks;
0817
0818 if (!try_lock_nodes(new_node->height(), prev_nodes, next_nodes, locks)) {
0819 return false;
0820 }
0821
0822 __TBB_ASSERT(allow_multimapping ||
0823 ((prev_nodes[0] == dummy_head ||
0824 my_compare(get_key(prev_nodes[0]), get_key(new_node))) &&
0825 (next_nodes[0] == nullptr || my_compare(get_key(new_node), get_key(next_nodes[0])))),
0826 "Wrong elements order");
0827
0828 for (size_type level = 0; level < new_node->height(); ++level) {
0829 __TBB_ASSERT(prev_nodes[level]->height() > level, NULL);
0830 __TBB_ASSERT(prev_nodes[level]->next(level) == next_nodes[level], NULL);
0831 new_node->set_next(level, next_nodes[level]);
0832 prev_nodes[level]->set_next(level, new_node);
0833 }
0834 new_node->mark_linked();
0835
0836 ++my_size;
0837
0838 return true;
0839 }
0840
0841 bool try_lock_nodes(size_type height, array_type& prevs, array_type& next_nodes, lock_array& locks) {
0842 for (size_type l = 0; l < height; ++l) {
0843 if (l == 0 || prevs[l] != prevs[l - 1])
0844 locks[l] = prevs[l]->acquire();
0845
0846 node_ptr next = prevs[l]->next(l);
0847 if ( next != next_nodes[l]) return false;
0848 }
0849
0850 return true;
0851 }
0852
0853 template <typename K, typename comparator>
0854 const_iterator internal_get_bound(const K& key, const comparator& cmp) const {
0855 node_ptr prev = dummy_head;
0856 __TBB_ASSERT(dummy_head->height() > 0, NULL);
0857 node_ptr next = nullptr;
0858
0859 for (size_type h = prev->height(); h > 0; --h) {
0860 next = internal_find_position(h - 1, prev, key, cmp);
0861 }
0862
0863 return const_iterator(next);
0864 }
0865
0866 template <typename K, typename comparator>
0867 iterator internal_get_bound(const K& key, const comparator& cmp){
0868 node_ptr prev = dummy_head;
0869 __TBB_ASSERT(dummy_head->height() > 0, NULL);
0870 node_ptr next = nullptr;
0871
0872 for (size_type h = prev->height(); h > 0; --h) {
0873 next = internal_find_position(h - 1, prev, key, cmp);
0874 }
0875
0876 return iterator(next);
0877 }
0878
0879
0880 std::pair<node_ptr, node_ptr> internal_extract(const_iterator it) {
0881 if ( it != end() ) {
0882 key_type key = traits_type::get_key(*it);
0883 __TBB_ASSERT(dummy_head->height() > 0, NULL);
0884
0885 array_type prev_nodes;
0886 array_type next_nodes;
0887
0888 fill_prev_next_by_ptr(prev_nodes, next_nodes, it, key, my_compare);
0889
0890 node_ptr erase_node = next_nodes[0];
0891 __TBB_ASSERT(erase_node != nullptr, NULL);
0892 node_ptr next_node = erase_node->next(0);
0893
0894 if (!my_compare(key, get_key(erase_node))) {
0895 for(size_type level = 0; level < erase_node->height(); ++level) {
0896 __TBB_ASSERT(prev_nodes[level]->height() > level, NULL);
0897 __TBB_ASSERT(next_nodes[level] == erase_node, NULL);
0898 prev_nodes[level]->set_next(level, erase_node->next(level));
0899 }
0900 --my_size;
0901 return std::pair<node_ptr, node_ptr>(erase_node, next_node);
0902 }
0903 }
0904 return std::pair<node_ptr, node_ptr>(nullptr, nullptr);
0905 }
0906
0907 protected:
0908 template<typename SourceType>
0909 void internal_merge(SourceType&& source) {
0910 using source_type = typename std::decay<SourceType>::type;
0911 using source_iterator = typename source_type::iterator;
0912 __TBB_STATIC_ASSERT((std::is_same<node_type, typename source_type::node_type>::value), "Incompatible containers cannot be merged");
0913
0914 for(source_iterator it = source.begin(); it != source.end();) {
0915 source_iterator where = it++;
0916 if (allow_multimapping || !contains(traits_type::get_key(*where))) {
0917 std::pair<node_ptr, node_ptr> extract_result = source.internal_extract(where);
0918
0919
0920 node_type handle(extract_result.first);
0921 __TBB_ASSERT(!handle.empty(), "Extracted handle in merge is empty");
0922
0923 if (!insert(std::move(handle)).second) {
0924 source.insert(std::move(handle));
0925 }
0926 handle.deactivate();
0927 }
0928 }
0929 }
0930
0931 private:
0932 void internal_copy(const concurrent_skip_list& other) {
0933 internal_copy(other.begin(), other.end());
0934 }
0935
0936 template<typename Iterator>
0937 void internal_copy(Iterator first, Iterator last) {
0938 clear();
0939 try {
0940 for (auto it = first; it != last; ++it)
0941 insert(*it);
0942 }
0943 catch (...) {
0944 clear();
0945 delete_dummy_head();
0946 throw;
0947 }
0948 }
0949
0950
0951 size_type random_level() {
0952 return my_rnd_generator();
0953 }
0954
0955 static size_type calc_node_size(size_type height) {
0956 return sizeof(list_node_type) + height*sizeof(typename list_node_type::atomic_node_pointer);
0957 }
0958
0959
0960 template <typename... Args>
0961 node_ptr create_node(Args&&... args) {
0962 size_type levels = random_level();
0963
0964 size_type sz = calc_node_size(levels);
0965
0966 node_ptr node = reinterpret_cast<node_ptr>(node_allocator_traits::allocate(my_node_allocator, sz));
0967
0968 try {
0969 node_allocator_traits::construct(my_node_allocator, node, levels);
0970
0971 }
0972 catch(...) {
0973 deallocate_node(node, sz);
0974 throw;
0975 }
0976
0977 try {
0978 node_allocator_traits::construct(my_node_allocator, node->storage(), std::forward<Args>(args)...);
0979 }
0980 catch (...) {
0981 node_allocator_traits::destroy(my_node_allocator, node);
0982 deallocate_node(node, sz);
0983 throw;
0984 }
0985
0986 return node;
0987 }
0988
0989 void create_dummy_head() {
0990 size_type sz = calc_node_size(MAX_LEVEL);
0991
0992 dummy_head = reinterpret_cast<node_ptr>(node_allocator_traits::allocate(my_node_allocator, sz));
0993
0994 auto max_level = MAX_LEVEL;
0995
0996 try {
0997 node_allocator_traits::construct(my_node_allocator, dummy_head, max_level);
0998 }
0999 catch(...) {
1000 deallocate_node(dummy_head, sz);
1001 throw;
1002 }
1003 }
1004
1005 template <bool is_dummy = false>
1006 void delete_node(node_ptr node) {
1007 size_type sz = calc_node_size(node->height());
1008
1009 if (!is_dummy) node_allocator_traits::destroy(my_node_allocator, node->storage());
1010
1011 node_allocator_traits::destroy(my_node_allocator, node);
1012
1013 deallocate_node(node, sz);
1014 }
1015
1016 void deallocate_node(node_ptr node, size_type sz) {
1017 node_allocator_traits::deallocate(my_node_allocator, reinterpret_cast<uint8_t*>(node), sz);
1018 }
1019
1020 void delete_dummy_head() {
1021 delete_node<true>(dummy_head);
1022 }
1023
1024 static iterator get_iterator(const_iterator it) {
1025 return iterator(it.my_node_ptr);
1026 }
1027
1028 void internal_move_assign(concurrent_skip_list&& other, std::true_type) {
1029 delete_dummy_head();
1030 tbb::internal::allocator_move_assignment(my_node_allocator, other.my_node_allocator, std::true_type());
1031 internal_move(std::move(other));
1032 }
1033
1034 void internal_move_assign(concurrent_skip_list&& other, std::false_type) {
1035 if (my_node_allocator == other.my_node_allocator) {
1036 delete_dummy_head();
1037 internal_move(std::move(other));
1038 } else {
1039 internal_copy(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
1040 }
1041 }
1042
1043 struct not_greater_compare {
1044 const key_compare& my_less_compare;
1045
1046 not_greater_compare(const key_compare& less_compare) : my_less_compare(less_compare) {}
1047
1048 template <typename K1, typename K2>
1049 bool operator()(const K1& first, const K2& second) const {
1050 return !my_less_compare(second, first);
1051 }
1052 };
1053
1054 node_allocator_type my_node_allocator;
1055 key_compare my_compare;
1056 random_level_generator_type my_rnd_generator;
1057 node_ptr dummy_head;
1058
1059 template<typename OtherTraits>
1060 friend class concurrent_skip_list;
1061
1062 std::atomic<size_type> my_size;
1063 };
1064
1065 template <size_t MAX_LEVEL>
1066 class concurrent_geometric_level_generator {
1067 public:
1068 static constexpr size_t max_level = MAX_LEVEL;
1069
1070 concurrent_geometric_level_generator() : engines(time(NULL)) {}
1071
1072 size_t operator()() {
1073 return (distribution(engines.local()) % MAX_LEVEL) + 1;
1074 }
1075
1076 private:
1077 tbb::enumerable_thread_specific<std::mt19937_64> engines;
1078 std::geometric_distribution<size_t> distribution;
1079 };
1080
1081 }
1082 }
1083 }
1084
1085 #endif