1 /*
2     Copyright (c) 2019-2021 Intel Corporation
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 __TBB_detail__concurrent_skip_list_H
18 #define __TBB_detail__concurrent_skip_list_H
19 
20 #if !defined(__TBB_concurrent_map_H) && !defined(__TBB_concurrent_set_H)
21 #error Do not #include this internal file directly; use public TBB headers instead.
22 #endif
23 
24 #include "_config.h"
25 #include "_range_common.h"
26 #include "_allocator_traits.h"
27 #include "_template_helpers.h"
28 #include "_node_handle.h"
29 #include "_containers_helpers.h"
30 #include "_assert.h"
31 #include "_exception.h"
32 #include "../enumerable_thread_specific.h"
33 #include <utility>
34 #include <initializer_list>
35 #include <atomic>
36 #include <array>
37 #include <type_traits>
38 #include <random> // Need std::geometric_distribution
39 #include <algorithm> // Need std::equal and std::lexicographical_compare
40 #include <cstdint>
41 #if __TBB_CPP20_COMPARISONS_PRESENT
42 #include <compare>
43 #endif
44 
45 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
46 #pragma warning(push)
47 #pragma warning(disable: 4127) // warning C4127: conditional expression is constant
48 #endif
49 
50 namespace tbb {
51 namespace detail {
52 namespace d2 {
53 
54 template <typename Value, typename Allocator>
55 class skip_list_node {
56     using node_ptr = skip_list_node*;
57 public:
58     using value_type = Value;
59     using atomic_node_ptr = std::atomic<node_ptr>;
60     using size_type = std::size_t;
61     using container_allocator_type = Allocator;
62 
63     using reference = value_type&;
64     using const_reference = const value_type&;
65 private:
66     using allocator_traits = tbb::detail::allocator_traits<container_allocator_type>;
67 
68     // Allocator is the same as the container allocator=> allocates unitptr_t
69     // It is required to rebind it to value_type to get the correct pointer and const_pointer
70     using value_allocator_traits = typename allocator_traits::template rebind_traits<value_type>;
71 public:
72     using pointer = typename value_allocator_traits::pointer;
73     using const_pointer = typename value_allocator_traits::const_pointer;
74 
75     //In perfect world these constructor and destructor would have been private,
76     //however this seems technically impractical due to use of allocator_traits.
77 
78     //Should not be called directly, instead use create method
79     skip_list_node( size_type levels )
80         : my_height(levels), my_index_number(0)
81     {}
82 
83     //Should not be called directly, instead use destroy method
84     ~skip_list_node() {}
85 
86     skip_list_node( const skip_list_node& ) = delete;
87     skip_list_node( skip_list_node&& ) = delete;
88     skip_list_node& operator=( const skip_list_node& ) = delete;
89     skip_list_node& operator=( skip_list_node&& ) = delete;
90 
91     static skip_list_node* create( container_allocator_type& alloc, size_type height ) {
92         size_type sz = calc_node_size(height);
93         static_assert(std::is_same<typename allocator_traits::value_type, std::uint8_t>::value, "skip_list_node assumes that passed in allocator operates on bytes");
94         auto* node = reinterpret_cast<skip_list_node*>(allocator_traits::allocate(alloc, sz));
95 
96         //Construct the node itself
97         allocator_traits::construct(alloc, node, height);
98 
99         //Construct the level pointers
100         for (size_type l = 0; l < height; ++l) {
101             allocator_traits::construct(alloc, &node->get_atomic_next(l), nullptr);
102         }
103 
104         return node;
105     }
106 
107     static void destroy( container_allocator_type& alloc, skip_list_node* node ) {
108         //Destroy the level pointers
109         for (size_type l = 0; l < node->height(); ++l) {
110             allocator_traits::destroy(alloc, &node->atomic_next(l));
111         }
112         size_type sz = calc_node_size(node->height());
113         // Destroy the node itself
114         allocator_traits::destroy(alloc, node);
115 
116         // Deallocate the node
117         allocator_traits::deallocate(alloc, reinterpret_cast<std::uint8_t*>(node), sz);
118     }
119 
120 
121     pointer storage() {
122         return &my_value;
123     }
124 
125     reference value() {
126         return *storage();
127     }
128 
129     node_ptr next( size_type level ) const {
130         node_ptr res = get_atomic_next(level).load(std::memory_order_acquire);
131         __TBB_ASSERT(res == nullptr || res->height() > level, "Broken internal structure");
132         return res;
133     }
134 
135     atomic_node_ptr& atomic_next( size_type level ) {
136         atomic_node_ptr& res = get_atomic_next(level);
137 #if TBB_USE_DEBUG
138         node_ptr node = res.load(std::memory_order_acquire);
139         __TBB_ASSERT(node == nullptr || node->height() > level, "Broken internal structure");
140 #endif
141         return res;
142     }
143 
144     void set_next( size_type level, node_ptr n ) {
145         __TBB_ASSERT(n == nullptr || n->height() > level, "Broken internal structure");
146         get_atomic_next(level).store(n, std::memory_order_relaxed);
147     }
148 
149     size_type height() const {
150         return my_height;
151     }
152 
153     void set_index_number( size_type index_num ) {
154         my_index_number = index_num;
155     }
156 
157     size_type index_number() const {
158         return my_index_number;
159     }
160 
161 private:
162     static size_type calc_node_size( size_type height ) {
163         static_assert(alignof(skip_list_node) >= alignof(atomic_node_ptr), "Incorrect alignment");
164         return sizeof(skip_list_node) + height * sizeof(atomic_node_ptr);
165     }
166 
167     atomic_node_ptr& get_atomic_next( size_type level ) {
168         atomic_node_ptr* arr = reinterpret_cast<atomic_node_ptr*>(this + 1);
169         return arr[level];
170     }
171 
172     const atomic_node_ptr& get_atomic_next( size_type level ) const {
173         const atomic_node_ptr* arr = reinterpret_cast<const atomic_node_ptr*>(this + 1);
174         return arr[level];
175     }
176 
177     union {
178         value_type my_value;
179     };
180     size_type my_height;
181     size_type my_index_number;
182 }; // class skip_list_node
183 
184 template <typename NodeType, typename ValueType>
185 class skip_list_iterator {
186     using node_type = NodeType;
187     using node_ptr = node_type*;
188 public:
189     using iterator_category = std::forward_iterator_tag;
190     using value_type = ValueType;
191 
192     using difference_type = std::ptrdiff_t;
193     using pointer = value_type*;
194     using reference = value_type&;
195 
196     skip_list_iterator() : skip_list_iterator(nullptr) {}
197 
198     skip_list_iterator( const skip_list_iterator<node_type, typename node_type::value_type>& other )
199         : my_node_ptr(other.my_node_ptr) {}
200 
201     skip_list_iterator& operator=( const skip_list_iterator<node_type, typename node_type::value_type>& other ) {
202         my_node_ptr = other.my_node_ptr;
203         return *this;
204     }
205 
206     reference operator*() const { return my_node_ptr->value(); }
207     pointer operator->() const { return my_node_ptr->storage(); }
208 
209     skip_list_iterator& operator++() {
210         __TBB_ASSERT(my_node_ptr != nullptr, nullptr);
211         my_node_ptr = my_node_ptr->next(0);
212         return *this;
213     }
214 
215     skip_list_iterator operator++(int) {
216         skip_list_iterator tmp = *this;
217         ++*this;
218         return tmp;
219     }
220 
221 private:
222     skip_list_iterator(node_type* n) : my_node_ptr(n) {}
223 
224     node_ptr my_node_ptr;
225 
226     template <typename Traits>
227     friend class concurrent_skip_list;
228 
229     template <typename N, typename V>
230     friend class skip_list_iterator;
231 
232     friend class const_range;
233     friend class range;
234 
235     friend bool operator==( const skip_list_iterator& lhs, const skip_list_iterator& rhs ) {
236         return lhs.my_node_ptr == rhs.my_node_ptr;
237     }
238 
239     friend bool operator!=( const skip_list_iterator& lhs, const skip_list_iterator& rhs ) {
240         return lhs.my_node_ptr != rhs.my_node_ptr;
241     }
242 }; // class skip_list_iterator
243 
244 template <typename Traits>
245 class concurrent_skip_list {
246 protected:
247     using container_traits = Traits;
248     using self_type = concurrent_skip_list<container_traits>;
249     using allocator_type = typename container_traits::allocator_type;
250     using allocator_traits_type = tbb::detail::allocator_traits<allocator_type>;
251     using key_compare = typename container_traits::compare_type;
252     using value_compare = typename container_traits::value_compare;
253     using key_type = typename container_traits::key_type;
254     using value_type = typename container_traits::value_type;
255     static_assert(std::is_same<value_type, typename allocator_type::value_type>::value,
256                   "value_type of the container should be the same as its allocator");
257 
258     using size_type = std::size_t;
259     using difference_type = std::ptrdiff_t;
260 
261     static constexpr size_type max_level = container_traits::max_level;
262 
263     using node_allocator_type = typename allocator_traits_type::template rebind_alloc<std::uint8_t>;
264     using node_allocator_traits = tbb::detail::allocator_traits<node_allocator_type>;
265 
266     using list_node_type = skip_list_node<value_type, node_allocator_type>;
267     using node_type = d1::node_handle<key_type, value_type, list_node_type, allocator_type>;
268 
269     using iterator = skip_list_iterator<list_node_type, value_type>;
270     using const_iterator = skip_list_iterator<list_node_type, const value_type>;
271 
272     using reference = value_type&;
273     using const_reference = const value_type&;
274     using pointer = typename allocator_traits_type::pointer;
275     using const_pointer = typename allocator_traits_type::const_pointer;
276 
277     using random_level_generator_type = typename container_traits::random_level_generator_type;
278 
279     using node_ptr = list_node_type*;
280 
281     using array_type = std::array<node_ptr, max_level>;
282 private:
283     template <typename T>
284     using is_transparent = dependent_bool<comp_is_transparent<key_compare>, T>;
285 public:
286     static constexpr bool allow_multimapping = container_traits::allow_multimapping;
287 
288     concurrent_skip_list() : my_head_ptr(nullptr), my_size(0), my_max_height(0) {}
289 
290     explicit concurrent_skip_list( const key_compare& comp, const allocator_type& alloc = allocator_type() )
291         : my_node_allocator(alloc), my_compare(comp), my_head_ptr(nullptr), my_size(0), my_max_height(0) {}
292 
293     explicit concurrent_skip_list( const allocator_type& alloc )
294         : concurrent_skip_list(key_compare(), alloc) {}
295 
296     template<typename InputIterator>
297     concurrent_skip_list( InputIterator first, InputIterator last, const key_compare& comp = key_compare(),
298                           const allocator_type& alloc = allocator_type() )
299         : concurrent_skip_list(comp, alloc)
300     {
301         internal_copy(first, last);
302     }
303 
304     template <typename InputIterator>
305     concurrent_skip_list( InputIterator first, InputIterator last, const allocator_type& alloc )
306         : concurrent_skip_list(first, last, key_compare(), alloc) {}
307 
308     concurrent_skip_list( std::initializer_list<value_type> init, const key_compare& comp = key_compare(),
309                           const allocator_type& alloc = allocator_type() )
310         : concurrent_skip_list(init.begin(), init.end(), comp, alloc) {}
311 
312     concurrent_skip_list( std::initializer_list<value_type> init, const allocator_type& alloc )
313         : concurrent_skip_list(init, key_compare(), alloc) {}
314 
315     concurrent_skip_list( const concurrent_skip_list& other )
316         : my_node_allocator(node_allocator_traits::select_on_container_copy_construction(other.get_allocator())),
317           my_compare(other.my_compare), my_rng(other.my_rng), my_head_ptr(nullptr),
318           my_size(0), my_max_height(0)
319     {
320         internal_copy(other);
321         __TBB_ASSERT(my_size == other.my_size, "Wrong size of copy-constructed container");
322     }
323 
324     concurrent_skip_list( const concurrent_skip_list& other, const allocator_type& alloc )
325         : my_node_allocator(alloc), my_compare(other.my_compare), my_rng(other.my_rng), my_head_ptr(nullptr),
326           my_size(0), my_max_height(0)
327     {
328         internal_copy(other);
329         __TBB_ASSERT(my_size == other.my_size, "Wrong size of copy-constructed container");
330     }
331 
332     concurrent_skip_list( concurrent_skip_list&& other )
333         : my_node_allocator(std::move(other.my_node_allocator)), my_compare(other.my_compare),
334           my_rng(std::move(other.my_rng)), my_head_ptr(nullptr) // my_head_ptr would be stored in internal_move
335     {
336         internal_move(std::move(other));
337     }
338 
339     concurrent_skip_list( concurrent_skip_list&& other, const allocator_type& alloc )
340         : my_node_allocator(alloc), my_compare(other.my_compare),
341           my_rng(std::move(other.my_rng)), my_head_ptr(nullptr)
342     {
343         using is_always_equal = typename allocator_traits_type::is_always_equal;
344         internal_move_construct_with_allocator(std::move(other), is_always_equal());
345     }
346 
347     ~concurrent_skip_list() {
348         clear();
349         delete_head();
350     }
351 
352     concurrent_skip_list& operator=( const concurrent_skip_list& other ) {
353         if (this != &other) {
354             clear();
355             copy_assign_allocators(my_node_allocator, other.my_node_allocator);
356             my_compare = other.my_compare;
357             my_rng = other.my_rng;
358             internal_copy(other);
359         }
360         return *this;
361     }
362 
363     concurrent_skip_list& operator=( concurrent_skip_list&& other ) {
364         if (this != &other) {
365             clear();
366             delete_head();
367 
368             my_compare = std::move(other.my_compare);
369             my_rng = std::move(other.my_rng);
370 
371             move_assign_allocators(my_node_allocator, other.my_node_allocator);
372             using pocma_type = typename node_allocator_traits::propagate_on_container_move_assignment;
373             using is_always_equal = typename node_allocator_traits::is_always_equal;
374             internal_move_assign(std::move(other), tbb::detail::disjunction<pocma_type, is_always_equal>());
375         }
376         return *this;
377     }
378 
379     concurrent_skip_list& operator=( std::initializer_list<value_type> il )
380     {
381         clear();
382         insert(il.begin(),il.end());
383         return *this;
384     }
385 
386     std::pair<iterator, bool> insert( const value_type& value ) {
387         return internal_insert(value);
388     }
389 
390     std::pair<iterator, bool> insert( value_type&& value ) {
391         return internal_insert(std::move(value));
392     }
393 
394     iterator insert( const_iterator, const_reference value ) {
395         // Ignore hint
396         return insert(value).first;
397     }
398 
399     iterator insert( const_iterator, value_type&& value ) {
400         // Ignore hint
401         return insert(std::move(value)).first;
402     }
403 
404     template<typename InputIterator>
405     void insert( InputIterator first, InputIterator last ) {
406         while (first != last) {
407             insert(*first);
408             ++first;
409         }
410     }
411 
412     void insert( std::initializer_list<value_type> init ) {
413         insert(init.begin(), init.end());
414     }
415 
416     std::pair<iterator, bool> insert( node_type&& nh ) {
417         if (!nh.empty()) {
418             auto insert_node = d1::node_handle_accessor::get_node_ptr(nh);
419             std::pair<iterator, bool> insert_result = internal_insert_node(insert_node);
420             if (insert_result.second) {
421                 d1::node_handle_accessor::deactivate(nh);
422             }
423             return insert_result;
424         }
425         return std::pair<iterator, bool>(end(), false);
426     }
427 
428     iterator insert( const_iterator, node_type&& nh ) {
429         // Ignore hint
430         return insert(std::move(nh)).first;
431     }
432 
433     template<typename... Args>
434     std::pair<iterator, bool> emplace( Args&&... args ) {
435         return internal_insert(std::forward<Args>(args)...);
436     }
437 
438     template<typename... Args>
439     iterator emplace_hint( const_iterator, Args&&... args ) {
440         // Ignore hint
441         return emplace(std::forward<Args>(args)...).first;
442     }
443 
444     iterator unsafe_erase( iterator pos ) {
445         std::pair<node_ptr, node_ptr> extract_result = internal_extract(pos);
446         if (extract_result.first) { // node was extracted
447             delete_value_node(extract_result.first);
448             return extract_result.second;
449         }
450         return end();
451     }
452 
453     iterator unsafe_erase( const_iterator pos ) {
454         return unsafe_erase(get_iterator(pos));
455     }
456 
457     iterator unsafe_erase( const_iterator first, const_iterator last ) {
458         while (first != last) {
459             // Unsafe erase returns the iterator which follows the erased one
460             first = unsafe_erase(first);
461         }
462         return get_iterator(first);
463     }
464 
465     size_type unsafe_erase( const key_type& key ) {
466         return internal_erase(key);
467     }
468 
469     template <typename K>
470     typename std::enable_if<is_transparent<K>::value
471                             && !std::is_convertible<K, const_iterator>::value
472                             && !std::is_convertible<K, iterator>::value,
473                             size_type>::type unsafe_erase( const K& key )
474     {
475         return internal_erase(key);
476     }
477 
478     node_type unsafe_extract( const_iterator pos ) {
479         std::pair<node_ptr, node_ptr> extract_result = internal_extract(pos);
480         return extract_result.first ? d1::node_handle_accessor::construct<node_type>(extract_result.first) : node_type();
481     }
482 
483     node_type unsafe_extract( iterator pos ) {
484         return unsafe_extract(const_iterator(pos));
485     }
486 
487     node_type unsafe_extract( const key_type& key ) {
488         return unsafe_extract(find(key));
489     }
490 
491     template <typename K>
492     typename std::enable_if<is_transparent<K>::value
493                             && !std::is_convertible<K, const_iterator>::value
494                             && !std::is_convertible<K, iterator>::value,
495                             node_type>::type unsafe_extract( const K& key )
496     {
497         return unsafe_extract(find(key));
498     }
499 
500     iterator lower_bound( const key_type& key ) {
501         return iterator(internal_get_bound(key, my_compare));
502     }
503 
504     const_iterator lower_bound( const key_type& key ) const {
505         return const_iterator(internal_get_bound(key, my_compare));
506     }
507 
508     template <typename K>
509     typename std::enable_if<is_transparent<K>::value, iterator>::type lower_bound( const K& key ) {
510         return iterator(internal_get_bound(key, my_compare));
511     }
512 
513     template <typename K>
514     typename std::enable_if<is_transparent<K>::value, const_iterator>::type lower_bound( const K& key ) const {
515         return const_iterator(internal_get_bound(key, my_compare));
516     }
517 
518     iterator upper_bound( const key_type& key ) {
519         return iterator(internal_get_bound(key, not_greater_compare(my_compare)));
520     }
521 
522     const_iterator upper_bound( const key_type& key ) const {
523         return const_iterator(internal_get_bound(key, not_greater_compare(my_compare)));
524     }
525 
526     template <typename K>
527     typename std::enable_if<is_transparent<K>::value, iterator>::type upper_bound( const K& key ) {
528         return iterator(internal_get_bound(key, not_greater_compare(my_compare)));
529     }
530 
531     template <typename K>
532     typename std::enable_if<is_transparent<K>::value, const_iterator>::type upper_bound( const K& key ) const {
533         return const_iterator(internal_get_bound(key, not_greater_compare(my_compare)));
534     }
535 
536     iterator find( const key_type& key ) {
537         return iterator(internal_find(key));
538     }
539 
540     const_iterator find( const key_type& key ) const {
541         return const_iterator(internal_find(key));
542     }
543 
544     template <typename K>
545     typename std::enable_if<is_transparent<K>::value, iterator>::type find( const K& key ) {
546         return iterator(internal_find(key));
547     }
548 
549     template <typename K>
550     typename std::enable_if<is_transparent<K>::value, const_iterator>::type find( const K& key ) const {
551         return const_iterator(internal_find(key));
552     }
553 
554     size_type count( const key_type& key ) const {
555         return internal_count(key);
556     }
557 
558     template <typename K>
559     typename std::enable_if<is_transparent<K>::value, size_type>::type count( const K& key ) const {
560         return internal_count(key);
561     }
562 
563     bool contains( const key_type& key ) const {
564         return find(key) != end();
565     }
566 
567     template <typename K>
568     typename std::enable_if<is_transparent<K>::value, bool>::type contains( const K& key ) const {
569         return find(key) != end();
570     }
571 
572     void clear() noexcept {
573         // clear is not thread safe - load can be relaxed
574         node_ptr head = my_head_ptr.load(std::memory_order_relaxed);
575 
576         if (head == nullptr) return; // Head is not allocated => container is empty
577 
578         node_ptr current = head->next(0);
579 
580         // Delete all value nodes in the container
581         while (current) {
582             node_ptr next = current->next(0);
583             delete_value_node(current);
584             current = next;
585         }
586 
587         for (size_type level = 0; level < head->height(); ++level) {
588             head->set_next(level, nullptr);
589         }
590 
591         my_size.store(0, std::memory_order_relaxed);
592         my_max_height.store(0, std::memory_order_relaxed);
593     }
594 
595     iterator begin() {
596         return iterator(internal_begin());
597     }
598 
599     const_iterator begin() const {
600         return const_iterator(internal_begin());
601     }
602 
603     const_iterator cbegin() const {
604         return const_iterator(internal_begin());
605     }
606 
607     iterator end() {
608         return iterator(nullptr);
609     }
610 
611     const_iterator end() const {
612         return const_iterator(nullptr);
613     }
614 
615     const_iterator cend() const {
616         return const_iterator(nullptr);
617     }
618 
619     size_type size() const {
620         return my_size.load(std::memory_order_relaxed);
621     }
622 
623     size_type max_size() const {
624         return node_allocator_traits::max_size(my_node_allocator);
625     }
626 
627     __TBB_nodiscard bool empty() const {
628         return 0 == size();
629     }
630 
631     allocator_type get_allocator() const {
632         return my_node_allocator;
633     }
634 
635     void swap(concurrent_skip_list& other) {
636         if (this != &other) {
637             using pocs_type = typename node_allocator_traits::propagate_on_container_swap;
638             using is_always_equal = typename node_allocator_traits::is_always_equal;
639             internal_swap(other, tbb::detail::disjunction<pocs_type, is_always_equal>());
640         }
641     }
642 
643     std::pair<iterator, iterator> equal_range(const key_type& key) {
644         return internal_equal_range(key);
645     }
646 
647     std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
648         return internal_equal_range(key);
649     }
650 
651     template <typename K>
652     typename std::enable_if<is_transparent<K>::value, std::pair<iterator, iterator>>::type equal_range( const K& key ) {
653         return internal_equal_range(key);
654     }
655 
656     template <typename K>
657     typename std::enable_if<is_transparent<K>::value, std::pair<const_iterator, const_iterator>>::type equal_range( const K& key ) const {
658         return internal_equal_range(key);
659     }
660 
661     key_compare key_comp() const { return my_compare; }
662 
663     value_compare value_comp() const { return container_traits::value_comp(my_compare); }
664 
665     class const_range_type {
666     public:
667         using size_type = typename concurrent_skip_list::size_type;
668         using difference_type = typename concurrent_skip_list::difference_type;
669         using iterator = typename concurrent_skip_list::const_iterator;
670         using value_type = typename iterator::value_type;
671         using reference = typename iterator::reference;
672 
673         bool empty() const {
674             return my_begin.my_node_ptr->next(0) == my_end.my_node_ptr;
675         }
676 
677         bool is_divisible() const {
678             return my_level != 0 ? my_begin.my_node_ptr->next(my_level - 1) != my_end.my_node_ptr : false;
679         }
680 
681         size_type size() const { return std::distance(my_begin, my_end); }
682 
683         const_range_type( const_range_type& r, split)
684             : my_end(r.my_end) {
685             my_begin = iterator(r.my_begin.my_node_ptr->next(r.my_level - 1));
686             my_level = my_begin.my_node_ptr->height();
687             r.my_end = my_begin;
688         }
689 
690         const_range_type( const concurrent_skip_list& l)
691             : my_end(l.end()), my_begin(l.begin()), my_level(my_begin.my_node_ptr->height() ) {}
692 
693         iterator begin() const { return my_begin; }
694         iterator end() const { return my_end; }
695         size_type grainsize() const { return 1; }
696 
697     private:
698         const_iterator my_end;
699         const_iterator my_begin;
700         size_type my_level;
701     }; // class const_range_type
702 
703     class range_type : public const_range_type {
704     public:
705         using iterator = typename concurrent_skip_list::iterator;
706         using value_type = typename iterator::value_type;
707         using reference = typename iterator::reference;
708 
709         range_type(range_type& r, split) : const_range_type(r, split()) {}
710         range_type(const concurrent_skip_list& l) : const_range_type(l) {}
711 
712         iterator begin() const {
713             node_ptr node = const_range_type::begin().my_node_ptr;
714             return iterator(node);
715         }
716 
717         iterator end() const {
718             node_ptr node = const_range_type::end().my_node_ptr;
719             return iterator(node);
720         }
721     }; // class range_type
722 
723     range_type range() { return range_type(*this); }
724     const_range_type range() const { return const_range_type(*this); }
725 
726 private:
727     node_ptr internal_begin() const {
728         node_ptr head = get_head();
729         return head == nullptr ? head : head->next(0);
730     }
731 
732     void internal_move(concurrent_skip_list&& other) {
733         my_head_ptr.store(other.my_head_ptr.load(std::memory_order_relaxed), std::memory_order_relaxed);
734         other.my_head_ptr.store(nullptr, std::memory_order_relaxed);
735 
736         my_size.store(other.my_size.load(std::memory_order_relaxed), std::memory_order_relaxed);
737         other.my_size.store(0, std::memory_order_relaxed);
738 
739         my_max_height.store(other.my_max_height.load(std::memory_order_relaxed), std::memory_order_relaxed);
740         other.my_max_height.store(0, std::memory_order_relaxed);
741     }
742 
743     void internal_move_construct_with_allocator(concurrent_skip_list&& other,
744                                                 /*is_always_equal = */std::true_type) {
745         internal_move(std::move(other));
746     }
747 
748     void internal_move_construct_with_allocator(concurrent_skip_list&& other,
749                                                 /*is_always_equal = */std::false_type) {
750         if (my_node_allocator == other.get_allocator()) {
751             internal_move(std::move(other));
752         } else {
753             my_size.store(0, std::memory_order_relaxed);
754             my_max_height.store(other.my_max_height.load(std::memory_order_relaxed), std::memory_order_relaxed);
755             internal_copy(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
756         }
757     }
758 
759     static const key_type& get_key( node_ptr n ) {
760         __TBB_ASSERT(n, nullptr);
761         return container_traits::get_key(static_cast<node_ptr>(n)->value());
762     }
763 
764     template <typename K>
765     bool found( node_ptr node, const K& key ) const {
766         return node != nullptr && !my_compare(key, get_key(node));
767     }
768 
769     template <typename K>
770     node_ptr internal_find(const K& key) const {
771         return allow_multimapping ? internal_find_multi(key) : internal_find_unique(key);
772     }
773 
774     template <typename K>
775     node_ptr internal_find_multi( const K& key ) const {
776         node_ptr prev = get_head();
777         if (prev == nullptr) return nullptr; // If the head node is not allocated - exit
778 
779         node_ptr curr = nullptr;
780         node_ptr old_curr = curr;
781 
782         for (size_type h = my_max_height.load(std::memory_order_acquire); h > 0; --h) {
783             curr = internal_find_position(h - 1, prev, key, my_compare);
784 
785             if (curr != old_curr && found(curr, key)) {
786                 return curr;
787             }
788             old_curr = curr;
789         }
790         return nullptr;
791     }
792 
793     template <typename K>
794     node_ptr internal_find_unique( const K& key ) const {
795         const_iterator it = lower_bound(key);
796         return (it == end() || my_compare(key, container_traits::get_key(*it))) ? nullptr : it.my_node_ptr;
797     }
798 
799     template <typename K>
800     size_type internal_count( const K& key ) const {
801         if (allow_multimapping) {
802             // TODO: reimplement without double traversal
803             std::pair<const_iterator, const_iterator> r = equal_range(key);
804             return std::distance(r.first, r.second);
805         }
806         return size_type(contains(key) ? 1 : 0);
807     }
808 
809     template <typename K>
810     std::pair<iterator, iterator> internal_equal_range(const K& key) const {
811         iterator lb = get_iterator(lower_bound(key));
812         auto result = std::make_pair(lb, lb);
813 
814         // If the lower bound points to the node with the requested key
815         if (found(lb.my_node_ptr, key)) {
816 
817             if (!allow_multimapping) {
818                 // For unique containers - move the second iterator forward and exit
819                 ++result.second;
820             } else {
821                 // For multi containers - find the upper bound starting from the lower bound
822                 node_ptr prev = lb.my_node_ptr;
823                 node_ptr curr = nullptr;
824                 not_greater_compare cmp(my_compare);
825 
826                 // Start from the lower bound of the range
827                 for (size_type h = prev->height(); h > 0; --h) {
828                     curr = prev->next(h - 1);
829                     while (curr && cmp(get_key(curr), key)) {
830                         prev = curr;
831                         // If the height of the next node is greater than the current one - jump to its height
832                         if (h < curr->height()) {
833                             h = curr->height();
834                         }
835                         curr = prev->next(h - 1);
836                     }
837                 }
838                 result.second = iterator(curr);
839             }
840         }
841 
842         return result;
843     }
844 
845     // Finds position on the level using comparator cmp starting from the node prev
846     template <typename K, typename Comparator>
847     node_ptr internal_find_position( size_type level, node_ptr& prev, const K& key,
848                                      const Comparator& cmp ) const {
849         __TBB_ASSERT(level < prev->height(), "Wrong level to find position");
850         node_ptr curr = prev->next(level);
851 
852         while (curr && cmp(get_key(curr), key)) {
853             prev = curr;
854             __TBB_ASSERT(level < prev->height(), nullptr);
855             curr = prev->next(level);
856         }
857 
858         return curr;
859     }
860 
861     // The same as previous overload, but allows index_number comparison
862     template <typename Comparator>
863     node_ptr internal_find_position( size_type level, node_ptr& prev, node_ptr node,
864                                      const Comparator& cmp ) const {
865         __TBB_ASSERT(level < prev->height(), "Wrong level to find position");
866         node_ptr curr = prev->next(level);
867 
868         while (curr && cmp(get_key(curr), get_key(node))) {
869             if (allow_multimapping && cmp(get_key(node), get_key(curr)) && curr->index_number() > node->index_number()) {
870                 break;
871             }
872 
873             prev = curr;
874             __TBB_ASSERT(level < prev->height(), nullptr);
875             curr = prev->next(level);
876         }
877         return curr;
878     }
879 
880     template <typename Comparator>
881     void fill_prev_curr_arrays(array_type& prev_nodes, array_type& curr_nodes, node_ptr node, const key_type& key,
882                                const Comparator& cmp, node_ptr head ) {
883 
884         size_type curr_max_height = my_max_height.load(std::memory_order_acquire);
885         size_type node_height = node->height();
886         if (curr_max_height < node_height) {
887             std::fill(prev_nodes.begin() + curr_max_height, prev_nodes.begin() + node_height, head);
888             std::fill(curr_nodes.begin() + curr_max_height, curr_nodes.begin() + node_height, nullptr);
889         }
890 
891         node_ptr prev = head;
892         for (size_type level = curr_max_height; level > 0; --level) {
893             node_ptr curr = internal_find_position(level - 1, prev, key, cmp);
894             prev_nodes[level - 1] = prev;
895             curr_nodes[level - 1] = curr;
896         }
897     }
898 
899     void fill_prev_array_for_existing_node( array_type& prev_nodes, node_ptr node ) {
900         node_ptr head = create_head_if_necessary();
901         prev_nodes.fill(head);
902 
903         node_ptr prev = head;
904         for (size_type level = node->height(); level > 0; --level) {
905             while (prev->next(level - 1) != node) {
906                 prev = prev->next(level - 1);
907             }
908             prev_nodes[level - 1] = prev;
909         }
910     }
911 
912     struct not_greater_compare {
913         const key_compare& my_less_compare;
914 
915         not_greater_compare( const key_compare& less_compare ) : my_less_compare(less_compare) {}
916 
917         template <typename K1, typename K2>
918         bool operator()( const K1& first, const K2& second ) const {
919             return !my_less_compare(second, first);
920         }
921     };
922 
923     not_greater_compare select_comparator( /*allow_multimapping = */ std::true_type ) {
924         return not_greater_compare(my_compare);
925     }
926 
927     key_compare select_comparator( /*allow_multimapping = */ std::false_type ) {
928         return my_compare;
929     }
930 
931     template<typename... Args>
932     std::pair<iterator, bool> internal_insert( Args&&... args ) {
933         node_ptr new_node = create_value_node(std::forward<Args>(args)...);
934         std::pair<iterator, bool> insert_result = internal_insert_node(new_node);
935         if (!insert_result.second) {
936             delete_value_node(new_node);
937         }
938         return insert_result;
939     }
940 
941     std::pair<iterator, bool> internal_insert_node( node_ptr new_node ) {
942         array_type prev_nodes;
943         array_type curr_nodes;
944         size_type new_height = new_node->height();
945         auto compare = select_comparator(std::integral_constant<bool, allow_multimapping>{});
946 
947         node_ptr head_node = create_head_if_necessary();
948 
949         for (;;) {
950             fill_prev_curr_arrays(prev_nodes, curr_nodes, new_node, get_key(new_node), compare, head_node);
951 
952             node_ptr prev = prev_nodes[0];
953             node_ptr next = curr_nodes[0];
954 
955             if (allow_multimapping) {
956                 new_node->set_index_number(prev->index_number() + 1);
957             } else {
958                 if (found(next, get_key(new_node))) {
959                     return std::pair<iterator, bool>(iterator(next), false);
960                 }
961             }
962 
963             new_node->set_next(0, next);
964             if (!prev->atomic_next(0).compare_exchange_strong(next, new_node)) {
965                 continue;
966             }
967 
968             // If the node was successfully linked on the first level - it will be linked on other levels
969             // Insertion cannot fail starting from this point
970 
971             // If the height of inserted node is greater than maximum - increase maximum
972             size_type max_height = my_max_height.load(std::memory_order_acquire);
973             for (;;) {
974                 if (new_height <= max_height || my_max_height.compare_exchange_strong(max_height, new_height)) {
975                     // If the maximum was successfully updated by current thread
976                     // or by an other thread for the value, greater or equal to new_height
977                     break;
978                 }
979             }
980 
981             for (std::size_t level = 1; level < new_height; ++level) {
982                 // Link the node on upper levels
983                 for (;;) {
984                     prev = prev_nodes[level];
985                     next = static_cast<node_ptr>(curr_nodes[level]);
986 
987                     new_node->set_next(level, next);
988                     __TBB_ASSERT(new_node->height() > level, "Internal structure break");
989                     if (prev->atomic_next(level).compare_exchange_strong(next, new_node)) {
990                         break;
991                     }
992 
993                     for (size_type lev = level; lev != new_height; ++lev ) {
994                         curr_nodes[lev] = internal_find_position(lev, prev_nodes[lev], new_node, compare);
995                     }
996                 }
997             }
998             ++my_size;
999             return std::pair<iterator, bool>(iterator(new_node), true);
1000         }
1001     }
1002 
1003     template <typename K, typename Comparator>
1004     node_ptr internal_get_bound( const K& key, const Comparator& cmp ) const {
1005         node_ptr prev = get_head();
1006         if (prev == nullptr) return nullptr; // If the head node is not allocated - exit
1007 
1008         node_ptr curr = nullptr;
1009 
1010         for (size_type h = my_max_height.load(std::memory_order_acquire); h > 0; --h) {
1011             curr = internal_find_position(h - 1, prev, key, cmp);
1012         }
1013 
1014         return curr;
1015     }
1016 
1017     template <typename K>
1018     size_type internal_erase( const K& key ) {
1019         auto eq = equal_range(key);
1020         size_type old_size = size();
1021         unsafe_erase(eq.first, eq.second);
1022         return old_size - size();
1023     }
1024 
1025     // Returns node_ptr to the extracted node and node_ptr to the next node after the extracted
1026     std::pair<node_ptr, node_ptr> internal_extract( const_iterator it ) {
1027         std::pair<node_ptr, node_ptr> result(nullptr, nullptr);
1028         if ( it != end() ) {
1029             array_type prev_nodes;
1030 
1031             node_ptr erase_node = it.my_node_ptr;
1032             node_ptr next_node = erase_node->next(0);
1033             fill_prev_array_for_existing_node(prev_nodes, erase_node);
1034 
1035             for (size_type level = 0; level < erase_node->height(); ++level) {
1036                 prev_nodes[level]->set_next(level, erase_node->next(level));
1037                 erase_node->set_next(level, nullptr);
1038             }
1039             my_size.fetch_sub(1, std::memory_order_relaxed);
1040 
1041             result.first = erase_node;
1042             result.second = next_node;
1043         }
1044         return result;
1045     }
1046 
1047 protected:
1048     template<typename SourceType>
1049     void internal_merge( SourceType&& source ) {
1050         using source_type = typename std::decay<SourceType>::type;
1051         using source_iterator = typename source_type::iterator;
1052         static_assert((std::is_same<node_type, typename source_type::node_type>::value), "Incompatible containers cannot be merged");
1053 
1054         for (source_iterator it = source.begin(); it != source.end();) {
1055             source_iterator where = it++;
1056             if (allow_multimapping || !contains(container_traits::get_key(*where))) {
1057                 node_type handle = source.unsafe_extract(where);
1058                 __TBB_ASSERT(!handle.empty(), "Extracted handle in merge is empty");
1059 
1060                 if (!insert(std::move(handle)).second) {
1061                     //If the insertion fails - return the node into source
1062                     source.insert(std::move(handle));
1063                 }
1064                 __TBB_ASSERT(handle.empty(), "Node handle should be empty after the insertion");
1065             }
1066         }
1067     }
1068 
1069 private:
1070     void internal_copy( const concurrent_skip_list& other ) {
1071         internal_copy(other.begin(), other.end());
1072     }
1073 
1074     template<typename Iterator>
1075     void internal_copy( Iterator first, Iterator last ) {
1076         try_call([&] {
1077             for (auto it = first; it != last; ++it) {
1078                 insert(*it);
1079             }
1080         }).on_exception([&] {
1081             clear();
1082             delete_head();
1083         });
1084     }
1085 
1086     node_ptr create_node( size_type height ) {
1087         return list_node_type::create(my_node_allocator, height);
1088     }
1089 
1090     template <typename... Args>
1091     node_ptr create_value_node( Args&&... args ) {
1092         node_ptr node = create_node(my_rng());
1093 
1094         // try_call API is not convenient here due to broken
1095         // variadic capture on GCC 4.8.5
1096         auto value_guard = make_raii_guard([&] {
1097             delete_node(node);
1098         });
1099 
1100         // Construct the value inside the node
1101         node_allocator_traits::construct(my_node_allocator, node->storage(), std::forward<Args>(args)...);
1102         value_guard.dismiss();
1103         return node;
1104     }
1105 
1106     node_ptr create_head_node() {
1107         return create_node(max_level);
1108     }
1109 
1110     void delete_head() {
1111         node_ptr head = my_head_ptr.load(std::memory_order_relaxed);
1112         if (head != nullptr) {
1113             delete_node(head);
1114             my_head_ptr.store(nullptr, std::memory_order_relaxed);
1115         }
1116     }
1117 
1118     void delete_node( node_ptr node ) {
1119         list_node_type::destroy(my_node_allocator, node);
1120     }
1121 
1122     void delete_value_node( node_ptr node ) {
1123         // Destroy the value inside the node
1124         node_allocator_traits::destroy(my_node_allocator, node->storage());
1125         delete_node(node);
1126     }
1127 
1128     node_ptr get_head() const {
1129         return my_head_ptr.load(std::memory_order_acquire);
1130     }
1131 
1132     node_ptr create_head_if_necessary() {
1133         node_ptr current_head = get_head();
1134         if (current_head == nullptr) {
1135             // Head node was not created - create it
1136             node_ptr new_head = create_head_node();
1137             if (my_head_ptr.compare_exchange_strong(current_head, new_head)) {
1138                 current_head = new_head;
1139             } else {
1140                 // If an other thread has already created the head node - destroy new_head
1141                 // current_head now points to the actual head node
1142                 delete_node(new_head);
1143             }
1144         }
1145         __TBB_ASSERT(my_head_ptr.load(std::memory_order_relaxed) != nullptr, nullptr);
1146         __TBB_ASSERT(current_head != nullptr, nullptr);
1147         return current_head;
1148     }
1149 
1150     static iterator get_iterator( const_iterator it ) {
1151         return iterator(it.my_node_ptr);
1152     }
1153 
1154     void internal_move_assign( concurrent_skip_list&& other, /*POCMA || is_always_equal =*/std::true_type ) {
1155         internal_move(std::move(other));
1156     }
1157 
1158     void internal_move_assign( concurrent_skip_list&& other, /*POCMA || is_always_equal =*/std::false_type ) {
1159         if (my_node_allocator == other.my_node_allocator) {
1160             internal_move(std::move(other));
1161         } else {
1162             internal_copy(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
1163         }
1164     }
1165 
1166     void internal_swap_fields( concurrent_skip_list& other ) {
1167         using std::swap;
1168         swap_allocators(my_node_allocator, other.my_node_allocator);
1169         swap(my_compare, other.my_compare);
1170         swap(my_rng, other.my_rng);
1171 
1172         swap_atomics_relaxed(my_head_ptr, other.my_head_ptr);
1173         swap_atomics_relaxed(my_size, other.my_size);
1174         swap_atomics_relaxed(my_max_height, other.my_max_height);
1175     }
1176 
1177     void internal_swap( concurrent_skip_list& other, /*POCMA || is_always_equal =*/std::true_type ) {
1178         internal_swap_fields(other);
1179     }
1180 
1181     void internal_swap( concurrent_skip_list& other, /*POCMA || is_always_equal =*/std::false_type ) {
1182         __TBB_ASSERT(my_node_allocator == other.my_node_allocator, "Swapping with unequal allocators is not allowed");
1183         internal_swap_fields(other);
1184     }
1185 
1186     node_allocator_type my_node_allocator;
1187     key_compare my_compare;
1188     random_level_generator_type my_rng;
1189     std::atomic<list_node_type*> my_head_ptr;
1190     std::atomic<size_type> my_size;
1191     std::atomic<size_type> my_max_height;
1192 
1193     template<typename OtherTraits>
1194     friend class concurrent_skip_list;
1195 }; // class concurrent_skip_list
1196 
1197 template <typename Traits>
1198 bool operator==( const concurrent_skip_list<Traits>& lhs, const concurrent_skip_list<Traits>& rhs ) {
1199     if (lhs.size() != rhs.size()) return false;
1200 #if _MSC_VER
1201     // Passing "unchecked" iterators to std::equal with 3 parameters
1202     // causes compiler warnings.
1203     // The workaround is to use overload with 4 parameters, which is
1204     // available since C++14 - minimally supported version on MSVC
1205     return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
1206 #else
1207     return std::equal(lhs.begin(), lhs.end(), rhs.begin());
1208 #endif
1209 }
1210 
1211 #if !__TBB_CPP20_COMPARISONS_PRESENT
1212 template <typename Traits>
1213 bool operator!=( const concurrent_skip_list<Traits>& lhs, const concurrent_skip_list<Traits>& rhs ) {
1214     return !(lhs == rhs);
1215 }
1216 #endif
1217 
1218 #if __TBB_CPP20_COMPARISONS_PRESENT && __TBB_CPP20_CONCEPTS_PRESENT
1219 template <typename Traits>
1220 tbb::detail::synthesized_three_way_result<typename Traits::value_type>
1221 operator<=>( const concurrent_skip_list<Traits>& lhs, const concurrent_skip_list<Traits>& rhs ) {
1222     return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(),
1223                                                   rhs.begin(), rhs.end(),
1224                                                   tbb::detail::synthesized_three_way_comparator{});
1225 }
1226 #else
1227 template <typename Traits>
1228 bool operator<( const concurrent_skip_list<Traits>& lhs, const concurrent_skip_list<Traits>& rhs ) {
1229     return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
1230 }
1231 
1232 template <typename Traits>
1233 bool operator>( const concurrent_skip_list<Traits>& lhs, const concurrent_skip_list<Traits>& rhs ) {
1234     return rhs < lhs;
1235 }
1236 
1237 template <typename Traits>
1238 bool operator<=( const concurrent_skip_list<Traits>& lhs, const concurrent_skip_list<Traits>& rhs ) {
1239     return !(rhs < lhs);
1240 }
1241 
1242 template <typename Traits>
1243 bool operator>=( const concurrent_skip_list<Traits>& lhs, const concurrent_skip_list<Traits>& rhs ) {
1244     return !(lhs < rhs);
1245 }
1246 #endif // __TBB_CPP20_COMPARISONS_PRESENT && __TBB_CPP20_CONCEPTS_PRESENT
1247 
1248 // Generates a number from the interval [0, MaxLevel).
1249 template <std::size_t MaxLevel>
1250 class concurrent_geometric_level_generator {
1251 public:
1252     static constexpr std::size_t max_level = MaxLevel;
1253     // TODO: modify the algorithm to accept other values of max_level
1254     static_assert(max_level == 32, "Incompatible max_level for rng");
1255 
1256     concurrent_geometric_level_generator() : engines(std::minstd_rand::result_type(time(nullptr))) {}
1257 
1258     std::size_t operator()() {
1259         // +1 is required to pass at least 1 into log2 (log2(0) is undefined)
1260         // -1 is required to have an ability to return 0 from the generator (max_level - log2(2^31) - 1)
1261         std::size_t result = max_level - std::size_t(tbb::detail::log2(engines.local()() + 1)) - 1;
1262         __TBB_ASSERT(result <= max_level, nullptr);
1263         return result;
1264     }
1265 
1266 private:
1267     tbb::enumerable_thread_specific<std::minstd_rand> engines;
1268 };
1269 
1270 } // namespace d2
1271 
1272 } // namespace detail
1273 } // namespace tbb
1274 
1275 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
1276 #pragma warning(pop) // warning 4127 is back
1277 #endif
1278 
1279 #endif // __TBB_detail__concurrent_skip_list_H
1280