BDE 4.39.x 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/// 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/// /// Stop monitoring timers and connections and join threads.
283/// void stop();
284/// };
285/// @endcode
286/// The constructor is simple: it initializes the internal `bdlcc::TimeQueue`
287/// and sets the I/O timeout value. The virtual destructor calls `stop()`.
288/// @code
289/// my_Server::my_Server(int ioTimeout, bslma::Allocator *basicAllocator)
290/// : d_timeQueue(basicAllocator)
291/// , d_ioTimeout(ioTimeout)
292/// , d_connectionThreadHandle(bslmt::ThreadUtil::invalidHandle())
293/// , d_timerThreadHandle(bslmt::ThreadUtil::invalidHandle())
294/// , d_done(false)
295/// {
296/// }
297///
298/// my_Server::~my_Server()
299/// {
300/// stop();
301/// }
302/// @endcode
303/// Member function `stop` signals all waiting threads by setting the `d_done`
304/// flag and broadcasting on the condition variable, then joins the connection
305/// and timer threads and resets their handles to invalid.
306/// @code
307/// void my_Server::stop()
308/// {
309/// {
310/// bslmt::LockGuard<bslmt::Mutex> lock(&d_timerMonitorMutex);
311/// d_done = true;
312/// d_timerChangedCond.broadcast();
313/// }
314/// if (bslmt::ThreadUtil::invalidHandle() != d_connectionThreadHandle) {
315/// bslmt::ThreadUtil::join(d_connectionThreadHandle);
316/// d_connectionThreadHandle = bslmt::ThreadUtil::invalidHandle();
317/// }
318/// if (bslmt::ThreadUtil::invalidHandle() != d_timerThreadHandle) {
319/// bslmt::ThreadUtil::join(d_timerThreadHandle);
320/// d_timerThreadHandle = bslmt::ThreadUtil::invalidHandle();
321/// }
322/// }
323/// @endcode
324/// Member function `newConnection` adds the `connection` to the current set of
325/// connections to be monitored. This is done in two steps. First, the
326/// `connection` is added to the internal array, and then a timer is set for the
327/// `connection` by creating a corresponding entry in the internal
328/// `bdlcc::TimeQueue`.
329/// @code
330/// void my_Server::newConnection(my_Connection *connection)
331/// {
332/// d_connections.push_back(connection);
333/// int isNewTop = 0;
334/// bslmt::LockGuard<bslmt::Mutex> lock(&d_timerMonitorMutex);
335/// connection->d_timerId = d_timeQueue.add(
336/// bdlt::CurrentTime::now() + d_ioTimeout,
337/// connection,
338/// &isNewTop);
339/// if (isNewTop) {
340/// d_timerChangedCond.signal();
341/// }
342/// }
343/// @endcode
344/// Member function `monitorConnections`, provided by the concrete
345/// implementation class, can use the internal array to determine the set of
346/// connections to be monitored.
347///
348/// Member function `removeConnection` removes the `connection` from the current
349/// set of connections to be monitored. This is done in two steps, in reversed
350/// order from `newConnection`. First, the `connection` is removed from the
351/// internal `bdlcc::TimeQueue`, and then the `connection` is removed from the
352/// internal array.
353///
354/// The concrete implementation class must provide an implementation of virtual
355/// function `closeConnection`; this implementation must call `removeConnection`
356/// when the actual connection is to be removed from the `my_Server` object.
357///
358/// Function `closeConnection` is in turn called by function `monitorTimers`,
359/// which manages the overall timer monitor thread. Because `monitorTimers`
360/// takes responsibility for notifying other threads when the queue status
361/// changes, function `removeConnection` does not address these concerns.
362/// @code
363/// void my_Server::removeConnection(my_Connection *connection)
364/// {
365/// // Remove from d_timeQueue
366/// d_timeQueue.remove(connection->d_timerId);
367/// // Remove from d_connections
368/// bsl::vector<my_Connection*>::iterator begin = d_connections.begin(),
369/// end = d_connections.end(),
370/// it = begin;
371/// for (; it != end; ++it) {
372/// if (connection == *it) {
373/// d_connections.erase(it);
374/// }
375/// }
376/// }
377/// @endcode
378/// The `dataAvailable` function will be called when data becomes available for
379/// a specific connection. It removes the connection from the timer queue while
380/// the connection is busy, processes the available data, and returns the
381/// connection to the queue with a new time value.
382/// @code
383/// void my_Server::dataAvailable(my_Connection *connection,
384/// void *buffer_p,
385/// int length)
386/// {
387/// {
388/// bslmt::LockGuard<bslmt::Mutex> lock(&d_timerMonitorMutex);
389/// if (connection->d_timerId) {
390/// if (d_timeQueue.remove(connection->d_timerId)) {
391/// return; // RETURN
392/// }
393/// connection->d_timerId = 0;
394/// }
395/// }
396/// connection->d_session_p->processData(buffer_p, length);
397///
398/// int isNewTop = 0;
399/// {
400/// bslmt::LockGuard<bslmt::Mutex> lock(&d_timerMonitorMutex);
401/// connection->d_timerId = d_timeQueue.add(
402/// bdlt::CurrentTime::now() + d_ioTimeout,
403/// connection,
404/// &isNewTop);
405/// if (isNewTop) {
406/// d_timerChangedCond.signal();
407/// }
408/// }
409/// }
410/// @endcode
411/// Function `monitorTimers` manages the timer monitor thread; it is called when
412/// the thread is spawned, and checks repeatedly for expired timers; after each
413/// check, it does a timed wait based upon the minimum time value seen in the
414/// queue after all expired timers have been removed.
415/// @code
416/// void my_Server::monitorTimers()
417/// {
418/// while (true) {
419/// bsl::vector<bdlcc::TimeQueueItem<my_Connection *> > expiredTimers;
420/// bslmt::LockGuard<bslmt::Mutex> lock(&d_timerMonitorMutex);
421///
422/// if (d_done) {
423/// break;
424/// }
425///
426/// bsls::TimeInterval minTime;
427/// int newLength;
428///
429/// d_timeQueue.popLE(bsls::SystemTime::nowRealtimeClock(),
430/// &expiredTimers,
431/// &newLength,
432/// &minTime);
433///
434/// if (!expiredTimers.size()) {
435/// if (newLength) {
436/// // no expired timers, but unexpired timers remain.
437/// d_timerChangedCond.timedWait(&d_timerMonitorMutex,
438/// minTime);
439/// }
440/// else {
441/// // no expired timers, and timer queue is empty.
442/// d_timerChangedCond.wait(&d_timerMonitorMutex);
443/// }
444/// continue;
445/// }
446///
447/// int length = static_cast<int>(expiredTimers.size());
448/// if (length) {
449/// bdlcc::TimeQueueItem<my_Connection *> *data =
450/// &expiredTimers.front();
451/// for (int i = 0; i < length; ++i) {
452/// closeConnection(data[i].data());
453/// }
454/// }
455/// }
456/// }
457/// @endcode
458/// Function `start` spawns two separate threads. The first thread will monitor
459/// connections and handle any data received on them. The second monitors the
460/// internal timer queue and removes connections that have timed out. Function
461/// `start` calls `bslmt::ThreadUtil::create`, which expects a function pointer
462/// to a function with the standard "C" callback signature
463/// `void *fn(void *data)`. This non-member function will call back into the
464/// `my_Server` object immediately.
465/// @code
466/// int my_Server::start()
467/// {
468/// bslmt::ThreadAttributes attr;
469///
470/// if (bslmt::ThreadUtil::create(&d_connectionThreadHandle, attr,
471/// &my_connectionMonitorThreadEntry,
472/// this)) {
473/// return -1; // RETURN
474/// }
475///
476/// if (bslmt::ThreadUtil::create(&d_timerThreadHandle, attr,
477/// &my_timerMonitorThreadEntry,
478/// this)) {
479/// return -1; // RETURN
480/// }
481/// return 0;
482/// }
483/// @endcode
484/// Finally, we are now in a position to implement the two thread dispatchers:
485/// @code
486/// extern "C" {
487///
488/// void *my_connectionMonitorThreadEntry(void *server)
489/// {
490/// ((my_Server*)server)->monitorConnections();
491/// return server;
492/// }
493///
494/// void *my_timerMonitorThreadEntry(void *server)
495/// {
496/// ((my_Server*)server)->monitorTimers();
497/// return server;
498/// }
499///
500/// }
501/// @endcode
502/// In order to test our server, we provide two concrete implementations of a
503/// test session and of a test server as follows.
504/// @code
505/// // myTestSession.h -*-C++-*-
506///
507/// /// Concrete implementation of my_Session, providing simple test
508/// /// semantics In particular, implement the virtual function
509/// /// processData() to record all incoming data for the controlling
510/// /// connection, and virtual function handleTimeout() for handling
511/// /// timeouts.
512/// class my_TestSession : public my_Session {
513///
514/// int d_verbose;
515///
516/// public:
517/// // CREATORS
518/// explicit
519/// my_TestSession(int verbose) : my_Session(), d_verbose(verbose) { }
520///
521/// // MANIPULATORS
522/// virtual int handleTimeout(my_Connection *connection)
523/// {
524/// // Do something to handle timeout.
525/// if (d_verbose) {
526/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
527/// bsl::cout << "Connection " << connection << "timed out.\n";
528/// }
529/// return 0;
530/// }
531///
532/// virtual int processData(void *data, int length)
533/// {
534/// // Do something with the data...
535/// if (d_verbose) {
536/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
537/// bsl::cout << "Processing data at address " << data
538/// << " and length " << length << ".\n";
539/// }
540/// return 0;
541/// }
542/// };
543///
544/// // myTestSession.h -*-C++-*-
545///
546/// /// Concrete implementation of my_Server, providing connection logic.
547/// class my_TestServer : public my_Server {
548///
549/// int d_verbose;
550///
551/// protected:
552/// /// Close the specified external `connection` and call
553/// /// `removeConnection` when done.
554/// virtual void closeConnection(my_Connection *connection);
555///
556/// /// Monitor all connections in the current `my_Server`. When data
557/// /// becomes available for a given connection, pass the data to that
558/// /// connection for processing.
559/// virtual void monitorConnections();
560///
561/// private:
562/// // NOT IMPLEMENTED
563/// my_TestServer(const my_TestServer&);
564///
565/// public:
566/// // CREATORS
567///
568/// explicit
569/// my_TestServer(int ioTimeout,
570/// int verbose = 0,
571/// bslma::Allocator *basicAllocator = 0)
572/// : my_Server(ioTimeout, basicAllocator)
573/// , d_verbose(verbose)
574/// {
575/// }
576///
577/// virtual ~my_TestServer();
578/// };
579///
580/// // myTestSession.cpp -*-C++-*-
581///
582/// my_TestServer::~my_TestServer()
583/// {
584/// stop();
585/// }
586///
587/// void my_TestServer::closeConnection(my_Connection *connection)
588/// {
589/// if (d_verbose) {
590/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
591/// bsl::cout << "Closing connection " << connection << bsl::endl;
592/// }
593/// delete connection;
594/// }
595///
596/// void my_TestServer::monitorConnections()
597/// {
598/// const bslma::ManagedPtr<my_Session> session =
599/// bslma::ManagedPtrUtil::makeManaged<my_TestSession>(d_verbose);
600///
601/// // Simulate connection monitor logic...
602/// my_Connection *connection1 = new my_Connection;
603/// connection1->d_session_p = session.get();
604/// newConnection(connection1);
605/// if (d_verbose) {
606/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
607/// bsl::cout << "Opening connection " << connection1 << endl;
608/// }
609///
610/// my_Connection *connection2 = new my_Connection;
611/// connection2->d_session_p = session.get();
612/// newConnection(connection2);
613/// if (d_verbose) {
614/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
615/// bsl::cout << "Opening connection " << connection2 << endl;
616/// }
617///
618/// bslmt::ThreadUtil::sleep(bsls::TimeInterval(2)); // 2s
619///
620/// // Simulate transmission...
621/// const int length = 1024;
622/// const char*buffer[length];
623/// if (d_verbose) {
624/// bsl::cout << bdlt::CurrentTime::utc() << ": ";
625/// bsl::cout << "Connection " << connection1
626/// << " receives " << length << " bytes " << endl;
627/// }
628/// dataAvailable(connection1, buffer, length);
629///
630/// // Wait for timeout to occur, otherwise session gets destroyed from
631/// // stack too early.
632///
633/// bslmt::ThreadUtil::sleep(bsls::TimeInterval(8)); // 8s
634/// }
635/// @endcode
636/// The program that would exercise this test server would simply consist of:
637/// @code
638/// int usageExample(int verbose)
639/// {
640/// my_TestServer mX(5, verbose); // timeout for connections: 5s
641/// mX.start();
642///
643/// // Wait sufficiently long to observe all events.
644/// bslmt::ThreadUtil::sleep(bsls::TimeInterval(10)); // 10s
645///
646/// return 0;
647/// }
648/// @endcode
649/// The output of this program would look something as follows:
650/// @code
651/// 17:10:35.000: Opening connection 0x00161880
652/// 17:10:35.000: Opening connection 0x001618b0
653/// 17:10:37.000: Connection 0x00161880 receives 1024 bytes
654/// 17:10:37.000: Processing data at address 0xfeefaf04 and length 1024.
655/// 17:10:40.000: Closing connection 0x001618b0
656/// 17:10:42.000: Closing connection 0x00161880
657/// @endcode
658/// @}
659/** @} */
660/** @} */
661
662/** @addtogroup bdl
663 * @{
664 */
665/** @addtogroup bdlcc
666 * @{
667 */
668/** @addtogroup bdlcc_timequeue
669 * @{
670 */
671
672#include <bdlscm_version.h>
673
675#include <bdlma_pool.h>
676
678
679#include <bslma_default.h>
682
683#include <bslmf_assert.h>
685
686#include <bslmt_lockguard.h>
687#include <bslmt_mutex.h>
688
689#include <bsls_alignment.h>
690#include <bsls_assert.h>
691#include <bsls_atomic.h>
692#include <bsls_keyword.h>
693#include <bsls_libraryfeatures.h>
694#include <bsls_platform.h>
695#include <bsls_timeinterval.h>
696
697#include <bsl_climits.h>
698#include <bsl_cstdint.h>
699#include <bsl_functional.h>
700#include <bsl_map.h>
701#include <bsl_vector.h>
702
703#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
705#include <bslalg_typetraits.h>
706#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
707
708#include <vector>
709
710
711namespace bdlcc {
712
713template <class DATA>
714class TimeQueueItem;
715
716 // ===============
717 // class TimeQueue
718 // ===============
719
720/// This parameterized class provides a public interface which is similar in
721/// structure and intent to `Queue<DATA>`, with the exception that each item
722/// stored in the `TimeQueue` has an associated time value. Items are
723/// retrieved or exchanged by proxy of a `TimeQueueItem<DATA>`, and are
724/// referred to by an opaque data type `TimeQueue::Handle` which serves to
725/// identify an individual element on the Time Queue. Idiomatic usage of
726/// `TimeQueue` includes the member function `popLE`, which finds all items
727/// on the queue whose `bsls::TimeInterval` are less than a specified value
728/// and transfers those items to a provided vector of items, and the member
729/// function `update`, which can update the time value for a specific
730/// `TimeQueueItem` without removing it from the queue.
731///
732/// See @ref bdlcc_timequeue
733template <class DATA>
735
736 // TYPES
737 enum {
738 k_NUM_INDEX_BITS_MIN = 8,
739 k_NUM_INDEX_BITS_MAX = 24,
740 k_NUM_INDEX_BITS_DEFAULT = 17
741 };
742
743 public:
744 // TYPES
745
746 /// `Handle` defines an alias for uniquely identifying a valid node in
747 /// the time queue. Handles are returned when nodes are added to the
748 /// time queue, and must be supplied to the `update` and `remove`
749 /// methods to identify existing nodes. When a node is removed, the
750 /// handle value becomes invalid, though invalidated handle values are
751 /// eventually reused. See the component-level documentation for more
752 /// details.
753 typedef int Handle;
754
755 /// This type is a wrapper around a void pointer that will be supplied
756 /// and used by clients to uniquely identify an item in the queue.
757 ///
758 /// See @ref bdlcc_timequeue
759 class Key {
760
761 // PRIVATE DATA MEMBERS
762 const void *d_key;
763
764 public:
765 // CREATORS
766
767 /// Create a `Key` object having the specified `key` value.
768 explicit Key(const void *key)
769 : d_key(key)
770 {}
771
772 /// Create a `Key` object having the specified `key` value cast to a
773 /// `void *`.
774 explicit Key(int key)
775 : d_key(reinterpret_cast<const void*>(static_cast<bsl::intptr_t>(key)))
776 {}
777
778 /// Destroy this `Key` object.
780 {}
781
782 // ACCESSORS
783
784 /// Return `true` if this object has the same value as the specified
785 /// `rhs` object, and `false` otherwise.
786 bool operator==(const Key& rhs) const
787 {
788 return d_key == rhs.d_key;
789 }
790
791 /// Return `true` if this object does not have the same value as the
792 /// specified `rhs` object, and `false` otherwise.
793 bool operator!=(const Key& rhs) const
794 {
795 return d_key != rhs.d_key;
796 }
797 };
798
799 private:
800
801 // PRIVATE TYPES
802 template <class VECTOR>
803 struct IsVector;
804
805 /// This queue is implemented internally as a map of time values, each
806 /// entry in the map storing a doubly-linked circular list of items
807 /// having the same time value. This struct provides the node in the
808 /// list.
809 ///
810 /// See @ref bdlcc_timequeue
811 struct Node {
812
813 // PUBLIC DATA MEMBERS
814 unsigned int d_index;
815 bsls::TimeInterval d_time;
816 Key d_key;
817 Node *d_prev_p;
818 Node *d_next_p;
820
821 // CREATORS
822
823 /// Create a `Node` having a time value of 0.
824 Node()
825 : d_index(0)
826 , d_key(0)
827 , d_prev_p(0)
828 , d_next_p(0)
829 {
830 }
831
832 /// Create a `Node` having the specified `time` value.
833 explicit
834 Node(const bsls::TimeInterval& time)
835 : d_index(0)
836 , d_time(time)
837 , d_key(0)
838 , d_prev_p(0)
839 , d_next_p(0)
840 {
841 }
842 };
843
844 /// Internal typedef for the time index map.
846
847 /// Internal typedef for the iterator type used to navigate the time
848 /// index.
849 typedef typename NodeMap::iterator MapIter;
850
851 /// Internal typedef for the const-iterator type used to navigate the
852 /// time index.
853 typedef typename NodeMap::const_iterator MapCIter;
854
855 // PRIVATE DATA MEMBERS
856 const unsigned int d_indexMask;
857 const unsigned int d_indexIterationMask;
858 const unsigned int d_indexIterationInc;
859
860 mutable bslmt::Mutex d_mutex; // used for synchronizing
861 // access to this queue
862
863 bsl::vector<Node*> d_nodeArray; // array of nodes in this queue
864
865 bsls::AtomicPointer<Node> d_nextFreeNode_p; // pointer to the next free
866 // node in this queue (the free
867 // list is singly linked only,
868 // using d_next_p)
869
870 NodeMap d_map; // list of time values in
871 // increasing time order
872
873 bsls::AtomicInt d_length; // number of items currently in
874 // this queue (not necessarily
875 // equal to d_map.size())
876
877 bslma::Allocator *d_allocator_p; // allocator (held, not owned)
878
879 // PRIVATE MANIPULATORS
880
881 /// Prepare the specified `node` for being reused on the free list by
882 /// incrementing the iteration count. Set `d_prev_p` field to 0.
883 void freeNode(Node *node);
884
885 /// Remove from this queue all the items that have a time value less
886 /// than or equal to the specified `time`, and optionally append into
887 /// the optionally specified `buffer` a list of the removed items,
888 /// ordered by their corresponding time values (top item first).
889 /// Optionally load into the optionally specified `newLength` the number
890 /// of items remaining in this queue, and into the optionally specified
891 /// `newMinTime` the lowest remaining time value in this queue.
892 ///
893 /// \note Note that `newMinTime` is only loaded if there are items remaining in the
894 /// time queue; therefore, `newLength` should be specified and examined
895 /// to determine whether items remain, and `newMinTime` used only when
896 /// `newLength` > 0. Also note that if `DATA` follows the `bdema`
897 /// allocator model, the allocator of the `buffer` vector is used to
898 /// supply memory for the items appended to the `buffer`.
899 template <class VECTOR>
900 void popLEImp(const bsls::TimeInterval& time,
901 VECTOR *buffer,
902 int *newLength = 0,
903 bsls::TimeInterval *newMinTime = 0);
904
905 /// Remove from this queue up to the specified `maxTimers` number of
906 /// items that have a time value less than or equal to the specified
907 /// `time`, and optionally append into the optionally specified `buffer`
908 /// a list of the removed items, ordered by their corresponding time
909 /// values (top item first). Optionally load into the optionally
910 /// specified `newLength` the number of items remaining in this queue,
911 /// and into the optionally specified `newMinTime` the lowest remaining time value in this queue.
912 ///
913 /// \pre The behavior is undefined unless `maxTimers` >= 0.
914 ///
915 /// \note Note that `newMinTime` is only loaded if there
916 /// are items remaining in the time queue; therefore, `newLength` should
917 /// be specified and examined to determine whether items remain, and
918 /// `newMinTime` used only when `newLength` > 0. Also note that if
919 /// `DATA` follows the `bdema` allocator model, the allocator of the
920 /// `buffer` vector is used to supply memory. Note finally that all the
921 /// items appended into `buffer` have a time value less than or equal to
922 /// the elements remaining in this queue.
923 template <class VECTOR>
924 void popLEImp(const bsls::TimeInterval& time,
925 int maxTimers,
926 VECTOR *buffer,
927 int *newLength = 0,
928 bsls::TimeInterval *newMinTime = 0);
929
930 /// Destroy the data located at the specified `node` and reattach this
931 /// `node` to the front of the free list starting at `d_nextFreeNode_p`, making `node` the new `d_nextFreeNode_p`.
932 ///
933 /// \note Note that the caller must
934 /// not have acquired the lock to this queue.
935 void putFreeNode(Node *node);
936
937 /// Destroy the `DATA` of every node in the singly-linked list starting
938 /// at the specified `begin` node and ending with a null pointer, and
939 /// reattach these nodes to the front of the free list starting at
940 /// `d_nextFreeNode_p`, making `begin` the new `d_nextFreeNode_p` and calling `freeNode`.
941 ///
942 /// \note Note that the caller must not have acquired the
943 /// lock to this queue.
944 void putFreeNodeList(Node *begin);
945
946 // PRIVATE ACCESSORS
947
948 /// Return a pointer to the node correlating to the specified `handle`
949 /// and `key` if such a node exists, otherwise return a null pointer.
950 Node* getNodeFromHandle(Handle handle, Key key) const;
951
952
953 private:
954 // NOT IMPLEMENTED
955 TimeQueue(const TimeQueue&) BSLS_KEYWORD_DELETED;
956 TimeQueue& operator=(const TimeQueue&) BSLS_KEYWORD_DELETED;
957
958 public:
959 // CREATORS
960
961 /// Create an empty time queue. Optionally specify `numIndexBits` to
962 /// configure the number of index bits used by this object. If
963 /// `numIndexBits` is not specified a default value of 17 is used.
964 /// Optionally specify a `basicAllocator` used to supply memory. If
965 /// `basicAllocator` is 0, the currently installed default allocator is used.
966 ///
967 /// \pre The behavior is undefined unless `8 <= numIndexBits <= 24`.
968 /// See the component-level documentation for more information regarding
969 /// `numIndexBits`.
970 explicit TimeQueue(bslma::Allocator *basicAllocator = 0);
971 explicit TimeQueue(int numIndexBits, bslma::Allocator *basicAllocator = 0);
972
973 /// @deprecated Use the other constructor overloads instead.
974 ///
975 /// \note Note that the specified `poolTimerMemory` argument controlled whether
976 /// additional memory used by an internal `bsl::map` was pooled. When
977 /// `bsl::map` was modified to pool its own nodes, this option became
978 /// irrelevant and is now ignored.
979 explicit TimeQueue(bool poolTimerMemory,
980 bslma::Allocator *basicAllocator = 0);
981 TimeQueue(int numIndexBits,
982 bool poolTimerMemory,
983 bslma::Allocator *basicAllocator = 0);
984
985 /// Destroy this time queue.
987
988 // MANIPULATORS
989
990 /// Add a new item to this queue having the specified `time` value, and
991 /// associated `data`. Optionally use the specified `key` to uniquely
992 /// identify the item in subsequent calls to `remove` and `update`.
993 /// Optionally load into the optionally specified `isNewTop` a non-zero
994 /// value if the item is now the lowest item in this queue, and a 0
995 /// value otherwise. If specified, load into the optionally specified
996 /// `newLength`, the new number of items in this queue. Return a value
997 /// that may be used to identify the newly added item in future calls to
998 /// time queue on success, and -1 if the maximum queue length has been
999 /// reached.
1001 const DATA& data,
1002 int *isNewTop = 0,
1003 int *newLength = 0);
1005 const DATA& data,
1006 const Key& key,
1007 int *isNewTop = 0,
1008 int *newLength = 0);
1009
1010 /// Add the value of the specified `item` to this queue. Optionally
1011 /// load into the optionally specified `isNewTop` a non-zero value if
1012 /// the replaces is now the lowest element in this queue, and a 0 value
1013 /// otherwise. If specified, load into the optionally specified
1014 /// `newLength`, the new number of elements in this queue. Return a
1015 /// value that may be used to identify the newly added item in future
1016 /// calls to time queue on success, and -1 if the maximum queue length
1017 /// has been reached.
1019 int *isNewTop = 0,
1020 int *newLength = 0);
1021
1022 /// Atomically remove the top item from this queue, and optionally load
1023 /// into the optionally specified `buffer` the time and associated data
1024 /// of the item removed. Optionally load into the optionally specified
1025 /// `newLength`, the number of items remaining in the queue. Optionally
1026 /// load into the optionally specified `newMinTime` the new lowest time
1027 /// in this queue. Return 0 on success, and a non-zero value if there are no items in the queue.
1028 ///
1029 /// \note Note that if `DATA` follows the `bdema`
1030 /// allocator model, the allocator of the `buffer` is used to supply
1031 /// memory.
1033 int *newLength = 0,
1034 bsls::TimeInterval *newMinTime = 0);
1035
1036 /// Remove from this queue all the items that have a time value less than
1037 /// or equal to the specified `time`, and optionally append into the
1038 /// optionally specified `buffer` a list of the removed items, ordered by
1039 /// their corresponding time values (top item first). Optionally load into
1040 /// the optionally specified `newLength` the number of items remaining in
1041 /// this queue, and into the optionally specified `newMinTime` the lowest remaining time value in this queue.
1042 ///
1043 /// \note Note that `newMinTime` is only
1044 /// loaded if there are items remaining in the time queue; therefore,
1045 /// `newLength` should be specified and examined to determine whether items
1046 /// remain, and `newMinTime` used only when `newLength > 0`. Also note
1047 /// that if `DATA` follows the `bdema` allocator model, the allocator of
1048 /// the `buffer` vector is used to supply memory for the items appended to
1049 /// the `buffer`.
1050 void popLE(const bsls::TimeInterval& time);
1051 void popLE(const bsls::TimeInterval& time,
1053 int *newLength = 0,
1054 bsls::TimeInterval *newMinTime = 0);
1055 void popLE(const bsls::TimeInterval& time,
1056 std::vector<TimeQueueItem<DATA> > *buffer,
1057 int *newLength = 0,
1058 bsls::TimeInterval *newMinTime = 0);
1059#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1060 void popLE(const bsls::TimeInterval& time,
1061 std::pmr::vector<TimeQueueItem<DATA> > *buffer,
1062 int *newLength = 0,
1063 bsls::TimeInterval *newMinTime = 0);
1064#endif
1065
1066 /// Remove from this queue up to the specified `maxTimers` number of items
1067 /// that have a time value less than or equal to the specified `time`, and
1068 /// optionally append into the optionally specified `buffer` a list of the
1069 /// removed items, ordered by their corresponding time values (top item
1070 /// first). Optionally load into the optionally specified `newLength` the
1071 /// number of items remaining in this queue, and into the optionally
1072 /// specified `newMinTime` the lowest remaining time value in this queue.
1073 ///
1074 /// \pre The behavior is undefined unless `maxTimers >= 0`.
1075 ///
1076 /// \note Note that `newMinTime` is only loaded if there are items remaining in the time
1077 /// queue; therefore, `newLength` should be specified and examined to
1078 /// determine whether items remain, and `newMinTime` used only when
1079 /// `newLength > 0`. Also note that if `DATA` follows the `bdema`
1080 /// allocator model, the allocator of the `buffer` vector is used to supply
1081 /// memory. Note finally that all the items appended into `buffer` have a
1082 /// time value less than or equal to the elements remaining in this queue.
1083 void popLE(const bsls::TimeInterval& time,
1084 int maxTimers);
1085 void popLE(const bsls::TimeInterval& time,
1086 int maxTimers,
1088 int *newLength = 0,
1089 bsls::TimeInterval *newMinTime = 0);
1090 void popLE(const bsls::TimeInterval& time,
1091 int maxTimers,
1092 std::vector<TimeQueueItem<DATA> > *buffer,
1093 int *newLength = 0,
1094 bsls::TimeInterval *newMinTime = 0);
1095#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1096 void popLE(const bsls::TimeInterval& time,
1097 int maxTimers,
1098 std::pmr::vector<TimeQueueItem<DATA> > *buffer,
1099 int *newLength = 0,
1100 bsls::TimeInterval *newMinTime = 0);
1101#endif
1102
1103 /// Remove from this queue the item having the specified `handle`, and
1104 /// optionally load into the optionally specified `item` the time and
1105 /// data values of the recently removed item. Optionally use the
1106 /// specified `key` to uniquely identify the item. If specified, load
1107 /// into the optionally specified `newMinTime`, the resulting lowest
1108 /// time value remaining in the queue. Return 0 on success, and a
1109 /// non-zero value if no item with the `handle` exists in the queue.
1110 ///
1111 /// \note Note that if `DATA` follows the `bdema` allocator model, the
1112 /// allocator of the `item` instance is used to supply memory.
1113 int remove(Handle handle,
1114 int *newLength = 0,
1115 bsls::TimeInterval *newMinTime = 0,
1116 TimeQueueItem<DATA> *item = 0);
1117 int remove(Handle handle,
1118 const Key& key,
1119 int *newLength = 0,
1120 bsls::TimeInterval *newMinTime = 0,
1121 TimeQueueItem<DATA> *item = 0);
1122
1123 /// Remove all the items from this queue. Optionally specify a
1124 /// `removedItems` vector in which to load the removed items. The
1125 /// resultant items in the `buffer` are ordered by increasing time
1126 /// interval; items of equivalent time interval have arbitrary ordering.
1127 ///
1128 /// \note Note that the allocator of the `removedItems` vector is used to supply
1129 /// memory.
1130 void removeAll(bsl::vector<TimeQueueItem<DATA> > *removedItems = 0);
1131
1132 /// Remove all the items from this queue for which `predicate` returns
1133 /// `true`. Optionally specify `newLength`, in which to load the number of
1134 /// items remaining in this queue. Optionally specify `newMinTime`, in
1135 /// which to load the lowest remaining time value in this queue.
1136 /// Optionally specify a vector of `removedItems` in which to load the
1137 /// removed items.
1138 void removeIf(const bsl::function<bool(const DATA&)>& predicate,
1139 int *newLength = 0,
1140 bsls::TimeInterval *newMinTime = 0,
1141 bsl::vector<TimeQueueItem<DATA> > *removedItems = 0);
1142
1143 /// Update the time value of the item having the specified `handle` to
1144 /// the specified `newTime` and optionally load into the optionally
1145 /// specified `isNewTop` a non-zero value if the modified item is now
1146 /// the lowest time value in the time queue or zero otherwise. Return 0
1147 /// on success, and a non-zero value if there is currently no item
1148 /// having the `handle` registered with this time queue.
1149 int update(Handle handle,
1150 const bsls::TimeInterval& newTime,
1151 int *isNewTop = 0);
1152 int update(Handle handle,
1153 const Key& key,
1154 const bsls::TimeInterval& newTime,
1155 int *isNewTop = 0);
1156
1157 // ACCESSORS
1158
1159 /// Return number of items in this queue.
1160 /// \note Note that the value returned
1161 /// may be obsolete by the time it is received.
1162 int length() const;
1163
1164 /// Return `true` if an item having specified `handle` is currently
1165 /// registered with this time queue and false otherwise.
1166 bool isRegisteredHandle(Handle handle) const;
1167 bool isRegisteredHandle(Handle handle, const Key& key) const;
1168
1169 /// Load into the specified `buffer`, the time value of the lowest time
1170 /// in this queue. Return 0 on success, and a non-zero value if this
1171 /// queue is empty.
1172 int minTime(bsls::TimeInterval *buffer) const;
1173
1174 /// Return the number of items in this queue that have a time value less than or equal to the specified `time`.
1175 ///
1176 /// \note Note that the value returned
1177 /// may be obsolete by the time it is received.
1178 int countLE(const bsls::TimeInterval& time) const;
1179};
1180
1181 // ====================
1182 // struct TimeQueueItem
1183 // ====================
1184
1185/// This parameterized structure holds a time, data and associated handle.
1186/// This structure is used in the interface of `TimeQueue<DATA>` to provide
1187/// thread-safe access to individual elements on the queue.
1188///
1189/// \note Note that `DATA` must be default-constructible.
1190///
1191/// See @ref bdlcc_timequeue
1192template <class DATA>
1194
1195 public:
1196 // TRAITS
1198
1199 // PUBLIC TYPES
1201 typedef typename TimeQueue<DATA>::Key Key;
1202
1203 private:
1204 bsls::TimeInterval d_time; // Time value
1205 DATA d_data; // Associated data value
1206 Handle d_handle; // Associated handle
1207 Key d_key; // Associated key
1208
1209 public:
1210 // CREATORS
1211
1212 /// Create an empty time queue item. Optionally specify a
1213 /// `basicAllocator` used to supply memory. If `basicAllocator` is
1214 /// zero, then use the currently installed default allocator.
1215 explicit
1216 TimeQueueItem(bslma::Allocator *basicAllocator = 0);
1217
1218 /// Create time queue item holding a copy of the specified `data`, with
1219 /// the specified associated `time` and `handle` information.
1220 /// Optionally specify a `basicAllocator` used to supply memory. If
1221 /// `basicAllocator` is zero, then use the currently installed default
1222 /// allocator.
1224 const DATA& data,
1225 Handle handle,
1226 bslma::Allocator *basicAllocator = 0);
1227
1228 /// Create time queue item holding a copy of the specified `data`, with
1229 /// the specified associated `time`, `handle`, and `key` information.
1230 /// Optionally specify a `basicAllocator` used to supply memory. If
1231 /// `basicAllocator` is zero, then use the currently installed default
1232 /// allocator.
1234 const DATA& data,
1235 Handle handle,
1236 const Key& key,
1237 bslma::Allocator *basicAllocator = 0);
1238
1239 /// Create a copy of the specified `original` time queue item.
1240 /// Optionally specify a `basicAllocator` used to supply memory. If
1241 /// `basicAllocator` is zero, then use the currently installed default
1242 /// allocator.
1243 TimeQueueItem(const TimeQueueItem<DATA>& original,
1244 bslma::Allocator *basicAllocator = 0);
1245
1246 // MANIPULATORS
1247
1248 /// Set the value of this `TimeQueueItem` to that of `rhs`.
1250
1251 /// Return the modifiable time value associated with this item.
1253
1254 /// Return the modifiable data instance associated with this item.
1255 DATA& data();
1256
1257 /// Return the modifiable handle value associated with this item.
1259 {
1260 // this definition was moved into the class declaration to work around
1261 // a Visual Studio .NET 2003 bug.
1262
1263 return d_handle;
1264 }
1265
1266 /// Return the modifiable key value associated with this item.
1267 Key& key();
1268
1269 // ACCESSORS
1270
1271 /// Return the non-modifiable time value associated with this item.
1272 const bsls::TimeInterval& time() const;
1273
1274 /// Return the non-modifiable data associated with this item.
1275 const DATA& data() const;
1276
1277 /// Return the non-modifiable handle value associated with this item.
1279 {
1280 // this definition was moved into the class declaration to work around
1281 // a Visual Studio .NET 2003 bug.
1282
1283 return d_handle;
1284 }
1285
1286 /// Return the non-modifiable key value associated with this item.
1287 const Key& key() const;
1288};
1289
1290 // =========================
1291 // TimeQueue<DATA>::IsVector
1292 // =========================
1293
1294/// This `struct` has a `value` that evaluates to `true` if the specified
1295/// `VECTOR` is a `bsl`, `std`, or `std::pmr` `vector<VALUE>`.
1296template <class DATA>
1297template <class VECTOR>
1298struct TimeQueue<DATA>::IsVector {
1299
1300 // TYPE
1301 typedef TimeQueueItem<DATA> Item;
1302
1303 // CLASS DATA
1304 static const bool value =
1305 bsl::is_same<bsl::vector<Item>, VECTOR>::value
1306#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1307 || bsl::is_same<std::pmr::vector<Item>, VECTOR>::value
1308#endif
1309 || bsl::is_same<std::vector<Item>, VECTOR>::value;
1310};
1311
1312// ============================================================================
1313// INLINE DEFINITIONS
1314// ============================================================================
1315
1316 // ---------
1317 // TimeQueue
1318 // ---------
1319
1320// PRIVATE MANIPULATORS
1321template <class DATA>
1322inline
1323void TimeQueue<DATA>::freeNode(Node *node)
1324{
1325 node->d_index = ((node->d_index + d_indexIterationInc) &
1326 d_indexIterationMask) | (node->d_index & d_indexMask);
1327
1328 if (!(node->d_index & d_indexIterationMask)) {
1329 node->d_index += d_indexIterationInc;
1330 }
1331 node->d_prev_p = 0;
1332}
1333
1334template <class DATA>
1335template <class VECTOR>
1336void TimeQueue<DATA>::popLEImp(const bsls::TimeInterval& time,
1337 VECTOR *buffer,
1338 int *newLength,
1339 bsls::TimeInterval *newMinTime)
1340{
1341 BSLMF_ASSERT(IsVector<VECTOR>::value);
1342
1343 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1344
1345 MapIter it = d_map.begin();
1346
1347 Node *begin = 0;
1348 while (d_map.end() != it && it->first <= time) {
1349 Node *const first = it->second;
1350 Node *const last = first->d_prev_p;
1351 Node *node = first;
1352
1353 do {
1354 if (buffer) {
1355 buffer->push_back(TimeQueueItem<DATA>(it->first,
1356 node->d_data.object(),
1357 node->d_index,
1358 node->d_key,
1359 d_allocator_p));
1360 }
1361 freeNode(node);
1362 node = node->d_next_p;
1363 --d_length;
1364 } while (node != first);
1365
1366 last->d_next_p = begin;
1367 begin = first;
1368
1369 MapIter condemned = it;
1370 ++it;
1371 d_map.erase(condemned);
1372 }
1373
1374 if (newLength) {
1375 *newLength = d_length;
1376 }
1377 if (d_map.end() != it && newMinTime) {
1378 *newMinTime = it->first;
1379 }
1380
1381 lock.release()->unlock();
1382 putFreeNodeList(begin);
1383}
1384
1385template <class DATA>
1386template <class VECTOR>
1387void TimeQueue<DATA>::popLEImp(const bsls::TimeInterval& time,
1388 int maxTimers,
1389 VECTOR *buffer,
1390 int *newLength,
1391 bsls::TimeInterval *newMinTime)
1392{
1393 BSLS_ASSERT(0 <= maxTimers);
1394
1395 BSLMF_ASSERT(IsVector<VECTOR>::value);
1396
1397 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1398
1399 MapIter it = d_map.begin();
1400
1401 Node *begin = 0;
1402 while (d_map.end() != it && it->first <= time && 0 < maxTimers) {
1403 Node *const first = it->second;
1404 Node *const last = first->d_prev_p;
1405 Node *node = first;
1406 Node *prevNode = first->d_prev_p;
1407
1408 do {
1409 if (buffer) {
1410 buffer->push_back(TimeQueueItem<DATA>(
1411 it->first,
1412 node->d_data.object(),
1413 node->d_index,
1414 node->d_key,
1415 d_allocator_p));
1416 }
1417 freeNode(node);
1418 prevNode = node;
1419 node = node->d_next_p;
1420 --d_length;
1421 --maxTimers;
1422 } while (0 < maxTimers && node != first);
1423
1424 prevNode->d_next_p = begin;
1425 begin = first;
1426
1427 if (node == first) {
1428 MapIter condemned = it;
1429 ++it;
1430 d_map.erase(condemned);
1431 }
1432 else {
1433 node->d_prev_p = last;
1434 last->d_next_p = node;
1435 it->second = node;
1436 break;
1437 }
1438 }
1439
1440 if (newLength) {
1441 *newLength = d_length;
1442 }
1443 if (d_map.end() != it && newMinTime) {
1444 *newMinTime = it->first;
1445 }
1446
1447 lock.release()->unlock();
1448 putFreeNodeList(begin);
1449}
1450
1451template <class DATA>
1452void TimeQueue<DATA>::putFreeNode(Node *node)
1453{
1454 node->d_data.object().~DATA();
1455
1456 Node *nextFreeNode = d_nextFreeNode_p;
1457 node->d_next_p = nextFreeNode;
1458 while (nextFreeNode != d_nextFreeNode_p.testAndSwap(nextFreeNode, node)) {
1459 nextFreeNode = d_nextFreeNode_p;
1460 node->d_next_p = nextFreeNode;
1461 }
1462}
1463
1464template <class DATA>
1465void TimeQueue<DATA>::putFreeNodeList(Node *begin)
1466{
1467 if (begin) {
1468 begin->d_data.object().~DATA();
1469
1470 Node *end = begin;
1471 while (end->d_next_p) {
1472 end = end->d_next_p;
1473 end->d_data.object().~DATA();
1474 }
1475
1476 Node *nextFreeNode = d_nextFreeNode_p;
1477 end->d_next_p = nextFreeNode;
1478
1479 while (nextFreeNode !=
1480 d_nextFreeNode_p.testAndSwap(nextFreeNode, begin)) {
1481 nextFreeNode = d_nextFreeNode_p;
1482 end->d_next_p = nextFreeNode;
1483 }
1484 }
1485 return;
1486}
1487
1488// PRIVATE ACCESSORS
1489template <class DATA>
1490typename TimeQueue<DATA>::Node *TimeQueue<DATA>::getNodeFromHandle(
1491 Handle handle,
1492 Key key) const
1493{
1494 unsigned int uhandle = static_cast<unsigned int>(handle) & d_indexMask;
1495 if (0 == uhandle || uhandle > d_nodeArray.size()) {
1496 return 0; // RETURN
1497 }
1498 Node *node = d_nodeArray[uhandle - 1];
1499 if (node->d_index != static_cast<unsigned>(handle) || node->d_key != key ||
1500 0 == node->d_prev_p) {
1501 return 0; // RETURN
1502 }
1503 return node;
1504}
1505
1506// CREATORS
1507template <class DATA>
1509: d_indexMask((1U << k_NUM_INDEX_BITS_DEFAULT) - 1)
1510, d_indexIterationMask(~d_indexMask)
1511, d_indexIterationInc(d_indexMask + 1)
1512, d_nodeArray(basicAllocator)
1513, d_nextFreeNode_p(0)
1514, d_map(basicAllocator)
1515, d_length(0)
1516, d_allocator_p(bslma::Default::allocator(basicAllocator))
1517{
1518}
1519
1520template <class DATA>
1521TimeQueue<DATA>::TimeQueue(bool poolTimerMemory,
1522 bslma::Allocator *basicAllocator)
1523: d_indexMask((1U << k_NUM_INDEX_BITS_DEFAULT) - 1)
1524, d_indexIterationMask(~d_indexMask)
1525, d_indexIterationInc(d_indexMask + 1)
1526, d_nodeArray(basicAllocator)
1527, d_nextFreeNode_p(0)
1528, d_map(basicAllocator)
1529, d_length(0)
1530, d_allocator_p(bslma::Default::allocator(basicAllocator))
1531{
1532 // The 'poolTimerMemory' option has been deprecated (see method
1533 // documentation).
1534
1535 (void)poolTimerMemory;
1536}
1537
1538template <class DATA>
1539TimeQueue<DATA>::TimeQueue(int numIndexBits, bslma::Allocator *basicAllocator)
1540: d_indexMask((1 << numIndexBits) - 1)
1541, d_indexIterationMask(~d_indexMask)
1542, d_indexIterationInc(d_indexMask + 1)
1543, d_nodeArray(basicAllocator)
1544, d_nextFreeNode_p(0)
1545, d_map(basicAllocator)
1546, d_length(0)
1547, d_allocator_p(bslma::Default::allocator(basicAllocator))
1548{
1549 BSLS_ASSERT(k_NUM_INDEX_BITS_MIN <= numIndexBits
1550 && k_NUM_INDEX_BITS_MAX >= numIndexBits);
1551}
1552
1553template <class DATA>
1555 bool poolTimerMemory,
1556 bslma::Allocator *basicAllocator)
1557: d_indexMask((1 << numIndexBits) - 1)
1558, d_indexIterationMask(~d_indexMask)
1559, d_indexIterationInc(d_indexMask + 1)
1560, d_nodeArray(basicAllocator)
1561, d_nextFreeNode_p(0)
1562, d_map(basicAllocator)
1563, d_length(0)
1564, d_allocator_p(bslma::Default::allocator(basicAllocator))
1565{
1566 BSLS_ASSERT(k_NUM_INDEX_BITS_MIN <= numIndexBits
1567 && k_NUM_INDEX_BITS_MAX >= numIndexBits);
1568
1569 // The 'poolTimerMemory' option has been deprecated (see method
1570 // documentation).
1571
1572 (void)poolTimerMemory;
1573
1574}
1575
1576template <class DATA>
1578{
1579 removeAll();
1580 if (!d_nodeArray.empty()) {
1581 Node **data = &d_nodeArray.front();
1582 const int numNodes = static_cast<int>(d_nodeArray.size());
1583 for (int i = 0; i < numNodes; ++i) {
1584 d_allocator_p->deleteObjectRaw(data[i]);
1585 }
1586 }
1587}
1588
1589// MANIPULATORS
1590template <class DATA>
1591inline
1593 const bsls::TimeInterval& time,
1594 const DATA& data,
1595 int *isNewTop,
1596 int *newLength)
1597{
1598 return add(time, data, Key(0), isNewTop, newLength);
1599}
1600
1601template <class DATA>
1603 const bsls::TimeInterval& time,
1604 const DATA& data,
1605 const Key& key,
1606 int *isNewTop,
1607 int *newLength)
1608
1609{
1610 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1611
1612 Node *node;
1613 if (d_nextFreeNode_p) {
1614 // All allocation of nodes goes through this routine, which is guarded
1615 // by the mutex. So no other thread will remove anything from the free
1616 // list while this code is executing. However, other threads may add
1617 // to the free list.
1618
1619 node = d_nextFreeNode_p;
1620 Node *next = node->d_next_p;
1621 while (node != d_nextFreeNode_p.testAndSwap(node, next)) {
1622 node = d_nextFreeNode_p;
1623 next = node->d_next_p;
1624 }
1625 }
1626 else {
1627 // The number of nodes cannot grow to a size larger than the range of
1628 // available indices.
1629
1630 if (d_nodeArray.size() >= d_indexMask - 1) {
1631 return -1; // RETURN
1632 }
1633
1634 node = new (*d_allocator_p) Node;
1635 d_nodeArray.push_back(node);
1636 node->d_index =
1637 static_cast<int>(d_nodeArray.size()) | d_indexIterationInc;
1638 }
1639 node->d_time = time;
1640 node->d_key = key;
1641 bslalg::ScalarPrimitives::copyConstruct(&node->d_data.object(),
1642 data,
1643 d_allocator_p);
1644
1645 {
1646 MapIter it = d_map.find(time);
1647
1648 if (d_map.end() == it) {
1649 node->d_prev_p = node;
1650 node->d_next_p = node;
1651 d_map[time] = node;
1652 }
1653 else {
1654 node->d_prev_p = it->second->d_prev_p;
1655 it->second->d_prev_p->d_next_p = node;
1656 node->d_next_p = it->second;
1657 it->second->d_prev_p = node;
1658 }
1659 }
1660
1661 ++d_length;
1662 if (isNewTop) {
1663 *isNewTop = d_map.begin()->second == node && node->d_prev_p == node;
1664 }
1665
1666 if (newLength) {
1667 *newLength = d_length;
1668 }
1669
1670 return node->d_index;
1671}
1672
1673template <class DATA>
1674inline
1676 const TimeQueueItem<DATA>& item,
1677 int *isNewTop,
1678 int *newLength)
1679{
1680 return add(item.time(), item.data(), item.key(), isNewTop, newLength);
1681}
1682
1683template <class DATA>
1685 int *newLength,
1686 bsls::TimeInterval *newMinTime)
1687{
1688 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1689 MapIter it = d_map.begin();
1690
1691 if (d_map.end() == it) {
1692 return 1; // RETURN
1693 }
1694 Node *node = it->second;
1695
1696 if (buffer) {
1697 buffer->time() = node->d_time;
1698 buffer->data() = node->d_data.object();
1699 buffer->handle() = node->d_index;
1700 buffer->key() = node->d_key;
1701 }
1702 if (node->d_next_p != node) {
1703 node->d_prev_p->d_next_p = node->d_next_p;
1704 node->d_next_p->d_prev_p = node->d_prev_p;
1705 if (it->second == node) {
1706 it->second = node->d_next_p;
1707 }
1708 }
1709 else {
1710 d_map.erase(it);
1711 }
1712
1713 freeNode(node);
1714 --d_length;
1715
1716 if (d_length && newMinTime && !d_map.empty()) {
1717 *newMinTime = d_map.begin()->first;
1718 }
1719
1720 if (newLength) {
1721 *newLength = d_length;
1722 }
1723
1724 lock.release()->unlock();
1725
1726 putFreeNode(node);
1727 return 0;
1728}
1729
1730template <class DATA>
1731inline
1733{
1734 popLEImp(time, static_cast<bsl::vector<TimeQueueItem<DATA> > *>(0));
1735}
1736
1737template <class DATA>
1738inline
1741 int *newLength,
1742 bsls::TimeInterval *newMinTime)
1743{
1744 popLEImp(time, buffer, newLength, newMinTime);
1745}
1746
1747template <class DATA>
1748inline
1750 std::vector<TimeQueueItem<DATA> > *buffer,
1751 int *newLength,
1752 bsls::TimeInterval *newMinTime)
1753{
1754 popLEImp(time, buffer, newLength, newMinTime);
1755}
1756
1757#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1758template <class DATA>
1759inline
1761 std::pmr::vector<TimeQueueItem<DATA> > *buffer,
1762 int *newLength,
1763 bsls::TimeInterval *newMinTime)
1764{
1765 popLEImp(time, buffer, newLength, newMinTime);
1766}
1767#endif
1768
1769template <class DATA>
1770inline
1771void TimeQueue<DATA>::popLE(const bsls::TimeInterval& time, int maxTimers)
1772{
1773 popLEImp(time,
1774 maxTimers,
1775 static_cast<bsl::vector<TimeQueueItem<DATA> > *>(0));
1776}
1777
1778template <class DATA>
1779inline
1781 int maxTimers,
1783 int *newLength,
1784 bsls::TimeInterval *newMinTime)
1785{
1786 popLEImp(time, maxTimers, buffer, newLength, newMinTime);
1787}
1788
1789template <class DATA>
1790inline
1792 int maxTimers,
1793 std::vector<TimeQueueItem<DATA> > *buffer,
1794 int *newLength,
1795 bsls::TimeInterval *newMinTime)
1796{
1797 popLEImp(time, maxTimers, buffer, newLength, newMinTime);
1798}
1799
1800#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1801template <class DATA>
1802inline
1804 int maxTimers,
1805 std::pmr::vector<TimeQueueItem<DATA> > *buffer,
1806 int *newLength,
1807 bsls::TimeInterval *newMinTime)
1808{
1809 popLEImp(time, maxTimers, buffer, newLength, newMinTime);
1810}
1811#endif
1812
1813template <class DATA>
1814inline
1816 int *newLength,
1817 bsls::TimeInterval *newMinTime,
1818 TimeQueueItem<DATA> *item)
1819{
1820 return remove(handle, Key(0), newLength, newMinTime, item);
1821}
1822
1823template <class DATA>
1825 const Key& key,
1826 int *newLength,
1827 bsls::TimeInterval *newMinTime,
1828 TimeQueueItem<DATA> *item)
1829{
1830 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1831
1832 Node *node = getNodeFromHandle(handle, key);
1833
1834 if (!node) {
1835 return 1; // RETURN
1836 }
1837
1838 if (item) {
1839 item->time() = node->d_time;
1840 item->data() = node->d_data.object();
1841 item->handle() = handle;
1842 item->key() = node->d_key;
1843 }
1844
1845 if (node->d_next_p != node) {
1846 node->d_prev_p->d_next_p = node->d_next_p;
1847 node->d_next_p->d_prev_p = node->d_prev_p;
1848
1849 MapIter it = d_map.find(node->d_time);
1850 if (it->second == node) {
1851 it->second = node->d_next_p;
1852 }
1853 }
1854 else {
1855 d_map.erase(node->d_time);
1856 }
1857 freeNode(node);
1858 --d_length;
1859
1860 if (newLength) {
1861 *newLength = d_length;
1862 }
1863
1864 if (d_length && newMinTime) {
1865 BSLS_ASSERT(! d_map.empty());
1866
1867 *newMinTime = d_map.begin()->first;
1868 }
1869
1870 lock.release()->unlock();
1871
1872 putFreeNode(node);
1873 return 0;
1874}
1875
1876template <class DATA>
1878{
1879 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1880 MapIter it = d_map.begin();
1881
1882 Node *begin = 0;
1883 while (d_map.end() != it) {
1884 Node *const first = it->second;
1885 Node *const last = first->d_prev_p;
1886 Node *node = first;
1887
1888 do {
1889 if (removedItems) {
1890 removedItems->push_back(TimeQueueItem<DATA>(
1891 it->first,
1892 node->d_data.object(),
1893 node->d_index,
1894 node->d_key,
1895 d_allocator_p));
1896 }
1897 freeNode(node);
1898 node = node->d_next_p;
1899 --d_length;
1900 } while (node != first);
1901
1902 last->d_next_p = begin;
1903 begin = first;
1904
1905 MapIter condemned = it;
1906 ++it;
1907 d_map.erase(condemned);
1908 }
1909
1910 lock.release()->unlock();
1911 putFreeNodeList(begin);
1912}
1913
1914template <class DATA>
1916 const bsl::function<bool(const DATA&)>& predicate,
1917 int *newLength,
1918 bsls::TimeInterval *newMinTime,
1919 bsl::vector<TimeQueueItem<DATA> > *removedItems)
1920{
1921 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1922
1923 MapIter it = d_map.begin();
1924 Node *freeNodeList = 0;
1925 while (d_map.end() != it) {
1926 // We cache the next iterator, in case we erase this element because
1927 // its linked list of nodes is empty.
1928
1929 MapIter nextIt = it;
1930 ++nextIt;
1931
1932 Node *const first = it->second;
1933 Node *const last = first->d_prev_p;
1934 Node *node = first;
1935 Node *prevNode = 0;
1936 do {
1937 // Iterate through the doubly linked list of nodes
1938 Node *nextNode = node->d_next_p;
1939
1940 if (predicate(node->d_data.object())) {
1941 // The predicate is `true`, this element should be erased.
1942 if (removedItems) {
1943 removedItems->push_back(TimeQueueItem<DATA>(
1944 it->first,
1945 node->d_data.object(),
1946 node->d_index,
1947 node->d_key,
1948 d_allocator_p));
1949 }
1950 if (node->d_next_p != node) {
1951 // There is more than one node left in the list of nodes,
1952 // unlink it.
1953
1954 node->d_prev_p->d_next_p = node->d_next_p;
1955 node->d_next_p->d_prev_p = node->d_prev_p;
1956
1957 if (it->second == node) {
1958 it->second = node->d_next_p;
1959 }
1960 }
1961 else {
1962 // There is only one node left. Erase the map element.
1963 d_map.erase(it);
1964 }
1965 freeNode(node);
1966 --d_length;
1967 node->d_next_p = freeNodeList;
1968 freeNodeList = node;
1969 }
1970 prevNode = node;
1971 node = nextNode;
1972 } while (prevNode != last);
1973 it = nextIt;
1974 }
1975 if (newLength) {
1976 *newLength = d_length;
1977 }
1978 if (d_length && newMinTime) {
1979 BSLS_ASSERT(! d_map.empty());
1980
1981 *newMinTime = d_map.begin()->first;
1982 }
1983 lock.release()->unlock();
1984 putFreeNodeList(freeNodeList);
1985}
1986
1987template <class DATA>
1988inline
1990 const bsls::TimeInterval& newTime,
1991 int *isNewTop)
1992{
1993 return update(handle, Key(0), newTime, isNewTop);
1994}
1995
1996template <class DATA>
1998 const Key& key,
1999 const bsls::TimeInterval& newTime,
2000 int *isNewTop)
2001{
2002 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2003
2004 Node *node = getNodeFromHandle(handle, key);
2005
2006 if (!node) {
2007 return 1; // RETURN
2008 }
2009
2010 if (node->d_prev_p != node) {
2011 node->d_prev_p->d_next_p = node->d_next_p;
2012 node->d_next_p->d_prev_p = node->d_prev_p;
2013
2014 MapIter it = d_map.find(node->d_time);
2015 if (it->second == node) {
2016 it->second = node->d_next_p;
2017 }
2018 }
2019 else {
2020 d_map.erase(node->d_time);
2021 }
2022 node->d_time = newTime;
2023
2024 MapIter it = d_map.find(newTime);
2025
2026 if (d_map.end() == it) {
2027 node->d_prev_p = node;
2028 node->d_next_p = node;
2029 d_map[newTime] = node;
2030 }
2031 else {
2032 node->d_prev_p = it->second->d_prev_p;
2033 it->second->d_prev_p->d_next_p = node;
2034 node->d_next_p = it->second;
2035 it->second->d_prev_p = node;
2036 }
2037
2038 if (isNewTop) {
2039 *isNewTop = d_map.begin()->second == node && node->d_prev_p == node;
2040 }
2041 return 0;
2042}
2043
2044// ACCESSORS
2045template <class DATA>
2046inline
2048{
2049 return d_length;
2050}
2051
2052template <class DATA>
2053inline
2055 typename TimeQueue<DATA>::Handle handle) const
2056{
2057 return isRegisteredHandle(handle, Key(0));
2058}
2059
2060template <class DATA>
2061inline
2063 typename TimeQueue<DATA>::Handle handle,
2064 const Key& key) const
2065{
2066 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2067
2068 Node *node = getNodeFromHandle(handle, key);
2069
2070 return node != 0;
2071}
2072
2073template <class DATA>
2074inline
2076{
2077 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2078
2079 if (d_map.empty()) {
2080 return 1; // RETURN
2081 }
2082
2083 *buffer = d_map.begin()->first;
2084 return 0;
2085}
2086
2087template <class DATA>
2088inline
2090{
2091 int count = 0;
2092
2093 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2094
2095 for (MapCIter it = d_map.cbegin();
2096 it != d_map.cend() && it->first <= time;
2097 ++it) {
2098 Node *first = it->second;
2099 Node *node = first;
2100
2101 do {
2102 BSLS_ASSERT(count < (1 << k_NUM_INDEX_BITS_MAX) - 1);
2103 // container size is bounded to 2^24-1
2104 BSLMF_ASSERT((1 << k_NUM_INDEX_BITS_MAX) - 1 <
2105 INT_MAX);
2106 // container size bound prevents overflow of 'count'
2107 ++count;
2108 node = node->d_next_p;
2109 } while (node != first);
2110 }
2111
2112 return count;
2113}
2114
2115 // --------------------
2116 // struct TimeQueueItem
2117 // --------------------
2118
2119// CREATORS
2120template <class DATA>
2122: d_key(0)
2123{
2124 bslma::DestructionUtil::destroy(&d_data);
2125 bslalg::ScalarPrimitives::defaultConstruct(&d_data, basicAllocator);
2126}
2127
2128template <class DATA>
2130TimeQueueItem(TimeQueueItem<DATA> const& original,
2131 bslma::Allocator *basicAllocator)
2132: d_time(original.d_time)
2133// require that 'd_data' be default-constructible, hopefully at no cost
2134, d_handle(original.d_handle)
2135, d_key(original.d_key)
2136{
2137 bslma::DestructionUtil::destroy(&d_data);
2139 original.d_data,
2140 basicAllocator);
2141}
2142
2143template <class DATA>
2146 const DATA& data,
2147 Handle handle,
2148 bslma::Allocator *basicAllocator)
2149: d_time(time)
2150// require that 'd_data' be default-constructible, hopefully at no cost
2151, d_handle(handle)
2152, d_key(0)
2153{
2154 bslma::DestructionUtil::destroy(&d_data);
2156 data,
2157 basicAllocator);
2158}
2159
2160template <class DATA>
2163 const DATA& data,
2164 Handle handle,
2165 const Key& key,
2166 bslma::Allocator *basicAllocator)
2167: d_time(time)
2168// require that 'd_data' be default-constructible, hopefully at no cost
2169, d_handle(handle)
2170, d_key(key)
2171{
2172 bslma::DestructionUtil::destroy(&d_data);
2174 data,
2175 basicAllocator);
2176}
2177
2178// MANIPULATORS
2179template <class DATA>
2180inline
2182 const TimeQueueItem<DATA>& rhs)
2183{
2184 d_time = rhs.d_time;
2185 d_data = rhs.d_data;
2186 d_handle = rhs.d_handle;
2187 d_key = rhs.d_key;
2188
2189 return *this;
2190}
2191
2192template <class DATA>
2193inline
2195{
2196 return d_time;
2197}
2198
2199template <class DATA>
2200inline
2202{
2203 return d_data;
2204}
2205} // close package namespace
2206
2207#if 0
2208
2209namespace bdlcc {
2210// this definition was moved into the class declaration
2211// to work around a Visual Studio .NET 2003 bug.
2212template <typename DATA>
2213inline
2216{
2217 return d_handle;
2218}
2219} // close package namespace
2220#endif
2221
2222namespace bdlcc {
2223
2224template <class DATA>
2225inline
2228{
2229 return d_key;
2230}
2231
2232// ACCESSORS
2233template <class DATA>
2234inline
2236{
2237 return d_time;
2238}
2239
2240template <class DATA>
2241inline
2242const DATA& TimeQueueItem<DATA>::data() const
2243{
2244 return d_data;
2245}
2246} // close package namespace
2247
2248#if 0
2249
2250namespace bdlcc {
2251// this definition was moved into the class declaration
2252// to work around a Visual Studio .NET 2003 bug.
2253template <typename DATA>
2254inline
2257{
2258 return d_handle;
2259}
2260} // close package namespace
2261#endif
2262
2263namespace bdlcc {
2264
2265template <class DATA>
2266inline
2267const typename TimeQueueItem<DATA>::Key&
2269{
2270 return d_key;
2271}
2272} // close package namespace
2273
2274
2275
2276#endif
2277
2278// ----------------------------------------------------------------------------
2279// Copyright 2015 Bloomberg Finance L.P.
2280//
2281// Licensed under the Apache License, Version 2.0 (the "License");
2282// you may not use this file except in compliance with the License.
2283// You may obtain a copy of the License at
2284//
2285// http://www.apache.org/licenses/LICENSE-2.0
2286//
2287// Unless required by applicable law or agreed to in writing, software
2288// distributed under the License is distributed on an "AS IS" BASIS,
2289// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2290// See the License for the specific language governing permissions and
2291// limitations under the License.
2292// ----------------------------- END-OF-FILE ----------------------------------
2293
2294/** @} */
2295/** @} */
2296/** @} */
Definition bdlcc_timequeue.h:1193
Handle & handle()
Return the modifiable handle value associated with this item.
Definition bdlcc_timequeue.h:1258
TimeQueue< DATA >::Handle Handle
Definition bdlcc_timequeue.h:1200
TimeQueueItem(bslma::Allocator *basicAllocator=0)
Definition bdlcc_timequeue.h:2121
BSLMF_NESTED_TRAIT_DECLARATION(TimeQueueItem, bslma::UsesBslmaAllocator)
Key & key()
Return the modifiable key value associated with this item.
Definition bdlcc_timequeue.h:2227
DATA & data()
Return the modifiable data instance associated with this item.
Definition bdlcc_timequeue.h:2201
TimeQueueItem & operator=(const TimeQueueItem< DATA > &rhs)
Set the value of this TimeQueueItem to that of rhs.
Definition bdlcc_timequeue.h:2181
Handle handle() const
Return the non-modifiable handle value associated with this item.
Definition bdlcc_timequeue.h:1278
TimeQueue< DATA >::Key Key
Definition bdlcc_timequeue.h:1201
bsls::TimeInterval & time()
Return the modifiable time value associated with this item.
Definition bdlcc_timequeue.h:2194
Definition bdlcc_timequeue.h:759
~Key()
Destroy this Key object.
Definition bdlcc_timequeue.h:779
Key(const void *key)
Create a Key object having the specified key value.
Definition bdlcc_timequeue.h:768
bool operator==(const Key &rhs) const
Definition bdlcc_timequeue.h:786
Key(int key)
Definition bdlcc_timequeue.h:774
bool operator!=(const Key &rhs) const
Definition bdlcc_timequeue.h:793
Definition bdlcc_timequeue.h:734
TimeQueue(int numIndexBits, bool poolTimerMemory, bslma::Allocator *basicAllocator=0)
Definition bdlcc_timequeue.h:1554
void popLE(const bsls::TimeInterval &time, std::vector< TimeQueueItem< DATA > > *buffer, int *newLength=0, bsls::TimeInterval *newMinTime=0)
Definition bdlcc_timequeue.h:1749
bool isRegisteredHandle(Handle handle) const
void popLE(const bsls::TimeInterval &time)
Definition bdlcc_timequeue.h:1732
int minTime(bsls::TimeInterval *buffer) const
Definition bdlcc_timequeue.h:2075
TimeQueue(bool poolTimerMemory, bslma::Allocator *basicAllocator=0)
Definition bdlcc_timequeue.h:1521
~TimeQueue()
Destroy this time queue.
Definition bdlcc_timequeue.h:1577
int Handle
Definition bdlcc_timequeue.h:753
int length() const
Definition bdlcc_timequeue.h:2047
TimeQueue(int numIndexBits, bslma::Allocator *basicAllocator=0)
Definition bdlcc_timequeue.h:1539
Handle add(const bsls::TimeInterval &time, const DATA &data, int *isNewTop=0, int *newLength=0)
Definition bdlcc_timequeue.h:1592
int countLE(const bsls::TimeInterval &time) const
Definition bdlcc_timequeue.h:2089
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:1739
TimeQueue(bslma::Allocator *basicAllocator=0)
Definition bdlcc_timequeue.h:1508
void popLE(const bsls::TimeInterval &time, int maxTimers)
Definition bdlcc_timequeue.h:1771
void popLE(const bsls::TimeInterval &time, int maxTimers, std::vector< TimeQueueItem< DATA > > *buffer, int *newLength=0, bsls::TimeInterval *newMinTime=0)
Definition bdlcc_timequeue.h:1791
int popFront(TimeQueueItem< DATA > *buffer=0, int *newLength=0, bsls::TimeInterval *newMinTime=0)
Definition bdlcc_timequeue.h:1684
Handle add(const bsls::TimeInterval &time, const DATA &data, const Key &key, int *isNewTop=0, int *newLength=0)
Definition bdlcc_timequeue.h:1602
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 removeAll(bsl::vector< TimeQueueItem< DATA > > *removedItems=0)
Definition bdlcc_timequeue.h:1877
void removeIf(const bsl::function< bool(const DATA &)> &predicate, int *newLength=0, bsls::TimeInterval *newMinTime=0, bsl::vector< TimeQueueItem< DATA > > *removedItems=0)
Definition bdlcc_timequeue.h:1915
void popLE(const bsls::TimeInterval &time, int maxTimers, bsl::vector< TimeQueueItem< DATA > > *buffer, int *newLength=0, bsls::TimeInterval *newMinTime=0)
Definition bdlcc_timequeue.h:1780
Handle add(const TimeQueueItem< DATA > &item, int *isNewTop=0, int *newLength=0)
Definition bdlcc_timequeue.h:1675
Forward declaration.
Definition bslstl_function.h:946
Definition bslstl_map.h:653
BloombergLP::bslstl::TreeIterator< const value_type, Node, difference_type > const_iterator
Definition bslstl_map.h:758
BloombergLP::bslstl::TreeIterator< value_type, Node, difference_type > iterator
Definition bslstl_map.h:756
size_type size() const BSLS_KEYWORD_NOEXCEPT
Return the number of elements in this vector.
Definition bslstl_vector.h:3019
bool empty() const BSLS_KEYWORD_NOEXCEPT
Return true if this vector has size 0, and false otherwise.
Definition bslstl_vector.h:3034
reference front()
Definition bslstl_vector.h:2922
Definition bslstl_vector.h:1120
void push_back(const VALUE_TYPE &value)
Definition bslstl_vector.h:4343
Definition bslma_allocator.h:545
void deleteObjectRaw(const TYPE *object)
Definition bslma_allocator.h:804
Definition bslmt_lockguard.h:234
T * release()
Definition bslmt_lockguard.h:506
Definition bslmt_mutex.h:317
Definition bsls_atomic.h:744
Definition bsls_atomic.h:1362
TYPE * testAndSwap(const TYPE *compareValue, TYPE *swapValue)
Definition bsls_atomic.h:2363
Definition bsls_timeinterval.h:307
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:651
Definition bdlcc_boundedqueue.h:270
Definition bdlat_valuetypefunctions.h:939
T::iterator begin(T &container)
Definition bslstl_iterator.h:1593
T::iterator end(T &container)
Definition bslstl_iterator.h:1621
Definition baljsn_encoder_testtypes.h:76
Definition bslmf_issame.h:146
static void defaultConstruct(TARGET_TYPE *address, bslma::Allocator *allocator)
Definition bslalg_scalarprimitives.h:1577
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_objectbuffer.h:277