BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlcc_skiplist.h
Go to the documentation of this file.
1/// @file bdlcc_skiplist.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlcc_skiplist.h -*-C++-*-
8#ifndef INCLUDED_BDLCC_SKIPLIST
9#define INCLUDED_BDLCC_SKIPLIST
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlcc_skiplist bdlcc_skiplist
15/// @brief Provide a generic thread-safe Skip List.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlcc
19/// @{
20/// @addtogroup bdlcc_skiplist
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlcc_skiplist-purpose"> Purpose</a>
25/// * <a href="#bdlcc_skiplist-classes"> Classes </a>
26/// * <a href="#bdlcc_skiplist-description"> Description </a>
27/// * <a href="#bdlcc_skiplist-template-requirements"> Template Requirements </a>
28/// * <a href="#bdlcc_skiplist-glossary"> Glossary </a>
29/// * <a href="#bdlcc_skiplist-r-methods-optimized-search-from-the-back-of-the-list"> "R" Methods: Optimized Search From The Back Of The List </a>
30/// * <a href="#bdlcc_skiplist-referring-to-elements-in-the-container"> Referring to Elements in the Container </a>
31/// * <a href="#bdlcc_skiplist-thread-safety"> Thread Safety </a>
32/// * <a href="#bdlcc_skiplist-exception-safety"> Exception Safety </a>
33/// * <a href="#bdlcc_skiplist-usage"> Usage </a>
34/// * <a href="#bdlcc_skiplist-example-1-creating-a-scheduler"> Example 1: Creating a Scheduler </a>
35///
36/// # Purpose {#bdlcc_skiplist-purpose}
37/// Provide a generic thread-safe Skip List.
38///
39/// # Classes {#bdlcc_skiplist-classes}
40///
41/// - bdlcc::SkipList: generic thread-aware ordered map
42/// - bdlcc::SkipListPair: type for opaque pointers
43/// - bdlcc::SkipListPairHandle: scope mechanism for safe item references
44///
45/// @see
46///
47/// # Description {#bdlcc_skiplist-description}
48/// This component provides a thread-safe value-semantic
49/// associative Skip List container. A Skip List stores objects of a
50/// parameterized `DATA` type, ordered by values of a parameterized `KEY` type.
51/// `DATA` objects can be added, looked up, and removed quickly on the basis of
52/// their `KEY` value. In addition, `bdlcc::SkipList` provides methods to
53/// change the `KEY` value associated with an object in the list such that it is
54/// efficiently moved to an appropriate location within the list for the new
55/// `KEY` value.
56///
57/// Associations (pairings of data objects with key values) in the list are
58/// identified by `bdlcc::SkipListPairHandle` objects or `bdlcc::SkipListPair`
59/// pointers. `bdlcc::SkipListPair` pointers must be used with caution: See the
60/// "`bdlcc::SkipListPair` Usage Rules" below. `bdlcc::SkipListPair` and
61/// `bdlcc::SkipListPairHandle` objects are optionally populated when new
62/// associations are added, and are also populated whenever associations are
63/// looked up (either by key or by position). Note that in addition to
64/// `addPairReferenceRaw`, member functions of `bdlcc::SkipList` such as
65/// `front`, `back`, and `find` also add a reference to the specified element.
66///
67/// ## Template Requirements {#bdlcc_skiplist-template-requirements}
68///
69///
70/// The `bdlcc::SkipList` ordered associative container is parameterized on two
71/// types, `KEY` and `DATA`. Each type must have a public copy constructor, and
72/// it is important to declare the "Uses bslma Allocator" trait if the type
73/// accepts a `bslma::Allocator` in its constructor (see @ref bslalg_typetraits ).
74/// In addition, operators `=`, `<`, and `==` must be defined for the type
75/// `KEY`; for correct behavior, operator `<` must define a Strict Weak Ordering
76/// on `KEY` values.
77///
78/// ## Glossary {#bdlcc_skiplist-glossary}
79///
80///
81/// Some terms used frequently in this documentation:
82///
83/// * **Back**
84/// > The last element in the list. The key value at the back is greater
85/// > than or equal to every other key value in the list.
86///
87/// * **Front**
88/// > The beginning of the list. The key value at the front is less than or
89/// > equal to every other key value in the list.
90///
91/// * **Pair**
92/// > An element of the list; a pairing (association) of a data object with a
93/// > key value. Also a type name used for *references* to such objects
94/// > (`bdlcc::SkipListPair` objects cannot be constructed directly).
95///
96/// * **PairHandle**
97/// > An object (of type `bdlcc::SkipListPairHandle`) with scope and copy
98/// > semantics that makes it easier to manage and use than a raw
99/// > `bdlcc::SkipListPair *`.
100///
101/// * **R**
102/// > Stands for "Reverse search" (see `"R" Methods` documentation below).
103///
104/// * **Reference**
105/// > An object referring to a pair; either a `bdlcc::SkipListPair *` which
106/// > has not yet been released, or a `bdlcc::SkipListPairHandle` object.
107///
108/// ## "R" Methods: Optimized Search From The Back Of The List {#bdlcc_skiplist-r-methods-optimized-search-from-the-back-of-the-list}
109///
110///
111/// The regular methods (no R suffix) of `bdlcc::SkipList` that result in a
112/// search through the list, search from the front of the list (i.e., in
113/// ascending order).
114///
115/// All methods of `bdlcc::SkipList` that result in a search through the list
116/// have corresponding "R" versions: for example, there are `add` and `addR`
117/// methods, `find` and `findR` methods, etc. The "R" versions of these methods
118/// search from the back of the list (i.e., in descending (reverse) order). Use
119/// of an "R" method is a hint to the Skip List that the desired key is more
120/// likely to be near the back than the front. In the event of duplicate keys,
121/// `find` will find the first matching key, and `findR` will find the last
122/// matching key. Note that if there are pairs in the list with duplicate keys,
123/// the specific pair found by `find` may (or may not) be different from the one
124/// found by `findR`.
125///
126/// ## Referring to Elements in the Container {#bdlcc_skiplist-referring-to-elements-in-the-container}
127///
128///
129/// `bdlcc::SkipList` has two `handle` types for referring to elements in the
130/// container:
131///
132/// * `bdlcc::SkipList::Pair *` -- raw pointer, no destructor,
133/// `bdlcc::SkipList::releaseReferenceRaw` must be called on these pointers
134/// before the container is destroyed.
135/// * `bdlcc::SkipList::PairHandle` -- `class`, has a destructor which will
136/// release the pair handle when it goes out of scope via RAII. If the pair
137/// handle will not be destroyed before the container is, it is necessary to
138/// call `bdlcc::SkipList::PairHandle::release` before the container is
139/// destroyed.
140///
141/// The `PairHandle` type has an implicit conversion to `Pair *`. In most cases
142/// `bdlcc::SkipList` provides dual functions supporting `Pair *` and
143/// `PairHandle`. Some functions, however, only support `Pair *` parameters;
144/// for these functions, either a `Pair *` or a `PairHandle` may be passed.
145///
146/// Unless the client has some reason to prefer the `Pair *` interface, the
147/// `PairHandle` interface is recommended since it provides RAII, making it
148/// harder to leak nodes.
149///
150/// Note that in some build modes, `SkipList` will attempt to detect leaked
151/// nodes, i.e., those that were referred to by `Pair *`s for which
152/// `releaseReferenceRaw` hasn't been called, and nodes referred to by
153/// `PairHandle`s that haven't been destroyed or `release`d at the time of the
154/// skip list's destruction.
155///
156/// ## Thread Safety {#bdlcc_skiplist-thread-safety}
157///
158///
159/// `bdlcc::SkipList` is thread-safe and thread-aware; that is, multiple threads
160/// may use their own Skip List objects or may concurrently use the same object.
161///
162/// Note that safe usage of the component depends upon correct usage of
163/// `bdlcc::SkipListPair` objects (see above).
164///
165/// `bdlcc::SkipListPairHandle` is only *const* *thread-safe*. It is not safe
166/// for multiple threads to invoke non-`const` methods on the same `PairHandle`
167/// object concurrently.
168///
169/// `bdlcc::SkipListPair` is a name used for opaque pointers; the concept of
170/// thread safety does not apply to it.
171///
172/// ## Exception Safety {#bdlcc_skiplist-exception-safety}
173///
174///
175/// `bdlcc::SkipList` is exception-neutral: no method invokes `throw` or
176/// `catch`. Insertion methods (`add`, `addR`, etc) invoke the copy
177/// constructors of the contained `KEY` and `DATA` types; if those constructors
178/// throw an exception, the list provides a full rollback guarantee (it will
179/// have the same state it had prior to the call to `add`). The assignment
180/// operator may also indirectly cause @ref bad_alloc to be thrown if the system is
181/// out of memory, but in that case there is *no* guarantee of rollback on the
182/// left-hand list.
183///
184/// No method of `bdlcc::SkipListPairHandle` can throw.
185///
186/// `bdlcc::SkipListPair` is only a name used for opaque pointers; the concept
187/// of exception safety does not apply to it.
188///
189/// ## Usage {#bdlcc_skiplist-usage}
190///
191///
192/// This section illustrates intended use of this component.
193///
194/// ### Example 1: Creating a Scheduler {#bdlcc_skiplist-example-1-creating-a-scheduler}
195///
196///
197/// The "R" methods of `bdlcc::SkipList` make it ideal for use in a scheduler,
198/// in which events are likely to be scheduled after existing events. In such
199/// an implementation, events are stored in the list with their scheduled
200/// execution times as `KEY` objects: Searching near the end of the list for the
201/// right location for new events, and removing events from the front of the
202/// list for execution, are very efficient operations. Being thread- enabled
203/// also makes `bdlcc::SkipList` well-suited to use in a scheduler - a
204/// "dispatcher" thread can safety use the list at the same time that events are
205/// being scheduled from other threads. The following is an implementation of a
206/// simple scheduler class using `bdlcc::SkipList`. Note that the mutex in the
207/// scheduler is used only in connection with the scheduler's condition variable
208/// - thread-safe access to the `bdlcc::SkipList` object does *not* require any
209/// synchronization.
210/// @code
211/// class SimpleScheduler
212/// {
213/// // TYPES
214/// typedef bdlcc::SkipList<bdlt::Datetime, bsl::function<void()> > List;
215///
216/// // DATA
217/// List d_list;
218/// bslmt::ThreadUtil::Handle d_dispatcher;
219/// bslmt::Condition d_notEmptyCond;
220/// bslmt::Condition d_emptyCond;
221/// bslmt::Barrier d_startBarrier;
222/// bslmt::Mutex d_condMutex;
223/// bsls::AtomicInt d_doneFlag;
224///
225/// private:
226/// // NOT IMPLEMENTED
227/// SimpleScheduler(const SimpleScheduler&);
228///
229/// private:
230/// // PRIVATE MANIPULATORS
231///
232/// /// Run a thread that executes functions off `d_list`.
233/// void dispatcherThread()
234/// {
235/// d_startBarrier.wait();
236///
237/// while (!d_doneFlag) {
238/// List::PairHandle firstItem;
239/// if (0 == d_list.front(&firstItem)) {
240/// // The list is not empty.
241///
242/// bsls::TimeInterval when =
243/// bdlt::IntervalConversionUtil::convertToTimeInterval(
244/// firstItem.key() - bdlt::CurrentTime::utc());
245/// if (when.totalSecondsAsDouble() <= 0) {
246/// // Execute now and remove from schedule, then iterate.
247///
248/// d_list.remove(firstItem);
249/// firstItem.data()();
250///
251/// List::PairHandle tmpItem;
252///
253/// bslmt::LockGuard<bslmt::Mutex> guard(&d_condMutex);
254///
255/// if (0 == d_list.length()) {
256/// d_emptyCond.broadcast();
257/// }
258/// }
259/// else {
260/// // Wait until the first scheduled item is due.
261///
262/// bslmt::LockGuard<bslmt::Mutex> guard(&d_condMutex);
263/// List::PairHandle newFirst;
264/// if (!d_doneFlag && (0 != d_list.front(&newFirst) ||
265/// newFirst.key() == firstItem.key())) {
266/// d_notEmptyCond.timedWait(&d_condMutex,
267/// bdlt::CurrentTime::now() + when);
268/// }
269/// }
270/// }
271/// else {
272/// // The list is empty; wait on the condition variable.
273///
274/// bslmt::LockGuard<bslmt::Mutex> guard(&d_condMutex);
275/// if (d_list.isEmpty() && !d_doneFlag) {
276/// d_notEmptyCond.wait(&d_condMutex);
277/// }
278/// }
279/// }
280/// }
281///
282/// public:
283/// // CREATORS
284/// explicit
285/// SimpleScheduler(bslma::Allocator *basicAllocator = 0)
286/// : d_list(basicAllocator)
287/// , d_startBarrier(2)
288/// , d_doneFlag(false)
289/// // Creator.
290/// {
291/// int rc = bslmt::ThreadUtil::create(
292/// &d_dispatcher,
293/// bdlf::BindUtil::bind(&SimpleScheduler::dispatcherThread,
294/// this));
295/// BSLS_ASSERT(0 == rc); (void)rc;
296/// d_startBarrier.wait();
297/// }
298///
299/// ~SimpleScheduler()
300/// // d'tor
301/// {
302/// stop();
303/// }
304///
305/// // MANIPULATORS
306///
307/// /// Block until the scheduler has no jobs.
308/// void drain()
309/// {
310/// bslmt::LockGuard<bslmt::Mutex> guard(&d_condMutex);
311///
312/// while (!d_doneFlag && 0 != d_list.length()) {
313/// d_emptyCond.wait(&d_condMutex);
314/// }
315/// }
316///
317/// /// Schedule the specified `event` to occur at the specified `when`.
318/// void scheduleEvent(const bsl::function<void()>& event,
319/// const bdlt::Datetime& when)
320/// {
321/// // Use `addR` since this event will probably be placed near the end
322/// // of the list.
323///
324/// bool newFrontFlag;
325/// d_list.addR(when, event, &newFrontFlag);
326/// if (newFrontFlag) {
327/// // This event is scheduled before all other events. Wake up
328/// // the dispatcher thread.
329///
330/// d_notEmptyCond.signal();
331/// }
332/// }
333///
334/// /// Stop the scheduler.
335/// void stop()
336/// {
337/// bslmt::LockGuard<bslmt::Mutex> guard(&d_condMutex);
338///
339/// d_list.removeAll();
340///
341/// d_doneFlag = true;
342/// d_notEmptyCond.signal();
343/// d_emptyCond.broadcast();
344///
345/// if (bslmt::ThreadUtil::invalidHandle() != d_dispatcher) {
346/// bslmt::ThreadUtil::Handle dispatcher = d_dispatcher;
347/// {
348/// bslmt::LockGuardUnlock<bslmt::Mutex> g(&d_condMutex);
349/// bslmt::ThreadUtil::join(dispatcher);
350/// }
351/// d_dispatcher = bslmt::ThreadUtil::invalidHandle();
352/// }
353/// }
354/// };
355/// @endcode
356/// We can verify the correct behavior of `SimpleScheduler`. First, we need a
357/// wrapper around vector<int>::push_back, since this function is overloaded and
358/// cannot be bound directly:
359/// @code
360/// /// Push the specified `item` onto the specified `vector`.
361/// void pushBackWrapper(bsl::vector<int> *vector, int item)
362/// {
363/// vector->push_back(item);
364/// }
365/// @endcode
366/// Now, in `main`, verify that the scheduler executes events when expected:
367/// @code
368/// SimpleScheduler scheduler;
369///
370/// bsl::vector<int> values;
371///
372/// const bdlt::Datetime start = bdlt::CurrentTime::utc();
373/// bdlt::Datetime scheduleTime;
374/// @endcode
375/// Add events out of sequence and ensure they are executed in the proper order.
376/// @code
377/// scheduleTime = start;
378/// scheduleTime.addMilliseconds(2250);
379/// scheduler.scheduleEvent(bdlf::BindUtil::bind(&pushBackWrapper, &values, 2),
380/// scheduleTime);
381///
382/// scheduleTime = start;
383/// scheduleTime.addMilliseconds(750);
384/// scheduler.scheduleEvent(bdlf::BindUtil::bind(&pushBackWrapper, &values, 0),
385/// scheduleTime);
386///
387/// scheduleTime = start;
388/// scheduleTime.addMilliseconds(1500);
389/// scheduler.scheduleEvent(bdlf::BindUtil::bind(&pushBackWrapper, &values, 1),
390/// scheduleTime);
391///
392/// assert(values.empty());
393///
394/// scheduler.drain();
395///
396/// bdlt::Datetime finish = bdlt::CurrentTime::utc();
397///
398/// assert(3 == values.size());
399/// assert(0 == values[0]);
400/// assert(1 == values[1]);
401/// assert(2 == values[2]);
402///
403/// const double elapsed = bdlt::IntervalConversionUtil::convertToTimeInterval(
404/// finish - start).totalSecondsAsDouble();
405///
406/// assert(2.25 <= elapsed);
407/// assert(elapsed < 2.75);
408/// @endcode
409/// Note that the destructor of `scheduler` will call `stop()`.
410/// @}
411/** @} */
412/** @} */
413
414/** @addtogroup bdl
415 * @{
416 */
417/** @addtogroup bdlcc
418 * @{
419 */
420/** @addtogroup bdlcc_skiplist
421 * @{
422 */
423
424#include <bdlscm_version.h>
425
426#include <bdlb_print.h>
427#include <bdlb_printmethods.h>
428
429#include <bslmt_mutexassert.h>
430#include <bslmt_lockguard.h>
431#include <bslmt_condition.h>
432#include <bslmt_mutex.h>
433#include <bslmt_threadutil.h>
434
436
437#include <bslma_allocator.h>
438#include <bslma_default.h>
440
441#include <bslmf_conditional.h>
443
445#include <bsls_assert.h>
446#include <bsls_atomic.h>
447#include <bsls_keyword.h>
448#include <bsls_libraryfeatures.h>
449#include <bsls_review.h>
450#include <bsls_types.h>
451#include <bsls_util.h>
452
453#include <bsl_algorithm.h>
454#include <bsl_functional.h>
455#include <bsl_ostream.h>
456#include <bsl_vector.h>
457
458#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
459#include <bslalg_typetraits.h>
460#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
461
462#include <vector>
463
464
465namespace bdlcc {
466
467template <class KEY, class DATA>
468class SkipList;
469
470
471 // =========================
472 // local class SkipList_Node
473 // =========================
474
475/// This component-private structure is a node in the SkipList.
476template<class KEY, class DATA>
478
479 // TYPES
481
482 struct Ptrs {
483 // PUBLIC DATA
486 };
487
488 // PUBLIC DATA
490 int d_level; // values in range '[ 0 .. 31 ]'
491 DATA d_data;
492 KEY d_key;
493 Ptrs d_ptrs[1]; // Must be last; each node has space for
494 // extra 'Ptrs' allocated based on its
495 // level.
496};
497
498 // ====================================
499 // local class SkipList_DoubleLockGuard
500 // ====================================
501
503 // DATA
504 bslmt::LockGuard<bslmt::Mutex> d_firstGuard, d_lastGuard;
505
506 public:
507 // CREATOR
508
509 /// Lock both `lock1` and `lock2`, the one in the lower memory location
510 /// first.
512};
513
514 // =========================================
515 // local class SkipList_RandomLevelGenerator
516 // =========================================
517
518/// This component-private class handles randomizing the levelization of
519/// list nodes.
520///
521/// See @ref bdlcc_skiplist
523
524 // PRIVATE TYPES
525 enum {
526 k_MAX_LEVEL = 31, // Also defined in SkipList and
527 // PoolManager
528 k_SEED = 0x12b9b0a1 // arbitrary
529 };
530
531 // DATA
532 bsls::AtomicInt d_seed; // current random seed
533
534 bsls::AtomicInt d_randomBits; // 14 random bits and a sentinel bit at the
535 // 15th position
536
537 public:
538 // CREATORS
539
540 /// Construct a thread-aware random-level generator.
542
543 // MANIPULATORS
544
545 /// Return a random integer between 0 and k_MAX_LEVEL.
547};
548
549 // ====================================
550 // local class bdlcc::SkipList_PoolUtil
551 // ====================================
552
553class SkipList_PoolManager;
554
555/// This component-private utility handles the lock-free pool of list nodes.
557
558 // TYPES
559 typedef SkipList_PoolManager PoolManager;
560
561 // CLASS METHODS
562
563 /// Reserve sufficient space for a node at the specified `level` from
564 /// the specified `poolManager`, and return the address of the reserved
565 /// memory.
566 static void *allocate(PoolManager *poolManager, int level);
567
568 /// Create a new pooled node allocator that manages nodes up to the
569 /// specified `numLevels` as described by the specified `objectSizes`.
570 /// For `i` in `[0, numLevels)`, a node at level `i` will have size
571 /// `objectSizes[i]` bytes. Use the specified `basicAllocator` to
572 /// supply memory. Return the address of the new allocator. Note that
573 /// the behavior is undefined if `basicAllocator` is 0.
574 static PoolManager *createPoolManager(int *objectSizes,
575 int numLevels,
576 bslma::Allocator *basicAllocator);
577
578 /// Return the node at the specified `address` to the specified
579 /// `poolManager`. The behavior is undefined if `address` was not
580 /// allocated from `poolManager`.
581 static void deallocate(PoolManager *poolManager, void *address);
582
583 /// Destroy the specified `poolManager` which was allocated from the
584 /// specified `basicAllocator`. The behavior is undefined if
585 /// `poolManager` was not allocated from `basicAllocator`.
586 static void deletePoolManager(bslma::Allocator *basicAllocator,
587 PoolManager *poolManager);
588};
589
590 // =======================================
591 // local class SkipList_NodeCreationHelper
592 // =======================================
593
594/// This component-private structure is a scoped guard that initializes new
595/// nodes and releases them in case of exception.
596///
597/// See @ref bdlcc_skiplist
598template<class KEY, class DATA>
600
601 // PRIVATE TYPES
602 typedef SkipList_PoolManager PoolManager;
604
606
607 // DATA
608 Node *d_node_p; // the node, or 0 if no managed node
609 PoolManager *d_poolManager_p; // pool from which node was allocated
610 bool d_keyFlag; // 'true' if the key was constructed
611 bslma::Allocator *d_allocator_p; // held
612
615
616 public:
617 // CREATORS
618
619 /// Create a new scoped guard object to assist in exception-safe
620 /// initialization of the specified `node`, which was allocated from the
621 /// specified `poolManager`. Optionally specify a `basicAllocator`
622 /// used to supply memory. If `basicAllocator` is 0, the currently
623 /// installed default allocator is used.
624 SkipList_NodeCreationHelper(PoolManager *poolManager,
625 Node *node,
626 bslma::Allocator *basicAllocator = 0);
627
628 /// Destroy this scoped guard. If the guard currently manages a node,
629 /// destroy its data as necessary and return it to the pool.
631
632 // MANIPULATORS
633
634 /// Attempt to copy-construct the specified `key` and `data` into the
635 /// node specified at construction; then release the node from
636 /// management. Note that if an exception is thrown during the
637 /// invocation of either constructor, the node will remain under
638 /// management and thus the destructor of this object will do the
639 /// appropriate cleanup. The behavior is undefined if `construct` has
640 /// already been invoked on this scoped guard object.
641 void construct(const KEY& key, const DATA& data);
642};
643
644 // ==================
645 // class SkipListPair
646 // ==================
647
648/// Pointers to objects of this class are used in the "raw" API of
649/// `SkipList`; however, objects of the class are never constructed as the
650/// class serves only to provide type-safe pointers.
651///
652/// In addition, this class defines `key` and `data` member functions that
653/// pass `this` to static methods of `SkipList`.
654///
655/// See @ref bdlcc_skiplist
656template <class KEY, class DATA>
658
659 // Note these data elements are never accessed. A pointer to this type
660 // will be cast to a pointer to `SkipList_Node` so make sure we are
661 // adequately aligned to avoid compiler warnings.
662
663 // DATA
664 SkipList_Node<KEY, DATA> d_node; // never directly accessed
665
666 private:
667 // NOT IMPLEMENTED
668 SkipListPair();
670 SkipListPair& operator=(const SkipListPair&);
671
672 public:
673 // ACCESSORS
674
675 /// Return a reference to the modifiable "data" of this pair.
676 DATA& data() const;
677
678 /// Return a reference to the non-modifiable "key" value of this pair.
679 const KEY& key() const;
680};
681
682 // ========================
683 // class SkipListPairHandle
684 // ========================
685
686/// Objects of this class refer to an association (pair) in a `SkipList`. A
687/// `bdlcc::SkipListPairHandle` is implicitly convertible to a `const Pair*`
688/// and thus may be used anywhere in the `SkipList` API that a `const Pair*`
689/// is expected.
690///
691/// See @ref bdlcc_skiplist
692template <class KEY, class DATA>
694
695 // PRIVATE TYPES
697
698 // DATA
699 SkipList<KEY, DATA> *d_list_p;
700 Pair *d_node_p;
701
702 // FRIENDS
703 friend class SkipList<KEY, DATA>;
704
705 private:
706 // PRIVATE CREATORS
707
708 /// Construct a new pair handle for the specified `list` that manages
709 /// the specified `reference`. Note that it is assumed that the
710 /// creating (calling) scope already owns the `reference`.
712
713 // PRIVATE MANIPULATORS
714
715 /// Change this `SkipListPairHandle` to refer to manage the specified
716 /// `reference` in the specified `list`. If this `SkipListPairHandle`
717 /// refers to a pair, release the reference. Note that it is assumed
718 /// that the calling scope already owns the `reference`.
719 void reset(const SkipList<KEY, DATA> *list, Pair *reference);
720
721 public:
722 // CREATORS
723
724 /// Construct a new PairHandle that does not refer to a pair.
726
727 /// Construct a new pair reference for the same list and pair as the
728 /// specified `original`.
729 SkipListPairHandle(const SkipListPairHandle& original);
730
731 /// Destroy this `SkipListPairHandle`. If this `SkipListPairHandle`
732 /// refers to a pair in the list, release the reference.
734
735 // MANIPULATORS
736
737 /// Change this `SkipListPairHandle` to refer to the same list and pair
738 /// as the specified `rhs`. If this `SkipListPairHandle` initially
739 /// refers to a pair, release the reference. Return `*this`.
741
742 /// Release the reference (if any) managed by this `SkipListPairHandle`.
743 void release();
744
745 /// Invoke `release` and populate the specified `list` and `reference`
746 /// pointers with the list and reference values of this
747 /// `SkipListPairHandle`.
748 void releaseReferenceRaw(SkipList<KEY, DATA> **list, Pair **reference);
749
750 // ACCESSORS
751
752 /// Return the address of the pair referred to by this
753 /// `SkipListPairHandle`, or 0 if this handle does not manage a
754 /// reference.
755 operator const Pair*() const;
756
757 /// Return a reference to the "data" value of the pair referred to by
758 /// this object. The behavior is undefined unless `isValid` returns
759 /// `true`.
760 DATA& data() const;
761
762 /// Return a reference to the non-modifiable "key" value of the pair
763 /// referred to by this object. The behavior is undefined unless
764 /// `isValid` returns `true`.
765 const KEY& key() const;
766
767 /// Return `true` if this PairHandle currently refers to a pair, and
768 /// `false` otherwise.
769 bool isValid() const;
770};
771
772 // ==============
773 // class SkipList
774 // ==============
775
776/// This class provides a generic thread-safe Skip List (an ordered
777/// associative container). It supports an almost complete set of *value*
778/// *semantic* operations, including copy construction, assignment, equality
779/// comparison, and `ostream` printing (but not BDEX serialization).
780///
781/// See @ref bdlcc_skiplist
782template<class KEY, class DATA>
783class SkipList {
784
785 public:
786 // CONSTANTS
787 enum {
791 e_INVALID = 3
792
793#ifndef BDE_OMIT_INTERNAL_DEPRECATED
802#endif // BDE_OMIT_INTERNAL_DEPRECATED
803 };
804
805 // TYPES
808
809 private:
810 // PRIVATE TYPES
811 typedef SkipList_PoolManager PoolManager;
813
816 NodeGuard;
817
818 typedef bslmt::Mutex Lock;
820
822
823 template <class VECTOR, class VALUE_TYPE>
824 class IsVector;
825 class PairFactory;
826 class PairHandleFactory;
827
828 // PRIVATE CONSTANTS
829 enum {
830 k_MAX_NUM_LEVELS = 32, // Also defined in RandomLevelGenerator
831 // and PoolManager
832
833 k_MAX_LEVEL = 31
834 };
835
836 // DATA
838
839 bsls::AtomicInt d_listLevel;
840 Node *d_head_p;
841 Node *d_tail_p;
842
843 mutable Lock d_lock;
844
845 int d_length;
846
847 PoolManager *d_poolManager_p; // owned
848
849 bslma::Allocator *d_allocator_p; // held
850
851 // FRIENDS
852 friend class SkipListPair<KEY, DATA>;
853 friend class SkipListPairHandle<KEY, DATA>;
854 template <class KEY2, class DATA2>
856 const SkipList<KEY2, DATA2>&);
857 template <class KEY2, class DATA2>
859 const SkipList<KEY2, DATA2>&);
860
861 // PRIVATE CLASS METHODS
862
863 /// Return a non-`const` reference to the "data" value of the pair
864 /// identified by the specified `reference`.
865 static DATA& data(const Pair *reference);
866
867 /// Return a `const` reference to the "key" value of the pair identified
868 /// by the specified `reference`.
869 static const KEY& key(const Pair *reference);
870
871 /// Return the offset in bytes of `d_ptrs` from the start of the
872 /// `SkipList_Node` struct. (similar to
873 /// `offsetof(SkipList_Node, d_ptrs)` but with no requirement that
874 /// `DATA` or `KEY` be PODs)
875 static inline BSLS_KEYWORD_CONSTEXPR bsls::Types::IntPtr offsetOfPtrs();
876
877 /// Cast the specified `reference` to a `Node *`.
878 static Node *pairToNode(Pair *reference);
879
880 /// Const-cast the specified `reference` to a `Node *`.
881 static Node *pairToNode(const Pair *reference);
882
883 // PRIVATE MANIPULATORS
884
885 /// Acquire the lock, add the specified `newNode` to the list, and
886 /// release the lock. If the specified `newFrontFlag` is not 0, load
887 /// into it a `true` value if the node is at the front of the list, and
888 /// a `false` value otherwise.
889 void addNode(bool *newFrontFlag, Node *newNode);
890
891 /// Acquire the lock if the specified `lock` is `true`, add the
892 /// specified `newNode` to the list, and release the lock (if acquired).
893 /// Search for the correct position for `newNode` from the back of the
894 /// list (in descending order by key value). If the specified
895 /// `newFrontFlag` is not 0, load into it a `true` value if the node is
896 /// at the front of the list, and a `false` value otherwise.
897 void addNodeImpR(bool *newFrontFlag, Node *newNode, bool lock);
898
899 /// Invoke `addNodeImpR` with lock=`true`. IMPLEMENTATION NOTE: this
900 /// *particular* flavor of "addNode" is factored into an
901 /// optionally-non-locking version to facilitate writing the assignment
902 /// operator. If the specified `newFrontFlag` is not 0, load into it a
903 /// `true` value if the node is at the front of the list, and a `false`
904 /// value otherwise.
905 ///
906 /// Acquire the lock, add the specified `newNode` to the list, and
907 /// release the lock (if acquired). Search for the correct position for
908 /// `newNode` from the back of the list (in descending order by key
909 /// value). If `newFrontFlag` is not 0, load into it a `true` value if
910 /// the node is at the front of the list, and a `false` value otherwise.
911 void addNodeR(bool *newFrontFlag, Node *newNode);
912
913 /// Acquire the lock, add the specified `newNode` to the list, and
914 /// release the lock. If the specified `newFrontFlag` is not 0, load
915 /// into it a `true` value if the node is at the front of the list, and
916 /// a `false` value otherwise. Return 0 on success, and a nonzero value
917 /// (with no effect on the list) if a node with the same "key" value as
918 /// `newNode` is in the list.
919 int addNodeUnique(bool *newFrontFlag, Node *newNode);
920
921 /// Acquire the lock, add the specified `newNode` to the list, and
922 /// release the lock. Search for the correct position for `newNode`
923 /// from the back of the list (in descending order by key value). If
924 /// the specified `newFrontFlag` is not 0, load into it a `true` value
925 /// if the node is at the front of the list, and a `false` value
926 /// otherwise. Return 0 on success, and a nonzero value (with no effect
927 /// on the list) if a node with the same "key" value as `newNode` is in
928 /// the list.
929 int addNodeUniqueR(bool *newFrontFlag, Node *newNode);
930
931 /// Allocate a node from the node pool of this list, and set its key
932 /// value to the specified `key` and data value to the specified `data`.
933 /// Set the node's level to the specified `level` if `level` is less
934 /// than or equal to the highest level of any node previously in the
935 /// list, or to one greater than that value otherwise. Return the
936 /// allocated node. Note that this method neither acquires nor requires
937 /// the lock.
938 Node *allocateNode(int level, const KEY& key, const DATA& data);
939
940 /// Populate the members of a new Skip List. This private manipulator
941 /// must be called only once, by the constructor.
942 void initialize();
943
944 /// Insert the specified `node` into this list immediately before the
945 /// specified `location` (which is populated by either
946 /// `lookupImpLowerBound` or `lookupImpLowerBoundR`). Load into the
947 /// specified `newFrontFlag` a `true` value if the node is inserted at
948 /// the front of the list, and `false` otherwise. This method must be
949 /// called under the lock.
950 void insertImp(bool *newFrontFlag, Node *location[], Node *node);
951
952 /// Insert the specified `node` into this list immediately before the
953 /// specified `location` (which is populated by either
954 /// `lookupImpLowerBound` or `lookupImpLowerBoundR`,
955 /// `lookupImpUpperBound`, or lookupImpUpperBoundR'). Load into the
956 /// specified `newFrontFlag` a `true` value if the node is inserted at
957 /// the front of the list, and `false` otherwise. This method must be
958 /// called under the lock.
959 ///
960 /// Like `insertImp`, but `node` must already be present in the list.
961 /// This internal method must be called under the lock.
962 void moveImp(bool *newFrontFlag, Node *location[], Node *node);
963
964 /// Acquire the lock, remove the front of the list, and release the
965 /// lock. Return the node that was at the front of the list, or 0 if
966 /// the list was empty.
967 Node *popFrontImp();
968
969 /// Decrement the reference count of the specified `node`, and if it
970 /// reaches 0, destroy `node` and return it to the pool. Note that this
971 /// method neither acquires nor requires the lock.
972 void releaseNode(Node *node);
973
974 /// Remove all items from this list, and append to the specified
975 /// `removed` vector objects referring to the removed nodes. Note that
976 /// the objects appended to `removed` will be in ascending order by key
977 /// value. Note that `removed` may be 0, in which case removed nodes
978 /// are released. Return the number of items that were removed from the
979 /// list. The behavior is undefined unless the mutex is already locked
980 /// before it is called.
981 template <class VECTOR>
982 int removeAllMaybeUnlock(VECTOR *removed, bool unlock);
983
984 /// Remove all items from this list, and append to the specified
985 /// `removed` vector objects referring to the removed nodes. Note that
986 /// the objects appended to `removed` will be in ascending order by key
987 /// value. Note that `removed` may be 0, in which case removed nodes
988 /// are released. Return the number of items that were removed from the
989 /// list. The behavior is undefined unless the mutex is already locked
990 /// before it is called.
991 template <class VECTOR>
992 int removeAllImp(VECTOR *removed);
993
994 /// Acquire the lock, remove the specified `node` from the list, and
995 /// release the lock. Return 0 on success, and `e_NOT_FOUND` if the
996 /// `node` is no longer in the list.
997 int removeNode(Node *node);
998
999 /// Acquire the lock, move the specified `node` to the correct position
1000 /// for the specified `newKey`, and release the lock. Update the key
1001 /// value of `node` to the `newKey` value. If the specified
1002 /// `newFrontFlag` is not 0, load into it a `true` value if the new
1003 /// location of the node is the front of the list, and a `false` value
1004 /// otherwise. If there will be multiple instances of `newKey` in the
1005 /// list after the update, the updated node will be the *first* node
1006 /// with the key `newKey`. Return 0 on success, `e_NOT_FOUND` if the
1007 /// node is no longer in the list, or `e_DUPLICATE` if the specified
1008 /// `allowDuplicates` is `false` and `newKey` already appears in the
1009 /// list.
1010 int updateNode(bool *newFrontFlag,
1011 Node *node,
1012 const KEY& newKey,
1013 bool allowDuplicates);
1014
1015 /// Acquire the lock, move the specified `node` to the correct position
1016 /// for the specified `newKey`, and release the lock. The search for
1017 /// the correct location for `newKey` proceeds from the back of the list
1018 /// in descending order by by key value. Update the key value of `node`
1019 /// to the `newKey` value. If the specified `newFrontFlag` is not 0,
1020 /// load into it a `true` value if the new location of the node is the
1021 /// front of the list, and a `false` value otherwise. If there will be
1022 /// multiple instances of `newKey` in the list after the update, the
1023 /// updated node will be the *last* node with the key `newKey`. Return
1024 /// 0 on success, `e_NOT_FOUND` if the node is no longer in the list, or
1025 /// `e_DUPLICATE` if the specified `allowDuplicates` is `false` and
1026 /// `newKey` already appears in the list.
1027 int updateNodeR(bool *newFrontFlag,
1028 Node *node,
1029 const KEY& newKey,
1030 bool allowDuplicates);
1031
1032 // PRIVATE ACCESSORS
1033
1034 /// Return the node at the back of the list, or 0 if the list is empty.
1035 /// This method acquires and releases the lock.
1036 Node *backNode() const;
1037
1038 /// This function is normally never called -- it is useful in debugging.
1039 /// If this function is called from anywhere other than the destructor,
1040 /// it is important that the mutex be locked.
1041 void checkInvariants() const;
1042
1043 /// Return the node with the specified `key`, or 0 if no node could be
1044 /// found. This method acquires and releases the lock.
1045 Node *findNode(const KEY& key) const;
1046
1047 /// Return the node with the specified `key`, or 0 if no node could be
1048 /// found. This method acquires and releases the lock.
1049 Node *findNodeR(const KEY& key) const;
1050
1051 /// Return the first node in this list whose key is not less than the
1052 /// specified `key`, found by searching the list from the front (in
1053 /// ascending order of key value), and 0 if no such node exists. This
1054 /// method acquires and releases the lock.
1055 Node *findNodeLowerBound(const KEY& key) const;
1056
1057 /// Return the first node in this list whose key is not less than the
1058 /// specified `key`, found by searching the list from the back (in
1059 /// descending order of key value), and 0 if no such node exists. This
1060 /// method acquires and releases the lock.
1061 Node *findNodeLowerBoundR(const KEY& key) const;
1062
1063 /// Return the first node in this list whose key is greater than the
1064 /// specified `key`, found by searching the list from the front (in
1065 /// ascending order of key value), and 0 if no such node exists. This
1066 /// method acquires and releases the lock.
1067 Node *findNodeUpperBound(const KEY& key) const;
1068
1069 /// Return the first node in this list whose key is greater than the
1070 /// specified `key`, found by searching the list from the back (in
1071 /// descending order of key value), and 0 if no such node exists. This
1072 /// method acquires and releases the lock.
1073 Node *findNodeUpperBoundR(const KEY& key) const;
1074
1075 /// Return the node at the front of the list, or 0 if the list is empty.
1076 /// This method acquires and releases the lock.
1077 Node *frontNode() const;
1078
1079 /// Populate the specified `location` array with the first node whose
1080 /// key is not less than the specified `key` at each level in the list,
1081 /// found by searching the list from the front (in ascending order of
1082 /// key value); if no such node exists at a given level, the
1083 /// tail-of-list sentinel is populated for that level. This method must
1084 /// be called under the lock.
1085 void lookupImpLowerBound(Node *location[], const KEY& key) const;
1086
1087 /// Populate the specified `location` array with the first node whose
1088 /// key is not less than the specified `key` at each level in the list,
1089 /// found by searching the list from the back (in descending order of
1090 /// key value); if no such node exists at a given level, the
1091 /// tail-of-list sentinel is populated for that level. This method must
1092 /// be called under the lock.
1093 void lookupImpLowerBoundR(Node *location[], const KEY& key) const;
1094
1095 /// Populate the specified `location` array with the first node whose
1096 /// key is greater than the specified `key` at each level in the list,
1097 /// found by searching the list from the front (in ascending order of
1098 /// key value); if no such node exists at a given level, the
1099 /// tail-of-list sentinel is populated for that level. This method must
1100 /// be called under the lock.
1101 void lookupImpUpperBound(Node *location[], const KEY& key) const;
1102
1103 /// Populate the specified `location` array with the first node whose
1104 /// key is greater than the specified `key` at each level in the list,
1105 /// found by searching the list from the back (in descending order of
1106 /// key value); if no such node exists at a given level, the
1107 /// tail-of-list sentinel is populated for that level. This method must
1108 /// be called under the lock.
1109 void lookupImpUpperBoundR(Node *location[], const KEY& key) const;
1110
1111 /// Return the node after to the specified `node`, or 0 if `node` is at
1112 /// the back of the list. This method acquires and releases the lock.
1113 Node *nextNode(Node *node) const;
1114
1115 /// Return the node prior to the specified `node`, or 0 if `node` is at
1116 /// the front of the list. This method acquires and releases the lock.
1117 Node *prevNode(Node *node) const;
1118
1119 /// If the item identified by the specified `node` is not at the front
1120 /// of the list, load a reference to the previous item in the list into
1121 /// `node`; otherwise load 0 into `node`. Return 0 on success, and
1122 /// `e_NOT_FOUND` (with no effect on the value of `node`) if `node` is
1123 /// no longer in the list. This method acquires and releases the lock.
1124 int skipBackward(Node **node) const;
1125
1126 /// If the item identified by the specified `node` is not at the back of
1127 /// the list, load a reference to the next item in the list into `node`;
1128 /// otherwise load 0 into `node`. Return 0 on success, and
1129 /// `e_NOT_FOUND` (with no effect on the value of `node`) if `node` is
1130 /// no longer in the list. This method acquires and releases the lock.
1131 int skipForward(Node **node) const;
1132
1133 private:
1134 // NOT IMPLEMENTED
1135 void addPairReferenceRaw(const PairHandle&);
1136
1137 /// These methods are declared `private` and not implemented to prevent
1138 /// the accidental casting of a `SkipListPairHandle` to a
1139 /// `SkipListPair *`.
1140 void releaseReferenceRaw(const PairHandle&);
1141
1142 public:
1143 // TRAITS
1145
1146 // CLASS METHODS
1147
1148 /// Return the level of the pair identified by the specified
1149 /// `reference`. This method is provided for testing.
1150 static int level(const Pair *reference);
1151
1152 // CREATORS
1153
1154 /// Create a new Skip List. Optionally specify a `basicAllocator` used
1155 /// to supply memory. If `basicAllocator` is 0, the currently installed
1156 /// default allocator is used.
1157 explicit SkipList(bslma::Allocator *basicAllocator = 0);
1158
1159 /// Create a new Skip List initialized to the value of the specified
1160 /// `original` list. Optionally specify a `basicAllocator` used to
1161 /// supply memory. If `basicAllocator` is 0, the currently installed
1162 /// default allocator is used.
1163 SkipList(const SkipList& original, bslma::Allocator *basicAllocator = 0);
1164
1165 /// Destroy this Skip List. The behavior is undefined if references are
1166 /// outstanding to any pairs in the list.
1168
1169 // MANIPULATORS
1170
1171 /// Assign to this Skip List the value of the specified `rhs` list and
1172 /// return a reference to the modifiable list.
1174
1175 /// Release the specified `reference`. After calling this method, the
1176 /// value of `reference` must not be used or released again.
1177 void releaseReferenceRaw(const Pair *reference);
1178
1179 // Insertion Methods
1180
1181 /// Add the specified `key` / `data` pair to this list. Load into the
1182 /// the optionally specified `newFrontFlag` a `true` value if the pair
1183 /// is at the front of the list, and a `false` value otherwise.
1184 void add(const KEY& key, const DATA& data, bool *newFrontFlag = 0);
1185
1186 /// Add the specified `key` / `data` pair to this list, and load into
1187 /// the specified `result` a reference to the pair in the list. Load
1188 /// into the optionally specified `newFrontFlag` a `true` value if the
1189 /// pair is at the front of the list, and a `false` value otherwise.
1190 void add(PairHandle *result,
1191 const KEY& key,
1192 const DATA& data,
1193 bool *newFrontFlag = 0);
1194
1195 /// Add the specified `key` / `data` pair to this list at the specified
1196 /// `level`, and load into the specified `result` a reference to the
1197 /// pair in the list. The `result` reference must be released (using
1198 /// `releaseReferenceRaw`) when it is no longer needed. Load into the
1199 /// the optionally specified `newFrontFlag` a `true` value if the pair
1200 /// is at the front of the list, and a `false` value otherwise. The
1201 /// behavior is undefined if `level` is greater than the
1202 /// implementation-defined maximum level of this class, or if `level` is
1203 /// negative. Note that this method is provided for testing purposes.
1204 void addAtLevelRaw(Pair **result,
1205 int level,
1206 const KEY& key,
1207 const DATA& data,
1208 bool *newFrontFlag = 0);
1209
1210 /// Add the specified `key` / `data` pair to this list at the specified
1211 /// `level`, and load into the specified `result` a reference to the
1212 /// pair in the list. The `result` reference must be released (using
1213 /// `releaseReferenceRaw`) when it is no longer needed. Load into the
1214 /// the optionally specified `newFrontFlag` a `true` value if the pair
1215 /// is at the front of the list, and a `false` value otherwise. The
1216 /// behavior is undefined if `level` is greater than the
1217 /// implementation-defined maximum level of this class, or if `level` is
1218 /// negative. Return 0 on success, and a non-zero value (with no effect
1219 /// on the list) if `key` is already in the list. Note that this method
1220 /// is provided for testing purposes.
1222 int level,
1223 const KEY& key,
1224 const DATA& data,
1225 bool *newFrontFlag = 0);
1226
1227 /// Add the specified `key` / `data` pair to this list, and load into
1228 /// the specified `result` a reference to the pair in the list. The
1229 /// `result` reference must be released (using `releaseReferenceRaw`)
1230 /// when it is no longer needed. Load into the optionally specified
1231 /// `newFrontFlag` a `true` value if the pair is at the front of the
1232 /// list, and a `false` value otherwise.
1233 void addRaw(Pair **result,
1234 const KEY& key,
1235 const DATA& data,
1236 bool *newFrontFlag = 0);
1237
1238 /// Add the specified `key` / `data` pair to this list. Load into the
1239 /// the optionally specified `newFrontFlag` a `true` value if the pair
1240 /// is at the front of the list, and a `false` value otherwise. Return
1241 /// 0 on success, and a non-zero value (with no effect on the list) if
1242 /// `key` is already in the list.
1243 int addUnique(const KEY& key, const DATA& data, bool *newFrontFlag = 0);
1244
1245 /// Add the specified `key` / `data` pair to this list, and load into
1246 /// the specified `result` a reference to the pair in the list. Load
1247 /// into the optionally specified `newFrontFlag` a `true` value if the
1248 /// pair is at the front of the list, and a `false` value otherwise.
1249 /// Return 0 on success, and a non-zero value (with no effect on the
1250 /// list) if `key` is already in the list.
1252 const KEY& key,
1253 const DATA& data,
1254 bool *newFrontFlag = 0);
1255
1256 /// Add the specified `key` / `data` pair to this list, and load into
1257 /// the specified `result` a reference to the pair in the list. The
1258 /// `result` reference must be released (using `releaseReferenceRaw`)
1259 /// when it is no longer needed. Load into the optionally specified
1260 /// `newFrontFlag` a `true` value if the pair is at the front of the
1261 /// list, and a `false` value otherwise. Return 0 on success, and a
1262 /// non-zero value (with no effect on the list) if `key` is already in
1263 /// the list.
1264 int addUniqueRaw(Pair **result,
1265 const KEY& key,
1266 const DATA& data,
1267 bool *newFrontFlag = 0);
1268
1269 // Insertion Methods (Reverse Search)
1270
1271 /// Add the specified `key` / `data` pair to this list at the specified
1272 /// `level`, and load into the specified `result` a reference to the
1273 /// pair in the list. Search for the correct position for `key` from
1274 /// the back of the list (in descending order by key value). The
1275 /// `result` reference must be released (using `releaseReferenceRaw`)
1276 /// when it is no longer needed. Load into the optionally specified
1277 /// `newFrontFlag` a `true` value if the pair is at the front of the
1278 /// list, and a `false` value otherwise. The behavior is undefined if
1279 /// `level` is greater than the implementation-defined maximum level of
1280 /// this class, or if `level` is negative. Note that this method is
1281 /// provided for testing purposes.
1282 void addAtLevelRawR(Pair **result,
1283 int level,
1284 const KEY& key,
1285 const DATA& data,
1286 bool *newFrontFlag = 0);
1287
1288 /// Add the specified `key` / `data` pair to this list at the specified
1289 /// `level`, and load into the specified `result` a reference to the
1290 /// pair in the list. Search for the correct position for `key` from
1291 /// the back of the list (in descending order by key value). The
1292 /// `result` reference must be released (using `releaseReferenceRaw`)
1293 /// when it is no longer needed. Load into the optionally specified
1294 /// `newFrontFlag` a `true` value if the pair is at the front of the
1295 /// list, and a `false` value otherwise. The behavior is undefined if
1296 /// `level` is greater than the implementation-defined maximum level of
1297 /// this class, or if `level` is negative. Return 0 on success, and a
1298 /// non-zero value (with no effect on the list) if `key` is already in
1299 /// the list. Note that this method is provided for testing purposes.
1301 int level,
1302 const KEY& key,
1303 const DATA& data,
1304 bool *newFrontFlag = 0);
1305
1306 /// Add the specified `key` / `data` pair to this list. Search for the
1307 /// correct position for `key` from the back of the list (in descending
1308 /// order by key value). Load into the optionally specified
1309 /// `newFrontFlag` a `true` value if the pair is at the front of the
1310 /// list, and a `false` value otherwise.
1311 void addR(const KEY& key, const DATA& data, bool *newFrontFlag = 0);
1312
1313 /// Add the specified `key` / `data` pair to this list, and load into
1314 /// the specified `result` a reference to the pair in the list. Search
1315 /// for the correct position for `key` from the back of the list (in
1316 /// descending order by key value). Load into the optionally specified
1317 /// `newFrontFlag` a `true` value if the pair is at the front of the
1318 /// list, and a `false` value otherwise.
1319 void addR(PairHandle *result,
1320 const KEY& key,
1321 const DATA& data,
1322 bool *newFrontFlag = 0);
1323
1324 /// Add the specified `key` / `data` pair to this list, and load into
1325 /// the specified `result` a reference to the pair in the list. Search
1326 /// for the correct position for `key` from the back of the list (in
1327 /// descending order by key value). The `result` reference must be
1328 /// released (using `releaseReferenceRaw`) when it is no longer needed.
1329 /// Load into the optionally specified `newFrontFlag` a `true` value if
1330 /// the pair is at the front of the list, and a `false` value otherwise.
1331 void addRawR(Pair **result,
1332 const KEY& key,
1333 const DATA& data,
1334 bool *newFrontFlag = 0);
1335
1336 /// Add the specified `key` / `data` pair to this list. Search for the
1337 /// correct position for `key` from the back of the list (in descending
1338 /// order by key value). Load into the optionally specified
1339 /// `newFrontFlag` a `true` value if the pair is at the front of the
1340 /// list, and a `false` value otherwise. Return 0 on success, and a
1341 /// non-zero value (with no effect on the list) if `key` is already in
1342 /// the list.
1343 int addUniqueR(const KEY& key, const DATA& data, bool *newFrontFlag = 0);
1344
1345 /// Add the specified `key` / `data` pair to this list, and load into
1346 /// the specified `result` a reference to the pair in the list. Search
1347 /// for the correct position for `key` from the back of the list (in
1348 /// descending order by key value). Load into the optionally specified
1349 /// `newFrontFlag` a `true` value if the pair is at the front of the
1350 /// list, and a `false` value otherwise. Return 0 on success, and a
1351 /// non-zero value (with no effect on the list) if `key` is already in
1352 /// the list.
1354 const KEY& key,
1355 const DATA& data,
1356 bool *newFrontFlag = 0);
1357
1358 /// Add the specified `key` / `data` pair to this list, and load into
1359 /// the specified `result` a reference to the pair in the list. Search
1360 /// for the correct position for `key` from the back of the list (in
1361 /// descending order by key value). The `result` reference must be
1362 /// released (using `releaseReferenceRaw`) when it is no longer needed.
1363 /// Load into the optionally specified `newFrontFlag` a `true` value if
1364 /// the pair is at the front of the list, and a `false` value otherwise.
1365 /// Return 0 on success, and a non-zero value (with no effect on the
1366 /// list) if `key` is already in the list.
1367 int addUniqueRawR(Pair **result,
1368 const KEY& key,
1369 const DATA& data,
1370 bool *newFrontFlag = 0);
1371
1372 // Removal Methods
1373
1374 /// Remove the first item from the list and load a reference to it into
1375 /// the optionally specified `item`. Return 0 on success, and a
1376 /// non-zero value if the list is empty.
1377 int popFront(PairHandle *item = 0);
1378
1379 /// Remove the first item from the list and load a reference to it into
1380 /// the specified `item`. This reference must be released (using
1381 /// `releaseReferenceRaw`) when it is no longer needed. Return 0 on
1382 /// success, and a non-zero value if the list is empty.
1383 int popFrontRaw(Pair **item);
1384
1385 /// Remove the item identified by the specified `reference` from the
1386 /// list. Return 0 on success, and a non-zero value if the pair has
1387 /// already been removed from the list.
1388 int remove(const Pair *reference);
1389
1392 /// Remove all items from this list. Optionally specify `removed`, a
1393 /// vector to which to append handles to the removed nodes. The items
1394 /// appended to `removed` will be in ascending order by key value.
1395 /// Return the number of items that were removed from this list. Note
1396 /// that all references in `removed` must be released (i.e., destroyed)
1397 /// before this skip list is destroyed. Note that if `removed` is not
1398 /// specified, all removed elements will be released by this method.
1399 int removeAll(std::vector<PairHandle> *removed);
1400#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1401 int removeAll(std::pmr::vector<PairHandle> *removed);
1402#endif
1403
1405 /// Remove all items from this list. Append to the specified
1406 /// `removed` vector pointers that can be used to refer to the removed
1407 /// items. *Each* such pointer must be released (using
1408 /// `releaseReferenceRaw`) when it is no longer needed. The pairs
1409 /// appended to `removed` will be in ascending order by key value.
1410 /// Return the number of items that were removed from this list.
1411 int removeAllRaw(std::vector<Pair *> *removed);
1412#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1413 int removeAllRaw(std::pmr::vector<Pair *> *removed);
1414#endif
1415
1416 // Update Methods
1417
1418 /// Assign the specified `newKey` value to the pair identified by the
1419 /// specified `reference`, moving the pair within the list as necessary.
1420 /// Load into the optionally specified `newFrontFlag` a `true` value if
1421 /// the new location of the pair is the front of the list. Return 0 on
1422 /// success, `e_NOT_FOUND` if the pair referred to by `reference` is no
1423 /// longer in the list, or `e_DUPLICATE` if the optionally specified
1424 /// `allowDuplicates` is `false` and `newKey` already appears in the
1425 /// list.
1426 int update(const Pair *reference,
1427 const KEY& newKey,
1428 bool *newFrontFlag = 0,
1429 bool allowDuplicates = true);
1430
1431 /// Assign the specified `newKey` value to the pair identified by the
1432 /// specified `reference`, moving the pair within the list as necessary.
1433 /// Search for the new position from the back of the list (in descending
1434 /// order by key value). Load into the optionally specified
1435 /// `newFrontFlag` a `true` value if the new location of the pair is the
1436 /// front of the list. Return 0 on success, `e_NOT_FOUND` if the pair
1437 /// referred to by `reference` is no longer in the list, or
1438 /// `e_DUPLICATE` if the optionally specified `allowDuplicates` is
1439 /// `false` and `newKey` already appears in the list.
1440 int updateR(const Pair *reference,
1441 const KEY& newKey,
1442 bool *newFrontFlag = 0,
1443 bool allowDuplicates = true);
1444
1445 // ACCESSORS
1446
1447 /// Increment the reference count for the list element referred to by
1448 /// the specified `reference`. There must be a corresponding call to
1449 /// `releaseReferenceRaw` when the reference is no longer needed. The
1450 /// behavior is undefined `item` has already been released. Return
1451 /// `reference`.
1452 Pair *addPairReferenceRaw(const Pair *reference) const;
1453
1454 /// Load into the specified `back` a reference to the last item in the
1455 /// list. Return 0 on success, and a non-zero value (with no effect on
1456 /// `back`) if the list is empty.
1457 int back(PairHandle *back) const;
1458
1459 /// Load into the specified `back` a reference to the last item in the
1460 /// list. The `back` reference must be released (using
1461 /// `releaseReferenceRaw`) when it is no longer needed. Return 0 on
1462 /// success, and a non-zero value if the list is empty. Note that if
1463 /// the list is empty, the value of `*back` is undefined.
1464 int backRaw(Pair **back) const;
1465
1466 /// Return `true` if there is a pair in the list with the specified
1467 /// `key`, and `false` otherwise.
1468 bool exists(const KEY& key) const;
1469
1470 /// Load into the specified `front` a reference to the first item in the
1471 /// list. Return 0 on success, and a non-zero value (with no effect on
1472 /// `front`) if the list is empty.
1474
1475 /// Load into the specified `front` a reference to the first item in the
1476 /// list. The `front` reference must be released (using
1477 /// `releaseReferenceRaw`) when it is no longer needed. Return 0 on
1478 /// success, and a non-zero value if the list is empty.
1479 int frontRaw(Pair **front) const;
1480
1481 /// Return `true` if this list is empty, and `false` otherwise.
1482 bool isEmpty() const;
1483
1484 /// Return the number of items in this list.
1485 int length() const;
1486
1487 /// Format this list object to the specified output `stream` at the
1488 /// (absolute value of) the optionally specified indentation `level` and
1489 /// return a reference to `stream`. If `level` is specified, optionally
1490 /// specify `spacesPerLevel`, the number of spaces per indentation level
1491 /// for this and all of its nested objects. If `level` is negative,
1492 /// suppress indentation of the first line. If `spacesPerLevel` is
1493 /// negative, suppress all indentation AND format the entire output on
1494 /// one line. If `stream` is not valid on entry, this operation has no
1495 /// effect.
1496 bsl::ostream& print(bsl::ostream& stream,
1497 int level = 0,
1498 int spacesPerLevel = 4) const;
1499
1500 // simple forward finds
1501
1502 /// Load into the specified `item` a reference to the element in this
1503 /// list with the specified `key` found by searching the list from the
1504 /// front (in ascending order of key value). If multiple elements
1505 /// having `key` are in the container, load `item` with the *first*
1506 /// matching element. Return 0 on success, and a non-zero value (with
1507 /// no effect on `item`) if no such element exists. If there are
1508 /// multiple elements in the list with the `key`, it is undefined which
1509 /// one is returned.
1510 int find(PairHandle *item, const KEY& key) const;
1511
1512 /// Load into the specified `item` a reference to the element in this
1513 /// list with the specified `key` found by searching the list from the
1514 /// front (in ascending order of key value). Return 0 on success, and a
1515 /// non-zero value (with no effect on `item`) if no such element exists.
1516 /// If there are multiple elements in the list with the `key`, it is
1517 /// undefined which one is returned. The `item` reference must be
1518 /// released (using `releaseReferenceRaw`) when it is no longer needed.
1519 int findRaw(Pair **item, const KEY& key) const;
1520
1521 // simple reverse finds
1522
1523 /// Load into the specified `item` a reference to the element in this
1524 /// list with the specified `key` found by searching the list from the
1525 /// back (in descending order of key value). If multiple elements
1526 /// having `key` are in the container, load `item` with the *last*
1527 /// matching element. `key` are present, find the last one. Return 0
1528 /// on success, and a non-zero value (with no effect on `item`) if no
1529 /// such element exists. If there are multiple elements in the list
1530 /// with the `key`, it is undefined which one is returned.
1531 int findR(PairHandle *item, const KEY& key) const;
1532
1533 /// Load into the specified `item` a reference to the element in this
1534 /// list with the specified `key` found by searching the list from the
1535 /// back (in descending order of key value). Return 0 on success, and a
1536 /// non-zero value (with no effect on `item`) if no such element exists.
1537 /// If there are multiple elements in the list with the `key`, it is
1538 /// undefined which one is returned. The `item` reference must be
1539 /// released (using `releaseReferenceRaw`) when it is no longer needed.
1540 int findRRaw(Pair **item, const KEY& key) const;
1541
1542 // find lower bound
1543
1544 /// Load into the specified `item` a reference to the first element in
1545 /// this list whose key value is not less than the specified `key` found
1546 /// by searching the list from the front (in ascending order of key
1547 /// value). Return 0 on success, and a non-zero value (with no effect
1548 /// on `item`) if no such element exists.
1549 int findLowerBound(PairHandle *item, const KEY& key) const;
1550
1551 /// Load into the specified `item` a reference to the first element in
1552 /// this list whose key value is not less than the specified `key` found
1553 /// by searching the list from the front (in ascending order of key
1554 /// value). Return 0 on success, and a non-zero value (with no effect
1555 /// on `item`) if no such element exists. The `item` reference must be
1556 /// released (using `releaseReferenceRaw`) when it is no longer needed.
1557 int findLowerBoundRaw(Pair **item, const KEY& key) const;
1558
1559 // find lower bound reverse
1560
1561 /// Load into the specified `item` a reference to the first element in
1562 /// this list whose key value is not less than the specified `key` found
1563 /// by searching the list from the back (in descending order of key
1564 /// value). Return 0 on success, and a non-zero value (with no effect
1565 /// on `item`) if no such element exists.
1566 int findLowerBoundR(PairHandle *item, const KEY& key) const;
1567
1568 /// Load into the specified `item` a reference to the first element in
1569 /// this list whose key value is not less than the specified `key` found
1570 /// by searching the list from the back (in descending order of key
1571 /// value). Return 0 on success, and a non-zero value (with no effect
1572 /// on `item`) if no such element exists. The `item` reference must be
1573 /// released (using `releaseReferenceRaw`) when it is no longer needed.
1574 int findLowerBoundRRaw(Pair **item, const KEY& key) const;
1575
1576 // find upper bound
1577
1578 /// Load into the specified `item` a reference to the first element in
1579 /// this list whose key value is greater than the specified `key` found
1580 /// by searching the list from the front (in ascending order of key
1581 /// value). Return 0 on success, and a non-zero value (with no effect
1582 /// on `item`) if no such element exists.
1583 int findUpperBound(PairHandle *item, const KEY& key) const;
1584
1585 /// Load into the specified `item` a reference to the first element in
1586 /// this list whose key value is greater than the specified `key` found
1587 /// by searching the list from the front (in ascending order of key
1588 /// value). Return 0 on success, and a non-zero value (with no effect
1589 /// on `item`) if no such element exists. The `item` reference must be
1590 /// released (using `releaseReferenceRaw`) when it is no longer needed.
1591 int findUpperBoundRaw(Pair **item, const KEY& key) const;
1592
1593 // find upper bound reverse
1594
1595 /// Load into the specified `item` a reference to the first element in
1596 /// this list whose key value is greater than the specified `key` found
1597 /// by searching the list from the back (in descending order of key
1598 /// value). Return 0 on success, and a non-zero value (with no effect
1599 /// on `item`) if no such element exists.
1600 int findUpperBoundR(PairHandle *item, const KEY& key) const;
1601
1602 /// Load into the specified `item` a reference to the first element in
1603 /// this list whose key value is greater than the specified `key` found
1604 /// by searching the list from the back (in descending order of key
1605 /// value). Return 0 on success, and a non-zero value (with no effect
1606 /// on `item`) if no such element exists. The `item` reference must be
1607 /// released (using `releaseReferenceRaw`) when it is no longer needed.
1608 int findUpperBoundRRaw(Pair **item, const KEY& key) const;
1609
1610 // next, previous, & skip*
1611
1612 /// Load into the specified `next` a reference to the item that appears
1613 /// in the list after the item identified by the specified `reference`.
1614 /// Return 0 on success, or a non-zero value if `reference` refers to
1615 /// the back of the list.
1616 int next(PairHandle *next, const Pair *reference) const;
1617
1618 /// Load into the specified `next` a reference to the item that appears
1619 /// in the list after the item identified by the specified `reference`.
1620 /// The `next` reference must be released (using `releaseReferenceRaw`)
1621 /// when it is no longer needed. Return 0 on success, or a non-zero
1622 /// value if `reference` refers to the back of the list.
1623 int nextRaw(Pair **next, const Pair *reference) const;
1624
1625 /// Load into the specified `prevPair` a reference to the pair that
1626 /// appears in the list before the pair identified by the specified
1627 /// `reference`. Return 0 on success, or a non-zero value if
1628 /// `reference` refers to the front of the list.
1629 int previous(PairHandle *prevPair, const Pair *reference) const;
1630
1631 /// Load into the specified `prevPair` a reference to the pair that
1632 /// appears in the list before the pair identified by the specified
1633 /// `reference`. The `prevPair` reference must be released (using
1634 /// `releaseReferenceRaw`) when it is no longer needed. Return 0 on
1635 /// success, or a non-zero value if `reference` refers to the front of
1636 /// the list.
1637 int previousRaw(Pair **prevPair, const Pair *reference) const;
1638
1639 /// If the item identified by the specified `item` is not at the front
1640 /// of the list, load a reference to the previous item in the list into
1641 /// `item`; otherwise reset the value of `item`. Return 0 on success,
1642 /// and `e_NOT_FOUND` (with no effect on the value of `item`) if `item`
1643 /// is no longer in the list.
1644 int skipBackward(PairHandle *item) const;
1645
1646 /// If the item identified by the specified `item` is not at the front
1647 /// of the list, load a reference to the previous item in the list into
1648 /// `item`; otherwise reset the value of `item`. Return 0 on success,
1649 /// and `e_NOT_FOUND` (with no effect on the value of `item`) if `item`
1650 /// is no longer in the list.
1651 int skipBackwardRaw(Pair **item) const;
1652
1653 /// If the item identified by the specified `item` is not at the end of
1654 /// the list, load a reference to the next item in the list into `item`;
1655 /// otherwise reset the value of `item`. Return 0 on success, and
1656 /// `e_NOT_FOUND` (with no effect on the value of `item`) if `item` is
1657 /// no longer in the list.
1658 int skipForward(PairHandle *item) const;
1659
1660 /// If the item identified by the specified `item` is not at the end of
1661 /// the list, load a reference to the next item in the list into `item`;
1662 /// otherwise reset the value of `item`. Return 0 on success, and
1663 /// `e_NOT_FOUND` (with no effect on the value of `item`) if `item` is
1664 /// no longer in the list.
1665 int skipForwardRaw(Pair **item) const;
1666
1667 // Aspects
1668
1669 /// Return the allocator used by this object to supply memory.
1671};
1672
1673// FREE OPERATORS
1674
1675/// Return `true` if the specified `lhs` list has the same value as the
1676/// specified `rhs` list, and `false` otherwise. Two lists A and B have the
1677/// same value if they have the same number of elements, and if for all i in
1678/// the range [0, numberOfElements), the i'th pair from the front of A has the
1679/// same key and data values as the i'th pair from the front of B. Note that
1680/// if there are duplicate key values in a list, the order of iteration over
1681/// those pairs may be different than for another list that was constructed
1682/// from the same sequence of values (and thus the lists may not compare
1683/// equal).
1684template <class KEY, class DATA>
1685bool operator==(const SkipList<KEY, DATA>& lhs,
1686 const SkipList<KEY, DATA>& rhs);
1687
1688/// Return `true` if the specified `lhs` list list has a different value from
1689/// the specified `rhs` list, and `false` otherwise. Two lists A and B have
1690/// different values if they have a different of elements, or if there exists
1691/// an i in the range [0, numberOfElements) such that the i'th pair from the
1692/// front of A differs in key or data values from i'th pair from the front of
1693/// B.
1694template <class KEY, class DATA>
1695bool operator!=(const SkipList<KEY, DATA>& lhs,
1696 const SkipList<KEY, DATA>& rhs);
1697
1698/// Write the specified `list` to the specified output `stream` and return a
1699/// reference to the modifiable `stream`.
1700template<class KEY, class DATA>
1701bsl::ostream& operator<<(bsl::ostream& stream,
1702 const SkipList<KEY, DATA>& list);
1703
1704 // ========================
1705 // class SkipList::IsVector
1706 // ========================
1707
1708/// This `struct` has a `value` that evaluates to `true` if the specified
1709/// `VECTOR` is a `bsl`, `std`, or `std::pmr` `vector<VALUE_TYPE>`.
1710template <class KEY, class DATA>
1711template <class VECTOR, class VALUE_TYPE>
1712class SkipList<KEY, DATA>::IsVector {
1713
1714 public:
1715 // PUBLIC CLASS DATA
1716 static const bool value =
1718#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1720#endif
1721 || bsl::is_same<std::vector<VALUE_TYPE>, VECTOR>::value;
1722};
1723
1724 // ===========================
1725 // class SkipList::PairFactory
1726 // ===========================
1727
1728template <class KEY, class DATA>
1729class SkipList<KEY, DATA>::PairFactory {
1730 public:
1731 // CREATORS
1732
1733 /// Create a `PairFactory`.
1734 explicit PairFactory(SkipList *);
1735
1736 // ACCESSOR
1737
1738 /// Convert the specified `node` to a `Pair *`.
1739 Pair *operator()(Node *node) const;
1740};
1741
1742 // =================================
1743 // class SkipList::PairHandleFactory
1744 // =================================
1745
1746template <class KEY, class DATA>
1747class SkipList<KEY, DATA>::PairHandleFactory {
1748 // DATA
1749 SkipList *d_list_p;
1750
1751 public:
1752 // CREATORS
1753
1754 /// Create a `PairHandleFactory` bound to the specified `list`.
1755 explicit PairHandleFactory(SkipList *list);
1756
1757 // ACCESSOR
1758
1759 /// Return a `PairHandle` bound to the list this object is bound to, and
1760 /// referring to the specified `node`.
1761 PairHandle operator()(Node *node) const;
1762};
1763
1764// ============================================================================
1765// INLINE DEFINITIONS
1766// ============================================================================
1767
1768 // ------------------------
1769 // SkipList_DoubleLockGuard
1770 // ------------------------
1771
1772inline
1774 bslmt::Mutex *lock2)
1775: d_firstGuard(bsl::min(lock1, lock2, bsl::less<bslmt::Mutex *>()))
1776, d_lastGuard( bsl::max(lock1, lock2, bsl::less<bslmt::Mutex *>()))
1777{}
1778
1779 // ------------------
1780 // class SkipListPair
1781 // ------------------
1782
1783// ACCESSORS
1784template <class KEY, class DATA>
1785inline
1787{
1788 return SkipList<KEY, DATA>::data(this);
1789}
1790
1791template <class KEY, class DATA>
1792inline
1794{
1795 return SkipList<KEY, DATA>::key(this);
1796}
1797
1798 // ------------------------
1799 // class SkipListPairHandle
1800 // ------------------------
1801
1802// CREATORS
1803template <class KEY, class DATA>
1804inline
1806: d_list_p(0)
1807, d_node_p(0)
1808{
1809}
1810
1811template <class KEY, class DATA>
1812inline
1814 SkipList<KEY, DATA> *list,
1815 Pair *reference)
1816: d_list_p(list)
1817, d_node_p(reference)
1818{
1819}
1820
1821template <class KEY, class DATA>
1822inline
1824 const SkipListPairHandle& original)
1825: d_list_p(original.d_list_p)
1826, d_node_p(original.d_node_p
1827 ? d_list_p->addPairReferenceRaw(original.d_node_p)
1828 : 0)
1829{
1830}
1831
1832template <class KEY, class DATA>
1833inline
1838
1839// MANIPULATORS
1840template <class KEY, class DATA>
1841inline
1844{
1845 reset(rhs.d_list_p, 0);
1846 d_node_p = rhs.d_node_p ? d_list_p->addPairReferenceRaw(rhs.d_node_p) : 0;
1847 return *this;
1848}
1849
1850template <class KEY, class DATA>
1851inline
1853{
1854 if (d_node_p) {
1855 BSLS_ASSERT(0 != d_list_p);
1856
1857 d_list_p->releaseReferenceRaw(d_node_p);
1858 d_node_p = 0;
1859 }
1860}
1861
1862template <class KEY, class DATA>
1863inline
1865 SkipList<KEY, DATA> **list,
1866 Pair **reference)
1867{
1868 BSLS_ASSERT(list);
1869 BSLS_ASSERT(reference);
1870
1871 *list = d_list_p;
1872 *reference = d_node_p;
1873 release();
1874}
1875
1876template <class KEY, class DATA>
1877inline
1879 Pair *reference)
1880{
1881 release();
1882 d_list_p = const_cast<SkipList<KEY, DATA> *>(list);
1883 d_node_p = reference;
1884}
1885
1886// ACCESSORS
1887template <class KEY, class DATA>
1888inline
1890{
1891 BSLS_ASSERT_SAFE(isValid());
1892
1893 return SkipList<KEY, DATA>::data(d_node_p);
1894}
1895
1896template <class KEY, class DATA>
1897inline
1899{
1900 return d_node_p != 0 && d_list_p != 0;
1901}
1902
1903template <class KEY, class DATA>
1904inline
1906{
1907 BSLS_ASSERT_SAFE(isValid());
1908
1909 return SkipList<KEY, DATA>::key(d_node_p);
1910}
1911
1912} // close package namespace
1913
1914// The scoping of "Pair" below should not be necessary, but xlC (versions 8 and
1915// 9) requires it.
1916
1917template <class KEY, class DATA>
1918inline
1920 operator const bdlcc::SkipListPair<KEY, DATA>*() const
1921{
1922 return d_node_p;
1923}
1924
1925namespace bdlcc {
1926
1927 // ---------------------------------
1928 // class SkipList_NodeCreationHelper
1929 // ---------------------------------
1930
1931template<class KEY, class DATA>
1932inline
1934 PoolManager *poolManager,
1935 Node *node,
1936 bslma::Allocator *basicAllocator)
1937: d_node_p(node)
1938, d_poolManager_p(poolManager)
1939, d_keyFlag(false)
1940, d_allocator_p(bslma::Default::allocator(basicAllocator))
1941{
1942}
1943
1944template<class KEY, class DATA>
1945inline
1947{
1948 if (d_node_p) {
1949 if (d_keyFlag) {
1950 d_node_p->d_key.~KEY();
1951 }
1952 PoolUtil::deallocate(d_poolManager_p, d_node_p);
1953 }
1954}
1955
1956template<class KEY, class DATA>
1957inline
1959 const DATA& data)
1960{
1961 BSLS_ASSERT(d_node_p);
1962
1964 BSLS_UTIL_ADDRESSOF(d_node_p->d_key),
1965 key,
1966 d_allocator_p);
1967 d_keyFlag = true;
1968
1970 BSLS_UTIL_ADDRESSOF(d_node_p->d_data),
1971 data,
1972 d_allocator_p);
1973
1974 d_node_p = 0;
1975}
1976
1977 // ---------------------------
1978 // class SkipList::PairFactory
1979 // ---------------------------
1980
1981// CREATORS
1982template<class KEY, class DATA>
1983inline
1986
1987// ACCESSOR
1988template<class KEY, class DATA>
1989inline
1992{
1993 return reinterpret_cast<Pair *>(node);
1994}
1995
1996 // ---------------------------------
1997 // class SkipList::PairHandleFactory
1998 // ---------------------------------
1999
2000// CREATORS
2001template<class KEY, class DATA>
2002inline
2006
2007// ACCESSOR
2008template<class KEY, class DATA>
2009inline
2012{
2013 return PairHandle(d_list_p, reinterpret_cast<Pair *>(node));
2014}
2015
2016 // --------------
2017 // class SkipList
2018 // --------------
2019
2020// PRIVATE CLASS METHODS
2021template<class KEY, class DATA>
2022inline
2023DATA& SkipList<KEY, DATA>::data(const Pair *reference)
2024{
2025 BSLS_ASSERT(reference);
2026
2027 Node *node = static_cast<Node *>(static_cast<void *>(
2028 const_cast<Pair *>(reference)));
2029 return node->d_data;
2030}
2031
2032template<class KEY, class DATA>
2033inline
2034const KEY& SkipList<KEY, DATA>::key(const Pair *reference)
2035{
2036 BSLS_ASSERT(reference);
2037
2038 const Node *node = static_cast<const Node *>(
2039 static_cast<const void *>(reference));
2040 return node->d_key;
2041}
2042
2043
2044template<class KEY, class DATA>
2045inline
2047bsls::Types::IntPtr SkipList<KEY, DATA>::offsetOfPtrs()
2048{
2049 typedef bsls::Types::IntPtr IntPtr;
2050
2051 // The null pointer dereference is just used for taking offsets and sizes
2052 // in the 'Node' struct. Note that we don't want to just create a default
2053 // constructed 'Node', because if 'KEY' or 'DATA' lack default constructors
2054 // then 'Node' has no default constructor.
2055
2056 return reinterpret_cast<IntPtr>(&reinterpret_cast<Node*>(0)->d_ptrs);
2057}
2058
2059template<class KEY, class DATA>
2060inline
2061typename SkipList<KEY, DATA>::Node
2062 *SkipList<KEY, DATA>::pairToNode(Pair *reference)
2063{
2064 return static_cast<Node *>(static_cast<void *>(reference));
2065}
2066
2067template<class KEY, class DATA>
2068inline
2069typename SkipList<KEY, DATA>::Node
2070 *SkipList<KEY, DATA>::pairToNode(const Pair *reference)
2071{
2072 return static_cast<Node *>(static_cast<void *>(
2073 const_cast<Pair *>(reference)));
2074}
2075
2076
2077// PRIVATE MANIPULATORS
2078template<class KEY, class DATA>
2079void SkipList<KEY, DATA>::addNode(bool *newFrontFlag, Node *newNode)
2080{
2081 LockGuard guard(&d_lock);
2082
2083 BSLS_ASSERT(newNode);
2084 BSLS_ASSERT(0 == newNode->d_ptrs[0].d_next_p);
2085
2086 Node *location[k_MAX_NUM_LEVELS];
2087 lookupImpLowerBound(location, newNode->d_key);
2088
2089 insertImp(newFrontFlag, location, newNode);
2090}
2091
2092template<class KEY, class DATA>
2093void SkipList<KEY, DATA>::addNodeImpR(bool *newFrontFlag,
2094 Node *newNode,
2095 bool lock)
2096{
2097 LockGuard lockGuard(&d_lock, !lock);
2098 if (!lock) {
2099 lockGuard.release();
2100 }
2101
2102 BSLS_ASSERT(newNode);
2103 BSLS_ASSERT(0 == newNode->d_ptrs[0].d_next_p);
2104
2105 Node *location[k_MAX_NUM_LEVELS];
2106 lookupImpUpperBoundR(location, newNode->d_key);
2107
2108 insertImp(newFrontFlag, location, newNode);
2109}
2110
2111template<class KEY, class DATA>
2112inline
2113void SkipList<KEY, DATA>::addNodeR(bool *newFrontFlag, Node *newNode)
2114{
2115 addNodeImpR(newFrontFlag, newNode, true); // true -> lock
2116}
2117
2118template<class KEY, class DATA>
2119int SkipList<KEY, DATA>::addNodeUnique(bool *newFrontFlag, Node *newNode)
2120{
2121 LockGuard guard(&d_lock);
2122
2123 BSLS_ASSERT(newNode);
2124 BSLS_ASSERT(0 == newNode->d_ptrs[0].d_next_p);
2125
2126 Node *location[k_MAX_NUM_LEVELS];
2127 lookupImpLowerBound(location, newNode->d_key);
2128
2129 Node *q = location[0];
2130 if (q != d_tail_p && q->d_key == newNode->d_key) {
2131 return e_DUPLICATE; // RETURN
2132 }
2133
2134 insertImp(newFrontFlag, location, newNode);
2135
2136 return 0;
2137}
2138
2139template<class KEY, class DATA>
2140int SkipList<KEY, DATA>::addNodeUniqueR(bool *newFrontFlag, Node *newNode)
2141{
2142 LockGuard guard(&d_lock);
2143
2144 BSLS_ASSERT(newNode);
2145 BSLS_ASSERT(0 == newNode->d_ptrs[0].d_next_p);
2146
2147 Node *location[k_MAX_NUM_LEVELS];
2148 lookupImpLowerBoundR(location, newNode->d_key);
2149
2150 Node *q = location[0];
2151 if (q != d_tail_p && q->d_key == newNode->d_key) {
2152 return e_DUPLICATE; // RETURN
2153 }
2154
2155 insertImp(newFrontFlag, location, newNode);
2156
2157 return 0;
2158}
2159
2160template<class KEY, class DATA>
2161SkipList_Node<KEY, DATA> *
2162SkipList<KEY, DATA>::allocateNode(int level, const KEY& key, const DATA& data)
2163{
2164 int listLevel = d_listLevel;
2165 if (level > listLevel) {
2166 level = listLevel + 1;
2167 }
2168
2169 Node *node = reinterpret_cast<Node *>(PoolUtil::allocate(d_poolManager_p,
2170 level));
2171
2172 NodeGuard nodeGuard(d_poolManager_p, node, d_allocator_p);
2173
2174 nodeGuard.construct(key, data);
2175
2176 ++node->d_refCount;
2177 node->d_ptrs[0].d_next_p = 0;
2178
2179 return node;
2180}
2181
2182template<class KEY, class DATA>
2183void SkipList<KEY, DATA>::initialize()
2184{
2185 typedef bsls::Types::IntPtr IntPtr;
2186
2187 static const int alignMask = bsls::AlignmentFromType<Node>::VALUE - 1;
2188
2189 // Assert that this method has not been invoked.
2190
2191 BSLS_ASSERT(0 == d_poolManager_p);
2192
2193 int nodeSizes[k_MAX_NUM_LEVELS];
2194
2195 const IntPtr offset = offsetOfPtrs();
2196 for (int i = 0; i < k_MAX_NUM_LEVELS; ++i) {
2197 IntPtr nodeSize = offset + (i + 1) * sizeof(typename Node::Ptrs);
2198 nodeSize = (nodeSize + alignMask) & ~alignMask;
2199 nodeSizes[i] = static_cast<int>(nodeSize);
2200 }
2201
2202 d_poolManager_p = PoolUtil::createPoolManager(nodeSizes,
2203 k_MAX_NUM_LEVELS,
2204 d_allocator_p);
2205
2206 d_head_p = reinterpret_cast<Node *>(PoolUtil::allocate(d_poolManager_p,
2207 k_MAX_LEVEL));
2208 d_tail_p = reinterpret_cast<Node *>(PoolUtil::allocate(d_poolManager_p,
2209 k_MAX_LEVEL));
2210
2211 for (int i = 0; i < k_MAX_NUM_LEVELS; ++i) {
2212 d_head_p->d_ptrs[i].d_prev_p = 0;
2213 d_head_p->d_ptrs[i].d_next_p = d_tail_p;
2214
2215 d_tail_p->d_ptrs[i].d_prev_p = d_head_p;
2216 d_tail_p->d_ptrs[i].d_next_p = 0;
2217 }
2218}
2219
2220template<class KEY, class DATA>
2221void SkipList<KEY, DATA>::insertImp(bool *newFrontFlag,
2222 Node *location[],
2223 Node *node)
2224{
2225 BSLS_ASSERT(location);
2226 BSLS_ASSERT(node);
2227
2228 int level = node->d_level;
2229 if (level > d_listLevel) {
2230 BSLS_ASSERT(level == d_listLevel + 1);
2231
2232 d_listLevel = level;
2233
2234 node->d_ptrs[level].d_prev_p = d_head_p;
2235 node->d_ptrs[level].d_next_p = d_tail_p;
2236
2237 d_head_p->d_ptrs[level].d_next_p = node;
2238 d_tail_p->d_ptrs[level].d_prev_p = node;
2239
2240 level--;
2241 }
2242
2243 for (int k = level; k >= 0; --k) {
2244 Node *p = location[k]->d_ptrs[k].d_prev_p;
2245 Node *q = location[k];
2246
2247 node->d_ptrs[k].d_prev_p = p;
2248 node->d_ptrs[k].d_next_p = q;
2249
2250 p->d_ptrs[k].d_next_p = node;
2251 q->d_ptrs[k].d_prev_p = node;
2252 }
2253
2254 if (newFrontFlag) {
2255 *newFrontFlag = (node->d_ptrs[0].d_prev_p == d_head_p);
2256 }
2257
2258 ++d_length;
2259}
2260
2261template<class KEY, class DATA>
2262void SkipList<KEY, DATA>::moveImp(bool *newFrontFlag,
2263 Node *location[],
2264 Node *node)
2265{
2266 BSLS_ASSERT(location);
2267 BSLS_ASSERT(node);
2268
2269 int level = node->d_level;
2270 BSLS_ASSERT(level <= d_listLevel);
2271
2272 for (int k = 0; k <= level; ++k) {
2273 Node *newP = location[k]->d_ptrs[k].d_prev_p;
2274 Node *newQ = location[k];
2275
2276 if (newP == node || newQ == node) {
2277 // The node's already in the right place. Since we started at
2278 // level 0, there's no more work to do.
2279
2280 break;
2281 }
2282
2283 Node *oldP = node->d_ptrs[k].d_prev_p;
2284 Node *oldQ = node->d_ptrs[k].d_next_p;
2285
2286 oldQ->d_ptrs[k].d_prev_p = oldP;
2287 oldP->d_ptrs[k].d_next_p = oldQ;
2288
2289 node->d_ptrs[k].d_prev_p = newP;
2290 node->d_ptrs[k].d_next_p = newQ;
2291
2292 newP->d_ptrs[k].d_next_p = node;
2293 newQ->d_ptrs[k].d_prev_p = node;
2294 }
2295
2296 if (newFrontFlag) {
2297 *newFrontFlag = (node->d_ptrs[0].d_prev_p == d_head_p);
2298 }
2299}
2300
2301template<class KEY, class DATA>
2302SkipList_Node<KEY, DATA> *SkipList<KEY, DATA>::popFrontImp()
2303{
2304 LockGuard guard(&d_lock);
2305
2306 Node *node = d_head_p->d_ptrs[0].d_next_p;
2307 if (node == d_tail_p) {
2308 return 0; // RETURN
2309 }
2310
2311 int level = node->d_level;
2312
2313 for (int k = level; k >= 0; --k) {
2314 Node *q = node->d_ptrs[k].d_next_p;
2315 q->d_ptrs[k].d_prev_p = d_head_p;
2316 d_head_p->d_ptrs[k].d_next_p = q;
2317 }
2318
2319 node->d_ptrs[0].d_next_p = 0;
2320 --d_length;
2321
2322 return node;
2323}
2324
2325template<class KEY, class DATA>
2326inline
2327void SkipList<KEY, DATA>::releaseNode(Node *node)
2328{
2329 BSLS_ASSERT(node);
2330
2331 const int refCnt = --node->d_refCount;
2332 if (!refCnt) {
2333 node->d_key.~KEY();
2334 node->d_data.~DATA();
2335
2336 BSLS_ASSERT(0 == node->d_ptrs[0].d_next_p);
2337
2338 PoolUtil::deallocate(d_poolManager_p, node);
2339 }
2340 else {
2341 BSLS_ASSERT_SAFE(0 < refCnt);
2342 }
2343}
2344
2345template<class KEY, class DATA>
2346template<class VECTOR>
2347int SkipList<KEY, DATA>::removeAllMaybeUnlock(VECTOR *removed, bool unlock)
2348{
2349 typedef typename VECTOR::value_type ValueType;
2350
2351 BSLMF_ASSERT((IsVector<VECTOR, ValueType>::value));
2352
2355
2357 PairFactory,
2358 PairHandleFactory>::type FactoryType;
2359
2361
2362 Node * const begin = d_head_p;
2363 Node * const end = d_tail_p->d_ptrs[0].d_prev_p;
2364 int numRemoved = d_length;
2365
2366 for (int ii = 0; ii <= d_listLevel; ++ii) {
2367 d_head_p->d_ptrs[ii].d_next_p = d_tail_p;
2368 d_tail_p->d_ptrs[ii].d_prev_p = d_head_p;
2369 }
2370 d_length = 0;
2371
2372 for (Node *q = end; begin != q; q = q->d_ptrs[0].d_prev_p) {
2373 q->d_ptrs[0].d_next_p = 0; // Marks node as removed from list,
2374 // must be done before mutex unlock.
2375 }
2376
2377 if (unlock) {
2378 d_lock.unlock();
2379 }
2380
2381 if (removed) {
2382 const FactoryType factory(this);
2383
2384 // 'oldSize' must be a signed type to be compared to the subtraction
2385 // in the assertion after the loop.
2386
2387 const bsls::Types::IntPtr oldSize = removed->size();
2388 removed->resize(oldSize + numRemoved);
2389 typename VECTOR::reverse_iterator removedIt = removed->rbegin();
2390 for (Node *q = end; begin != q; q = q->d_ptrs[0].d_prev_p) {
2391 *removedIt++ = factory(q);
2392 }
2393 BSLS_ASSERT(oldSize == removed->rend() - removedIt);
2394 }
2395 else {
2396 for (Node *q = end; begin != q; ) {
2397 Node *condemned = q;
2398 q = q->d_ptrs[0].d_prev_p;
2399
2400 releaseNode(condemned);
2401 }
2402 }
2403
2404 return numRemoved;
2405}
2406
2407template<class KEY, class DATA>
2408template<class VECTOR>
2409int SkipList<KEY, DATA>::removeAllImp(VECTOR *removed)
2410{
2411 d_lock.lock();
2412 return removeAllMaybeUnlock(removed, true);
2413}
2414
2415template<class KEY, class DATA>
2416int SkipList<KEY, DATA>::removeNode(Node *node)
2417{
2418 BSLS_ASSERT(node);
2419
2420 LockGuard guard(&d_lock);
2421
2422 if (0 == node->d_ptrs[0].d_next_p) {
2423 return e_NOT_FOUND; // RETURN
2424 }
2425
2426 int level = node->d_level;
2427
2428 for (int k = level; k >= 0; --k) {
2429 Node *p = node->d_ptrs[k].d_prev_p;
2430 Node *q = node->d_ptrs[k].d_next_p;
2431
2432 q->d_ptrs[k].d_prev_p = p;
2433 p->d_ptrs[k].d_next_p = q;
2434 }
2435
2436 node->d_ptrs[0].d_next_p = 0;
2437 --d_length;
2438 return 0;
2439}
2440
2441template<class KEY, class DATA>
2442int SkipList<KEY, DATA>::updateNode(bool *newFrontFlag,
2443 Node *node,
2444 const KEY& newKey,
2445 bool allowDuplicates)
2446{
2447 BSLS_ASSERT(node);
2448
2449 LockGuard guard(&d_lock);
2450
2451 if (0 == node->d_ptrs[0].d_next_p) {
2452 return e_NOT_FOUND; // RETURN
2453 }
2454
2455 Node *location[k_MAX_NUM_LEVELS];
2456 lookupImpLowerBound(location, newKey);
2457
2458 if (!allowDuplicates) {
2459 Node *q = location[0];
2460 if (q != d_tail_p && q != node && q->d_key == newKey) {
2461 return e_DUPLICATE; // RETURN
2462 }
2463 }
2464
2465 node->d_key = newKey; // may throw
2466
2467 // now we are committed: change the list!
2468
2469 moveImp(newFrontFlag, location, node);
2470
2471 return 0;
2472}
2473
2474template<class KEY, class DATA>
2475int SkipList<KEY, DATA>::updateNodeR(bool *newFrontFlag,
2476 Node *node,
2477 const KEY& newKey,
2478 bool allowDuplicates)
2479{
2480 BSLS_ASSERT(node);
2481
2482 LockGuard guard(&d_lock);
2483
2484 if (0 == node->d_ptrs[0].d_next_p) {
2485 return e_NOT_FOUND; // RETURN
2486 }
2487
2488 Node *location[k_MAX_NUM_LEVELS];
2489
2490 if (!allowDuplicates) {
2491 lookupImpLowerBoundR(location, newKey);
2492 Node *p = location[0];
2493 if (p != d_tail_p && p != node && p->d_key == newKey) {
2494 return e_DUPLICATE; // RETURN
2495 }
2496 }
2497 else {
2498 lookupImpUpperBoundR(location, newKey);
2499 }
2500
2501 node->d_key = newKey; // may throw
2502
2503 // now we are committed: change the list!
2504
2505 moveImp(newFrontFlag, location, node);
2506
2507 return 0;
2508}
2509
2510// PRIVATE ACCESSORS
2511template<class KEY, class DATA>
2512SkipList_Node<KEY, DATA> *
2513SkipList<KEY, DATA>::backNode() const
2514{
2515 LockGuard guard(&d_lock);
2516
2517 Node *node = d_tail_p->d_ptrs[0].d_prev_p;
2518 if (node == d_head_p) {
2519 return 0; // RETURN
2520 }
2521
2522 ++node->d_refCount;
2523 return node;
2524}
2525
2526template<class KEY, class DATA>
2527void SkipList<KEY, DATA>::checkInvariants() const
2528{
2529 for (int ii = 0; ii <= d_listLevel; ++ii) {
2530 int numNodes = 0;
2531 Node *prev = d_head_p;
2532 for (Node *q = d_head_p->d_ptrs[ii].d_next_p; d_tail_p != q;
2533 prev = q, q = q->d_ptrs[ii].d_next_p) {
2534 ++numNodes;
2535
2536 BSLS_ASSERT(q->d_ptrs[ii].d_prev_p == prev);
2537
2538 BSLS_ASSERT(0 < q->d_refCount);
2539 BSLS_ASSERT(q->d_level >= ii);
2540 BSLS_ASSERT(q->d_level <= d_listLevel);
2541
2542 for (int jj = ii - 1; 0 <= jj; --jj) {
2543 BSLS_ASSERT(q->d_ptrs[jj].d_next_p);
2544 BSLS_ASSERT(q->d_ptrs[jj].d_prev_p);
2545 }
2546 }
2547
2548 BSLS_ASSERT(numNodes <= d_length); (void)numNodes;
2549 BSLS_ASSERT(0 != ii || numNodes == d_length);
2550
2551 BSLS_ASSERT(0 == d_head_p->d_ptrs[ii].d_prev_p);
2552 BSLS_ASSERT(0 == d_tail_p->d_ptrs[ii].d_next_p);
2553 }
2554}
2555
2556template<class KEY, class DATA>
2557SkipList_Node<KEY, DATA> *SkipList<KEY, DATA>::findNode(const KEY& key) const
2558{
2559 Node *locator[k_MAX_NUM_LEVELS];
2560
2561 LockGuard guard(&d_lock);
2562 lookupImpLowerBound(locator, key);
2563
2564 Node *q = locator[0];
2565 if (q != d_tail_p && q->d_key == key) {
2566 ++q->d_refCount;
2567 return q; // RETURN
2568 }
2569
2570 return 0;
2571}
2572
2573template<class KEY, class DATA>
2574SkipList_Node<KEY, DATA> *SkipList<KEY, DATA>::findNodeR(const KEY& key) const
2575{
2576 Node *locator[k_MAX_NUM_LEVELS];
2577
2578 LockGuard guard(&d_lock);
2579 lookupImpUpperBoundR(locator, key);
2580
2581 Node *p = locator[0];
2582 if (d_head_p != p) {
2583 p = p->d_ptrs[0].d_prev_p;
2584 if (d_head_p != p && key == p->d_key) {
2585 ++p->d_refCount;
2586 return p; // RETURN
2587 }
2588 }
2589
2590 return 0;
2591}
2592
2593template<class KEY, class DATA>
2594SkipList_Node<KEY, DATA> *SkipList<KEY, DATA>::findNodeLowerBound(
2595 const KEY& key) const
2596{
2597 Node *locator[k_MAX_NUM_LEVELS];
2598
2599 LockGuard guard(&d_lock);
2600 lookupImpLowerBound(locator, key);
2601
2602 Node *q = locator[0];
2603 if (q != d_tail_p) {
2604 ++q->d_refCount;
2605 return q; // RETURN
2606 }
2607
2608 return 0;
2609}
2610
2611template<class KEY, class DATA>
2612SkipList_Node<KEY, DATA> *SkipList<KEY, DATA>::findNodeUpperBound(
2613 const KEY& key) const
2614{
2615 Node *locator[k_MAX_NUM_LEVELS];
2616
2617 LockGuard guard(&d_lock);
2618 lookupImpUpperBound(locator, key);
2619
2620 Node *q = locator[0];
2621 if (q != d_tail_p) {
2622 ++q->d_refCount;
2623 return q; // RETURN
2624 }
2625
2626 return 0;
2627}
2628
2629template<class KEY, class DATA>
2630SkipList_Node<KEY, DATA> *SkipList<KEY, DATA>::findNodeLowerBoundR(
2631 const KEY& key) const
2632{
2633 Node *locator[k_MAX_NUM_LEVELS];
2634
2635 LockGuard guard(&d_lock);
2636 lookupImpLowerBoundR(locator, key);
2637
2638 Node *q = locator[0];
2639 if (q != d_tail_p) {
2640 ++q->d_refCount;
2641 return q; // RETURN
2642 }
2643
2644 return 0;
2645}
2646
2647template<class KEY, class DATA>
2648SkipList_Node<KEY, DATA> *SkipList<KEY, DATA>::findNodeUpperBoundR(
2649 const KEY& key) const
2650{
2651 Node *locator[k_MAX_NUM_LEVELS];
2652
2653 LockGuard guard(&d_lock);
2654 lookupImpUpperBoundR(locator, key);
2655
2656 Node *q = locator[0];
2657 if (q != d_tail_p) {
2658 ++q->d_refCount;
2659 return q; // RETURN
2660 }
2661
2662 return 0;
2663}
2664
2665template<class KEY, class DATA>
2666SkipList_Node<KEY, DATA> *SkipList<KEY, DATA>::frontNode() const
2667{
2668 LockGuard guard(&d_lock);
2669
2670 Node *node = d_head_p->d_ptrs[0].d_next_p;
2671 if (node == d_tail_p) {
2672 return 0; // RETURN
2673 }
2674
2675 ++node->d_refCount;
2676 return node;
2677}
2678
2679template<class KEY, class DATA>
2680void SkipList<KEY, DATA>::lookupImpLowerBound(Node *location[],
2681 const KEY& key) const
2682{
2683 Node *p = d_head_p;
2684 for (int k = d_listLevel; k >= 0; --k) {
2685 Node *q = p->d_ptrs[k].d_next_p;
2686 while (q != d_tail_p && q->d_key < key) {
2687 p = q;
2688 q = p->d_ptrs[k].d_next_p;
2689 }
2690 location[k] = q;
2691 }
2692
2693 BSLS_ASSERT_SAFE(d_head_p != location[0]);
2694}
2695
2696template<class KEY, class DATA>
2697void SkipList<KEY, DATA>::lookupImpLowerBoundR(Node *location[],
2698 const KEY& key) const
2699{
2700 Node *q = d_tail_p;
2701 for (int k = d_listLevel; k >= 0; --k) {
2702 Node *p = q->d_ptrs[k].d_prev_p;
2703 while (p != d_head_p && !(p->d_key < key)) {
2704 q = p;
2705 p = p->d_ptrs[k].d_prev_p;
2706 }
2707 location[k] = q;
2708 }
2709
2710 BSLS_ASSERT_SAFE(d_head_p != location[0]);
2711}
2712
2713template<class KEY, class DATA>
2714void SkipList<KEY, DATA>::lookupImpUpperBound(Node *location[],
2715 const KEY& key) const
2716{
2717 Node *p = d_head_p;
2718 for (int k = d_listLevel; k >= 0; --k) {
2719 Node *q = p->d_ptrs[k].d_next_p;
2720 while (q != d_tail_p && !(key < q->d_key)) {
2721 p = q;
2722 q = p->d_ptrs[k].d_next_p;
2723 }
2724
2725 location[k] = q;
2726 }
2727
2728 BSLS_ASSERT_SAFE(d_head_p != location[0]);
2729}
2730
2731template<class KEY, class DATA>
2732void SkipList<KEY, DATA>::lookupImpUpperBoundR(Node *location[],
2733 const KEY& key) const
2734{
2735 Node *q = d_tail_p;
2736 for (int k = d_listLevel; k >= 0; --k) {
2737 Node *p = q->d_ptrs[k].d_prev_p;
2738 while (p != d_head_p && key < p->d_key) {
2739 q = p;
2740 p = q->d_ptrs[k].d_prev_p;
2741 }
2742 location[k] = q;
2743 }
2744
2745 BSLS_ASSERT_SAFE(d_head_p != location[0]);
2746}
2747
2748template<class KEY, class DATA>
2749SkipList_Node<KEY, DATA> *
2750SkipList<KEY, DATA>::nextNode(Node *node) const
2751{
2752 BSLS_ASSERT(node != d_head_p);
2753 BSLS_ASSERT(node != d_tail_p);
2754
2755 LockGuard guard(&d_lock);
2756
2757 Node *next = node->d_ptrs[0].d_next_p;
2758 if (0 == next || d_tail_p == next) {
2759 return 0; // RETURN
2760 }
2761
2762 ++next->d_refCount;
2763 return next;
2764}
2765
2766template<class KEY, class DATA>
2767SkipList_Node<KEY, DATA> *
2768SkipList<KEY, DATA>::prevNode(Node *node) const
2769{
2770 BSLS_ASSERT(node != d_head_p);
2771 BSLS_ASSERT(node != d_tail_p);
2772
2773 LockGuard guard(&d_lock);
2774 if (0 == node->d_ptrs[0].d_next_p) {
2775 return 0; // RETURN
2776 }
2777
2778 Node *prev = node->d_ptrs[0].d_prev_p;
2779 if (d_head_p == prev) {
2780 return 0; // RETURN
2781 }
2782
2783 ++prev->d_refCount;
2784 return prev;
2785}
2786
2787template<class KEY, class DATA>
2788int SkipList<KEY, DATA>::skipBackward(Node **node) const
2789{
2790 BSLS_ASSERT(node);
2791
2792 Node *current = *node;
2793 BSLS_ASSERT(current);
2794 BSLS_ASSERT(current != d_head_p);
2795 BSLS_ASSERT(current != d_tail_p);
2796
2797 LockGuard guard(&d_lock);
2798
2799 if (0 == current->d_ptrs[0].d_next_p) {
2800 // The node is no longer on the list.
2801
2802 return e_NOT_FOUND; // RETURN
2803 }
2804
2805 const int count = --current->d_refCount;
2806 BSLS_ASSERT(0 < count);
2807 (void) count; // suppress 'unused variable' warnings
2808
2809 Node *prev = current->d_ptrs[0].d_prev_p;
2810 if (d_head_p == prev) {
2811 *node = 0;
2812 return 0; // RETURN
2813 }
2814
2815 ++prev->d_refCount;
2816 *node = prev;
2817 return 0;
2818}
2819
2820template<class KEY, class DATA>
2821int SkipList<KEY, DATA>::skipForward(Node **node) const
2822{
2823 BSLS_ASSERT(node);
2824
2825 Node *current = *node;
2826 BSLS_ASSERT(current);
2827 BSLS_ASSERT(current != d_head_p);
2828 BSLS_ASSERT(current != d_tail_p);
2829
2830 LockGuard guard(&d_lock);
2831
2832 if (0 == current->d_ptrs[0].d_next_p) {
2833 // The node is no longer on the list.
2834
2835 return e_NOT_FOUND; // RETURN
2836 }
2837
2838 const int count = --current->d_refCount;
2839 BSLS_ASSERT(0 < count);
2840 (void) count; // suppress 'unused variable' warnings
2841
2842 Node *next = current->d_ptrs[0].d_next_p;
2843 if (d_tail_p == next) {
2844 *node = 0;
2845 return 0; // RETURN
2846 }
2847
2848 ++next->d_refCount;
2849 *node = next;
2850 return 0;
2851}
2852
2853// CLASS METHODS
2854template<class KEY, class DATA>
2855inline
2857{
2858 BSLS_ASSERT(reference);
2859
2860 Node *node = pairToNode(reference);
2861 return node->d_level;
2862}
2863
2864// CREATORS
2865template<class KEY, class DATA>
2867: d_listLevel(0)
2868, d_length(0)
2869, d_poolManager_p(0)
2870, d_allocator_p(bslma::Default::allocator(basicAllocator))
2871{
2872 initialize();
2873}
2874
2875template<class KEY, class DATA>
2877 bslma::Allocator *basicAllocator)
2878: d_listLevel(0)
2879, d_length(0)
2880, d_poolManager_p(0)
2881, d_allocator_p(bslma::Default::allocator(basicAllocator))
2882{
2883 initialize();
2884
2885 *this = original;
2886}
2887
2888template<class KEY, class DATA>
2890{
2891#if defined(BSLS_ASSERT_SAFE_IS_ACTIVE)
2892 checkInvariants();
2893#endif
2894
2895 for (Node *p = d_tail_p->d_ptrs[0].d_prev_p; d_head_p != p; ) {
2896 BSLS_ASSERT(1 == p->d_refCount);
2897
2898 Node *condemned = p;
2899 p = p->d_ptrs[0].d_prev_p;
2900 condemned->d_ptrs[0].d_next_p = 0;
2901
2902 releaseNode(condemned);
2903 }
2904
2905 PoolUtil::deallocate(d_poolManager_p, d_head_p);
2906 PoolUtil::deallocate(d_poolManager_p, d_tail_p);
2907
2908 PoolUtil::deletePoolManager(d_allocator_p, d_poolManager_p);
2909}
2910
2911// MANIPULATORS
2912template<class KEY, class DATA>
2915{
2916 if (&rhs == this) {
2917 return *this; // RETURN
2918 }
2919
2920 DoubleLockGuard guard(&d_lock, &rhs.d_lock);
2921
2922 // first empty this list
2923
2924 removeAllMaybeUnlock(static_cast<bsl::vector<Pair *> *>(0), false);
2925
2926 // Now get handles to all of 'rhs's elements. Since rhs.d_lock is locked,
2927 // we need to do all operations manually because the important functions of
2928 // 'rhs' (like frontNode and nextNode) will lock the mutex.
2929
2930 bsl::vector<PairHandle> rhsElements;
2931 rhsElements.reserve(rhs.d_length);
2932 for (Node *node = rhs.d_head_p->d_ptrs[0].d_next_p;
2933 node && node != rhs.d_tail_p;
2934 node = node->d_ptrs[0].d_next_p)
2935 {
2936 ++node->d_refCount;
2937 rhsElements.insert(rhsElements.end(),
2938 PairHandle())->reset(
2939 &rhs,
2940 reinterpret_cast<Pair *>(node));
2941 }
2942
2943 // Note that unlocking 'rhs.d_lock' here causes a data race if another
2944 // thread calls 'update' or 'updateR' on a node in 'rhs'.
2945
2946 for (typename bsl::vector<PairHandle>::iterator it = rhsElements.begin();
2947 it != rhsElements.end(); ++it) {
2948 Node *node = allocateNode(d_rand.randomLevel(),
2949 it->key(), it->data());
2950 addNodeImpR(0, node, false); // false -> do not lock (already locked)
2951 }
2952
2953 return *this;
2954}
2955
2956template<class KEY, class DATA>
2957inline
2959{
2960 Node *node = pairToNode(reference);
2961 releaseNode(node);
2962}
2963
2964 // Insertion Methods
2965
2966template<class KEY, class DATA>
2967inline
2969 const KEY& key,
2970 const DATA& data,
2971 bool *newFrontFlag)
2972{
2973 Pair *handle;
2974 addRaw(&handle, key, data, newFrontFlag);
2975 result->reset(this, handle);
2976}
2977
2978template<class KEY, class DATA>
2979inline
2980void SkipList<KEY, DATA>::add(const KEY& key,
2981 const DATA& data,
2982 bool *newFrontFlag)
2983{
2984 Pair **zeroPair = 0;
2985 addRaw(zeroPair, key, data, newFrontFlag);
2986}
2987
2988template<class KEY, class DATA>
2989inline
2991 int level,
2992 const KEY& key,
2993 const DATA& data,
2994 bool *newFrontFlag)
2995{
2996 Node *node = allocateNode(level, key, data);
2997 if (result) {
2998 ++node->d_refCount;
2999 *result = reinterpret_cast<Pair *>(node);
3000 }
3001
3002 addNode(newFrontFlag, node);
3003}
3004
3005template<class KEY, class DATA>
3007 int level,
3008 const KEY& key,
3009 const DATA& data,
3010 bool *newFrontFlag)
3011{
3012 Node *node = allocateNode(level, key, data);
3013 if (result) {
3014 ++node->d_refCount;
3015 *result = reinterpret_cast<Pair *>(node);
3016 }
3017
3018 int ret = addNodeUnique(newFrontFlag, node);
3019 if (ret) {
3020 if (result) {
3021 --node->d_refCount;
3022 *result = 0;
3023 }
3024 releaseNode(node);
3025 return ret; // RETURN
3026 }
3027
3028 return 0;
3029}
3030
3031template<class KEY, class DATA>
3032inline
3034 const KEY& key,
3035 const DATA& data,
3036 bool *newFrontFlag)
3037{
3038 addAtLevelRaw(result, d_rand.randomLevel(), key, data, newFrontFlag);
3039}
3040
3041template<class KEY, class DATA>
3042inline
3044 const KEY& key,
3045 const DATA& data,
3046 bool *newFrontFlag)
3047{
3048 Pair *handle;
3049 int rc = addUniqueRaw(&handle, key, data, newFrontFlag);
3050 if (0 != rc) {
3051 return rc; // RETURN
3052 }
3053 result->reset(this, handle);
3054 return 0;
3055}
3056
3057template<class KEY, class DATA>
3058inline
3060 const DATA& data,
3061 bool *newFrontFlag)
3062{
3063
3064 Pair **zeroPair = 0;
3065 return addUniqueRaw(zeroPair, key, data, newFrontFlag);
3066}
3067
3068template<class KEY, class DATA>
3069inline
3071 const KEY& key,
3072 const DATA& data,
3073 bool *newFrontFlag)
3074{
3075 return addAtLevelUniqueRaw(result, d_rand.randomLevel(), key, data,
3076 newFrontFlag);
3077}
3078
3079 // Insertion Methods (Reverse Search)
3080
3081template<class KEY, class DATA>
3082inline
3084 int level,
3085 const KEY& key,
3086 const DATA& data,
3087 bool *newFrontFlag)
3088{
3089 Node *node = allocateNode(level, key, data);
3090 if (result) {
3091 ++node->d_refCount;
3092 *result = reinterpret_cast<Pair *>(node);
3093 }
3094
3095 addNodeR(newFrontFlag, node);
3096}
3097
3098template<class KEY, class DATA>
3100 int level,
3101 const KEY& key,
3102 const DATA& data,
3103 bool *newFrontFlag)
3104{
3105 Node *node = allocateNode(level, key, data);
3106 if (result) {
3107 ++node->d_refCount;
3108 *result = reinterpret_cast<Pair *>(node);
3109 }
3110
3111 int ret = addNodeUniqueR(newFrontFlag, node);
3112 if (ret) {
3113 if (result) {
3114 --node->d_refCount;
3115 *result = 0;
3116 }
3117 releaseNode(node);
3118 return ret; // RETURN
3119 }
3120
3121 return 0;
3122}
3123
3124template<class KEY, class DATA>
3125inline
3127 const KEY& key,
3128 const DATA& data,
3129 bool *newFrontFlag)
3130{
3131 Pair *handle;
3132 addRawR(&handle, key, data, newFrontFlag);
3133 result->reset(this, handle);
3134}
3135
3136template<class KEY, class DATA>
3137inline
3138void SkipList<KEY, DATA>::addR(const KEY& key,
3139 const DATA& data,
3140 bool *newFrontFlag)
3141{
3142 Pair **zeroPair = 0;
3143 addRawR(zeroPair, key, data, newFrontFlag);
3144}
3145
3146template<class KEY, class DATA>
3147inline
3149 const KEY& key,
3150 const DATA& data,
3151 bool *newFrontFlag)
3152{
3153 addAtLevelRawR(result, d_rand.randomLevel(), key, data, newFrontFlag);
3154}
3155
3156template<class KEY, class DATA>
3158 const KEY& key,
3159 const DATA& data,
3160 bool *newFrontFlag)
3161{
3162 Pair *handle;
3163 int rc = addUniqueRawR(&handle, key, data, newFrontFlag);
3164 if (0 != rc) {
3165 return rc; // RETURN
3166 }
3167 result->reset(this, handle);
3168
3169 return 0;
3170}
3171
3172template<class KEY, class DATA>
3173inline
3175 const DATA& data,
3176 bool *newFrontFlag)
3177{
3178 Pair **zeroPair = 0;
3179 return addUniqueRawR(zeroPair, key, data, newFrontFlag);
3180}
3181
3182template<class KEY, class DATA>
3183inline
3185 const KEY& key,
3186 const DATA& data,
3187 bool *newFrontFlag)
3188{
3189 return addAtLevelUniqueRawR(result, d_rand.randomLevel(), key, data,
3190 newFrontFlag);
3191}
3192
3193 // Removal Methods
3194
3195template<class KEY, class DATA>
3196inline
3198{
3199 Node *node = popFrontImp();
3200 if (!node) {
3201 return e_NOT_FOUND; // RETURN
3202 }
3203
3204 if (item) {
3205 item->reset(this, reinterpret_cast<Pair *>(node));
3206 }
3207 else {
3208 releaseNode(node);
3209 }
3210
3211 return 0;
3212}
3213
3214template<class KEY, class DATA>
3215inline
3217{
3218 Node *node = popFrontImp();
3219 if (!node) {
3220 return e_NOT_FOUND; // RETURN
3221 }
3222
3223 if (item) {
3224 *item = reinterpret_cast<Pair *>(node);
3225 }
3226 else {
3227 releaseNode(node);
3228 }
3229
3230 return 0;
3231}
3232
3233template<class KEY, class DATA>
3234inline
3236{
3237 if (0 == reference) {
3238 return e_INVALID; // RETURN
3239 }
3240
3241 Node *node = pairToNode(reference);
3242
3243 int ret = removeNode(node);
3244 if (ret) {
3245 return ret; // RETURN
3246 }
3247
3248 releaseNode(node);
3249 return 0;
3250}
3251
3252template<class KEY, class DATA>
3253inline
3255{
3256 return removeAllImp(static_cast<bsl::vector<PairHandle> *>(0));
3257}
3258
3259template<class KEY, class DATA>
3260inline
3262{
3263 return removeAllImp(removed);
3264}
3265
3266template<class KEY, class DATA>
3267inline
3268int SkipList<KEY, DATA>::removeAll(std::vector<PairHandle> *removed)
3269{
3270 return removeAllImp(removed);
3271}
3272
3273#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
3274template<class KEY, class DATA>
3275inline
3276int SkipList<KEY, DATA>::removeAll(std::pmr::vector<PairHandle> *removed)
3277{
3278 return removeAllImp(removed);
3279}
3280#endif
3281
3282template<class KEY, class DATA>
3283inline
3285{
3286 return removeAllImp(removed);
3287}
3288
3289template<class KEY, class DATA>
3290inline
3291int SkipList<KEY, DATA>::removeAllRaw(std::vector<Pair *> *removed)
3292{
3293 return removeAllImp(removed);
3294}
3295
3296#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
3297template<class KEY, class DATA>
3298inline
3299int SkipList<KEY, DATA>::removeAllRaw(std::pmr::vector<Pair *> *removed)
3300{
3301 return removeAllImp(removed);
3302}
3303#endif
3304
3305 // Update Methods
3306
3307template<class KEY, class DATA>
3308inline
3310 const KEY& newKey,
3311 bool *newFrontFlag,
3312 bool allowDuplicates)
3313{
3314 if (0 == reference) {
3315 return e_INVALID; // RETURN
3316 }
3317
3318 Node *node = pairToNode(reference);
3319 return updateNode(newFrontFlag, node, newKey, allowDuplicates);
3320}
3321
3322template<class KEY, class DATA>
3323inline
3325 const KEY& newKey,
3326 bool *newFrontFlag,
3327 bool allowDuplicates)
3328{
3329 if (0 == reference) {
3330 return e_INVALID; // RETURN
3331 }
3332
3333 Node *node = pairToNode(reference);
3334 return updateNodeR(newFrontFlag, node, newKey, allowDuplicates);
3335}
3336
3337// ACCESSORS
3338template<class KEY, class DATA>
3339inline
3342{
3343 Node *node = pairToNode(reference);
3344 ++node->d_refCount;
3345 return const_cast<Pair *>(reference);
3346}
3347
3348template<class KEY, class DATA>
3349inline
3351{
3352 Pair *backPtr = reinterpret_cast<Pair *>(backNode());
3353 if (backPtr) {
3354 back->reset(this, backPtr);
3355 return 0; // RETURN
3356 }
3357 return -1;
3358}
3359
3360template<class KEY, class DATA>
3361inline
3363{
3364 *back = reinterpret_cast<Pair *>(backNode());
3365 return *back ? 0 : -1;
3366}
3367
3368template<class KEY, class DATA>
3369bool SkipList<KEY, DATA>::exists(const KEY& key) const
3370{
3371 Node *locator[k_MAX_NUM_LEVELS];
3372
3373 LockGuard guard(&d_lock);
3374 lookupImpLowerBound(locator, key);
3375
3376 Node *q = locator[0];
3377 if (q != d_tail_p && q->d_key == key) {
3378 return true; // RETURN
3379 }
3380
3381 return false;
3382}
3383
3384template<class KEY, class DATA>
3385inline
3387{
3388 BSLS_ASSERT(front);
3389
3390 Pair *frontPtr = reinterpret_cast<Pair *>(frontNode());
3391 if (frontPtr) {
3392 front->reset(this, frontPtr);
3393 return 0; // RETURN
3394 }
3395 return -1;
3396}
3397
3398template<class KEY, class DATA>
3399inline
3401{
3402 BSLS_ASSERT(front);
3403
3404 *front = reinterpret_cast<Pair *>(frontNode());
3405 return *front ? 0 : -1;
3406}
3407
3408template<class KEY, class DATA>
3409inline
3411{
3412 LockGuard guard(&d_lock);
3413
3414 return d_tail_p == d_head_p->d_ptrs[0].d_next_p;
3415}
3416
3417template<class KEY, class DATA>
3418inline
3420{
3421 LockGuard guard(&d_lock);
3422
3423 return d_length;
3424}
3425
3426template<class KEY, class DATA>
3427bsl::ostream&
3428SkipList<KEY, DATA>::print(bsl::ostream& stream,
3429 int level,
3430 int spacesPerLevel) const
3431{
3432 if (stream.bad()) {
3433 return stream; // RETURN
3434 }
3435
3436 bdlb::Print::indent(stream, level, spacesPerLevel);
3437
3438 LockGuard guard(&d_lock);
3439 // Now we must do all operations manually, since all important functions
3440 // like frontNode() and nextNode will lock the mutex
3441
3442 if (0 <= spacesPerLevel) {
3443 // Multi-line output.
3444
3445 if (level < 0) {
3446 level = -level;
3447 }
3448
3449 stream << "[\n";
3450
3451 const int levelPlus1 = level + 1;
3452
3453 for (Node *node = d_head_p->d_ptrs[0].d_next_p;
3454 node && node != d_tail_p;
3455 node = node->d_ptrs[0].d_next_p) {
3456 bdlb::Print::indent(stream, levelPlus1, spacesPerLevel);
3457 stream << "[\n";
3458
3459 const int levelPlus2 = level + 2;
3460 bdlb::Print::indent(stream, levelPlus2, spacesPerLevel);
3461 stream << "level = " << node->d_level << "\n";
3462
3464 node->d_key,
3465 levelPlus2,
3466 spacesPerLevel);
3467
3468 bdlb::Print::indent(stream, levelPlus2, spacesPerLevel);
3469 stream << "=>\n";
3470
3472 node->d_data,
3473 levelPlus2,
3474 spacesPerLevel);
3475 bdlb::Print::indent(stream, levelPlus1, spacesPerLevel);
3476 stream << "]\n";
3477 }
3478
3479 bdlb::Print::indent(stream, level, spacesPerLevel);
3480
3481 stream << "]\n";
3482 }
3483 else {
3484 // Output on a single line and suppress any further indentation.
3485
3486 stream << "[";
3487
3488 for (Node *node = d_head_p->d_ptrs[0].d_next_p;
3489 node && node != d_tail_p;
3490 node = node->d_ptrs[0].d_next_p) {
3491 stream << "[ (level = " << node->d_level << ") ";
3492
3493 bdlb::PrintMethods::print(stream, node->d_key, 0, -1);
3494 stream << " => ";
3495 bdlb::PrintMethods::print(stream, node->d_data, 0, -1);
3496
3497 stream << " ]";
3498
3499 }
3500
3501 stream << "]";
3502 }
3503
3504 return stream << bsl::flush;
3505}
3506
3507 // simple forward finds
3508
3509template<class KEY, class DATA>
3510inline
3511int SkipList<KEY, DATA>::find(PairHandle *item, const KEY& key) const
3512{
3513 BSLS_ASSERT(item);
3514
3515 Pair *itemPtr = reinterpret_cast<Pair *>(findNode(key));
3516 if (itemPtr) {
3517 item->reset(this, itemPtr);
3518 return 0; // RETURN
3519 }
3520 return -1;
3521}
3522
3523template<class KEY, class DATA>
3524inline
3525int SkipList<KEY, DATA>::findRaw(Pair **item, const KEY& key) const
3526{
3527 BSLS_ASSERT(item);
3528
3529 *item = reinterpret_cast<Pair *>(findNode(key));
3530 return *item ? 0 : -1;
3531}
3532
3533 // simple reverse finds
3534
3535template<class KEY, class DATA>
3536inline
3537int SkipList<KEY, DATA>::findR(PairHandle *item, const KEY& key) const
3538{
3539 BSLS_ASSERT(item);
3540
3541 Pair *itemPtr = reinterpret_cast<Pair *>(findNodeR(key));
3542 if (itemPtr) {
3543 item->reset(this, itemPtr);
3544 return 0; // RETURN
3545 }
3546 return -1;
3547}
3548
3549template<class KEY, class DATA>
3550inline
3551int SkipList<KEY, DATA>::findRRaw(Pair **item, const KEY& key) const
3552{
3553 BSLS_ASSERT(item);
3554
3555 *item = reinterpret_cast<Pair *>(findNodeR(key));
3556 return *item ? 0 : -1;
3557}
3558
3559 // find lower bound
3560
3561template<class KEY, class DATA>
3562inline
3563int SkipList<KEY, DATA>::findLowerBound(PairHandle *item, const KEY& key) const
3564{
3565 BSLS_ASSERT(item);
3566
3567 Pair *itemPtr = reinterpret_cast<Pair *>(findNodeLowerBound(key));
3568 if (itemPtr) {
3569 item->reset(this, itemPtr);
3570 return 0; // RETURN
3571 }
3572 return -1;
3573}
3574
3575template<class KEY, class DATA>
3576inline
3577int SkipList<KEY, DATA>::findLowerBoundRaw(Pair **item, const KEY& key) const
3578{
3579 BSLS_ASSERT(item);
3580
3581 *item = reinterpret_cast<Pair *>(findNodeLowerBound(key));
3582 return *item ? 0 : -1;
3583}
3584
3585 // find lower bound reverse
3586
3587template<class KEY, class DATA>
3588inline
3590 const KEY& key) const
3591{
3592 BSLS_ASSERT(item);
3593
3594 Pair *itemPtr = reinterpret_cast<Pair *>(findNodeLowerBoundR(key));
3595 if (itemPtr) {
3596 item->reset(this, itemPtr);
3597 return 0; // RETURN
3598 }
3599 return -1;
3600}
3601
3602template<class KEY, class DATA>
3603inline
3604int SkipList<KEY, DATA>::findLowerBoundRRaw(Pair **item, const KEY& key) const
3605{
3606 BSLS_ASSERT(item);
3607
3608 *item = reinterpret_cast<Pair *>(findNodeLowerBoundR(key));
3609 return *item ? 0 : -1;
3610}
3611
3612 // find upper bound
3613
3614template<class KEY, class DATA>
3615inline
3617 const KEY& key) const
3618{
3619 BSLS_ASSERT(item);
3620
3621 Pair *itemPtr = reinterpret_cast<Pair *>(findNodeUpperBound(key));
3622 if (itemPtr) {
3623 item->reset(this, itemPtr);
3624 return 0; // RETURN
3625 }
3626 return -1;
3627}
3628
3629template<class KEY, class DATA>
3630inline
3631int SkipList<KEY, DATA>::findUpperBoundRaw(Pair **item, const KEY& key) const
3632{
3633 BSLS_ASSERT(item);
3634
3635 *item = reinterpret_cast<Pair *>(findNodeUpperBound(key));
3636 return *item ? 0 : -1;
3637}
3638
3639 // find upper bound reverse
3640
3641template<class KEY, class DATA>
3642inline
3644 const KEY& key) const
3645{
3646 BSLS_ASSERT(item);
3647
3648 Pair *itemPtr = reinterpret_cast<Pair *>(findNodeUpperBoundR(key));
3649 if (itemPtr) {
3650 item->reset(this, itemPtr);
3651 return 0; // RETURN
3652 }
3653 return -1;
3654}
3655
3656template<class KEY, class DATA>
3657inline
3658int SkipList<KEY, DATA>::findUpperBoundRRaw(Pair **item, const KEY& key) const
3659{
3660 BSLS_ASSERT(item);
3661
3662 *item = reinterpret_cast<Pair *>(findNodeUpperBoundR(key));
3663 return *item ? 0 : -1;
3664}
3665
3666 // next, previous, & skip*
3667template<class KEY, class DATA>
3668inline
3669int SkipList<KEY, DATA>::next(PairHandle *next, const Pair *reference) const
3670{
3671 if (0 == reference) {
3672 return e_INVALID; // RETURN
3673 }
3674
3675 Node *node = pairToNode(reference);
3676 Node *nNode = nextNode(node);
3677 if (nNode) {
3678 next->reset(this, reinterpret_cast<Pair *>(nNode));
3679 return 0; // RETURN
3680 }
3681 return -1;
3682}
3683
3684template<class KEY, class DATA>
3685inline
3686int SkipList<KEY, DATA>::nextRaw(Pair **next, const Pair *reference) const
3687{
3688 BSLS_ASSERT(next);
3689 BSLS_ASSERT(reference);
3690
3691 Node *node = pairToNode(reference);
3692 *next = reinterpret_cast<Pair *>(nextNode(node));
3693
3694 return *next ? 0 : -1;
3695}
3696
3697template<class KEY, class DATA>
3698inline
3700 const Pair *reference) const
3701{
3702 if (0 == reference) {
3703 return e_INVALID; // RETURN
3704 }
3705
3706 Node *node = pairToNode(reference);
3707 Node *pNode = prevNode(node);
3708 if (pNode) {
3709 prevPair->reset(this, reinterpret_cast<Pair *>(pNode));
3710 return 0; // RETURN
3711 }
3712 return -1;
3713}
3714
3715template<class KEY, class DATA>
3716inline
3717int
3718SkipList<KEY, DATA>::previousRaw(Pair **prevPair, const Pair *reference) const
3719{
3720 BSLS_ASSERT(prevPair);
3721 BSLS_ASSERT(reference);
3722
3723 Node *node = pairToNode(reference);
3724 *prevPair = reinterpret_cast<Pair *>(prevNode(node));
3725 return *prevPair ? 0 : -1;
3726}
3727
3728template<class KEY, class DATA>
3729inline
3731{
3732 BSLS_ASSERT(item->isValid());
3733
3734 Node **node_p = reinterpret_cast<Node **>(&item->d_node_p);
3735 return skipBackward(node_p);
3736}
3737
3738template<class KEY, class DATA>
3739inline
3741{
3742 BSLS_ASSERT(item);
3743
3744 Node **node_p = reinterpret_cast<Node **>(item);
3745 return skipBackward(node_p);
3746}
3747
3748template<class KEY, class DATA>
3749inline
3751{
3752 BSLS_ASSERT(item->isValid());
3753
3754 Node **node_p = reinterpret_cast<Node **>(&item->d_node_p);
3755 return skipForward(node_p);
3756}
3757
3758template<class KEY, class DATA>
3759inline
3761{
3762 BSLS_ASSERT(item);
3763
3764 Node **node_p = reinterpret_cast<Node **>(item);
3765 return skipForward(node_p);
3766}
3767
3768 // Aspects
3769
3770template<class KEY, class DATA>
3771inline
3773{
3774 return d_allocator_p;
3775}
3776
3777} // close package namespace
3778
3779// FREE OPERATORS
3780template<class KEY, class DATA>
3781bool bdlcc::operator==(const SkipList<KEY, DATA>& lhs,
3782 const SkipList<KEY, DATA>& rhs)
3783{
3784 if (&lhs == &rhs) {
3785 return true; // RETURN
3786 }
3787
3788 bdlcc::SkipList_DoubleLockGuard guard(&lhs.d_lock, &rhs.d_lock);
3789
3790 // Once we have locked the lists, we need to do all operations manually
3791 // because the important functions of the lists (like frontNode and
3792 // nextNode) will lock the mutex.
3793
3794 for (SkipList_Node<KEY, DATA>
3795 *lhsNode = lhs.d_head_p->d_ptrs[0].d_next_p,
3796 *rhsNode = rhs.d_head_p->d_ptrs[0].d_next_p;
3797 ;
3798 lhsNode = lhsNode->d_ptrs[0].d_next_p,
3799 rhsNode = rhsNode->d_ptrs[0].d_next_p)
3800 {
3801 if ((!lhsNode && !rhsNode)
3802 || (lhsNode == lhs.d_tail_p && rhsNode == rhs.d_tail_p)) {
3803 // we reached the end of both lists at the same time
3804
3805 return true; // RETURN
3806 }
3807 if (!lhsNode || !rhsNode
3808 || lhsNode == lhs.d_tail_p || rhsNode == rhs.d_tail_p) {
3809 // We reached the end of one list before the other
3810
3811 return false; // RETURN
3812 }
3813
3814 if (!(lhsNode->d_key == rhsNode->d_key
3815 && lhsNode->d_data == rhsNode->d_data)) {
3816 return false; // RETURN
3817 }
3818 }
3819
3820 BSLS_ASSERT(0 == "unreachable");
3821
3822 return false;
3823}
3824
3825template<class KEY, class DATA>
3826bool bdlcc::operator!=(const SkipList<KEY, DATA>& lhs,
3827 const SkipList<KEY, DATA>& rhs)
3828{
3829 if (&lhs == &rhs) {
3830 return false; // RETURN
3831 }
3832
3833 bdlcc::SkipList_DoubleLockGuard guard(&lhs.d_lock, &rhs.d_lock);
3834
3835 // Once we have locked the lists, we need to do all operations manually
3836 // because the important functions of the lists (like frontNode and
3837 // nextNode) will lock the mutex.
3838
3839 for (SkipList_Node<KEY, DATA>
3840 *lhsNode = lhs.d_head_p->d_ptrs[0].d_next_p,
3841 *rhsNode = rhs.d_head_p->d_ptrs[0].d_next_p;
3842 ;
3843 lhsNode = lhsNode->d_ptrs[0].d_next_p,
3844 rhsNode = rhsNode->d_ptrs[0].d_next_p)
3845 {
3846 if ((!lhsNode && !rhsNode)
3847 || (lhsNode == lhs.d_tail_p && rhsNode == rhs.d_tail_p)) {
3848 // we reached the end of both lists at the same time
3849
3850 return false; // RETURN
3851 }
3852 if (!lhsNode || !rhsNode
3853 || lhsNode == lhs.d_tail_p || rhsNode == rhs.d_tail_p) {
3854 // We reached the end of one list before the other
3855
3856 return true; // RETURN
3857 }
3858
3859 if (!(lhsNode->d_key == rhsNode->d_key)
3860 || !(lhsNode->d_data == rhsNode->d_data)) {
3861 return true; // RETURN
3862 }
3863 }
3864
3865 BSLS_ASSERT(0 == "unreachable");
3866
3867 return false;
3868}
3869
3870template<class KEY, class DATA>
3871inline
3872bsl::ostream& bdlcc::operator<<(bsl::ostream& stream,
3873 const SkipList<KEY, DATA>& list)
3874{
3875 return list.print(stream, 0, -1);
3876}
3877
3878
3879
3880#endif
3881
3882// ----------------------------------------------------------------------------
3883// Copyright 2015 Bloomberg Finance L.P.
3884//
3885// Licensed under the Apache License, Version 2.0 (the "License");
3886// you may not use this file except in compliance with the License.
3887// You may obtain a copy of the License at
3888//
3889// http://www.apache.org/licenses/LICENSE-2.0
3890//
3891// Unless required by applicable law or agreed to in writing, software
3892// distributed under the License is distributed on an "AS IS" BASIS,
3893// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3894// See the License for the specific language governing permissions and
3895// limitations under the License.
3896// ----------------------------- END-OF-FILE ----------------------------------
3897
3898/** @} */
3899/** @} */
3900/** @} */
#define BSLMF_NESTED_TRAIT_DECLARATION(t_TYPE, t_TRAIT)
Definition bslmf_nestedtraitdeclaration.h:231
Definition bdlcc_skiplist.h:693
bool isValid() const
Definition bdlcc_skiplist.h:1898
void release()
Release the reference (if any) managed by this SkipListPairHandle.
Definition bdlcc_skiplist.h:1852
void releaseReferenceRaw(SkipList< KEY, DATA > **list, Pair **reference)
Definition bdlcc_skiplist.h:1864
~SkipListPairHandle()
Definition bdlcc_skiplist.h:1834
SkipListPairHandle()
Construct a new PairHandle that does not refer to a pair.
Definition bdlcc_skiplist.h:1805
DATA & data() const
Definition bdlcc_skiplist.h:1889
SkipListPairHandle & operator=(const SkipListPairHandle &rhs)
Definition bdlcc_skiplist.h:1843
const KEY & key() const
Definition bdlcc_skiplist.h:1905
Definition bdlcc_skiplist.h:657
const KEY & key() const
Return a reference to the non-modifiable "key" value of this pair.
Definition bdlcc_skiplist.h:1793
DATA & data() const
Return a reference to the modifiable "data" of this pair.
Definition bdlcc_skiplist.h:1786
Definition bdlcc_skiplist.h:1729
PairFactory(SkipList *)
Create a PairFactory.
Definition bdlcc_skiplist.h:1984
Pair * operator()(Node *node) const
Convert the specified node to a Pair *.
Definition bdlcc_skiplist.h:1991
Definition bdlcc_skiplist.h:1747
PairHandleFactory(SkipList *list)
Create a PairHandleFactory bound to the specified list.
Definition bdlcc_skiplist.h:2003
PairHandle operator()(Node *node) const
Definition bdlcc_skiplist.h:2011
Definition bdlcc_skiplist.h:502
SkipList_DoubleLockGuard(bslmt::Mutex *lock1, bslmt::Mutex *lock2)
Definition bdlcc_skiplist.h:1773
Definition bdlcc_skiplist.h:599
SkipList_NodeCreationHelper(PoolManager *poolManager, Node *node, bslma::Allocator *basicAllocator=0)
Definition bdlcc_skiplist.h:1933
~SkipList_NodeCreationHelper()
Definition bdlcc_skiplist.h:1946
void construct(const KEY &key, const DATA &data)
Definition bdlcc_skiplist.h:1958
Definition bdlcc_skiplist.h:522
SkipList_RandomLevelGenerator()
Construct a thread-aware random-level generator.
int randomLevel()
Return a random integer between 0 and k_MAX_LEVEL.
Definition bdlcc_skiplist.h:783
int find(PairHandle *item, const KEY &key) const
Definition bdlcc_skiplist.h:3511
int findRRaw(Pair **item, const KEY &key) const
Definition bdlcc_skiplist.h:3551
~SkipList()
Definition bdlcc_skiplist.h:2889
void releaseReferenceRaw(const Pair *reference)
Definition bdlcc_skiplist.h:2958
int remove(const Pair *reference)
Definition bdlcc_skiplist.h:3235
int back(PairHandle *back) const
Definition bdlcc_skiplist.h:3350
int skipForward(PairHandle *item) const
Definition bdlcc_skiplist.h:3750
friend bool operator!=(const SkipList< KEY2, DATA2 > &, const SkipList< KEY2, DATA2 > &)
int addUnique(const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3059
int addUniqueRaw(Pair **result, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3070
int skipBackwardRaw(Pair **item) const
Definition bdlcc_skiplist.h:3740
bool isEmpty() const
Return true if this list is empty, and false otherwise.
Definition bdlcc_skiplist.h:3410
int skipForwardRaw(Pair **item) const
Definition bdlcc_skiplist.h:3760
bslma::Allocator * allocator() const
Return the allocator used by this object to supply memory.
Definition bdlcc_skiplist.h:3772
int removeAll(std::vector< PairHandle > *removed)
Definition bdlcc_skiplist.h:3268
void addR(const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3138
SkipList(const SkipList &original, bslma::Allocator *basicAllocator=0)
Definition bdlcc_skiplist.h:2876
int findLowerBoundRRaw(Pair **item, const KEY &key) const
Definition bdlcc_skiplist.h:3604
int nextRaw(Pair **next, const Pair *reference) const
Definition bdlcc_skiplist.h:3686
int addUniqueR(const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3174
void addR(PairHandle *result, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3126
int removeAllRaw(bsl::vector< Pair * > *removed)
Definition bdlcc_skiplist.h:3284
bsl::ostream & print(bsl::ostream &stream, int level=0, int spacesPerLevel=4) const
Definition bdlcc_skiplist.h:3428
int removeAllRaw(std::vector< Pair * > *removed)
Definition bdlcc_skiplist.h:3291
int length() const
Return the number of items in this list.
Definition bdlcc_skiplist.h:3419
int findLowerBoundRaw(Pair **item, const KEY &key) const
Definition bdlcc_skiplist.h:3577
friend bool operator==(const SkipList< KEY2, DATA2 > &, const SkipList< KEY2, DATA2 > &)
void addAtLevelRawR(Pair **result, int level, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3083
int findUpperBound(PairHandle *item, const KEY &key) const
Definition bdlcc_skiplist.h:3616
int removeAll(bsl::vector< PairHandle > *removed)
Definition bdlcc_skiplist.h:3261
int next(PairHandle *next, const Pair *reference) const
Definition bdlcc_skiplist.h:3669
int findLowerBoundR(PairHandle *item, const KEY &key) const
Definition bdlcc_skiplist.h:3589
int popFront(PairHandle *item=0)
Definition bdlcc_skiplist.h:3197
static int level(const Pair *reference)
Definition bdlcc_skiplist.h:2856
int previous(PairHandle *prevPair, const Pair *reference) const
Definition bdlcc_skiplist.h:3699
SkipList(bslma::Allocator *basicAllocator=0)
Definition bdlcc_skiplist.h:2866
int popFrontRaw(Pair **item)
Definition bdlcc_skiplist.h:3216
int update(const Pair *reference, const KEY &newKey, bool *newFrontFlag=0, bool allowDuplicates=true)
Definition bdlcc_skiplist.h:3309
int findR(PairHandle *item, const KEY &key) const
Definition bdlcc_skiplist.h:3537
SkipListPairHandle< KEY, DATA > PairHandle
Definition bdlcc_skiplist.h:807
int addUniqueRawR(Pair **result, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3184
int addUniqueR(PairHandle *result, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3157
SkipList & operator=(const SkipList &rhs)
Definition bdlcc_skiplist.h:2914
@ RET_INVALID
Definition bdlcc_skiplist.h:801
@ RET_NOT_FOUND
Definition bdlcc_skiplist.h:799
@ RET_SUCCESS
Definition bdlcc_skiplist.h:798
@ e_INVALID
Definition bdlcc_skiplist.h:791
@ BCEC_NOT_FOUND
Definition bdlcc_skiplist.h:795
@ BCEC_INVALID
Definition bdlcc_skiplist.h:797
@ e_NOT_FOUND
Definition bdlcc_skiplist.h:789
@ RET_DUPLICATE
Definition bdlcc_skiplist.h:800
@ BCEC_SUCCESS
Definition bdlcc_skiplist.h:794
@ e_SUCCESS
Definition bdlcc_skiplist.h:788
@ BCEC_DUPLICATE
Definition bdlcc_skiplist.h:796
@ e_DUPLICATE
Definition bdlcc_skiplist.h:790
void add(const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:2980
int addUnique(PairHandle *result, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3043
void add(PairHandle *result, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:2968
void addRawR(Pair **result, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3148
SkipListPair< KEY, DATA > Pair
Definition bdlcc_skiplist.h:806
bool exists(const KEY &key) const
Definition bdlcc_skiplist.h:3369
int addAtLevelUniqueRawR(Pair **result, int level, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3099
Pair * addPairReferenceRaw(const Pair *reference) const
Definition bdlcc_skiplist.h:3341
BSLMF_NESTED_TRAIT_DECLARATION(SkipList, bslma::UsesBslmaAllocator)
void addRaw(Pair **result, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3033
int backRaw(Pair **back) const
Definition bdlcc_skiplist.h:3362
void addAtLevelRaw(Pair **result, int level, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:2990
int findUpperBoundRRaw(Pair **item, const KEY &key) const
Definition bdlcc_skiplist.h:3658
int findLowerBound(PairHandle *item, const KEY &key) const
Definition bdlcc_skiplist.h:3563
int updateR(const Pair *reference, const KEY &newKey, bool *newFrontFlag=0, bool allowDuplicates=true)
Definition bdlcc_skiplist.h:3324
int findUpperBoundR(PairHandle *item, const KEY &key) const
Definition bdlcc_skiplist.h:3643
int findUpperBoundRaw(Pair **item, const KEY &key) const
Definition bdlcc_skiplist.h:3631
int addAtLevelUniqueRaw(Pair **result, int level, const KEY &key, const DATA &data, bool *newFrontFlag=0)
Definition bdlcc_skiplist.h:3006
int removeAll()
Definition bdlcc_skiplist.h:3254
int findRaw(Pair **item, const KEY &key) const
Definition bdlcc_skiplist.h:3525
int skipBackward(PairHandle *item) const
Definition bdlcc_skiplist.h:3730
int frontRaw(Pair **front) const
Definition bdlcc_skiplist.h:3400
int front(PairHandle *front) const
Definition bdlcc_skiplist.h:3386
int previousRaw(Pair **prevPair, const Pair *reference) const
Definition bdlcc_skiplist.h:3718
iterator begin() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:2511
iterator end() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:2519
Definition bslstl_vector.h:1025
iterator insert(const_iterator position, const VALUE_TYPE &value)
Definition bslstl_vector.h:3803
void reserve(size_type newCapacity)
Definition bslstl_vector.h:3690
VALUE_TYPE * iterator
Definition bslstl_vector.h:1057
Definition bslma_allocator.h:457
Definition bslmt_lockguard.h:234
Definition bslmt_mutex.h:315
void lock()
Definition bslmt_mutex.h:392
void unlock()
Definition bslmt_mutex.h:410
Definition bsls_atomic.h:743
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLMT_MUTEXASSERT_IS_LOCKED(mutex_p)
Definition bslmt_mutexassert.h:299
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_CONSTEXPR
Definition bsls_keyword.h:588
#define BSLS_UTIL_ADDRESSOF(OBJ)
Definition bsls_util.h:289
bsl::ostream & print(bsl::ostream &stream, const TYPE &object, int level=0, int spacesPerLevel=4)
Definition bdlb_printmethods.h:719
Definition bdlcc_boundedqueue.h:270
bool operator!=(const SkipList< KEY, DATA > &lhs, const SkipList< KEY, DATA > &rhs)
bool operator==(const SkipList< KEY, DATA > &lhs, const SkipList< KEY, DATA > &rhs)
bsl::ostream & operator<<(bsl::ostream &stream, const SkipList< KEY, DATA > &list)
Definition bdlb_printmethods.h:283
T::iterator begin(T &container)
Definition bslstl_iterator.h:1495
T::iterator end(T &container)
Definition bslstl_iterator.h:1523
Definition balxml_encoderoptions.h:68
Definition bslmt_barrier.h:344
static bsl::ostream & indent(bsl::ostream &stream, int level, int spacesPerLevel=4)
Definition bdlcc_skiplist.h:482
Node * d_prev_p
Definition bdlcc_skiplist.h:485
Node * d_next_p
Definition bdlcc_skiplist.h:484
This component-private structure is a node in the SkipList.
Definition bdlcc_skiplist.h:477
DATA d_data
Definition bdlcc_skiplist.h:491
SkipList_Node< KEY, DATA > Node
Definition bdlcc_skiplist.h:480
Ptrs d_ptrs[1]
Definition bdlcc_skiplist.h:493
int d_level
Definition bdlcc_skiplist.h:490
KEY d_key
Definition bdlcc_skiplist.h:492
bsls::AtomicInt d_refCount
Definition bdlcc_skiplist.h:489
This component-private utility handles the lock-free pool of list nodes.
Definition bdlcc_skiplist.h:556
static void deallocate(PoolManager *poolManager, void *address)
static PoolManager * createPoolManager(int *objectSizes, int numLevels, bslma::Allocator *basicAllocator)
static void deletePoolManager(bslma::Allocator *basicAllocator, PoolManager *poolManager)
SkipList_PoolManager PoolManager
Definition bdlcc_skiplist.h:559
static void * allocate(PoolManager *poolManager, int level)
Definition bslmf_conditional.h:120
Definition bslmf_issame.h:146
static void copyConstruct(TARGET_TYPE *address, const TARGET_TYPE &original, bslma::Allocator *allocator)
Definition bslalg_scalarprimitives.h:1599
Definition bslma_usesbslmaallocator.h:343
Definition bsls_alignmentfromtype.h:376
std::ptrdiff_t IntPtr
Definition bsls_types.h:130