BDE 4.14.0 Production release
|
Provide a generic thread-safe Skip List.
This component provides a thread-safe value-semantic associative Skip List container. A Skip List stores objects of a parameterized DATA
type, ordered by values of a parameterized KEY
type. DATA
objects can be added, looked up, and removed quickly on the basis of their KEY
value. In addition, bdlcc::SkipList
provides methods to change the KEY
value associated with an object in the list such that it is efficiently moved to an appropriate location within the list for the new KEY
value.
Associations (pairings of data objects with key values) in the list are identified by bdlcc::SkipListPairHandle
objects or bdlcc::SkipListPair
pointers. bdlcc::SkipListPair
pointers must be used with caution: See the "`bdlcc::SkipListPair` Usage Rules" below. bdlcc::SkipListPair
and bdlcc::SkipListPairHandle
objects are optionally populated when new associations are added, and are also populated whenever associations are looked up (either by key or by position). Note that in addition to addPairReferenceRaw
, member functions of bdlcc::SkipList
such as front
, back
, and find
also add a reference to the specified element.
The bdlcc::SkipList
ordered associative container is parameterized on two types, KEY
and DATA
. Each type must have a public copy constructor, and it is important to declare the "Uses bslma Allocator" trait if the type accepts a bslma::Allocator
in its constructor (see bslalg_typetraits ). In addition, operators =
, <
, and ==
must be defined for the type KEY
; for correct behavior, operator <
must define a Strict Weak Ordering on KEY
values.
Some terms used frequently in this documentation:
The last element in the list. The key value at the back is greater than or equal to every other key value in the list.
The beginning of the list. The key value at the front is less than or equal to every other key value in the list.
An element of the list; a pairing (association) of a data object with a key value. Also a type name used for references to such objects (
bdlcc::SkipListPair
objects cannot be constructed directly).
An object (of type
bdlcc::SkipListPairHandle
) with scope and copy semantics that makes it easier to manage and use than a rawbdlcc::SkipListPair *
.
Stands for "Reverse search" (see
"R" Methods
documentation below).
An object referring to a pair; either a
bdlcc::SkipListPair *
which has not yet been released, or abdlcc::SkipListPairHandle
object.
The regular methods (no R suffix) of bdlcc::SkipList
that result in a search through the list, search from the front of the list (i.e., in ascending order).
All methods of bdlcc::SkipList
that result in a search through the list have corresponding "R" versions: for example, there are add
and addR
methods, find
and findR
methods, etc. The "R" versions of these methods search from the back of the list (i.e., in descending (reverse) order). Use of an "R" method is a hint to the Skip List that the desired key is more likely to be near the back than the front. In the event of duplicate keys, find
will find the first matching key, and findR
will find the last matching key. Note that if there are pairs in the list with duplicate keys, the specific pair found by find
may (or may not) be different from the one found by findR
.
bdlcc::SkipList
has two handle
types for referring to elements in the container:
bdlcc::SkipList::Pair *
– raw pointer, no destructor, bdlcc::SkipList::releaseReferenceRaw
must be called on these pointers before the container is destroyed.bdlcc::SkipList::PairHandle
– class
, has a destructor which will release the pair handle when it goes out of scope via RAII. If the pair handle will not be destroyed before the container is, it is necessary to call bdlcc::SkipList::PairHandle::release
before the container is destroyed.The PairHandle
type has an implicit conversion to Pair *
. In most cases bdlcc::SkipList
provides dual functions supporting Pair *
and PairHandle
. Some functions, however, only support Pair *
parameters; for these functions, either a Pair *
or a PairHandle
may be passed.
Unless the client has some reason to prefer the Pair *
interface, the PairHandle
interface is recommended since it provides RAII, making it harder to leak nodes.
Note that in some build modes, SkipList
will attempt to detect leaked nodes, i.e., those that were referred to by Pair *
s for which releaseReferenceRaw
hasn't been called, and nodes referred to by PairHandle
s that haven't been destroyed or release
d at the time of the skip list's destruction.
bdlcc::SkipList
is thread-safe and thread-aware; that is, multiple threads may use their own Skip List objects or may concurrently use the same object.
Note that safe usage of the component depends upon correct usage of bdlcc::SkipListPair
objects (see above).
bdlcc::SkipListPairHandle
is only const thread-safe. It is not safe for multiple threads to invoke non-const
methods on the same PairHandle
object concurrently.
bdlcc::SkipListPair
is a name used for opaque pointers; the concept of thread safety does not apply to it.
bdlcc::SkipList
is exception-neutral: no method invokes throw
or catch
. Insertion methods (add
, addR
, etc) invoke the copy constructors of the contained KEY
and DATA
types; if those constructors throw an exception, the list provides a full rollback guarantee (it will have the same state it had prior to the call to add
). The assignment operator may also indirectly cause bad_alloc to be thrown if the system is out of memory, but in that case there is no guarantee of rollback on the left-hand list.
No method of bdlcc::SkipListPairHandle
can throw.
bdlcc::SkipListPair
is only a name used for opaque pointers; the concept of exception safety does not apply to it.
This section illustrates intended use of this component.
The "R" methods of bdlcc::SkipList
make it ideal for use in a scheduler, in which events are likely to be scheduled after existing events. In such an implementation, events are stored in the list with their scheduled execution times as KEY
objects: Searching near the end of the list for the right location for new events, and removing events from the front of the list for execution, are very efficient operations. Being thread- enabled also makes bdlcc::SkipList
well-suited to use in a scheduler - a "dispatcher" thread can safety use the list at the same time that events are being scheduled from other threads. The following is an implementation of a simple scheduler class using bdlcc::SkipList
. Note that the mutex in the scheduler is used only in connection with the scheduler's condition variable
bdlcc::SkipList
object does not require any synchronization. SimpleScheduler
. First, we need a wrapper around vector<int>::push_back, since this function is overloaded and cannot be bound directly: main
, verify that the scheduler executes events when expected: Add events out of sequence and ensure they are executed in the proper order. scheduler
will call stop()
.