BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlcc_timequeue.h
Go to the documentation of this file.
1/// @file bdlcc_timequeue.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlcc_timequeue.h -*-C++-*-
8#ifndef INCLUDED_BDLCC_TIMEQUEUE
9#define INCLUDED_BDLCC_TIMEQUEUE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlcc_timequeue bdlcc_timequeue
15/// @brief Provide an efficient queue for time events.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlcc
19/// @{
20/// @addtogroup bdlcc_timequeue
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlcc_timequeue-purpose"> Purpose</a>
25/// * <a href="#bdlcc_timequeue-classes"> Classes </a>
26/// * <a href="#bdlcc_timequeue-description"> Description </a>
27/// * <a href="#bdlcc_timequeue-bdlcc-timequeue-handle-uniqueness-reuse-and-numindexbits"> bdlcc::TimeQueue::Handle Uniqueness, Reuse and numIndexBits </a>
28/// * <a href="#bdlcc_timequeue-thread-safety"> Thread Safety </a>
29/// * <a href="#bdlcc_timequeue-ordering"> Ordering </a>
30/// * <a href="#bdlcc_timequeue-usage"> Usage </a>
31/// * <a href="#bdlcc_timequeue-forward-declarations"> Forward Declarations </a>
32/// * <a href="#bdlcc_timequeue-struct-my_connection"> struct my_Connection </a>
33/// * <a href="#bdlcc_timequeue-protocol-classes"> Protocol Classes </a>
34///
35/// # Purpose {#bdlcc_timequeue-purpose}
36/// Provide an efficient queue for time events.
37///
38/// # Classes {#bdlcc_timequeue-classes}
39///
40/// - bdlcc::TimeQueue: Templatized time event queue
41/// - bdlcc::TimeQueueItem: (`struct`) Templatized item in the time event queue
42///
43/// @see
44///
45/// # Description {#bdlcc_timequeue-description}
46/// This component provides a thread-safe and efficient templatized
47/// time queue. The queue stores an ordered list of time values and associated
48/// `DATA`. Each item added to the queue is assigned a unique identifier that
49/// can be used to efficiently remove the item making this queue suitable for
50/// conditions where time items are added and removed very frequently.
51///
52/// Class `bdlcc::TimeQueue<DATA>` provides a public interface which is similar
53/// in structure and intent to `bdlcc::Queue<DATA>`, with the exception that
54/// each item stored in the `bdlcc::TimeQueue` is of type
55/// `bdlcc::TimeQueueItem<DATA>`. This structure contains a single
56/// `bsls::TimeInterval` value along with the `DATA` value.
57///
58/// Idiomatic usage of `bdlcc::TimeQueue` includes the member function `popLE`,
59/// which finds all items on the queue whose `bsls::TimeInterval` are less than
60/// a specified value, and transfers those items to a provided vector of items.
61/// Through the use of this member function, clients can retrieve and process
62/// multiple elements that have expired, that is, whose `bsls::TimeInterval`
63/// values are in the past.
64///
65/// `bdlcc::TimeQueue` also makes use of an opaque data type
66/// `bdlcc::TimeQueue::Handle` which serves to identify an individual element on
67/// the Time Queue. A value of type `Handle` is returned from the `add` member
68/// function, and can then be used to remove or modify the corresponding element
69/// on the queue. In this way, the `update` member function can update the time
70/// value for a specific `bdlcc::TimeQueueItem` without removing it from the
71/// queue.
72///
73/// ### bdlcc::TimeQueue::Handle Uniqueness, Reuse and numIndexBits {#bdlcc_timequeue-bdlcc-timequeue-handle-uniqueness-reuse-and-numindexbits}
74///
75///
76/// `bdlcc::TimeQueue::Handle` is an alias for a 32-bit `int` type. A handle
77/// consists of two parts, the "index section" and the "iteration section". The
78/// index section, which is the low-order `numIndexBits` (which defaults to
79/// `numIndexBits == 17`), uniquely identifies the node. Once a node is added,
80/// it never ceases to exist - it may be freed, but it will be kept on a free
81/// list to be eventually recycled, and the same index section will always
82/// identify that node. The iteration section, the high-order
83/// `32 - numIndexBits`, is changed every time a node is freed, so that an
84/// out-of-date handle can be identified as out-of-date. But since the
85/// iteration section has only a finite number of bits, if a node is freed and
86/// re-added enough times, old handle values will eventually be reused.
87///
88/// Up to `2 ** numIndexBits - 1` nodes can exist in a given time queue. A
89/// given handle won't be reused for a node until that node has been freed and
90/// reused `2 ** (32 - numIndexBits) - 1` times.
91///
92/// `numIndexBits` is an optional parameter to the time queue constructors. If
93/// unspecified, it has a value of 17. The behavior is undefined unless the
94/// specified `numIndexBits` is in the range `8 <= numIndexBits <= 24`.
95///
96/// ### Thread Safety {#bdlcc_timequeue-thread-safety}
97///
98///
99/// It is safe to access or modify two distinct `bdlcc::TimeQueue` objects
100/// simultaneously, each from a separate thread. It is safe to access or modify
101/// a single `bdlcc::TimeQueue` object simultaneously from two or more separate
102/// threads.
103///
104/// It is safe to enqueue objects in a `bdlcc::TimeQueue` object whose
105/// destructor may access or even modify the same `bdlcc::TimeQueue` object.
106/// However, there is no guarantee regarding the safety of enqueuing objects
107/// whose copy constructors or assignment operators may modify or even merely
108/// access the same `bdlcc::TimeQueue` object (except `length`). Such attempts
109/// generally lead to a deadlock.
110///
111/// ### Ordering {#bdlcc_timequeue-ordering}
112///
113///
114/// For a given `bsls::TimeInterval` value, the order of item removal (via
115/// `popFront`, `popLE`, `removeAll`, etc.) is guaranteed to match the order of
116/// item insertion (via `add`) for a particular insertion thread or group of
117/// externally synchronized insertion threads.
118///
119/// ## Usage {#bdlcc_timequeue-usage}
120///
121///
122/// The following shows a typical usage of the `bdlcc::TimeQueue` class,
123/// implementing a simple threaded server `my_Server` that manages individual
124/// Connections (`my_Connection`) on behalf of multiple Sessions (`my_Session`).
125/// Each Connection is timed, such that input requests on that Connection will
126/// "time out" after a user-specified time interval. When a specific Connection
127/// times out, that Connection is removed from the `bdlcc::TimeQueue` and the
128/// corresponding `my_Session` is informed.
129///
130/// In this simplified example, class `my_Session` will terminate when its
131/// Connection times out. A more sophisticated implementation of `my_Session`
132/// would attempt recovery, perhaps by closing and reopening the physical
133/// Connection.
134///
135/// ### Forward Declarations {#bdlcc_timequeue-forward-declarations}
136///
137///
138/// Class `my_Server` will spawn two service threads to monitor connections for
139/// available data and to manage time-outs, respectively. Two forward-declared
140/// "C" functions are invoked as the threads are spawned. The signature of each
141/// function follows the "C" standard "`void *`" interface for spawning threads.
142/// Each function will be called on a new thread when the `start` method is
143/// invoked for a given `my_Server` object. Each function then delegates
144/// processing for the thread back to the `my_Server` object that spawned it.
145/// @code
146/// extern "C" {
147///
148/// void *my_connectionMonitorThreadEntry(void *server);
149///
150/// void *my_timerMonitorThreadEntry(void *server);
151///
152/// }
153/// @endcode
154///
155/// ### struct my_Connection {#bdlcc_timequeue-struct-my_connection}
156///
157///
158/// The `my_Connection` structure is used by `my_Server` to manage a single
159/// physical connection on behalf of a `my_Session`.
160/// @code
161/// class my_Session;
162/// struct my_Connection {
163/// int d_timerId;
164/// my_Session *d_session_p;
165/// };
166/// @endcode
167///
168/// ### Protocol Classes {#bdlcc_timequeue-protocol-classes}
169///
170///
171/// Protocol class `my_Session` provides a pure abstract protocol to manage a
172/// single "session" to be associated with a specific connection on a server.
173/// @code
174/// /// Pure protocol class to process a data buffer of arbitrary size.
175/// /// Concrete implementations in the "real world" would typically manage
176/// /// an external connection like a socket.
177/// class my_Session {
178///
179/// public:
180/// my_Session();
181/// virtual int processData(void *data, int length) = 0;
182/// virtual int handleTimeout(my_Connection *connection) = 0;
183/// virtual ~my_Session();
184/// };
185/// @endcode
186/// The constructor and destructor do nothing:
187/// @code
188/// my_Session::my_Session()
189/// {
190/// }
191///
192/// my_Session::~my_Session()
193/// {
194/// }
195/// @endcode
196/// Protocol class `my_Server` provides a partial implementation of a simple
197/// server that supports and monitors an arbitrary number of connections and
198/// handles incoming data for those connections. Clients must provide a
199/// concrete implementation that binds connections to concrete `my_Session`
200/// objects and monitors all open connections for incoming requests. The
201/// concrete implementation calls `my_Server::newConnection()` when a new
202/// connections is required, and implements the virtual function
203/// `monitorConnections` to monitor all open connections.
204/// @code
205/// /// Simple server supporting multiple Connections.
206/// class my_Server {
207///
208/// bsl::vector<my_Connection*> d_connections;
209/// bdlcc::TimeQueue<my_Connection*> d_timeQueue;
210/// int d_ioTimeout;
211/// bslmt::Mutex d_timerMonitorMutex;
212/// bslmt::Condition d_timerChangedCond;
213/// bslmt::ThreadUtil::Handle d_connectionThreadHandle;
214/// bslmt::ThreadUtil::Handle d_timerThreadHandle;
215/// volatile bool d_done;
216///
217/// protected:
218/// /// Add the specified `connection` to the current `my_Server`,
219/// /// setting the new timeout value to the current time plus the
220/// /// timeout value provided at construction of this `my_Server`
221/// /// instance. If the added connection is the new "top" of the
222/// /// queue, signal that the minimum time on the queue has changed.
223/// /// Upon seeing this signal, the TimerMonitor thread will wake up
224/// /// and look for expired timers.
225/// ///
226/// /// Behavior is undefined if `connection` has already been added to
227/// /// any `my_Server` and has not been removed via member function
228/// /// `closeConnection`.
229/// void newConnection(my_Connection *connection);
230///
231/// /// Remove the specified `connection` from the current `my_Server`,
232/// /// so that it will no longer be monitored for available data.
233/// void removeConnection(my_Connection *connection);
234///
235/// /// Provide a mechanism for a concrete implementation to close a
236/// /// specified `connection`.
237/// virtual void closeConnection(my_Connection *connection)=0;
238///
239/// /// Receive in the specified `buffer_p` a pointer to a data buffer
240/// /// of the specified `length` bytes, and pass this to the specified
241/// /// `connection` to be processed. Behavior is undefined if
242/// /// `connection` is not currently added to this `my_Server` object,
243/// /// or if `length` <= 0.
244/// void dataAvailable(my_Connection *connection,
245/// void *buffer_p,
246/// int length);
247///
248/// protected:
249/// /// Monitor all connections in the current `my_Server`. When data
250/// /// becomes available for a given connection, pass the data to that
251/// /// connection for processing.
252/// virtual void monitorConnections()=0;
253///
254/// /// Monitor all timers in the current `my_Server`, and handle each
255/// /// timer as it expires.
256/// void monitorTimers();
257///
258/// friend void *my_connectionMonitorThreadEntry(void *server);
259/// friend void *my_timerMonitorThreadEntry(void *server);
260///
261/// private:
262/// // Not implemented:
263/// my_Server(const my_Server&);
264///
265/// public:
266/// // CREATORS
267///
268/// /// Construct a `my_Server` object with a timeout value of the
269/// /// specified `ioTimeout` seconds. Use the optionally specified
270/// /// `basicAllocator` for all memory allocation for data members of
271/// /// `my_Server`.
272/// explicit
273/// my_Server(int ioTimeout, bslma::Allocator *basicAllocator = 0);
274///
275/// virtual ~my_Server();
276///
277/// // MANIPULATORS
278///
279/// /// Begin monitoring timers and connections.
280/// int start();
281/// };
282/// @endcode
283/// The constructor is simple: it initializes the internal `bdlcc::TimeQueue`
284/// and sets the I/O timeout value. The virtual destructor sets a shared
285/// completion flag to indicate completion, wakes up all waiting threads, and
286/// waits for them to join.
287/// @code
288/// my_Server::my_Server(int ioTimeout, bslma::Allocator *basicAllocator)
289/// : d_timeQueue(basicAllocator)
290/// , d_ioTimeout(ioTimeout)
291/// , d_connectionThreadHandle(bslmt::ThreadUtil::invalidHandle())
292/// , d_timerThreadHandle(bslmt::ThreadUtil::invalidHandle())
293/// {
294/// }
295///
296/// my_Server::~my_Server()
297/// {
298/// d_done = true;
299/// d_timerChangedCond.broadcast();
300/// if (bslmt::ThreadUtil::invalidHandle() != d_connectionThreadHandle) {
301/// bslmt::ThreadUtil::join(d_connectionThreadHandle);
302/// }
303/// if (bslmt::ThreadUtil::invalidHandle()!= d_timerThreadHandle) {
304/// bslmt::ThreadUtil::join(d_timerThreadHandle);
305/// }
306/// }
307/// @endcode
308/// Member function `newConnection` adds the `connection` to the current set of
309/// connections to be monitored. This is done in two steps. First, the
310/// `connection` is added to the internal array, and then a timer is set for the
311/// `connection` by creating a corresponding entry in the internal
312/// `bdlcc::TimeQueue`.
313/// @code
314/// void my_Server::newConnection(my_Connection *connection)
315/// {
316/// d_connections.push_back(connection);
317/// int isNewTop = 0;
318/// connection->d_timerId = d_timeQueue.add(bdlt::CurrentTime::now() +
319/// d_ioTimeout,
320/// connection,
321/// &isNewTop);
322/// if (isNewTop) {
323/// bslmt::LockGuard<bslmt::Mutex> lock(&d_timerMonitorMutex);
324/// d_timerChangedCond.signal();
325/// }
326/// }
327/// @endcode
328/// Member function `monitorConnections`, provided by the concrete
329/// implementation class, can use the internal array to determine the set of
330/// connections to be monitored.
331///
332/// Member function `removeConnection` removes the `connection` from the current
333/// set of connections to be monitored. This is done in two steps, in reversed
334/// order from `newConnection`. First, the `connection` is removed from the
335/// internal `bdlcc::TimeQueue`, and then the `connection` is removed from the
336/// internal array.
337///
338/// The concrete implementation class must provide an implementation of virtual
339/// function `closeConnection`; this implementation must call `removeConnection`
340/// when the actual connection is to be removed from the `my_Server` object.
341///
342/// Function `closeConnection` is in turn called by function `monitorTimers`,
343/// which manages the overall timer monitor thread. Because `monitorTimers`
344/// takes responsibility for notifying other threads when the queue status
345/// changes, function `removeConnection` does not address these concerns.
346/// @code
347/// void my_Server::removeConnection(my_Connection *connection)
348/// {
349/// // Remove from d_timeQueue
350/// d_timeQueue.remove(connection->d_timerId);
351/// // Remove from d_connections
352/// bsl::vector<my_Connection*>::iterator begin = d_connections.begin(),
353/// end = d_connections.end(),
354/// it = begin;
355/// for (; it != end; ++it) {
356/// if (connection == *it) {
357/// d_connections.erase(it);
358/// }
359/// }
360/// }
361/// @endcode
362/// The `dataAvailable` function will be called when data becomes available for
363/// a specific connection. It removes the connection from the timer queue while
364/// the connection is busy, processes the available data, and returns the
365/// connection to the queue with a new time value.
366/// @code
367/// void my_Server::dataAvailable(my_Connection *connection,
368/// void *buffer_p,
369/// int length)
370/// {
371/// if (connection->d_timerId) {
372/// if (d_timeQueue.remove(connection->d_timerId)) return; // RETURN
373/// connection->d_timerId = 0;
374/// }
375/// connection->d_session_p->processData(buffer_p, length);
376///
377/// int isNewTop = 0;
378///
379/// connection->d_timerId = d_timeQueue.add(bdlt::CurrentTime::now() +
380/// d_ioTimeout,
381/// connection,
382/// &isNewTop);
383/// if (isNewTop) {
384/// bslmt::LockGuard<bslmt::Mutex> lock(&d_timerMonitorMutex);
385/// d_timerChangedCond.signal();
386/// }
387/// }
388/// @endcode
389/// Function `monitorTimers` manages the timer monitor thread; it is called when
390/// the thread is spawned, and checks repeatedly for expired timers; after each
391/// check, it does a timed wait based upon the minimum time value seen in the
392/// queue after all expired timers have been removed.
393/// @code
394/// void my_Server::monitorTimers()
395/// {
396/// while (!d_done) {
397/// bsl::vector<bdlcc::TimeQueueItem<my_Connection*> > expiredTimers;
398/// {
399/// bslmt::LockGuard<bslmt::Mutex> lock(&d_timerMonitorMutex);
400/// bsls::TimeInterval minTime;
401/// int newLength;
402///
403/// d_timeQueue.popLE(bdlt::CurrentTime::now(),
404/// &expiredTimers,
405/// &newLength,
406/// &minTime );
407///
408/// if (!expiredTimers.size()) {
409/// if (newLength) {
410/// // no expired timers, but unexpired timers remain.
411/// d_timerChangedCond.timedWait(&d_timerMonitorMutex,
412/// minTime);
413/// }
414/// else {
415/// // no expired timers, and timer queue is empty.
416/// d_timerChangedCond.wait(&d_timerMonitorMutex);
417/// }
418/// continue;
419/// }
420/// }
421///
422/// int length = static_cast<int>(expiredTimers.size());
423/// if (length) {
424/// bdlcc::TimeQueueItem<my_Connection*> *data =
425/// &expiredTimers.front();
426/// for (int i = 0; i < length; ++i) {
427/// closeConnection(data[i].data());
428/// }
429/// }
430/// }
431/// }
432/// @endcode
433/// Function `start` spawns two separate threads. The first thread will monitor
434/// connections and handle any data received on them. The second monitors the
435/// internal timer queue and removes connections that have timed out. Function
436/// `start` calls `bslmt::ThreadUtil::create`, which expects a function pointer
437/// to a function with the standard "C" callback signature
438/// `void *fn(void *data)`. This non-member function will call back into the
439/// `my_Server` object immediately.
440/// @code
441/// int my_Server::start()
442/// {
443/// bslmt::ThreadAttributes attr;
444///
445/// if (bslmt::ThreadUtil::create(&d_connectionThreadHandle, attr,
446/// &my_connectionMonitorThreadEntry,
447/// this)) {
448/// return -1; // RETURN
449/// }
450///
451/// if (bslmt::ThreadUtil::create(&d_timerThreadHandle, attr,
452/// &my_timerMonitorThreadEntry,
453/// this)) {
454/// return -1; // RETURN
455/// }
456/// return 0;
457/// }
458/// @endcode
459/// Finally, we are now in a position to implement the two thread dispatchers:
460/// @code
461/// extern "C" {
462///
463/// void *my_connectionMonitorThreadEntry(void *server)
464/// {
465/// ((my_Server*)server)->monitorConnections();
466/// return server;
467/// }
468///
469/// void *my_timerMonitorThreadEntry(void *server)
470/// {
471/// ((my_Server*)server)->monitorTimers();
472/// return server;
473/// }
474///
475/// }
476/// @endcode
477/// In order to test our server, we provide two concrete implementations of a
478/// test session and of a test server as follows.
479/// @code
480/// // myTestSession.h -*-C++-*-
481///
482/// /// Concrete implementation of my_Session, providing simple test
483/// /// semantics In particular, implement the virtual function
484/// /// processData() to record all incoming data for the controlling
485/// /// connection, and virtual function handleTimeout() for handling
486/// /// timeouts.
487/// class my_TestSession : public my_Session {
488///
489/// int d_verbose;
490///
491/// public:
492/// // CREATORS
493/// explicit
494/// my_TestSession(int verbose) : my_Session(), d_verbose(verbose) { }
495///
496/// // MANIPULATORS
497/// virtual int handleTimeout(my_Connection *connection)
498/// {
499/// // Do something to handle timeout.
500/// if (d_verbose) {
501/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
502/// bsl::cout << "Connection " << connection << "timed out.\n";
503/// }
504/// return 0;
505/// }
506///
507/// virtual int processData(void *data, int length)
508/// {
509/// // Do something with the data...
510/// if (d_verbose) {
511/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
512/// bsl::cout << "Processing data at address " << data
513/// << " and length " << length << ".\n";
514/// }
515/// return 0;
516/// }
517/// };
518///
519/// // myTestSession.h -*-C++-*-
520///
521/// /// Concrete implementation of my_Server, providing connection logic.
522/// class my_TestServer : public my_Server {
523///
524/// int d_verbose;
525///
526/// protected:
527/// /// Close the specified external `connection` and call
528/// /// `removeConnection` when done.
529/// virtual void closeConnection(my_Connection *connection);
530///
531/// /// Monitor all connections in the current `my_Server`. When data
532/// /// becomes available for a given connection, pass the data to that
533/// /// connection for processing.
534/// virtual void monitorConnections();
535///
536/// private:
537/// // NOT IMPLEMENTED
538/// my_TestServer(const my_TestServer&);
539///
540/// public:
541/// // CREATORS
542///
543/// explicit
544/// my_TestServer(int ioTimeout,
545/// int verbose = 0,
546/// bslma::Allocator *basicAllocator = 0)
547/// : my_Server(ioTimeout, basicAllocator)
548/// , d_verbose(verbose)
549/// {
550/// }
551///
552/// virtual ~my_TestServer();
553/// };
554///
555/// // myTestSession.cpp -*-C++-*-
556///
557/// my_TestServer::~my_TestServer()
558/// {
559/// }
560///
561/// void my_TestServer::closeConnection(my_Connection *connection)
562/// {
563/// if (d_verbose) {
564/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
565/// bsl::cout << "Closing connection " << connection << bsl::endl;
566/// }
567/// delete connection;
568/// }
569///
570/// void my_TestServer::monitorConnections()
571/// {
572/// my_Session *session = new my_TestSession(d_verbose);
573///
574/// // Simulate connection monitor logic...
575/// my_Connection *connection1 = new my_Connection;
576/// connection1->d_session_p = session;
577/// newConnection(connection1);
578/// if (d_verbose) {
579/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
580/// bsl::cout << "Opening connection " << connection1 << endl;
581/// }
582///
583/// my_Connection *connection2 = new my_Connection;
584/// connection2->d_session_p = session;
585/// newConnection(connection2);
586/// if (d_verbose) {
587/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
588/// bsl::cout << "Opening connection " << connection2 << endl;
589/// }
590///
591/// bslmt::ThreadUtil::sleep(bsls::TimeInterval(2)); // 2s
592///
593/// // Simulate transmission...
594/// const int length = 1024;
595/// const char*buffer[length];
596/// if (d_verbose) {
597/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
598/// bsl::cout << "Connection " << connection1
599/// << " receives " << length << " bytes " << endl;
600/// }
601/// dataAvailable(connection1, buffer, length);
602///
603/// // Wait for timeout to occur, otherwise session gets destroyed from
604/// // stack too early.
605///
606/// bslmt::ThreadUtil::sleep(bsls::TimeInterval(8)); // 8s
607/// }
608/// @endcode
609/// The program that would exercise this test server would simply consist of:
610/// @code
611/// int usageExample(int verbose)
612/// {
613/// my_TestServer mX(5, verbose); // timeout for connections: 5s
614/// mX.start();
615///
616/// // Wait sufficiently long to observe all events.
617/// bslmt::ThreadUtil::sleep(bsls::TimeInterval(10)); // 10s
618///
619/// return 0;
620/// }
621/// @endcode
622/// The output of this program would look something as follows:
623/// @code
624/// 17:10:35.000: Opening connection 0x00161880
625/// 17:10:35.000: Opening connection 0x001618b0
626/// 17:10:37.000: Connection 0x00161880 receives 1024 bytes
627/// 17:10:37.000: Processing data at address 0xfeefaf04 and length 1024.
628/// 17:10:40.000: Closing connection 0x001618b0
629/// 17:10:42.000: Closing connection 0x00161880
630/// @endcode
631/// @}
632/** @} */
633/** @} */
634
635/** @addtogroup bdl
636 * @{
637 */
638/** @addtogroup bdlcc
639 * @{
640 */
641/** @addtogroup bdlcc_timequeue
642 * @{
643 */
644
645#include <bdlscm_version.h>
646
648#include <bdlma_pool.h>
649
651
652#include <bslma_default.h>
655
656#include <bslmf_assert.h>
658
659#include <bslmt_lockguard.h>
660#include <bslmt_mutex.h>
661
662#include <bsls_alignment.h>
663#include <bsls_assert.h>
664#include <bsls_atomic.h>
665#include <bsls_keyword.h>
666#include <bsls_libraryfeatures.h>
667#include <bsls_platform.h>
668#include <bsls_timeinterval.h>
669
670#include <bsl_climits.h>
671#include <bsl_cstdint.h>
672#include <bsl_map.h>
673#include <bsl_vector.h>
674
675#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
677#include <bslalg_typetraits.h>
678#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
679
680#include <vector>
681
682
683namespace bdlcc {
684
685template <class DATA>
686class TimeQueueItem;
687
688 // ===============
689 // class TimeQueue
690 // ===============
691
692/// This parameterized class provides a public interface which is similar in
693/// structure and intent to `Queue<DATA>`, with the exception that each item
694/// stored in the `TimeQueue` has an associated time value. Items are
695/// retrieved or exchanged by proxy of a `TimeQueueItem<DATA>`, and are
696/// referred to by an opaque data type `TimeQueue::Handle` which serves to
697/// identify an individual element on the Time Queue. Idiomatic usage of
698/// `TimeQueue` includes the member function `popLE`, which finds all items
699/// on the queue whose `bsls::TimeInterval` are less than a specified value
700/// and transfers those items to a provided vector of items, and the member
701/// function `update`, which can update the time value for a specific
702/// `TimeQueueItem` without removing it from the queue.
703///
704/// See @ref bdlcc_timequeue
705template <class DATA>
707
708 // TYPES
709 enum {
710 k_NUM_INDEX_BITS_MIN = 8,
711 k_NUM_INDEX_BITS_MAX = 24,
712 k_NUM_INDEX_BITS_DEFAULT = 17
713 };
714
715 public:
716 // TYPES
717
718 /// `Handle` defines an alias for uniquely identifying a valid node in
719 /// the time queue. Handles are returned when nodes are added to the
720 /// time queue, and must be supplied to the `update` and `remove`
721 /// methods to identify existing nodes. When a node is removed, the
722 /// handle value becomes invalid, though invalidated handle values are
723 /// eventually reused. See the component-level documentation for more
724 /// details.
725 typedef int Handle;
726
727 /// This type is a wrapper around a void pointer that will be supplied
728 /// and used by clients to uniquely identify an item in the queue.
729 ///
730 /// See @ref bdlcc_timequeue
731 class Key {
732
733 // PRIVATE DATA MEMBERS
734 const void *d_key;
735
736 public:
737 // CREATORS
738
739 /// Create a `Key` object having the specified `key` value.
740 explicit Key(const void *key)
741 : d_key(key)
742 {}
743
744 /// Create a `Key` object having the specified `key` value cast to a
745 /// `void *`.
746 explicit Key(int key)
747 : d_key(reinterpret_cast<const void*>(static_cast<bsl::intptr_t>(key)))
748 {}
749
750 /// Destroy this `Key` object.
752 {}
753
754 // ACCESSORS
755
756 /// Return `true` if this object has the same value as the specified
757 /// `rhs` object, and `false` otherwise.
758 bool operator==(const Key& rhs) const
759 {
760 return d_key == rhs.d_key;
761 }
762
763 /// Return `true` if this object does not have the same value as the
764 /// specified `rhs` object, and `false` otherwise.
765 bool operator!=(const Key& rhs) const
766 {
767 return d_key != rhs.d_key;
768 }
769 };
770
771 private:
772
773 // PRIVATE TYPES
774 template <class VECTOR>
775 struct IsVector;
776
777 /// This queue is implemented internally as a map of time values, each
778 /// entry in the map storing a doubly-linked circular list of items
779 /// having the same time value. This struct provides the node in the
780 /// list.
781 struct Node {
782
783 // PUBLIC DATA MEMBERS
784 unsigned int d_index;
785 bsls::TimeInterval d_time;
786 Key d_key;
787 Node *d_prev_p;
788 Node *d_next_p;
790
791 // CREATORS
792
793 /// Create a `Node` having a time value of 0.
794 Node()
795 : d_index(0)
796 , d_key(0)
797 , d_prev_p(0)
798 , d_next_p(0)
799 {
800 }
801
802 /// Create a `Node` having the specified `time` value.
803 explicit
804 Node(const bsls::TimeInterval& time)
805 : d_index(0)
806 , d_time(time)
807 , d_key(0)
808 , d_prev_p(0)
809 , d_next_p(0)
810 {
811 }
812 };
813
814 /// Internal typedef for the time index map.
816
817 /// Internal typedef for the iterator type used to navigate the time
818 /// index.
819 typedef typename NodeMap::iterator MapIter;
820
821 /// Internal typedef for the const-iterator type used to navigate the
822 /// time index.
823 typedef typename NodeMap::const_iterator MapCIter;
824
825 // PRIVATE DATA MEMBERS
826 const unsigned int d_indexMask;
827 const unsigned int d_indexIterationMask;
828 const unsigned int d_indexIterationInc;
829
830 mutable bslmt::Mutex d_mutex; // used for synchronizing
831 // access to this queue
832
833 bsl::vector<Node*> d_nodeArray; // array of nodes in this queue
834
835 bsls::AtomicPointer<Node> d_nextFreeNode_p; // pointer to the next free
836 // node in this queue (the free
837 // list is singly linked only,
838 // using d_next_p)
839
840 NodeMap d_map; // list of time values in
841 // increasing time order
842
843 bsls::AtomicInt d_length; // number of items currently in
844 // this queue (not necessarily
845 // equal to d_map.size())
846
847 bslma::Allocator *d_allocator_p; // allocator (held, not owned)
848
849 // PRIVATE MANIPULATORS
850
851 /// Prepare the specified `node` for being reused on the free list by
852 /// incrementing the iteration count. Set `d_prev_p` field to 0.
853 void freeNode(Node *node);
854
855 /// Remove from this queue all the items that have a time value less
856 /// than or equal to the specified `time`, and optionally append into
857 /// the optionally specified `buffer` a list of the removed items,
858 /// ordered by their corresponding time values (top item first).
859 /// Optionally load into the optionally specified `newLength` the number
860 /// of items remaining in this queue, and into the optionally specified
861 /// `newMinTime` the lowest remaining time value in this queue. Note
862 /// that `newMinTime` is only loaded if there are items remaining in the
863 /// time queue; therefore, `newLength` should be specified and examined
864 /// to determine whether items remain, and `newMinTime` used only when
865 /// `newLength` > 0. Also note that if `DATA` follows the `bdema`
866 /// allocator model, the allocator of the `buffer` vector is used to
867 /// supply memory for the items appended to the `buffer`.
868 template <class VECTOR>
869 void popLEImp(const bsls::TimeInterval& time,
870 VECTOR *buffer,
871 int *newLength = 0,
872 bsls::TimeInterval *newMinTime = 0);
873
874 /// Remove from this queue up to the specified `maxTimers` number of
875 /// items that have a time value less than or equal to the specified
876 /// `time`, and optionally append into the optionally specified `buffer`
877 /// a list of the removed items, ordered by their corresponding time
878 /// values (top item first). Optionally load into the optionally
879 /// specified `newLength` the number of items remaining in this queue,
880 /// and into the optionally specified `newMinTime` the lowest remaining
881 /// time value in this queue. The behavior is undefined unless
882 /// `maxTimers` >= 0. Note that `newMinTime` is only loaded if there
883 /// are items remaining in the time queue; therefore, `newLength` should
884 /// be specified and examined to determine whether items remain, and
885 /// `newMinTime` used only when `newLength` > 0. Also note that if
886 /// `DATA` follows the `bdema` allocator model, the allocator of the
887 /// `buffer` vector is used to supply memory. Note finally that all the
888 /// items appended into `buffer` have a time value less than or equal to
889 /// the elements remaining in this queue.
890 template <class VECTOR>
891 void popLEImp(const bsls::TimeInterval& time,
892 int maxTimers,
893 VECTOR *buffer,
894 int *newLength = 0,
895 bsls::TimeInterval *newMinTime = 0);
896
897 /// Destroy the data located at the specified `node` and reattach this
898 /// `node` to the front of the free list starting at `d_nextFreeNode_p`,
899 /// making `node` the new `d_nextFreeNode_p`. Note that the caller must
900 /// not have acquired the lock to this queue.
901 void putFreeNode(Node *node);
902
903 /// Destroy the `DATA` of every node in the singly-linked list starting
904 /// at the specified `begin` node and ending with a null pointer, and
905 /// reattach these nodes to the front of the free list starting at
906 /// `d_nextFreeNode_p`, making `begin` the new `d_nextFreeNode_p` and
907 /// calling `freeNode`. Note that the caller must not have acquired the
908 /// lock to this queue.
909 void putFreeNodeList(Node *begin);
910
911 // PRIVATE ACCESSORS
912
913 /// Return a pointer to the node correlating to the specified `handle`
914 /// and `key` if such a node exists, otherwise return a null pointer.
915 Node* getNodeFromHandle(Handle handle, Key key) const;
916
917
918 private:
919 // NOT IMPLEMENTED
920 TimeQueue(const TimeQueue&) BSLS_KEYWORD_DELETED;
921 TimeQueue& operator=(const TimeQueue&) BSLS_KEYWORD_DELETED;
922
923 public:
924 // CREATORS
925
926 explicit TimeQueue(bslma::Allocator *basicAllocator = 0);
927 /// Create an empty time queue. Optionally specify `numIndexBits` to
928 /// configure the number of index bits used by this object. If
929 /// `numIndexBits` is not specified a default value of 17 is used.
930 /// Optionally specify a `basicAllocator` used to supply memory. If
931 /// `basicAllocator` is 0, the currently installed default allocator is
932 /// used. The behavior is undefined unless `8 <= numIndexBits <= 24`.
933 /// See the component-level documentation for more information regarding
934 /// `numIndexBits`.
935 explicit TimeQueue(int numIndexBits, bslma::Allocator *basicAllocator = 0);
936
937 explicit TimeQueue(bool poolTimerMemory,
938 bslma::Allocator *basicAllocator = 0);
939 /// [**DEPRECATED**] Use the other constructor overloads instead. Note
940 /// that the specified `poolTimerMemory` argument controlled whether
941 /// additional memory used by an internal `bsl::map` was pooled. When
942 /// `bsl::map` was modified to pool its own nodes, this option became
943 /// irrelevant and is now ignored.
944 TimeQueue(int numIndexBits,
945 bool poolTimerMemory,
946 bslma::Allocator *basicAllocator = 0);
947
948 /// Destroy this time queue.
950
951 // MANIPULATORS
952
954 const DATA& data,
955 int *isNewTop = 0,
956 int *newLength = 0);
957 /// Add a new item to this queue having the specified `time` value, and
958 /// associated `data`. Optionally use the specified `key` to uniquely
959 /// identify the item in subsequent calls to `remove` and `update`.
960 /// Optionally load into the optionally specified `isNewTop` a non-zero
961 /// value if the item is now the lowest item in this queue, and a 0
962 /// value otherwise. If specified, load into the optionally specified
963 /// `newLength`, the new number of items in this queue. Return a value
964 /// that may be used to identify the newly added item in future calls to
965 /// time queue on success, and -1 if the maximum queue length has been
966 /// reached.
968 const DATA& data,
969 const Key& key,
970 int *isNewTop = 0,
971 int *newLength = 0);
972
973 /// Add the value of the specified `item` to this queue. Optionally
974 /// load into the optionally specified `isNewTop` a non-zero value if
975 /// the replaces is now the lowest element in this queue, and a 0 value
976 /// otherwise. If specified, load into the optionally specified
977 /// `newLength`, the new number of elements in this queue. Return a
978 /// value that may be used to identify the newly added item in future
979 /// calls to time queue on success, and -1 if the maximum queue length
980 /// has been reached.
982 int *isNewTop = 0,
983 int *newLength = 0);
984
985 /// Atomically remove the top item from this queue, and optionally load
986 /// into the optionally specified `buffer` the time and associated data
987 /// of the item removed. Optionally load into the optionally specified
988 /// `newLength`, the number of items remaining in the queue. Optionally
989 /// load into the optionally specified `newMinTime` the new lowest time
990 /// in this queue. Return 0 on success, and a non-zero value if there
991 /// are no items in the queue. Note that if `DATA` follows the `bdema`
992 /// allocator model, the allocator of the `buffer` is used to supply
993 /// memory.
995 int *newLength = 0,
996 bsls::TimeInterval *newMinTime = 0);
997
998 void popLE(const bsls::TimeInterval& time);
999 void popLE(const bsls::TimeInterval& time,
1001 int *newLength = 0,
1002 bsls::TimeInterval *newMinTime = 0);
1003 /// Remove from this queue all the items that have a time value less than
1004 /// or equal to the specified `time`, and optionally append into the
1005 /// optionally specified `buffer` a list of the removed items, ordered by
1006 /// their corresponding time values (top item first). Optionally load into
1007 /// the optionally specified `newLength` the number of items remaining in
1008 /// this queue, and into the optionally specified `newMinTime` the lowest
1009 /// remaining time value in this queue. Note that `newMinTime` is only
1010 /// loaded if there are items remaining in the time queue; therefore,
1011 /// `newLength` should be specified and examined to determine whether items
1012 /// remain, and `newMinTime` used only when `newLength > 0`. Also note
1013 /// that if `DATA` follows the `bdema` allocator model, the allocator of
1014 /// the `buffer` vector is used to supply memory for the items appended to
1015 /// the `buffer`.
1016 void popLE(const bsls::TimeInterval& time,
1017 std::vector<TimeQueueItem<DATA> > *buffer,
1018 int *newLength = 0,
1019 bsls::TimeInterval *newMinTime = 0);
1020#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1021 void popLE(const bsls::TimeInterval& time,
1022 std::pmr::vector<TimeQueueItem<DATA> > *buffer,
1023 int *newLength = 0,
1024 bsls::TimeInterval *newMinTime = 0);
1025#endif
1026
1027 void popLE(const bsls::TimeInterval& time,
1028 int maxTimers);
1029 void popLE(const bsls::TimeInterval& time,
1030 int maxTimers,
1032 int *newLength = 0,
1033 bsls::TimeInterval *newMinTime = 0);
1034 /// Remove from this queue up to the specified `maxTimers` number of items
1035 /// that have a time value less than or equal to the specified `time`, and
1036 /// optionally append into the optionally specified `buffer` a list of the
1037 /// removed items, ordered by their corresponding time values (top item
1038 /// first). Optionally load into the optionally specified `newLength` the
1039 /// number of items remaining in this queue, and into the optionally
1040 /// specified `newMinTime` the lowest remaining time value in this queue.
1041 /// The behavior is undefined unless `maxTimers >= 0`. Note that
1042 /// `newMinTime` is only loaded if there are items remaining in the time
1043 /// queue; therefore, `newLength` should be specified and examined to
1044 /// determine whether items remain, and `newMinTime` used only when
1045 /// `newLength > 0`. Also note that if `DATA` follows the `bdema`
1046 /// allocator model, the allocator of the `buffer` vector is used to supply
1047 /// memory. Note finally that all the items appended into `buffer` have a
1048 /// time value less than or equal to the elements remaining in this queue.
1049 void popLE(const bsls::TimeInterval& time,
1050 int maxTimers,
1051 std::vector<TimeQueueItem<DATA> > *buffer,
1052 int *newLength = 0,
1053 bsls::TimeInterval *newMinTime = 0);
1054#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1055 void popLE(const bsls::TimeInterval& time,
1056 int maxTimers,
1057 std::pmr::vector<TimeQueueItem<DATA> > *buffer,
1058 int *newLength = 0,
1059 bsls::TimeInterval *newMinTime = 0);
1060#endif
1061
1062 int remove(Handle handle,
1063 int *newLength = 0,
1064 bsls::TimeInterval *newMinTime = 0,
1065 TimeQueueItem<DATA> *item = 0);
1066 /// Remove from this queue the item having the specified `handle`, and
1067 /// optionally load into the optionally specified `item` the time and
1068 /// data values of the recently removed item. Optionally use the
1069 /// specified `key` to uniquely identify the item. If specified, load
1070 /// into the optionally specified `newMinTime`, the resulting lowest
1071 /// time value remaining in the queue. Return 0 on success, and a
1072 /// non-zero value if no item with the `handle` exists in the queue.
1073 /// Note that if `DATA` follows the `bdema` allocator model, the
1074 /// allocator of the `item` instance is used to supply memory.
1075 int remove(Handle handle,
1076 const Key& key,
1077 int *newLength = 0,
1078 bsls::TimeInterval *newMinTime = 0,
1079 TimeQueueItem<DATA> *item = 0);
1080
1081 /// Remove all the items from this queue. Optionally specify a `buffer`
1082 /// in which to load the removed items. The resultant items in the
1083 /// `buffer` are ordered by increasing time interval; items of
1084 /// equivalent time interval have arbitrary ordering. Note that the
1085 /// allocator of the `buffer` vector is used to supply memory.
1087
1088 int update(Handle handle,
1089 const bsls::TimeInterval& newTime,
1090 int *isNewTop = 0);
1091 /// Update the time value of the item having the specified `handle` to
1092 /// the specified `newTime` and optionally load into the optionally
1093 /// specified `isNewTop` a non-zero value if the modified item is now
1094 /// the lowest time value in the time queue or zero otherwise. Return 0
1095 /// on success, and a non-zero value if there is currently no item
1096 /// having the `handle` registered with this time queue.
1097 int update(Handle handle,
1098 const Key& key,
1099 const bsls::TimeInterval& newTime,
1100 int *isNewTop = 0);
1101
1102 // ACCESSORS
1103
1104 /// Return number of items in this queue. Note that the value returned
1105 /// may be obsolete by the time it is received.
1106 int length() const;
1107
1108 /// Return `true` if an item having specified `handle` is currently
1109 /// registered with this time queue and false otherwise.
1110 bool isRegisteredHandle(Handle handle) const;
1111 bool isRegisteredHandle(Handle handle, const Key& key) const;
1112
1113 /// Load into the specified `buffer`, the time value of the lowest time
1114 /// in this queue. Return 0 on success, and a non-zero value if this
1115 /// queue is empty.
1116 int minTime(bsls::TimeInterval *buffer) const;
1117
1118 /// Return the number of items in this queue that have a time value less
1119 /// than or equal to the specified `time`. Note that the value returned
1120 /// may be obsolete by the time it is received.
1121 int countLE(const bsls::TimeInterval& time) const;
1122};
1123
1124 // ====================
1125 // struct TimeQueueItem
1126 // ====================
1127
1128/// This parameterized structure holds a time, data and associated handle.
1129/// This structure is used in the interface of `TimeQueue<DATA>` to provide
1130/// thread-safe access to individual elements on the queue. Note that
1131/// `DATA` must be default-constructible.
1132///
1133/// See @ref bdlcc_timequeue
1134template <class DATA>
1136
1137 public:
1138 // TRAITS
1140
1141 // PUBLIC TYPES
1143 typedef typename TimeQueue<DATA>::Key Key;
1144
1145 private:
1146 bsls::TimeInterval d_time; // Time value
1147 DATA d_data; // Associated data value
1148 Handle d_handle; // Associated handle
1149 Key d_key; // Associated key
1150
1151 public:
1152 // CREATORS
1153
1154 /// Create an empty time queue item. Optionally specify a
1155 /// `basicAllocator` used to supply memory. If `basicAllocator` is
1156 /// zero, then use the currently installed default allocator.
1157 explicit
1158 TimeQueueItem(bslma::Allocator *basicAllocator = 0);
1159
1160 /// Create time queue item holding a copy of the specified `data`, with
1161 /// the specified associated `time` and `handle` information.
1162 /// Optionally specify a `basicAllocator` used to supply memory. If
1163 /// `basicAllocator` is zero, then use the currently installed default
1164 /// allocator.
1166 const DATA& data,
1167 Handle handle,
1168 bslma::Allocator *basicAllocator = 0);
1169
1170 /// Create time queue item holding a copy of the specified `data`, with
1171 /// the specified associated `time`, `handle`, and `key` information.
1172 /// Optionally specify a `basicAllocator` used to supply memory. If
1173 /// `basicAllocator` is zero, then use the currently installed default
1174 /// allocator.
1176 const DATA& data,
1177 Handle handle,
1178 const Key& key,
1179 bslma::Allocator *basicAllocator = 0);
1180
1181 /// Create a copy of the specified `original` time queue item.
1182 /// Optionally specify a `basicAllocator` used to supply memory. If
1183 /// `basicAllocator` is zero, then use the currently installed default
1184 /// allocator.
1185 TimeQueueItem(const TimeQueueItem<DATA>& original,
1186 bslma::Allocator *basicAllocator = 0);
1187
1188 // MANIPULATORS
1189
1190 /// Set the value of this `TimeQueueItem` to that of `rhs`.
1192
1193 /// Return the modifiable time value associated with this item.
1195
1196 /// Return the modifiable data instance associated with this item.
1197 DATA& data();
1198
1199 /// Return the modifiable handle value associated with this item.
1201 {
1202 // this definition was moved into the class declaration to work around
1203 // a Visual Studio .NET 2003 bug.
1204
1205 return d_handle;
1206 }
1207
1208 /// Return the modifiable key value associated with this item.
1209 Key& key();
1210
1211 // ACCESSORS
1212
1213 /// Return the non-modifiable time value associated with this item.
1214 const bsls::TimeInterval& time() const;
1215
1216 /// Return the non-modifiable data associated with this item.
1217 const DATA& data() const;
1218
1219 /// Return the non-modifiable handle value associated with this item.
1221 {
1222 // this definition was moved into the class declaration to work around
1223 // a Visual Studio .NET 2003 bug.
1224
1225 return d_handle;
1226 }
1227
1228 /// Return the non-modifiable key value associated with this item.
1229 const Key& key() const;
1230};
1231
1232 // =========================
1233 // TimeQueue<DATA>::IsVector
1234 // =========================
1235
1236/// This `struct` has a `value` that evaluates to `true` if the specified
1237/// `VECTOR` is a `bsl`, `std`, or `std::pmr` `vector<VALUE>`.
1238template <class DATA>
1239template <class VECTOR>
1240struct TimeQueue<DATA>::IsVector {
1241
1242 // TYPE
1243 typedef TimeQueueItem<DATA> Item;
1244
1245 // CLASS DATA
1246 static const bool value =
1247 bsl::is_same<bsl::vector<Item>, VECTOR>::value
1248#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1249 || bsl::is_same<std::pmr::vector<Item>, VECTOR>::value
1250#endif
1251 || bsl::is_same<std::vector<Item>, VECTOR>::value;
1252};
1253
1254// ============================================================================
1255// INLINE DEFINITIONS
1256// ============================================================================
1257
1258 // ---------
1259 // TimeQueue
1260 // ---------
1261
1262// PRIVATE MANIPULATORS
1263template <class DATA>
1264inline
1265void TimeQueue<DATA>::freeNode(Node *node)
1266{
1267 node->d_index = ((node->d_index + d_indexIterationInc) &
1268 d_indexIterationMask) | (node->d_index & d_indexMask);
1269
1270 if (!(node->d_index & d_indexIterationMask)) {
1271 node->d_index += d_indexIterationInc;
1272 }
1273 node->d_prev_p = 0;
1274}
1275
1276template <class DATA>
1277template <class VECTOR>
1278void TimeQueue<DATA>::popLEImp(const bsls::TimeInterval& time,
1279 VECTOR *buffer,
1280 int *newLength,
1281 bsls::TimeInterval *newMinTime)
1282{
1283 BSLMF_ASSERT(IsVector<VECTOR>::value);
1284
1285 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1286
1287 MapIter it = d_map.begin();
1288
1289 Node *begin = 0;
1290 while (d_map.end() != it && it->first <= time) {
1291 Node *const first = it->second;
1292 Node *const last = first->d_prev_p;
1293 Node *node = first;
1294
1295 do {
1296 if (buffer) {
1297 buffer->push_back(TimeQueueItem<DATA>(it->first,
1298 node->d_data.object(),
1299 node->d_index,
1300 node->d_key,
1301 d_allocator_p));
1302 }
1303 freeNode(node);
1304 node = node->d_next_p;
1305 --d_length;
1306 } while (node != first);
1307
1308 last->d_next_p = begin;
1309 begin = first;
1310
1311 MapIter condemned = it;
1312 ++it;
1313 d_map.erase(condemned);
1314 }
1315
1316 if (newLength) {
1317 *newLength = d_length;
1318 }
1319 if (d_map.end() != it && newMinTime) {
1320 *newMinTime = it->first;
1321 }
1322
1323 lock.release()->unlock();
1324 putFreeNodeList(begin);
1325}
1326
1327template <class DATA>
1328template <class VECTOR>
1329void TimeQueue<DATA>::popLEImp(const bsls::TimeInterval& time,
1330 int maxTimers,
1331 VECTOR *buffer,
1332 int *newLength,
1333 bsls::TimeInterval *newMinTime)
1334{
1335 BSLS_ASSERT(0 <= maxTimers);
1336
1337 BSLMF_ASSERT(IsVector<VECTOR>::value);
1338
1339 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1340
1341 MapIter it = d_map.begin();
1342
1343 Node *begin = 0;
1344 while (d_map.end() != it && it->first <= time && 0 < maxTimers) {
1345 Node *const first = it->second;
1346 Node *const last = first->d_prev_p;
1347 Node *node = first;
1348 Node *prevNode = first->d_prev_p;
1349
1350 do {
1351 if (buffer) {
1352 buffer->push_back(TimeQueueItem<DATA>(
1353 it->first,
1354 node->d_data.object(),
1355 node->d_index,
1356 node->d_key,
1357 d_allocator_p));
1358 }
1359 freeNode(node);
1360 prevNode = node;
1361 node = node->d_next_p;
1362 --d_length;
1363 --maxTimers;
1364 } while (0 < maxTimers && node != first);
1365
1366 prevNode->d_next_p = begin;
1367 begin = first;
1368
1369 if (node == first) {
1370 MapIter condemned = it;
1371 ++it;
1372 d_map.erase(condemned);
1373 }
1374 else {
1375 node->d_prev_p = last;
1376 last->d_next_p = node;
1377 it->second = node;
1378 break;
1379 }
1380 }
1381
1382 if (newLength) {
1383 *newLength = d_length;
1384 }
1385 if (d_map.end() != it && newMinTime) {
1386 *newMinTime = it->first;
1387 }
1388
1389 lock.release()->unlock();
1390 putFreeNodeList(begin);
1391}
1392
1393template <class DATA>
1394void TimeQueue<DATA>::putFreeNode(Node *node)
1395{
1396 node->d_data.object().~DATA();
1397
1398 Node *nextFreeNode = d_nextFreeNode_p;
1399 node->d_next_p = nextFreeNode;
1400 while (nextFreeNode != d_nextFreeNode_p.testAndSwap(nextFreeNode, node)) {
1401 nextFreeNode = d_nextFreeNode_p;
1402 node->d_next_p = nextFreeNode;
1403 }
1404}
1405
1406template <class DATA>
1407void TimeQueue<DATA>::putFreeNodeList(Node *begin)
1408{
1409 if (begin) {
1410 begin->d_data.object().~DATA();
1411
1412 Node *end = begin;
1413 while (end->d_next_p) {
1414 end = end->d_next_p;
1415 end->d_data.object().~DATA();
1416 }
1417
1418 Node *nextFreeNode = d_nextFreeNode_p;
1419 end->d_next_p = nextFreeNode;
1420
1421 while (nextFreeNode !=
1422 d_nextFreeNode_p.testAndSwap(nextFreeNode, begin)) {
1423 nextFreeNode = d_nextFreeNode_p;
1424 end->d_next_p = nextFreeNode;
1425 }
1426 }
1427 return;
1428}
1429
1430// PRIVATE ACCESSORS
1431template <class DATA>
1432typename TimeQueue<DATA>::Node *TimeQueue<DATA>::getNodeFromHandle(
1433 Handle handle,
1434 Key key) const
1435{
1436 unsigned int uhandle = static_cast<unsigned int>(handle) & d_indexMask;
1437 if (0 == uhandle || uhandle > d_nodeArray.size()) {
1438 return 0; // RETURN
1439 }
1440 Node *node = d_nodeArray[uhandle - 1];
1441 if (node->d_index != static_cast<unsigned>(handle) || node->d_key != key ||
1442 0 == node->d_prev_p) {
1443 return 0; // RETURN
1444 }
1445 return node;
1446}
1447
1448// CREATORS
1449template <class DATA>
1451: d_indexMask((1U << k_NUM_INDEX_BITS_DEFAULT) - 1)
1452, d_indexIterationMask(~d_indexMask)
1453, d_indexIterationInc(d_indexMask + 1)
1454, d_nodeArray(basicAllocator)
1455, d_nextFreeNode_p(0)
1456, d_map(basicAllocator)
1457, d_length(0)
1458, d_allocator_p(bslma::Default::allocator(basicAllocator))
1459{
1460}
1461
1462template <class DATA>
1463TimeQueue<DATA>::TimeQueue(bool poolTimerMemory,
1464 bslma::Allocator *basicAllocator)
1465: d_indexMask((1U << k_NUM_INDEX_BITS_DEFAULT) - 1)
1466, d_indexIterationMask(~d_indexMask)
1467, d_indexIterationInc(d_indexMask + 1)
1468, d_nodeArray(basicAllocator)
1469, d_nextFreeNode_p(0)
1470, d_map(basicAllocator)
1471, d_length(0)
1472, d_allocator_p(bslma::Default::allocator(basicAllocator))
1473{
1474 // The 'poolTimerMemory' option has been deprecated (see method
1475 // documentation).
1476
1477 (void)poolTimerMemory;
1478}
1479
1480template <class DATA>
1481TimeQueue<DATA>::TimeQueue(int numIndexBits, bslma::Allocator *basicAllocator)
1482: d_indexMask((1 << numIndexBits) - 1)
1483, d_indexIterationMask(~d_indexMask)
1484, d_indexIterationInc(d_indexMask + 1)
1485, d_nodeArray(basicAllocator)
1486, d_nextFreeNode_p(0)
1487, d_map(basicAllocator)
1488, d_length(0)
1489, d_allocator_p(bslma::Default::allocator(basicAllocator))
1490{
1491 BSLS_ASSERT(k_NUM_INDEX_BITS_MIN <= numIndexBits
1492 && k_NUM_INDEX_BITS_MAX >= numIndexBits);
1493}
1494
1495template <class DATA>
1497 bool poolTimerMemory,
1498 bslma::Allocator *basicAllocator)
1499: d_indexMask((1 << numIndexBits) - 1)
1500, d_indexIterationMask(~d_indexMask)
1501, d_indexIterationInc(d_indexMask + 1)
1502, d_nodeArray(basicAllocator)
1503, d_nextFreeNode_p(0)
1504, d_map(basicAllocator)
1505, d_length(0)
1506, d_allocator_p(bslma::Default::allocator(basicAllocator))
1507{
1508 BSLS_ASSERT(k_NUM_INDEX_BITS_MIN <= numIndexBits
1509 && k_NUM_INDEX_BITS_MAX >= numIndexBits);
1510
1511 // The 'poolTimerMemory' option has been deprecated (see method
1512 // documentation).
1513
1514 (void)poolTimerMemory;
1515
1516}
1517
1518template <class DATA>
1520{
1521 removeAll();
1522 if (!d_nodeArray.empty()) {
1523 Node **data = &d_nodeArray.front();
1524 const int numNodes = static_cast<int>(d_nodeArray.size());
1525 for (int i = 0; i < numNodes; ++i) {
1526 d_allocator_p->deleteObjectRaw(data[i]);
1527 }
1528 }
1529}
1530
1531// MANIPULATORS
1532template <class DATA>
1533inline
1535 const bsls::TimeInterval& time,
1536 const DATA& data,
1537 int *isNewTop,
1538 int *newLength)
1539{
1540 return add(time, data, Key(0), isNewTop, newLength);
1541}
1542
1543template <class DATA>
1545 const bsls::TimeInterval& time,
1546 const DATA& data,
1547 const Key& key,
1548 int *isNewTop,
1549 int *newLength)
1550
1551{
1552 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1553
1554 Node *node;
1555 if (d_nextFreeNode_p) {
1556 // All allocation of nodes goes through this routine, which is guarded
1557 // by the mutex. So no other thread will remove anything from the free
1558 // list while this code is executing. However, other threads may add
1559 // to the free list.
1560
1561 node = d_nextFreeNode_p;
1562 Node *next = node->d_next_p;
1563 while (node != d_nextFreeNode_p.testAndSwap(node, next)) {
1564 node = d_nextFreeNode_p;
1565 next = node->d_next_p;
1566 }
1567 }
1568 else {
1569 // The number of nodes cannot grow to a size larger than the range of
1570 // available indices.
1571
1572 if (d_nodeArray.size() >= d_indexMask - 1) {
1573 return -1; // RETURN
1574 }
1575
1576 node = new (*d_allocator_p) Node;
1577 d_nodeArray.push_back(node);
1578 node->d_index =
1579 static_cast<int>(d_nodeArray.size()) | d_indexIterationInc;
1580 }
1581 node->d_time = time;
1582 node->d_key = key;
1583 bslalg::ScalarPrimitives::copyConstruct(&node->d_data.object(),
1584 data,
1585 d_allocator_p);
1586
1587 {
1588 MapIter it = d_map.find(time);
1589
1590 if (d_map.end() == it) {
1591 node->d_prev_p = node;
1592 node->d_next_p = node;
1593 d_map[time] = node;
1594 }
1595 else {
1596 node->d_prev_p = it->second->d_prev_p;
1597 it->second->d_prev_p->d_next_p = node;
1598 node->d_next_p = it->second;
1599 it->second->d_prev_p = node;
1600 }
1601 }
1602
1603 ++d_length;
1604 if (isNewTop) {
1605 *isNewTop = d_map.begin()->second == node && node->d_prev_p == node;
1606 }
1607
1608 if (newLength) {
1609 *newLength = d_length;
1610 }
1611
1612 return node->d_index;
1613}
1614
1615template <class DATA>
1616inline
1618 const TimeQueueItem<DATA>& item,
1619 int *isNewTop,
1620 int *newLength)
1621{
1622 return add(item.time(), item.data(), item.key(), isNewTop, newLength);
1623}
1624
1625template <class DATA>
1627 int *newLength,
1628 bsls::TimeInterval *newMinTime)
1629{
1630 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1631 MapIter it = d_map.begin();
1632
1633 if (d_map.end() == it) {
1634 return 1; // RETURN
1635 }
1636 Node *node = it->second;
1637
1638 if (buffer) {
1639 buffer->time() = node->d_time;
1640 buffer->data() = node->d_data.object();
1641 buffer->handle() = node->d_index;
1642 buffer->key() = node->d_key;
1643 }
1644 if (node->d_next_p != node) {
1645 node->d_prev_p->d_next_p = node->d_next_p;
1646 node->d_next_p->d_prev_p = node->d_prev_p;
1647 if (it->second == node) {
1648 it->second = node->d_next_p;
1649 }
1650 }
1651 else {
1652 d_map.erase(it);
1653 }
1654
1655 freeNode(node);
1656 --d_length;
1657
1658 if (d_length && newMinTime && !d_map.empty()) {
1659 *newMinTime = d_map.begin()->first;
1660 }
1661
1662 if (newLength) {
1663 *newLength = d_length;
1664 }
1665
1666 lock.release()->unlock();
1667
1668 putFreeNode(node);
1669 return 0;
1670}
1671
1672template <class DATA>
1673inline
1675{
1676 popLEImp(time, static_cast<bsl::vector<TimeQueueItem<DATA> > *>(0));
1677}
1678
1679template <class DATA>
1680inline
1683 int *newLength,
1684 bsls::TimeInterval *newMinTime)
1685{
1686 popLEImp(time, buffer, newLength, newMinTime);
1687}
1688
1689template <class DATA>
1690inline
1692 std::vector<TimeQueueItem<DATA> > *buffer,
1693 int *newLength,
1694 bsls::TimeInterval *newMinTime)
1695{
1696 popLEImp(time, buffer, newLength, newMinTime);
1697}
1698
1699#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1700template <class DATA>
1701inline
1703 std::pmr::vector<TimeQueueItem<DATA> > *buffer,
1704 int *newLength,
1705 bsls::TimeInterval *newMinTime)
1706{
1707 popLEImp(time, buffer, newLength, newMinTime);
1708}
1709#endif
1710
1711template <class DATA>
1712inline
1713void TimeQueue<DATA>::popLE(const bsls::TimeInterval& time, int maxTimers)
1714{
1715 popLEImp(time,
1716 maxTimers,
1717 static_cast<bsl::vector<TimeQueueItem<DATA> > *>(0));
1718}
1719
1720template <class DATA>
1721inline
1723 int maxTimers,
1725 int *newLength,
1726 bsls::TimeInterval *newMinTime)
1727{
1728 popLEImp(time, maxTimers, buffer, newLength, newMinTime);
1729}
1730
1731template <class DATA>
1732inline
1734 int maxTimers,
1735 std::vector<TimeQueueItem<DATA> > *buffer,
1736 int *newLength,
1737 bsls::TimeInterval *newMinTime)
1738{
1739 popLEImp(time, maxTimers, buffer, newLength, newMinTime);
1740}
1741
1742#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1743template <class DATA>
1744inline
1746 int maxTimers,
1747 std::pmr::vector<TimeQueueItem<DATA> > *buffer,
1748 int *newLength,
1749 bsls::TimeInterval *newMinTime)
1750{
1751 popLEImp(time, maxTimers, buffer, newLength, newMinTime);
1752}
1753#endif
1754
1755template <class DATA>
1756inline
1758 int *newLength,
1759 bsls::TimeInterval *newMinTime,
1760 TimeQueueItem<DATA> *item)
1761{
1762 return remove(handle, Key(0), newLength, newMinTime, item);
1763}
1764
1765template <class DATA>
1767 const Key& key,
1768 int *newLength,
1769 bsls::TimeInterval *newMinTime,
1770 TimeQueueItem<DATA> *item)
1771{
1772 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1773
1774 Node *node = getNodeFromHandle(handle, key);
1775
1776 if (!node) {
1777 return 1; // RETURN
1778 }
1779
1780 if (item) {
1781 item->time() = node->d_time;
1782 item->data() = node->d_data.object();
1783 item->handle() = handle;
1784 item->key() = node->d_key;
1785 }
1786
1787 if (node->d_next_p != node) {
1788 node->d_prev_p->d_next_p = node->d_next_p;
1789 node->d_next_p->d_prev_p = node->d_prev_p;
1790
1791 MapIter it = d_map.find(node->d_time);
1792 if (it->second == node) {
1793 it->second = node->d_next_p;
1794 }
1795 }
1796 else {
1797 d_map.erase(node->d_time);
1798 }
1799 freeNode(node);
1800 --d_length;
1801
1802 if (newLength) {
1803 *newLength = d_length;
1804 }
1805
1806 if (d_length && newMinTime) {
1807 BSLS_ASSERT(! d_map.empty());
1808
1809 *newMinTime = d_map.begin()->first;
1810 }
1811
1812 lock.release()->unlock();
1813
1814 putFreeNode(node);
1815 return 0;
1816}
1817
1818template <class DATA>
1820{
1821 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1822 MapIter it = d_map.begin();
1823
1824 Node *begin = 0;
1825 while (d_map.end() != it) {
1826 Node *const first = it->second;
1827 Node *const last = first->d_prev_p;
1828 Node *node = first;
1829
1830 do {
1831 if (buffer) {
1832 buffer->push_back(TimeQueueItem<DATA>(
1833 it->first,
1834 node->d_data.object(),
1835 node->d_index,
1836 node->d_key,
1837 d_allocator_p));
1838 }
1839 freeNode(node);
1840 node = node->d_next_p;
1841 --d_length;
1842 } while (node != first);
1843
1844 last->d_next_p = begin;
1845 begin = first;
1846
1847 MapIter condemned = it;
1848 ++it;
1849 d_map.erase(condemned);
1850 }
1851
1852 lock.release()->unlock();
1853 putFreeNodeList(begin);
1854}
1855
1856template <class DATA>
1857inline
1859 const bsls::TimeInterval& newTime,
1860 int *isNewTop)
1861{
1862 return update(handle, Key(0), newTime, isNewTop);
1863}
1864
1865template <class DATA>
1867 const Key& key,
1868 const bsls::TimeInterval& newTime,
1869 int *isNewTop)
1870{
1871 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1872
1873 Node *node = getNodeFromHandle(handle, key);
1874
1875 if (!node) {
1876 return 1; // RETURN
1877 }
1878
1879 if (node->d_prev_p != node) {
1880 node->d_prev_p->d_next_p = node->d_next_p;
1881 node->d_next_p->d_prev_p = node->d_prev_p;
1882
1883 MapIter it = d_map.find(node->d_time);
1884 if (it->second == node) {
1885 it->second = node->d_next_p;
1886 }
1887 }
1888 else {
1889 d_map.erase(node->d_time);
1890 }
1891 node->d_time = newTime;
1892
1893 MapIter it = d_map.find(newTime);
1894
1895 if (d_map.end() == it) {
1896 node->d_prev_p = node;
1897 node->d_next_p = node;
1898 d_map[newTime] = node;
1899 }
1900 else {
1901 node->d_prev_p = it->second->d_prev_p;
1902 it->second->d_prev_p->d_next_p = node;
1903 node->d_next_p = it->second;
1904 it->second->d_prev_p = node;
1905 }
1906
1907 if (isNewTop) {
1908 *isNewTop = d_map.begin()->second == node && node->d_prev_p == node;
1909 }
1910 return 0;
1911}
1912
1913// ACCESSORS
1914template <class DATA>
1915inline
1917{
1918 return d_length;
1919}
1920
1921template <class DATA>
1922inline
1924 typename TimeQueue<DATA>::Handle handle) const
1925{
1926 return isRegisteredHandle(handle, Key(0));
1927}
1928
1929template <class DATA>
1930inline
1932 typename TimeQueue<DATA>::Handle handle,
1933 const Key& key) const
1934{
1935 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1936
1937 Node *node = getNodeFromHandle(handle, key);
1938
1939 return node != 0;
1940}
1941
1942template <class DATA>
1943inline
1945{
1946 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1947
1948 if (d_map.empty()) {
1949 return 1; // RETURN
1950 }
1951
1952 *buffer = d_map.begin()->first;
1953 return 0;
1954}
1955
1956template <class DATA>
1957inline
1959{
1960 int count = 0;
1961
1962 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1963
1964 for (MapCIter it = d_map.cbegin();
1965 it != d_map.cend() && it->first <= time;
1966 ++it) {
1967 Node *first = it->second;
1968 Node *node = first;
1969
1970 do {
1971 BSLS_ASSERT(count < (1 << k_NUM_INDEX_BITS_MAX) - 1);
1972 // container size is bounded to 2^24-1
1973 BSLMF_ASSERT((1 << k_NUM_INDEX_BITS_MAX) - 1 <
1974 INT_MAX);
1975 // container size bound prevents overflow of 'count'
1976 ++count;
1977 node = node->d_next_p;
1978 } while (node != first);
1979 }
1980
1981 return count;
1982}
1983
1984 // --------------------
1985 // struct TimeQueueItem
1986 // --------------------
1987
1988// CREATORS
1989template <class DATA>
1991: d_key(0)
1992{
1993 bslma::DestructionUtil::destroy(&d_data);
1994 bslalg::ScalarPrimitives::defaultConstruct(&d_data, basicAllocator);
1995}
1996
1997template <class DATA>
1999TimeQueueItem(TimeQueueItem<DATA> const& original,
2000 bslma::Allocator *basicAllocator)
2001: d_time(original.d_time)
2002// require that 'd_data' be default-constructible, hopefully at no cost
2003, d_handle(original.d_handle)
2004, d_key(original.d_key)
2005{
2006 bslma::DestructionUtil::destroy(&d_data);
2008 original.d_data,
2009 basicAllocator);
2010}
2011
2012template <class DATA>
2015 const DATA& data,
2016 Handle handle,
2017 bslma::Allocator *basicAllocator)
2018: d_time(time)
2019// require that 'd_data' be default-constructible, hopefully at no cost
2020, d_handle(handle)
2021, d_key(0)
2022{
2023 bslma::DestructionUtil::destroy(&d_data);
2025 data,
2026 basicAllocator);
2027}
2028
2029template <class DATA>
2032 const DATA& data,
2033 Handle handle,
2034 const Key& key,
2035 bslma::Allocator *basicAllocator)
2036: d_time(time)
2037// require that 'd_data' be default-constructible, hopefully at no cost
2038, d_handle(handle)
2039, d_key(key)
2040{
2041 bslma::DestructionUtil::destroy(&d_data);
2043 data,
2044 basicAllocator);
2045}
2046
2047// MANIPULATORS
2048template <class DATA>
2049inline
2051 const TimeQueueItem<DATA>& rhs)
2052{
2053 d_time = rhs.d_time;
2054 d_data = rhs.d_data;
2055 d_handle = rhs.d_handle;
2056 d_key = rhs.d_key;
2057
2058 return *this;
2059}
2060
2061template <class DATA>
2062inline
2064{
2065 return d_time;
2066}
2067
2068template <class DATA>
2069inline
2071{
2072 return d_data;
2073}
2074} // close package namespace
2075
2076#if 0
2077
2078namespace bdlcc {
2079// this definition was moved into the class declaration
2080// to work around a Visual Studio .NET 2003 bug.
2081template <typename DATA>
2082inline
2085{
2086 return d_handle;
2087}
2088} // close package namespace
2089#endif
2090
2091namespace bdlcc {
2092
2093template <class DATA>
2094inline
2097{
2098 return d_key;
2099}
2100
2101// ACCESSORS
2102template <class DATA>
2103inline
2105{
2106 return d_time;
2107}
2108
2109template <class DATA>
2110inline
2111const DATA& TimeQueueItem<DATA>::data() const
2112{
2113 return d_data;
2114}
2115} // close package namespace
2116
2117#if 0
2118
2119namespace bdlcc {
2120// this definition was moved into the class declaration
2121// to work around a Visual Studio .NET 2003 bug.
2122template <typename DATA>
2123inline
2126{
2127 return d_handle;
2128}
2129} // close package namespace
2130#endif
2131
2132namespace bdlcc {
2133
2134template <class DATA>
2135inline
2136const typename TimeQueueItem<DATA>::Key&
2138{
2139 return d_key;
2140}
2141} // close package namespace
2142
2143
2144
2145#endif
2146
2147// ----------------------------------------------------------------------------
2148// Copyright 2015 Bloomberg Finance L.P.
2149//
2150// Licensed under the Apache License, Version 2.0 (the "License");
2151// you may not use this file except in compliance with the License.
2152// You may obtain a copy of the License at
2153//
2154// http://www.apache.org/licenses/LICENSE-2.0
2155//
2156// Unless required by applicable law or agreed to in writing, software
2157// distributed under the License is distributed on an "AS IS" BASIS,
2158// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2159// See the License for the specific language governing permissions and
2160// limitations under the License.
2161// ----------------------------- END-OF-FILE ----------------------------------
2162
2163/** @} */
2164/** @} */
2165/** @} */
Definition bdlcc_timequeue.h:1135
Handle & handle()
Return the modifiable handle value associated with this item.
Definition bdlcc_timequeue.h:1200
TimeQueue< DATA >::Handle Handle
Definition bdlcc_timequeue.h:1142
TimeQueueItem(bslma::Allocator *basicAllocator=0)
Definition bdlcc_timequeue.h:1990
BSLMF_NESTED_TRAIT_DECLARATION(TimeQueueItem, bslma::UsesBslmaAllocator)
Key & key()
Return the modifiable key value associated with this item.
Definition bdlcc_timequeue.h:2096
DATA & data()
Return the modifiable data instance associated with this item.
Definition bdlcc_timequeue.h:2070
TimeQueueItem & operator=(const TimeQueueItem< DATA > &rhs)
Set the value of this TimeQueueItem to that of rhs.
Definition bdlcc_timequeue.h:2050
Handle handle() const
Return the non-modifiable handle value associated with this item.
Definition bdlcc_timequeue.h:1220
TimeQueue< DATA >::Key Key
Definition bdlcc_timequeue.h:1143
bsls::TimeInterval & time()
Return the modifiable time value associated with this item.
Definition bdlcc_timequeue.h:2063
Definition bdlcc_timequeue.h:731
~Key()
Destroy this Key object.
Definition bdlcc_timequeue.h:751
Key(const void *key)
Create a Key object having the specified key value.
Definition bdlcc_timequeue.h:740
bool operator==(const Key &rhs) const
Definition bdlcc_timequeue.h:758
Key(int key)
Definition bdlcc_timequeue.h:746
bool operator!=(const Key &rhs) const
Definition bdlcc_timequeue.h:765
Definition bdlcc_timequeue.h:706
TimeQueue(int numIndexBits, bool poolTimerMemory, bslma::Allocator *basicAllocator=0)
Definition bdlcc_timequeue.h:1496
void popLE(const bsls::TimeInterval &time, std::vector< TimeQueueItem< DATA > > *buffer, int *newLength=0, bsls::TimeInterval *newMinTime=0)
Definition bdlcc_timequeue.h:1691
bool isRegisteredHandle(Handle handle) const
void popLE(const bsls::TimeInterval &time)
Definition bdlcc_timequeue.h:1674
int minTime(bsls::TimeInterval *buffer) const
Definition bdlcc_timequeue.h:1944
TimeQueue(bool poolTimerMemory, bslma::Allocator *basicAllocator=0)
Definition bdlcc_timequeue.h:1463
~TimeQueue()
Destroy this time queue.
Definition bdlcc_timequeue.h:1519
int Handle
Definition bdlcc_timequeue.h:725
int length() const
Definition bdlcc_timequeue.h:1916
TimeQueue(int numIndexBits, bslma::Allocator *basicAllocator=0)
Definition bdlcc_timequeue.h:1481
Handle add(const bsls::TimeInterval &time, const DATA &data, int *isNewTop=0, int *newLength=0)
Definition bdlcc_timequeue.h:1534
int countLE(const bsls::TimeInterval &time) const
Definition bdlcc_timequeue.h:1958
bool isRegisteredHandle(Handle handle, const Key &key) const
int update(Handle handle, const bsls::TimeInterval &newTime, int *isNewTop=0)
void popLE(const bsls::TimeInterval &time, bsl::vector< TimeQueueItem< DATA > > *buffer, int *newLength=0, bsls::TimeInterval *newMinTime=0)
Definition bdlcc_timequeue.h:1681
TimeQueue(bslma::Allocator *basicAllocator=0)
Definition bdlcc_timequeue.h:1450
void popLE(const bsls::TimeInterval &time, int maxTimers)
Definition bdlcc_timequeue.h:1713
void popLE(const bsls::TimeInterval &time, int maxTimers, std::vector< TimeQueueItem< DATA > > *buffer, int *newLength=0, bsls::TimeInterval *newMinTime=0)
Definition bdlcc_timequeue.h:1733
int popFront(TimeQueueItem< DATA > *buffer=0, int *newLength=0, bsls::TimeInterval *newMinTime=0)
Definition bdlcc_timequeue.h:1626
Handle add(const bsls::TimeInterval &time, const DATA &data, const Key &key, int *isNewTop=0, int *newLength=0)
Definition bdlcc_timequeue.h:1544
void removeAll(bsl::vector< TimeQueueItem< DATA > > *buffer=0)
Definition bdlcc_timequeue.h:1819
int remove(Handle handle, const Key &key, int *newLength=0, bsls::TimeInterval *newMinTime=0, TimeQueueItem< DATA > *item=0)
int remove(Handle handle, int *newLength=0, bsls::TimeInterval *newMinTime=0, TimeQueueItem< DATA > *item=0)
int update(Handle handle, const Key &key, const bsls::TimeInterval &newTime, int *isNewTop=0)
void popLE(const bsls::TimeInterval &time, int maxTimers, bsl::vector< TimeQueueItem< DATA > > *buffer, int *newLength=0, bsls::TimeInterval *newMinTime=0)
Definition bdlcc_timequeue.h:1722
Handle add(const TimeQueueItem< DATA > &item, int *isNewTop=0, int *newLength=0)
Definition bdlcc_timequeue.h:1617
Definition bslstl_map.h:619
BloombergLP::bslstl::TreeIterator< const value_type, Node, difference_type > const_iterator
Definition bslstl_map.h:724
BloombergLP::bslstl::TreeIterator< value_type, Node, difference_type > iterator
Definition bslstl_map.h:722
Definition bslstl_vector.h:1025
Definition bslma_allocator.h:457
Definition bslmt_lockguard.h:234
T * release()
Definition bslmt_lockguard.h:493
Definition bslmt_mutex.h:315
Definition bsls_atomic.h:743
Definition bsls_atomic.h:1349
Definition bsls_timeinterval.h:301
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:609
Definition bdlcc_boundedqueue.h:270
Definition bdlb_printmethods.h:283
T::iterator begin(T &container)
Definition bslstl_iterator.h:1495
T::iterator end(T &container)
Definition bslstl_iterator.h:1523
Definition balxml_encoderoptions.h:68
Definition bslmf_issame.h:146
static void defaultConstruct(TARGET_TYPE *address, bslma::Allocator *allocator)
Definition bslalg_scalarprimitives.h:1559
static void copyConstruct(TARGET_TYPE *address, const TARGET_TYPE &original, bslma::Allocator *allocator)
Definition bslalg_scalarprimitives.h:1599
Definition bslma_usesbslmaallocator.h:343
Definition bsls_objectbuffer.h:276