Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:12:45

0001 /*
0002     Copyright (c) 2019-2020 Intel Corporation
0003 
0004     Licensed under the Apache License, Version 2.0 (the "License");
0005     you may not use this file except in compliance with the License.
0006     You may obtain a copy of the License at
0007 
0008         http://www.apache.org/licenses/LICENSE-2.0
0009 
0010     Unless required by applicable law or agreed to in writing, software
0011     distributed under the License is distributed on an "AS IS" BASIS,
0012     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013     See the License for the specific language governing permissions and
0014     limitations under the License.
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) // warning 4189 -- local variable is initialized but not referenced
0048 #pragma warning(disable: 4127) // warning 4127 -- while (true) has a constant expression in it
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     /** @return number of layers */
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     // TODO: the code above does not compile in VS2015 (seems like a bug) - consider enabling it for all other platforms
0159     // template <typename T = void, typename = typename std::enable_if<is_const, T>::type>
0160     // skip_list_iterator(const skip_list_iterator<node_type, false>& other) : my_node_ptr(other.my_node_ptr) {}
0161 
0162     // skip_list_iterator(const skip_list_iterator& other) : my_node_ptr(other.my_node_ptr) {}
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, /*is_const=*/false>;
0233     using const_iterator = skip_list_iterator<list_node_type, /*is_const=*/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      * Default constructor. Construct empty skip list.
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     /** Copy constructor */
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         // Ignore hint
0363         return insert(value).first;
0364     }
0365 
0366     iterator insert(const_iterator, value_type&& value) {
0367         // Ignore hint
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         // Ignore hint
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         // Ignore hint
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) { // node was extracted
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     }; // class const_range_type
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     }; // class range_type
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      * Finds position on the @param level using @param cmp
0714      * @param level - on which level search prev node
0715      * @param prev - pointer to the start node to search
0716      * @param key - key to search
0717      * @param cmp - callable object to compare two objects
0718      *  (my_compare member is default comparator)
0719      * @returns pointer to the node which is not satisfy the comparison with @param key
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                 // TODO: do we really need to wait?
0798                 while (!next->fully_linked()) {
0799                     // TODO: atomic backoff
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     // Returns node_ptr to the extracted node and node_ptr to the next node after the extracted
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                 //If the insertion fails - return the node into source
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     /** Generate random level */
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     /** Creates new node */
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         // TODO: investigate linkage fail in debug without this workaround
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         // Destroy value
1009         if (!is_dummy) node_allocator_traits::destroy(my_node_allocator, node->storage());
1010         // Destroy node
1011         node_allocator_traits::destroy(my_node_allocator, node);
1012         // Deallocate memory
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, /*POCMA=*/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, /*POCMA=*/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 }; // class concurrent_skip_list
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 } // namespace internal
1082 } // namespace interface10
1083 } // namespace tbb
1084 
1085 #endif // __TBB_concurrent_skip_list_H