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