BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlcc_deque.h
Go to the documentation of this file.
1/// @file bdlcc_deque.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlcc_deque.h -*-C++-*-
8#ifndef INCLUDED_BDLCC_DEQUE
9#define INCLUDED_BDLCC_DEQUE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlcc_deque bdlcc_deque
15/// @brief Provide a fully thread-safe deque container.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlcc
19/// @{
20/// @addtogroup bdlcc_deque
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlcc_deque-purpose"> Purpose</a>
25/// * <a href="#bdlcc_deque-classes"> Classes </a>
26/// * <a href="#bdlcc_deque-description"> Description </a>
27/// * <a href="#bdlcc_deque-thread-safety"> Thread Safety </a>
28/// * <a href="#bdlcc_deque-exception-safety"> Exception Safety </a>
29/// * <a href="#bdlcc_deque-design-rationale-for-bdlcc-deque"> Design Rationale for bdlcc::Deque </a>
30/// * <a href="#bdlcc_deque-high-water-mark-feature"> High-Water Mark Feature </a>
31/// * <a href="#bdlcc_deque-proctor-access"> Proctor Access </a>
32/// * <a href="#bdlcc_deque-supported-clock-types"> Supported Clock-Types </a>
33/// * <a href="#bdlcc_deque-warning-synchronization-required-on-destruction"> WARNING: Synchronization Required on Destruction </a>
34/// * <a href="#bdlcc_deque-tips-for-migrating-from-bcec_queue"> Tips For Migrating From bcec_Queue </a>
35/// * <a href="#bdlcc_deque-usage"> Usage </a>
36/// * <a href="#bdlcc_deque-example-1-a-queue-of-work-requests"> Example 1: A Queue of Work Requests </a>
37/// * <a href="#bdlcc_deque-example-2-a-queue-of-events"> Example 2: A Queue of Events </a>
38///
39/// # Purpose {#bdlcc_deque-purpose}
40/// Provide a fully thread-safe deque container.
41///
42/// # Classes {#bdlcc_deque-classes}
43///
44/// - bdlcc::Deque: thread-safe `bsl::deque` wrapper
45///
46/// @see bsl::deque
47///
48/// # Description {#bdlcc_deque-description}
49/// This component provides `bdlcc::Deque<TYPE>`, a fully
50/// thread-safe implementation of an efficient, double-ended queue of
51/// (template parameter) `TYPE` values. `bdlcc::Deque` is effectively a
52/// thread-safe wrapper for `bsl::deque`, whose interface is also made available
53/// through proctor types that are nested classes.
54///
55/// ## Thread Safety {#bdlcc_deque-thread-safety}
56///
57///
58/// `bdlcc::Deque` is fully *thread-safe*, meaning that all non-creator
59/// operations on an object can be safely invoked simultaneously from multiple
60/// threads.
61///
62/// ## Exception Safety {#bdlcc_deque-exception-safety}
63///
64///
65/// Provided the template parameter `TYPE` provides the following exception
66/// safety guarantees:
67/// 1. The destructor provides the no-throw guarantee.
68/// 2. Copy construction and assignment provide the strong guarantee and do not
69/// modify the source.
70/// 3. Move construction and assignment where the allocators of the source and
71/// destination match, or if the type is non-allocating, provide the no-throw
72/// guarantee.
73/// 4. Move construction and assignment where the allocators of source and
74/// destination do not match behave like non-moving copy construction and
75/// assignment.
76/// All operations on `bdlcc::Deque` provide the strong exception guarantee,
77/// both for the `bdlcc::Deque`s own salient state and the salient state of the
78/// `vector`, if any, passed to manipulators. However, the non-salient
79/// `capacity` of the underlying `bsl::deque` and of the passed `vector` may be
80/// modified.
81///
82/// ## Design Rationale for bdlcc::Deque {#bdlcc_deque-design-rationale-for-bdlcc-deque}
83///
84///
85/// The fully thread-safe `bdlcc::Deque` is similar to `bsl::deque` in many
86/// regards, but there are several differences in method behavior and signature
87/// that arise due to the thread-aware nature of the container and its
88/// anticipated usage pattern.
89///
90/// A user of `bsl::deque` is expected to consult the `size` or `empty`
91/// accessors before reading or popping to determine whether elements are
92/// available in the container to be read or popped. This won't work in a
93/// multithreaded context since reading the accessor is a separate operation
94/// than the read or pop, and another thread may have altered the state of the
95/// container in between.
96///
97/// So we have eliminated the `front`, `back` and random-access methods.
98/// Reading is done from the ends of the container via the `popFront` and
99/// `popBack` methods, which return a `TYPE` object *by* *value*, rather than
100/// returning `void`, as @ref pop_front and @ref pop_back in `bsl::deque` do.
101/// Moreover, if a `bdlcc::Deque` object is empty, `popFront` and `popBack` will
102/// block indefinitely until an item is added to the container.
103///
104/// ## High-Water Mark Feature {#bdlcc_deque-high-water-mark-feature}
105///
106///
107/// The behaviors of the `push` methods differ from those of `bsl::deque` in
108/// that they can block under certain circumstances. `bdlcc::Deque` supports
109/// the notion of a *suggested* maximum capacity known as the *high-water*
110/// *mark*. The high-water mark value is supplied at construction, and affects
111/// some of the various forms of `push*` methods. The container is considered
112/// to be *full* if it contains (at least) the high-water mark number of items,
113/// and the container has *space* *available* if it is not full. The high-water
114/// mark is set at construction and cannot be changed afterward. If no
115/// high-water mark is specified, the high-water mark of the container is
116/// effectively infinite. Some of the variants of push operations (described
117/// below) may fail, and the return status of those operations indicates whether
118/// the operation succeeded, failed, or partially succeeded (which may happen,
119/// for example, when pushing a range of values).
120///
121/// `bdlcc::Deque` supports four variants of the two `push` methods, whose
122/// behaviors differ when the container is *full* (i.e. when the push would
123/// raise the length of the container above the high-water mark).
124///
125/// 1. **blocking**: (`pushBack`, `pushFront`): If the container is full, block
126/// until space is available, then push, otherwise push immediately.
127/// 2. **try** (`tryPushBack`, `tryPushFront`): If the container is full, fail
128/// immediately. If space is available, succeed immediately. Note that
129/// partial success is possible in the case of a range try push.
130/// 3. **timed blocking**: (`timedPushBack`, `timedPushFront`): If the container
131/// is full, block until either space is available or the specified timeout
132/// has been reached. If space was, or became, available, push and succeed,
133/// otherwise fail.
134/// 4. **force**: (`forcePushBack`, `forcePushFront`): If the container is full,
135/// push anyway, increasing the container's size above its high-water mark,
136/// always succeeding immediately.
137///
138/// Note that the availability of force pushes means that the high-water mark is
139/// a suggestion and not an invariant.
140///
141/// The purpose of a high-water mark is to enable the client to use the
142/// container as a fixed-length container, where pushes that will grow it above
143/// a certain size will block. The purpose of the force pushes is to allow
144/// high-priority items to be pushed regardless of whether the container is
145/// full.
146///
147/// ## Proctor Access {#bdlcc_deque-proctor-access}
148///
149///
150/// There are public nested classes `bdlcc::Deque::Proctor` and
151/// `bdlcc::Deque::ConstProctor` through which the client can directly access
152/// the underlying `bsl::deque` contained in the `bdlcc::Deque`. When a proctor
153/// object is created, it acquires the container's mutex, and allows the client
154/// to use the overloaded `->` and `*` operators on the proctor object to access
155/// the underlying `bsl::deque`. `operator[]` is also provided for direct
156/// random access to that deque. Because the mutex is locked, manipulators of
157/// `bdlcc::Deque` called by other threads will block, thus allowing safe access
158/// to the underlying thread-unsafe container. When the proctor is destroyed
159/// (or released via the `release` method), the proctor signals the thread-aware
160/// container's condition variables to inform manipulators in other threads of
161/// new items being available for pops or new space becoming available for
162/// pushes.
163///
164/// ## Supported Clock-Types {#bdlcc_deque-supported-clock-types}
165///
166///
167/// The component `bsls::SystemClockType` supplies the enumeration indicating
168/// the system clock on which the `timedPush*` and `timedPop*` methods should be
169/// based. If the clock type indicated at construction is
170/// `bsls::SystemClockType::e_REALTIME`, time should be expressed as an absolute
171/// offset since 00:00:00 UTC, January 1, 1970 (which matches the epoch used in
172/// `bdlt::SystemTime::now(bsls::SystemClockType::e_REALTIME)`. If the clock
173/// type indicated at construction is `bsls::SystemClockType::e_MONOTONIC`, time
174/// should be expressed as an absolute offset since the epoch of this clock
175/// (which matches the epoch used in
176/// `bsls::SystemTime::now(bsls::SystemClockType::e_MONOTONIC)`.
177///
178/// ## WARNING: Synchronization Required on Destruction {#bdlcc_deque-warning-synchronization-required-on-destruction}
179///
180///
181/// The behavior for the destructor is undefined unless all access or
182/// modification of the object is completed prior to its destruction. Some form
183/// of synchronization, external to the component, is required to ensure this
184/// precondition on the destructor is met. For example, if two (or more)
185/// threads are manipulating a queue, it is *not* safe to anticipate the number
186/// of elements added to the queue, and destroy that queue immediately after the
187/// last element is popped (without additional synchronization) because one of
188/// the corresponding push functions may not have completed (push may, for
189/// instance, signal waiting threads after the element is considered added to
190/// the queue).
191///
192/// ## Tips For Migrating From bcec_Queue {#bdlcc_deque-tips-for-migrating-from-bcec_queue}
193///
194///
195/// * `InitialCapacity` has been eliminated. Instead, construct your
196/// `bdlcc::Deque` object and then use proctor access to call `reserve` on
197/// the contained `bsl::deque` to reserve the desired initial capacity.
198/// (Note that `deque::reserve` is not part of the C++ standard, though
199/// `bsl::deque` does implement it).
200/// * The mutex and condition variables are no longer directly exposed, in
201/// favor of the new proctor access, which gives direct access to the
202/// underlying `bsl::deque`, automatically locking the mutex and updating the
203/// condition variables as necessary.
204/// * A new, thread-safe `length` accessor is provided, eliminating the need to
205/// access the underlying thread-unsafe container to obtain its length.
206///
207/// ## Usage {#bdlcc_deque-usage}
208///
209///
210/// This section illustrates intended use of this component.
211///
212/// ### Example 1: A Queue of Work Requests {#bdlcc_deque-example-1-a-queue-of-work-requests}
213///
214///
215/// First, declarer the struct `WordData`. Imagine it contains some data one
216/// wants to process:
217/// @code
218/// struct WorkData {
219/// // work data...
220/// };
221/// @endcode
222/// Then, create the function that will produce a `WorkData` object:
223/// @code
224/// /// Dummy implementation of `getWorkData` function required by the usage
225/// /// example.
226/// bool getWorkData(WorkData *)
227/// {
228/// static bsls::AtomicInt i(1);
229/// return ++i < 1000;
230/// }
231/// @endcode
232/// Next, declare `WorkRequest`, the type of object that will be stored in
233/// the container:
234/// @code
235/// struct WorkRequest {
236/// // PUBLIC TYPES
237/// enum RequestType {
238/// e_WORK = 1,
239/// e_STOP = 2
240/// };
241///
242/// // PUBLIC DATA
243/// RequestType d_type;
244/// WorkData d_data;
245/// };
246/// @endcode
247/// Then, create the function that will do work on a `WorkRequest` object:
248/// @code
249/// /// Function that pretends to do work on the specified `workData`.
250/// void doWork(WorkData *workData)
251/// {
252/// // do some stuff with `*workData` ...
253///
254/// (void) workData;
255/// }
256/// @endcode
257/// Next, create the functor that will be run in the consumer threads:
258/// @code
259/// struct ConsumerFunctor {
260/// // DATA
261/// bdlcc::Deque<WorkRequest> *d_deque_p;
262///
263/// // CREATORS
264///
265/// // Create a ``ConsumerFunctor` object that will consumer work
266/// // requests from the specified `container`.
267/// explicit
268/// ConsumerFunctor(bdlcc::Deque<WorkRequest> *container)
269/// : d_deque_p(container)
270/// {}
271///
272/// // MANIPULATORS
273///
274/// /// Pop work requests off the deque and process them until an
275/// /// `e_STOP` request is encountered.
276/// void operator()()
277/// {
278/// WorkRequest item;
279///
280/// do {
281/// item = d_deque_p->popFront();
282/// if (WorkRequest::e_WORK == item.d_type) {
283/// doWork(&item.d_data);
284/// }
285/// } while (WorkRequest::e_STOP != item.d_type);
286/// }
287/// };
288/// @endcode
289/// Then, create the functor that will be run in the producer threads:
290/// @code
291/// struct ProducerFunctor {
292/// // DATA
293/// bdlcc::Deque<WorkRequest> *d_deque_p;
294///
295/// // CREATORS
296///
297/// /// Create a `ProducerFunctor` object that will enqueue work
298/// /// requests into the specified `container`.
299/// explicit
300/// ProducerFunctor(bdlcc::Deque<WorkRequest> *container)
301/// : d_deque_p(container)
302/// {}
303///
304/// // MANIPULATORS
305///
306/// /// Enqueue work requests to the container until `getWorkData`
307/// /// returns `false`, then enqueue an `e_STOP` request.
308/// void operator()()
309/// {
310/// WorkRequest item;
311/// WorkData workData;
312///
313/// while (!getWorkData(&workData)) {
314/// item.d_type = WorkRequest::e_WORK;
315/// item.d_data = workData;
316/// d_deque_p->pushBack(item);
317/// }
318///
319/// item.d_type = WorkRequest::e_STOP;
320/// d_deque_p->pushBack(item);
321/// }
322/// };
323/// @endcode
324/// Next, in `main`, define the number of consumer and producer threads (these
325/// numbers must be equal).
326/// @code
327/// enum { k_NUM_CONSUMER_THREADS = 10,
328/// k_NUM_PRODUCER_THREADS = k_NUM_CONSUMER_THREADS };
329/// @endcode
330/// Then, create our container:
331/// @code
332/// bdlcc::Deque<WorkRequest> deque;
333/// @endcode
334/// Next, create the array of thread handles for the threads we will spawn:
335/// @code
336/// bslmt::ThreadUtil::Handle handles[k_NUM_CONSUMER_THREADS +
337/// k_NUM_PRODUCER_THREADS];
338/// @endcode
339/// Now, spawn all the consumers and producers:
340/// @code
341/// int ti = 0, rc;
342/// while (ti < k_NUM_CONSUMER_THREADS) {
343/// rc = bslmt::ThreadUtil::create(&handles[ti++],
344/// ConsumerFunctor(&deque));
345/// assert(0 == rc);
346/// }
347/// while (ti < k_NUM_CONSUMER_THREADS + k_NUM_PRODUCER_THREADS) {
348/// rc = bslmt::ThreadUtil::create(&handles[ti++],
349/// ProducerFunctor(&deque));
350/// assert(0 == rc);
351/// }
352/// @endcode
353/// Finally, join all the threads after they finish and confirm the container is
354/// empty afterward:
355/// @code
356/// while (ti > 0) {
357/// rc = bslmt::ThreadUtil::join(handles[--ti]);
358/// assert(0 == rc);
359/// }
360/// assert(0 == deque.length());
361/// @endcode
362///
363/// ### Example 2: A Queue of Events {#bdlcc_deque-example-2-a-queue-of-events}
364///
365///
366/// First, we declare the `Event` type, that will be contained in our
367/// `bdlcc::Deque` object.
368/// @code
369/// struct Event {
370/// enum EventType {
371/// e_IN_PROGRESS = 1,
372/// e_TASK_COMPLETE = 2 };
373///
374/// EventType d_type;
375/// int d_workerId;
376/// int d_eventNumber;
377/// const char *d_eventText_p;
378/// };
379///
380/// Then, we define the number of events each thread will push:
381///
382/// const int k_NUM_TO_PUSH = 5;
383///
384/// Next, we declare our 'WorkerFunctor' type, that will push 'k_NUM_TO_PUSH'
385/// events into the deque.
386///
387/// struct WorkerFunctor {
388/// int d_workerId;
389/// bdlcc::Deque<Event> *d_deque_p;
390/// bslmt::Barrier *d_barrier_p;
391///
392/// /// All the threads will block on the same barrier so they all start
393/// /// at once to maximize concurrency.
394/// void operator()()
395/// {
396/// d_barrier_p->wait();
397///
398/// // Loop to push 'k_NUM_TO_PUSH - 1' events onto the deque.
399///
400/// int evnum = 1;
401/// while (evnum < k_NUM_TO_PUSH) {
402/// // Yield every loop to maximize concurrency.
403///
404/// bslmt::ThreadUtil::yield();
405///
406/// // Create the event object.
407///
408/// Event ev = {
409/// Event::e_IN_PROGRESS,
410/// d_workerId,
411/// evnum++,
412/// "In-Progress Event"
413/// };
414///
415/// // Push the event object.
416///
417/// d_deque_p->pushBack(ev);
418/// }
419///
420/// // Create the completing event object.
421///
422/// Event ev = {
423/// Event::e_TASK_COMPLETE,
424/// d_workerId,
425/// evnum,
426/// "Task Complete"
427/// };
428///
429/// // Push the completing event object.
430///
431/// d_deque_p->pushBack(ev);
432/// }
433/// };
434/// @endcode
435/// Next, in `main`, define the number of threads:
436/// @code
437/// const int k_NUM_THREADS = 10;
438/// @endcode
439/// Then, declare out `bdlcc::Deque` object, the set of handles of the
440/// subthreads, and our barrier object:
441/// @code
442/// bdlcc::Deque<Event> myDeque;
443/// bslmt::ThreadUtil::Handle handles[k_NUM_THREADS];
444/// bslmt::Barrier barrier(k_NUM_THREADS + 1);
445/// @endcode
446/// Next, spawn the worker threads:
447/// @code
448/// for (int ti = 0; ti < k_NUM_THREADS; ++ti) {
449/// WorkerFunctor functor = { ti, &myDeque, &barrier };
450///
451/// int rc = bslmt::ThreadUtil::create(&handles[ti], functor);
452/// assert(0 == rc);
453/// }
454/// @endcode
455/// Then, wait on the barrier, that will set all the subthreads running:
456/// @code
457/// barrier.wait();
458/// @endcode
459/// Now, loop to pop the events off the deque, and keep track of how many
460/// `e_COMPLETE` events have been popped. When this equals the number of
461/// subthreads, we are done.
462/// @code
463/// int numCompleted = 0, numEvents = 0;
464/// while (numCompleted < k_NUM_THREADS) {
465/// Event ev = myDeque.popFront();
466/// ++numEvents;
467/// if (verbose) {
468/// cout << "[" << ev.d_workerId << "] "
469/// << ev.d_eventNumber << ". "
470/// << ev.d_eventText_p << endl;
471/// }
472/// if (Event::e_TASK_COMPLETE == ev.d_type) {
473/// ++numCompleted;
474/// int rc = bslmt::ThreadUtil::join(handles[ev.d_workerId]);
475/// assert(!rc);
476/// }
477/// }
478/// @endcode
479/// Finally, perform some sanity checks:
480/// @code
481/// assert(k_NUM_THREADS * k_NUM_TO_PUSH == numEvents);
482/// assert(0 == myDeque.length());
483/// @endcode
484/// @}
485/** @} */
486/** @} */
487
488/** @addtogroup bdl
489 * @{
490 */
491/** @addtogroup bdlcc
492 * @{
493 */
494/** @addtogroup bdlcc_deque
495 * @{
496 */
497
498#include <bdlscm_version.h>
499
500#include <bslmt_condition.h>
501#include <bslmt_lockguard.h>
502#include <bslmt_mutex.h>
503
504#include <bslma_allocator.h>
505
506#include <bslmf_assert.h>
508#include <bslmf_movableref.h>
509
510#include <bsls_assert.h>
511#include <bsls_libraryfeatures.h>
512#include <bsls_review.h>
513#include <bsls_systemclocktype.h>
514#include <bsls_timeinterval.h>
515
516#include <bsl_algorithm.h>
517#include <bsl_deque.h>
518#include <bsl_vector.h>
519#include <bsl_limits.h>
520#include <bsl_cstddef.h>
521#include <bsl_cstdio.h>
522
523#include <vector>
524
525
526namespace bdlcc {
527
528 // ===========
529 // class Deque
530 // ===========
531
532/// This class provides a fully thread-safe implementation of an efficient,
533/// in-place, indexable, double-ended queue of (template parameter) `TYPE`
534/// values. Direct access to the underlying `bsl::deque<TYPE>` object is
535/// provided through the nested `Proctor` and `ConstProctor` classes. While
536/// this class is not value-semantic, the underlying `bsl::deque<TYPE>` class
537/// is.
538///
539/// See @ref bdlcc_deque
540template <class TYPE>
541class Deque {
542
543 // PRIVATE TYPES
544 class DequeThrowGuard;
545 template <class VECTOR>
546 class VectorThrowGuard;
547
548 template <class VECTOR>
549 struct IsVector;
550
551 public:
552 // PUBLIC TYPES
555
556 class Proctor; // defined after this `class`
557 class ConstProctor; // defined after this `class`
558
559 private:
560 // DATA
561 mutable
562 bslmt::Mutex d_mutex; // mutex object used to
563 // synchronize access to the
564 // underlying `deque`.
565
566 bslmt::Condition d_notEmptyCondition; // condition variable used to
567 // signal that new data is
568 // available in the container
569
570 bslmt::Condition d_notFullCondition; // condition variable used to
571 // signal when there is room
572 // available to add new data to
573 // the container
574
575 MonoDeque d_monoDeque; // the underlying deque.
576
577 const size_type d_highWaterMark; // positive maximum number of
578 // items that can be contained
579 // before insertions will be
580 // blocked.
581
583 d_clockType; // clock type used
584
585 private:
586 // NOT IMPLEMENTED
587 Deque<TYPE>& operator=(const Deque<TYPE>&);
588
589 // PRIVATE MANIPULATORS
590
591 /// If the optionally specified `buffer` is non-zero, append all the
592 /// elements from this container to `*buffer` in the same order, then,
593 /// regardless of whether `buffer` is zero, clear this container.
594 ///
595 /// \note Note that the previous contents of `*buffer` are not discarded -- the
596 /// removed items are appended to it.
597 template <class VECTOR>
598 void removeAllImp(VECTOR *buffer = 0);
599
600 /// Remove up to the specified `maxNumItems` from the back of this
601 /// container. Optionally specify a `buffer` into which the items
602 /// removed from the container are loaded. If `buffer` is non-null, the
603 /// removed items are appended to it as if by repeated application of
604 /// `buffer->push_back(popBack())` while the container is not empty and `maxNumItems` have not yet been removed.
605 ///
606 /// \note Note that the ordering of
607 /// the items in `*buffer` after the call is the reverse of the ordering
608 /// they had in the deque. Also note that `*buffer` is not cleared --
609 /// the popped items are appended after any pre-existing contents.
610 template <class VECTOR>
611 void tryPopBackImp(size_type maxNumItems,
612 VECTOR *buffer);
613
614 /// Remove up to the specified `maxNumItems` from the front of this
615 /// container. Optionally specify a `buffer` into which the items
616 /// removed from the container are appended. If `buffer` is non-null,
617 /// the removed items are appended to it as if by repeated application
618 /// of `buffer->push_back(popFront())` while the const is not empty and `maxNumItems` have not yet been removed.
619 ///
620 /// \note Note that `*buffer` is not
621 /// cleared -- the popped items are appended after any pre-existing
622 /// contents.
623 template <class VECTOR>
624 void tryPopFrontImp(size_type maxNumItems,
625 VECTOR *buffer);
626
627 public:
628 // CLASS METHODS
629
630 /// Return the maximum value that can be stored in a veriable of type
631 /// `size_type`. The high water mark defaults to having this value.
632 static
634
635 // CREATORS
636
637 /// Create a container of objects of (template parameter) `TYPE`, with no
638 /// high water mark, and use the specified `clockType` to indicate the
639 /// epoch used for all time intervals (see {Supported Clock-Types} in the
640 /// component documentation). If `basicAllocator` is 0, the currently
641 /// installed default allocator is used.
642 explicit
643 Deque(bslma::Allocator *basicAllocator = 0);
644 explicit
646 bslma::Allocator *basicAllocator = 0);
647
648 /// Create a container of objects of (template parameter) `TYPE`, with the
649 /// specified `highWaterMark`, and use the specified `clockType` to
650 /// indicate the epoch used for all time intervals (see {Supported
651 /// Clock-Types} in the component documentation). Optionally specify a
652 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0, the
653 /// currently installed default allocator is used.
654 ///
655 /// \pre The behavior is undefined unless `highWaterMark > 0`.
656 explicit
657 Deque(bsl::size_t highWaterMark,
658 bslma::Allocator *basicAllocator = 0);
659 Deque(bsl::size_t highWaterMark,
661 bslma::Allocator *basicAllocator = 0);
662
663 /// Create a container of objects of (template parameter) `TYPE`
664 /// containing the sequence of elements in the specified range
665 /// `[begin .. end)`, having no high water mark, and use the specified
666 /// `clockType` to indicate the epoch used for all time intervals (see
667 /// {Supported Clock-Types} in the component documentation). Optionally
668 /// specify a `basicAllocator` used to supply memory. If
669 /// `basicAllocator` is 0, the currently installed default allocator is used.
670 ///
671 /// \note Note that the items in the range are treated as `const`
672 /// objects, copied without being modified.
673 template <class INPUT_ITER>
674 Deque(INPUT_ITER begin,
675 INPUT_ITER end,
676 bslma::Allocator *basicAllocator = 0);
677 template <class INPUT_ITER>
678 Deque(INPUT_ITER begin,
679 INPUT_ITER end,
681 bslma::Allocator *basicAllocator = 0);
682
683 /// Create a container of objects of (template parameter) `TYPE`
684 /// containing the sequence of `TYPE` values in the specified range
685 /// `[begin .. end)` having the specified `highWaterMark`, and use the
686 /// specified `clockType` to indicate the epoch used for all time
687 /// intervals (see {Supported Clock-Types} in the component
688 /// documentation). Optionally specify a `basicAllocator` used to
689 /// supply memory. If `basicAllocator` is 0, the currently installed default allocator is used.
690 ///
691 /// \pre The behavior is undefined unless `highWaterMark > 0`.
692 ///
693 /// \note Note that if the number of elements in the
694 /// range `[begin, end)` exceeds `highWaterMark`, the effect will be the
695 /// same as if the extra elements were added by forced pushes. Also
696 /// note that the items in the range are treated as `const` objects,
697 /// copied without being modified.
698 template <class INPUT_ITER>
699 Deque(INPUT_ITER begin,
700 INPUT_ITER end,
701 bsl::size_t highWaterMark,
702 bslma::Allocator *basicAllocator = 0);
703 template <class INPUT_ITER>
704 Deque(INPUT_ITER begin,
705 INPUT_ITER end,
706 bsl::size_t highWaterMark,
708 bslma::Allocator *basicAllocator = 0);
709
710 /// Create a container having the same value as the specified `original`
711 /// object. Optionally specify a `basicAllocator` used to supply
712 /// memory. If `basicAllocator` is 0, the currently installed default
713 /// allocator is used.
714 Deque(const Deque<TYPE>& original, bslma::Allocator *basicAllocator = 0);
715
716 /// Destroy this container.
717 /// \pre The behavior is undefined unless all access
718 /// or modification of the container has completed prior to the
719 /// destruction of this object.
720 ~Deque();
721
722 // MANIPULATORS
723
724 /// Append the specified `item` to the back of this container without regard for the high-water mark.
725 ///
726 /// \note Note that this method is provided
727 /// to allow high priority items to be inserted when the container is
728 /// full; `pushFront` and `pushBack` should be used for general use.
729 void forcePushBack(const TYPE& item);
730
731 /// Append the specified move-insertable `item` to the back of this
732 /// container without regard for the high-water mark. `item` is left in a valid but unspecified state.
733 ///
734 /// \note Note that this method is provided to
735 /// allow high priority items to be inserted when the container is full;
736 /// `pushFront` and `pushBack` should be used for general use.
738
739 /// Append the specified specified range `[begin .. end)` of items to
740 /// the back of this container without regard for the high-water mark.
741 ///
742 /// \note Note that the items in the range are treated as `const` objects,
743 /// copied without being modified.
744 template <class INPUT_ITER>
745 void forcePushBack(INPUT_ITER begin,
746 INPUT_ITER end);
747
748 /// Append the specified `item` to the front of this container without regard for the high-water mark.
749 ///
750 /// \note Note that this method is provided
751 /// to allow high priority items to be inserted when the container is
752 /// full; `pushFront` and `pushBack` should be used for general use.
753 void forcePushFront(const TYPE& item);
754
755 /// Append the specified move-insertable `item` to the front of this
756 /// container without regard for the high-water mark. `item` is left in a valid but unspecified state.
757 ///
758 /// \note Note that this method is provided to
759 /// allow high priority items to be inserted when the container is full;
760 /// `pushFront` and `pushBack` should be used for general use.
762
763 /// Append the specified specified range `[begin .. end)` of items to
764 /// the front of this container without regard for the high-water mark.
765 ///
766 /// \note Note that pushed the items will be in the container in the reverse
767 /// of the order in which they occur in the range. Also note that the
768 /// items in the range are treated as `const` objects, copied without
769 /// being modified.
770 template <class INPUT_ITER>
771 void forcePushFront(INPUT_ITER begin,
772 INPUT_ITER end);
773
774 /// Return the last item in this container and remove it. If this
775 /// container is empty, block until an item is available.
776 TYPE popBack();
777
778 /// Remove the last item in this container and load that item into the
779 /// specified `*item`. If this container is empty, block until an item
780 /// is available.
781 void popBack(TYPE *item);
782
783 /// Return the first item in this container and remove it. If this
784 /// container is empty, block until an item is available.
785 TYPE popFront();
786
787 /// Remove the first item in this container and load that item into the
788 /// specified `*item`. If the container is empty, block until an item
789 /// is available.
790 void popFront(TYPE *item);
791
792 /// Block until space in this container becomes available (see
793 /// {`High-Water Mark` Feature}), then append the specified `item` to
794 /// the back of this container.
795 void pushBack(const TYPE& item);
796
797 /// Block until space in this container becomes available (see
798 /// {`High-Water Mark` Feature}), then append the specified
799 /// move-insertable `item` to the back of this container. `item` is
800 /// left in a valid but unspecified state.
802
803 /// Block until space in this container becomes available (see
804 /// {`High-Water Mark` Feature}), then append the specified `item` to
805 /// the front of this container.
806 void pushFront(const TYPE& item);
807
808 /// Block until space in this container becomes available (see
809 /// {`High-Water Mark` Feature}), then append the specified
810 /// move-insertable `item` to the front of this container. `item` is
811 /// left in a valid but unspecified state.
813
814 /// If the optionally specified `buffer` is non-zero, append all the
815 /// elements from this container to `*buffer` in the same order, then,
816 /// regardless of whether `buffer` is zero, clear this container.
817 ///
818 /// \note Note that the previous contents of `*buffer` are not discarded -- the
819 /// removed items are appended to it.
820 void removeAll();
821 void removeAll(bsl::vector<TYPE> *buffer);
822 void removeAll(std::vector<TYPE> *buffer);
823#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
824 void removeAll(std::pmr::vector<TYPE> *buffer);
825#endif
826
827 /// Remove the last item in this container and load that item value into
828 /// the specified `*item`. If this container is empty, block until an
829 /// item is available or until the specified `timeout` (expressed as the
830 /// **ABSOLUTE** time from 00:00:00 UTC, January 1, 1970) expires. Return
831 /// 0 on success, and a non-zero value if the call timed out before an item was available.
832 ///
833 /// \note Note that this method can block indefinitely if
834 /// another thread has the mutex locked, particularly by a proctor
835 /// object -- there is no guarantee that this method will return after
836 /// `timeout`.
837 int timedPopBack(TYPE *item, const bsls::TimeInterval& timeout);
838
839 /// Remove the first item in this container and load that item value
840 /// into the specified `*item`. If this container is empty, block until
841 /// an item is available or until the specified `timeout` (expressed as
842 /// the **ABSOLUTE** time from 00:00:00 UTC, January 1, 1970) expires.
843 /// Return 0 on success, and a non-zero value if the call timed out before an item was available.
844 ///
845 /// \note Note that this method can block
846 /// indefinitely if another thread has the mutex locked, particularly by
847 /// a proctor object -- there is no guarantee that this method will
848 /// return after `timeout`.
849 int timedPopFront(TYPE *item, const bsls::TimeInterval& timeout);
850
851 /// Append the specified `item` to the back of this container if space
852 /// is available, otherwise (if the container is full) block waiting for
853 /// space to become available or until the specified `timeout`
854 /// (expressed as the **ABSOLUTE** time from 00:00:00 UTC, January 1,
855 /// 1970) expires. Return 0 if space was or became available and this
856 /// container was updated, and a non-zero value if the call timed out
857 /// before space became available and this container was left unmodified.
858 ///
859 /// \note Note that this method can block indefinitely if another
860 /// thread has the mutex locked, particularly by a proctor object --
861 /// there is no guarantee that this method will return after `timeout`.
862 int timedPushBack(const TYPE& item,
863 const bsls::TimeInterval& timeout);
864
865 /// Append the specified move-insertable `item` to the back of this
866 /// container if space is available, otherwise (if the container is
867 /// full) block waiting for space to become available or until the
868 /// specified `timeout` (expressed as the **ABSOLUTE** time from 00:00:00
869 /// UTC, January 1, 1970) expires. If the container is modified, `item`
870 /// is left in a valid but unspecified state, otherwise `item` is
871 /// unchanged. Return 0 if space was or became available and this
872 /// container was updated, and a non-zero value if the call timed out
873 /// before space became available and this container was left unmodified.
874 ///
875 /// \note Note that this method can block indefinitely if another
876 /// thread has the mutex locked, particularly by a proctor object --
877 /// there is no guarantee that this method will return after `timeout`.
879 const bsls::TimeInterval& timeout);
880
881 /// Append the specified `item` to the front of this container if space
882 /// is available, otherwise (if the container is full) block waiting for
883 /// space to become available or until the specified `timeout`
884 /// (expressed as the **ABSOLUTE** time from 00:00:00 UTC, January 1,
885 /// 1970) expires. Return 0 if space was or became available and this
886 /// container was updated, and a non-zero value if the call timed out
887 /// before space became available and this container was left unmodified.
888 ///
889 /// \note Note that this method can block indefinitely if another
890 /// thread has the mutex locked, particularly by a proctor object --
891 /// there is no guarantee that this method will return after `timeout`.
892 int timedPushFront(const TYPE& item,
893 const bsls::TimeInterval& timeout);
894
895 /// Append the specified move-insertable `item` to the front of this
896 /// container if space is available, otherwise (if the container is
897 /// full) block waiting for space to become available or until the
898 /// specified `timeout` (expressed as the **ABSOLUTE** time from 00:00:00
899 /// UTC, January 1, 1970) expires. If the container is modified,`item`
900 /// is left in a valid but unspecified state, otherwise `item` is left
901 /// unchanged. Return 0 if space was or became available and this
902 /// container was updated, and a non-zero value if the call timed out
903 /// before space became available and this container was left unmodified.
904 ///
905 /// \note Note that this method can block indefinitely if another
906 /// thread has the mutex locked, particularly by a proctor object --
907 /// there is no guarantee that this method will return after `timeout`.
909 const bsls::TimeInterval& timeout);
910
911 /// If this container is non-empty, remove the last item, load that item
912 /// into the specified `*item`, and return 0 indicating success. If
913 /// this container is empty, return a non-zero value with no effect on
914 /// `item` or the state of this container.
915 int tryPopBack(TYPE *item);
916
917 /// Remove up to the specified `maxNumItems` from the back of this
918 /// container. Optionally specify a `buffer` into which the items
919 /// removed from the container are loaded. If `buffer` is non-null, the
920 /// removed items are appended to it as if by repeated application of
921 /// `buffer->push_back(popBack())` while the container is not empty and `maxNumItems` have not yet been removed.
922 ///
923 /// \note Note that the ordering of
924 /// the items in `*buffer` after the call is the reverse of the ordering
925 /// they had in the deque. Also note that `*buffer` is not cleared --
926 /// the popped items are appended after any pre-existing contents.
927 ///
928 /// Also note that to transfer the entire contents of a `Deque` `d` to a
929 /// vector `v`, use `d.removeAll(&v);`.
930 void tryPopBack(size_type maxNumItems);
931 void tryPopBack(size_type maxNumItems,
932 bsl::vector<TYPE> *buffer);
933 void tryPopBack(size_type maxNumItems,
934 std::vector<TYPE> *buffer);
935#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
936 void tryPopBack(size_type maxNumItems,
937 std::pmr::vector<TYPE> *buffer);
938#endif
939
940 /// If this container is non-empty, remove the first item, load that
941 /// item into the specified `*item`, and return 0 indicating success.
942 /// If this container is empty, return a non-zero value with no effect
943 /// on `*item` or the state of this container.
944 int tryPopFront(TYPE *item);
945
946 /// Remove up to the specified `maxNumItems` from the front of this
947 /// container. Optionally specify a `buffer` into which the items
948 /// removed from the container are appended. If `buffer` is non-null,
949 /// the removed items are appended to it as if by repeated application
950 /// of `buffer->push_back(popFront())` while the const is not empty and `maxNumItems` have not yet been removed.
951 ///
952 /// \note Note that `*buffer` is not
953 /// cleared -- the popped items are appended after any pre-existing
954 /// contents.
955 ///
956 /// Also note that to transfer the entire contents of a `Deque` `d` to a
957 /// vector `v`, use `d.removeAll(&v);`.
958 void tryPopFront(size_type maxNumItems);
959 void tryPopFront(size_type maxNumItems,
960 bsl::vector<TYPE> *buffer);
961 void tryPopFront(size_type maxNumItems,
962 std::vector<TYPE> *buffer);
963#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
964 void tryPopFront(size_type maxNumItems,
965 std::pmr::vector<TYPE> *buffer);
966#endif
967
968 /// If the container is not full (see {`High-Water Mark` Feature}),
969 /// append the specified `item` to the back of the container, otherwise
970 /// leave the container unchanged. Return 0 if the container was
971 /// updated and a non-zero value otherwise.
972 int tryPushBack(const TYPE& item);
973
974 /// If the container is not full (see {`High-Water Mark` Feature}),
975 /// append the specified move-insertable `item` to the back of the
976 /// container, otherwise leave the container unchanged. If the
977 /// container is modified, `item` is left in a valid but unspecified
978 /// state, otherwise `item` is unchanged. Return 0 if the container was
979 /// updated and a non-zero value otherwise.
981
982 /// Push as many of the items in the specified range `[begin .. end)` as
983 /// there is space available for (see {`High-Water Mark` Feature}) to
984 /// the back of the container, stopping if the container high-water mark is reached. Return the number of items pushed.
985 ///
986 /// \note Note that the items
987 /// in the range are treated as `const` objects, copied without being
988 /// modified.
989 template <class INPUT_ITER>
990 size_type tryPushBack(INPUT_ITER begin,
991 INPUT_ITER end);
992
993 /// If the container is not full (see {`High-Water Mark` Feature}),
994 /// append the specified `item` to the front of the container, otherwise
995 /// leave the container unchanged. Return 0 if the container was
996 /// updated and a non-zero value otherwise.
997 int tryPushFront(const TYPE& item);
998
999 /// If the container is not full (see {`High-Water Mark` Feature}),
1000 /// append the specified move-insertable `item` to the front of the
1001 /// container, otherwise leave the container unchanged. If the
1002 /// container is modified, `item` is left in a valid but unspecified
1003 /// state, otherwise `item` is unchanged. Return 0 if the container was
1004 /// updated and a non-zero value otherwise.
1006
1007 /// Push as many of the items in the specified range `[begin .. end)` as
1008 /// there is space available for (see {`High-Water Mark` Feature}) to
1009 /// the front of the container, stopping if the container high-water mark is reached. Return the number of items pushed.
1010 ///
1011 /// \note Note that the
1012 /// pushed items will be in the container in the reverse of the order in
1013 /// which they occur in the range. Also note that the items in the
1014 /// range are treated as `const` objects, copied without being modified.
1015 template <class INPUT_ITER>
1016 size_type tryPushFront(INPUT_ITER begin,
1017 INPUT_ITER end);
1018
1019 // ACCESSORS
1020
1021 /// Return the allocator used by this container for allocating memory.
1022 bslma::Allocator *allocator() const;
1023
1024 /// Return the system clock type used for timing `timed*` operations on
1025 /// this object (see {Supported Clock-Types} in the component
1026 /// documentation).
1028
1029 /// Return the high-water mark value for this container.
1030 size_type highWaterMark() const;
1031
1032 /// Return the number of elements contained in this container.
1033 ///
1034 /// \note Note that this method temporarily acquires the mutex, so that this method
1035 /// must not be called while a proctor in the same thread has this
1036 /// container locked, and the value returned is potentially obsolete
1037 /// before it is returned if any other threads are simultaneously
1038 /// modifying this container. To find the length while a proctor has
1039 /// the container locked, call `proctor->size()`.
1040 size_type length() const;
1041};
1042
1043/// This private `class` is used to manage a `bsl::deque`, during the course of
1044/// an operation by a `bdlcc::Deque`. Because it has a `release` method, it is
1045/// actually a proctor, but we call it a `guard` to avoid having clients
1046/// confuse it with this component's `Proctor` and `ConstProctor` types. A
1047/// `deque` that is being managed may only grow, and only on one end or the
1048/// other. If a throw happens during the course of the operation and this
1049/// guard's destructor is called while still managing the object, it will
1050/// restore the managed object to its initial state via operations that are
1051/// guaranteed not to throw.
1052template <class TYPE>
1054
1055 // PRIVATE TYPES
1057 typedef typename MonoDeque::size_type size_type;
1058 typedef typename MonoDeque::const_iterator MDCIter;
1059
1060 // DATA
1061 MonoDeque *d_monoDeque_p;
1062 const MDCIter d_mdBegin;
1063 const MDCIter d_mdEnd;
1064 const bool d_mdWasEmpty;
1065
1066 private:
1067 // NOT IMPLEMENTED
1069 DequeThrowGuard& operator=(const DequeThrowGuard&);
1070
1071 public:
1072 // CREATORS
1073
1074 /// Create a `Deque_DequeThrowGuard` object that will manage the specified `*monoDeque_p`.
1075 ///
1076 /// \pre The behavior is undefined if
1077 /// `0 == monoDeque_p`.
1078 explicit
1079 DequeThrowGuard(MonoDeque *monoDeque_p);
1080
1081 /// If a `MonoDeque` is being managed by this `ThrowGuard`, restore it
1082 /// to the state it was in when this object was created.
1084
1085 // MANIPULATOR
1086
1087 /// Release the monitored `MonoDeque` from management by this
1088 /// `Deque_DequeThrowGuard` object.
1089 void release();
1090};
1091
1092/// This private `class` is used to manage one `vector` object during the
1093/// course of an operation by a `bdlcc::Deque`. Because it has a `release`
1094/// method, it is actually a proctor, but we call it a `guard` to avoid having
1095/// clients confuse it with the `Proctor` and `ConstProctor` types. The vector
1096/// may only grow by having objects appended to it. If a throw happens during
1097/// the course of the operation and the guard's destructor is called while
1098/// still managing the object, it will restore the managed object to its
1099/// initial state via operations that are guaranteed not to throw.
1100template <class TYPE>
1101template <class VECTOR>
1102class Deque<TYPE>::VectorThrowGuard {
1103
1104 // PRIVATE TYPES
1105 typedef typename VECTOR::size_type VSize;
1106
1107 // DATA
1108 VECTOR *d_vector_p;
1109 const VSize d_vSize;
1110
1111 private:
1112 // NOT IMPLEMENTED
1113 VectorThrowGuard(const VectorThrowGuard&);
1114 VectorThrowGuard& operator=(const VectorThrowGuard&);
1115
1116 public:
1117 // CREATORS
1118
1119 /// Create a `VectorThrowGuard` object that will manage the specified `*vector_p`.
1120 ///
1121 /// \note Note that the case where `0 == vector_p` is explicitly
1122 /// permitted, in which case this object will not manage anything.
1123 explicit
1124 VectorThrowGuard(VECTOR *vector_p);
1125
1126 /// If a `vector` is being managed by this `VectorThrowGuard`, restore
1127 /// it to the state it was in when this object was created.
1128 ~VectorThrowGuard();
1129
1130 // MANIPULATOR
1131
1132 /// Release the monitored `vector` from management by this
1133 /// `VectorThrowGuard` object.
1134 void release();
1135};
1136
1137/// This `struct` has a `value` that evaluates to `true` if the specified
1138/// `VECTOR` is a `bsl`, `std`, or `std::pmr` `vector<VALUE>`.
1139template <class TYPE>
1140template <class VECTOR>
1141struct Deque<TYPE>::IsVector {
1142
1143 static const bool value =
1144 bsl::is_same<bsl::vector<TYPE>, VECTOR>::value
1145#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1146 || bsl::is_same<std::pmr::vector<TYPE>, VECTOR>::value
1147#endif
1148 || bsl::is_same<std::vector<TYPE>, VECTOR>::value;
1149};
1150
1151 // ====================
1152 // class Deque::Proctor
1153 // ====================
1154
1155/// This class defines a proctor type that provides direct access to the
1156/// underlying `bsl::deque` contained in a `Deque`. Creation of a `Proctor`
1157/// object locks the mutex of the `Deque`, and destruction unlocks it.
1158template <class TYPE>
1159class Deque<TYPE>::Proctor {
1160
1161 // PRIVATE TYPES
1163 typedef typename MonoDeque::size_type size_type;
1164
1165 // DATA
1166 Deque<TYPE> *d_container_p;
1167 size_type d_startLength; // If '!d_container_p', this field may
1168 // be left uninitialized.
1169
1170 private:
1171 // NOT IMPLEMENTED
1172 Proctor(const Proctor&);
1173 Proctor& operator=(const Proctor&);
1174
1175 public:
1176 // CREATORS
1177
1178 /// Create a `Proctor` object to provide access to the underlying
1179 /// `bsl::deque` contained in the optionally specified `*container`,
1180 /// locking `container`s mutex. If no `container` is specified, this
1181 /// object will be null.
1182 explicit
1183 Proctor(Deque<TYPE> *container = 0);
1184
1185 /// Release the lock on the mutex of the `Deque` that was provided at
1186 /// contstuction and destroy this `Proctor` object. Signal the conditions
1187 /// on the `Deque` that was supplied to this object at construction to
1188 /// reflect any changes that have been made to its contents since
1189 /// construction.
1190 ~Proctor();
1191
1192 // MANIPULATORS
1193
1194 /// In the case where this `Proctor` has been released, attach this
1195 /// object to the specified `container`. If this object is already
1196 /// attached, release the previous object first.
1197 ///
1198 /// \pre The behavior is undefined if `0 == container`.
1199 void load(Deque<TYPE> *container);
1200
1201 /// Release this proctor without destroying it. Afterward the
1202 /// destructor will have no effect. This may be called multiple times;
1203 /// only the first call has any effect.
1204 void release();
1205
1206 // ACCESSORS
1207
1208 /// Return a pointer to the `bsl::deque` contained in the `Deque` managed by this `Proctor` object'.
1209 ///
1210 /// \pre The behavior is undefined if
1211 /// this `Proctor` has been released.
1212 MonoDeque *operator->() const;
1213
1214 /// Return a reference to the `bsl::deque` managed by this `Proctor` object.
1215 ///
1216 /// \pre The behavior is undefined if this `Proctor` has been
1217 /// released.
1218 MonoDeque& operator*() const;
1219
1220 /// Return a reference providing modifiable access to the element at the
1221 /// specified `position` in the `bsl::deque` held by this proctor.
1222 ///
1223 /// \pre The behavior is undefined unless `position < size` where `size` is the
1224 /// the number of elements in that deque.
1225 TYPE& operator[](typename MonoDeque::size_type position) const;
1226
1227 /// Return `true` if this object is not associated with a `Deque` object.
1228 bool isNull() const;
1229};
1230
1231 // =========================
1232 // class Deque::ConstProctor
1233 // =========================
1234
1235/// This class defines a proctor type that provides direct const access to the
1236/// underlying `bsl::deque` contained in a `Deque`.
1237template <class TYPE>
1238class Deque<TYPE>::ConstProctor {
1239
1240 // PRIVATE TYPES
1242 typedef typename MonoDeque::size_type size_type;
1243
1244 // DATA
1245 const Deque<TYPE> *d_container_p;
1246 size_type d_startLength; // If '!d_container_p', this field may
1247 // be left uninitialized.
1248
1249 private:
1250 // NOT IMPLEMENTED
1251 ConstProctor(const ConstProctor&);
1252 ConstProctor& operator=(const ConstProctor&);
1253
1254 public:
1255 // CREATORS
1256
1257 /// Create a `ConstProctor` object to provide const access to the
1258 /// underlying `bsl::deque` contained in the optionally specified
1259 /// `*container`, locking `container`s mutex. If no `container` is
1260 /// specified, this object will be null.
1261 explicit
1262 ConstProctor(const Deque<TYPE> *container = 0);
1263
1264 /// Release the lock on the mutex of the `Deque` that was provided at
1265 /// contstuction and destroy this `Proctor` object.
1266 ///
1267 /// \pre The behavior is undefined if the `Deque` has been modified since the construction of
1268 /// this object.
1269 ~ConstProctor();
1270
1271 // MANIPULATORS
1272
1273 /// In the case where this `Proctor` has been released, attach this
1274 /// object to the specified `container`. If this object is already
1275 /// attached, release the previous object first.
1276 ///
1277 /// \pre The behavior is undefined if `0 == container`.
1278 void load(const Deque<TYPE> *container);
1279
1280 /// Release this proctor without destroying it. Afterward the
1281 /// destructor will have no effect. This may be called multiple times;
1282 /// only the first call has any effect;
1283 void release();
1284
1285 // ACCESSORS
1286
1287 /// Return a pointer to the `bsl::deque` contained in the `Deque` managed by this object.
1288 ///
1289 /// \pre The behavior is undefined if this
1290 /// `ConstProctor` has been released.
1291 const MonoDeque *operator->() const;
1292
1293 /// Return a reference to the `bsl::deque` managed by this `Proctor` object.
1294 ///
1295 /// \pre The behavior is undefined if this `ConstProctor` has been
1296 /// released.
1297 const MonoDeque& operator*() const;
1298
1299 /// Return a reference providing non-modifiable access to the element at
1300 /// the specified `position` in the `bsl::deque` held by this proctor.
1301 ///
1302 /// \pre The behavior is undefined unless `position < size` where `size` is
1303 /// the number of elements in that deque.
1304 const TYPE& operator[](size_type position) const;
1305
1306 /// Return `true` if this object is not associated with a `Deque`
1307 /// object.
1308 bool isNull() const;
1309};
1310
1311// ============================================================================
1312// INLINE DEFINITIONS
1313// ============================================================================
1314
1315 // ---------------------
1316 // bdlcc::Deque::Proctor
1317 // ---------------------
1318
1319// CREATORS
1320template <class TYPE>
1321inline
1323: d_container_p(0)
1324, d_startLength(0)
1325{
1326 if (container) {
1327 this->load(container);
1328 }
1329}
1330
1331template <class TYPE>
1332inline
1334{
1335 this->release();
1336}
1337
1338// MANIPULATORS
1339template <class TYPE>
1340inline
1342{
1343 BSLS_ASSERT(0 != container);
1344
1345 if (0 != d_container_p) {
1346 this->release();
1347 }
1348
1349 container->d_mutex.lock();
1350 d_container_p = container;
1351 d_startLength = d_container_p->d_monoDeque.size();
1352}
1353
1354template <class TYPE>
1356{
1357 if (0 == d_container_p) {
1358 return; // RETURN
1359 }
1360
1361 const size_type sz = d_container_p->d_monoDeque.size();
1362 size_type ii = d_startLength;
1363
1364 d_container_p->d_mutex.unlock();
1365
1366 if (ii < sz) {
1367 do {
1368 d_container_p->d_notEmptyCondition.signal();
1369 } while (++ii < sz);
1370 }
1371 else {
1372 if (d_container_p->d_highWaterMark < ii) {
1373 ii = d_container_p->d_highWaterMark;
1374 }
1375 for (; ii > sz; --ii) {
1376 d_container_p->d_notFullCondition.signal();
1377 }
1378 }
1379
1380 d_container_p = 0;
1381}
1382
1383// ACCESSORS
1384template <class TYPE>
1385inline
1387{
1388 BSLS_ASSERT(d_container_p);
1389
1390 return &d_container_p->d_monoDeque;
1391}
1392
1393template <class TYPE>
1394inline
1396{
1397 BSLS_ASSERT(d_container_p);
1398
1399 return d_container_p->d_monoDeque;
1400}
1401
1402template <class TYPE>
1403inline
1404TYPE& Deque<TYPE>::Proctor::operator[](size_type position) const
1405{
1406 BSLS_ASSERT(position < d_container_p->d_monoDeque.size());
1407
1408 return d_container_p->d_monoDeque[position];
1409}
1410
1411template <class TYPE>
1412inline
1414{
1415 return 0 == d_container_p;
1416}
1417
1418 // --------------------------
1419 // bdlcc::Deque::ConstProctor
1420 // --------------------------
1421
1422
1423// CREATORS
1424template <class TYPE>
1425inline
1427: d_container_p(0)
1428, d_startLength(0)
1429{
1430 if (container) {
1431 this->load(container);
1432 }
1433}
1434
1435template <class TYPE>
1436inline
1438{
1439 this->release();
1440}
1441
1442// MANIPULATORS
1443template <class TYPE>
1444inline
1446{
1447 BSLS_ASSERT(0 != container);
1448
1449 this->release();
1450
1451 container->d_mutex.lock();
1452 d_container_p = container;
1453 d_startLength = d_container_p->d_monoDeque.size();
1454}
1455
1456template <class TYPE>
1457inline
1459{
1460 // It is important that nobody did a const_cast and modified the underlying
1461 // 'bsls::deque' since this destructor won't signal the appropriate
1462 // condtions in the 'Deque' in that case. If they wanted to modify the
1463 // 'bsl::deque' they should have used a 'Proctor' instead of a
1464 // 'ConstProctor'.
1465
1466 if (0 == d_container_p) {
1467 return; // RETURN
1468 }
1469
1470 BSLS_ASSERT_OPT(d_container_p->d_monoDeque.size() == d_startLength &&
1471 "Underlying 'bsl::deque' modified through ConstProcter.");
1472
1473 bslmt::Mutex *mutex = &d_container_p->d_mutex;
1474 d_container_p = 0;
1475 mutex->unlock();
1476}
1477
1478// ACCESSORS
1479template <class TYPE>
1480inline
1482{
1483 BSLS_ASSERT(d_container_p);
1484
1485 return &d_container_p->d_monoDeque;
1486}
1487
1488template <class TYPE>
1489inline
1491{
1492 BSLS_ASSERT(d_container_p);
1493
1494 return d_container_p->d_monoDeque;
1495}
1496
1497template <class TYPE>
1498inline
1499const TYPE& Deque<TYPE>::ConstProctor::operator[](size_type position) const
1500{
1501 BSLS_ASSERT(position < d_container_p->d_monoDeque.size());
1502
1503 return d_container_p->d_monoDeque[position];
1504}
1505
1506template <class TYPE>
1507inline
1509{
1510 return 0 == d_container_p;
1511}
1512
1513 // -----------------------------------
1514 // bdlcc::Deque<TYPE>::DequeThrowGuard
1515 // -----------------------------------
1516
1517// CREATORS
1518template <class TYPE>
1519inline
1521: d_monoDeque_p(monoDeque_p)
1522, d_mdBegin( monoDeque_p->cbegin())
1523, d_mdEnd( monoDeque_p->cend())
1524, d_mdWasEmpty(monoDeque_p->empty())
1525{
1526 BSLS_ASSERT(0 != monoDeque_p);
1527}
1528
1529template <class TYPE>
1530inline
1532{
1533 if (d_monoDeque_p) {
1534 if (d_mdWasEmpty) {
1535 // In the case where the mono deque started out empty, pushing to
1536 // it can invalidate the iterators that were copied to 'd_mdBegin'
1537 // and 'd_mdEnd' when it was empty, so comparisons between
1538 // 'newBegin' & 'newEnd' and the old iterators will yield undefined
1539 // results. So we kept a separate boolean, 'd_mdWasEmpty', to
1540 // track that case, which we handle specially here.
1541
1542 d_monoDeque_p->clear();
1543
1544 return; // RETURN
1545 }
1546
1547 const MDCIter newBegin = d_monoDeque_p->cbegin();
1548 const MDCIter newEnd = d_monoDeque_p->cend();
1549
1550 // While range-based 'erase' of 'bsl::deque' does not always provide
1551 // the no-throw guarantee, all the erasing here is done at the ends of
1552 // the 'bsl::deque', so no items have to be copied around, so no
1553 // throwing should occur.
1554
1555 // The 'MonoDeque' may have been pushed to, but only on one end or the
1556 // other. It should never have been deleted from.
1557
1558 if (newBegin < d_mdBegin) {
1559 BSLS_ASSERT(d_mdEnd == newEnd);
1560
1561 d_monoDeque_p->erase(newBegin, d_mdBegin);
1562 }
1563 else {
1564 BSLS_ASSERT(newBegin == d_mdBegin);
1565
1566 if (d_mdEnd < newEnd) {
1567 d_monoDeque_p->erase(d_mdEnd, newEnd);
1568 }
1569 else {
1570 BSLS_ASSERT(d_mdEnd == newEnd);
1571 }
1572 }
1573 }
1574}
1575
1576// MANIPULATOR
1577template <class TYPE>
1578inline
1580{
1581 d_monoDeque_p = 0;
1582}
1583
1584 // --------------------------------------------
1585 // bdlcc::Deque<TYPE>::VectorThrowGuard<VECTOR>
1586 // --------------------------------------------
1587
1588// CREATORS
1589template <class TYPE>
1590template <class VECTOR>
1591inline
1593: d_vector_p(vector_p)
1594, d_vSize(vector_p ? vector_p->size() : 0)
1595{
1596}
1597
1598template <class TYPE>
1599template <class VECTOR>
1600inline
1602{
1603 if (d_vector_p) {
1604 const VSize newSize = d_vector_p->size();
1605
1606 // While 'vector::resize' does not always provide the no-throw
1607 // guarantee, here we are always shrinking the vector, so it should not
1608 // throw.
1609
1610 // The vector may have grown, it should never have been shrunk.
1611
1612 if (d_vSize < newSize) {
1613 d_vector_p->resize(d_vSize);
1614 }
1615 else {
1616 BSLS_ASSERT(d_vSize == newSize);
1617 }
1618 }
1619}
1620
1621// MANIPULATOR
1622template <class TYPE>
1623template <class VECTOR>
1624inline
1625void Deque<TYPE>::VectorThrowGuard<VECTOR>::release()
1626{
1627 d_vector_p = 0;
1628}
1629
1630 // ------------
1631 // bdlcc::Deque
1632 // ------------
1633
1634// PRIVATE MANIPULATORS
1635template <class TYPE>
1636template <class VECTOR>
1637inline
1638void Deque<TYPE>::removeAllImp(VECTOR *buffer)
1639{
1640 BSLMF_ASSERT(IsVector<VECTOR>::value);
1641
1642 Proctor proctor(this);
1643
1644 VectorThrowGuard<VECTOR> tg(buffer);
1645
1646 if (buffer) {
1647 const size_type size = d_monoDeque.size();
1648 buffer->reserve(buffer->size() + size);
1649
1650 for (size_type ii = 0; ii < size; ++ii) {
1651 buffer->push_back(bslmf::MovableRefUtil::move(d_monoDeque[ii]));
1652 }
1653 }
1654
1655 proctor->clear();
1656
1657 tg.release();
1658}
1659
1660
1661template <class TYPE>
1662template <class VECTOR>
1664 VECTOR *buffer)
1665{
1666 BSLMF_ASSERT(IsVector<VECTOR>::value);
1667
1668 Proctor proctor(this);
1669 VectorThrowGuard<VECTOR> tg(buffer);
1670
1671 // First, calculate 'toMove', which drives how the rest of the function
1672 // behaves.
1673
1674 const size_type size = d_monoDeque.size();
1675 const size_type toMove = bsl::min(size, maxNumItems);
1676
1677 if (buffer) {
1678 buffer->reserve(buffer->size() + toMove);
1679
1680 const size_type lastMovedIdx = size - toMove;
1681 for (size_type ii = size; lastMovedIdx < ii--; ) {
1682 buffer->push_back(bslmf::MovableRefUtil::move(d_monoDeque[ii]));
1683 }
1684 }
1685 d_monoDeque.erase(d_monoDeque.end() - toMove, d_monoDeque.end());
1686
1687 tg.release();
1688
1689 // Signalling will happen automatically when proctor is destroyed.
1690}
1691
1692template <class TYPE>
1693template <class VECTOR>
1695 VECTOR *buffer)
1696{
1697 BSLMF_ASSERT(IsVector<VECTOR>::value);
1698
1699 typedef typename MonoDeque::iterator Iterator;
1700
1701 Proctor proctor(this);
1702 VectorThrowGuard<VECTOR> tg(buffer);
1703
1704 // First, calculate 'toMove', which drives how the rest of the function
1705 // behaves.
1706
1707 const size_type toMove = bsl::min(d_monoDeque.size(), maxNumItems);
1708 const Iterator beginRange = d_monoDeque.begin();
1709 const Iterator endRange = beginRange + toMove;
1710
1711 if (buffer) {
1712 buffer->reserve(buffer->size() + toMove);
1713
1714 for (size_type ii = 0; ii < toMove; ++ii) {
1715 buffer->push_back(bslmf::MovableRefUtil::move(d_monoDeque[ii]));
1716 }
1717 }
1718 proctor->erase(beginRange, endRange);
1719
1720 tg.release();
1721
1722 // Signalling will happen automatically when proctor is destroyed.
1723}
1724
1725// CLASS METHODS
1726template <class TYPE>
1727inline
1729{
1730 return bsl::numeric_limits<size_type>::max();
1731}
1732
1733// CREATORS
1734template <class TYPE>
1735inline
1737: d_mutex()
1738, d_notEmptyCondition()
1739, d_notFullCondition()
1740, d_monoDeque(basicAllocator)
1741, d_highWaterMark(maxSizeT())
1742, d_clockType(bsls::SystemClockType::e_REALTIME)
1743{
1744}
1745
1746template <class TYPE>
1747inline
1749 bslma::Allocator *basicAllocator)
1750: d_mutex()
1751, d_notEmptyCondition(clockType)
1752, d_notFullCondition(clockType)
1753, d_monoDeque(basicAllocator)
1754, d_highWaterMark(maxSizeT())
1755, d_clockType(clockType)
1756{
1757}
1758
1759template <class TYPE>
1760inline
1761Deque<TYPE>::Deque(bsl::size_t highWaterMark,
1762 bslma::Allocator *basicAllocator)
1763: d_mutex()
1764, d_notEmptyCondition()
1765, d_notFullCondition()
1766, d_monoDeque(basicAllocator)
1767, d_highWaterMark(highWaterMark)
1768, d_clockType(bsls::SystemClockType::e_REALTIME)
1769{
1771}
1772
1773template <class TYPE>
1774inline
1775Deque<TYPE>::Deque(bsl::size_t highWaterMark,
1777 bslma::Allocator *basicAllocator)
1778: d_mutex()
1779, d_notEmptyCondition(clockType)
1780, d_notFullCondition(clockType)
1781, d_monoDeque(basicAllocator)
1782, d_highWaterMark(highWaterMark)
1783, d_clockType(clockType)
1784{
1786}
1787
1788template <class TYPE>
1789template <class INPUT_ITER>
1790inline
1791Deque<TYPE>::Deque(INPUT_ITER begin,
1792 INPUT_ITER end,
1793 bslma::Allocator *basicAllocator)
1794: d_mutex()
1795, d_notEmptyCondition()
1796, d_notFullCondition()
1797, d_monoDeque(begin, end, basicAllocator)
1798, d_highWaterMark(maxSizeT())
1799, d_clockType(bsls::SystemClockType::e_REALTIME)
1800{
1801}
1802
1803template <class TYPE>
1804template <class INPUT_ITER>
1805inline
1806Deque<TYPE>::Deque(INPUT_ITER begin,
1807 INPUT_ITER end,
1809 bslma::Allocator *basicAllocator)
1810: d_mutex()
1811, d_notEmptyCondition(clockType)
1812, d_notFullCondition(clockType)
1813, d_monoDeque(begin, end, basicAllocator)
1814, d_highWaterMark(maxSizeT())
1815, d_clockType(clockType)
1816{
1817}
1818
1819template <class TYPE>
1820template <class INPUT_ITER>
1821inline
1822Deque<TYPE>::Deque(INPUT_ITER begin,
1823 INPUT_ITER end,
1824 bsl::size_t highWaterMark,
1825 bslma::Allocator *basicAllocator)
1826: d_mutex()
1827, d_notEmptyCondition()
1828, d_notFullCondition()
1829, d_monoDeque(begin, end, basicAllocator)
1830, d_highWaterMark(highWaterMark)
1831, d_clockType(bsls::SystemClockType::e_REALTIME)
1832{
1834}
1835
1836template <class TYPE>
1837template <class INPUT_ITER>
1838inline
1839Deque<TYPE>::Deque(INPUT_ITER begin,
1840 INPUT_ITER end,
1841 bsl::size_t highWaterMark,
1843 bslma::Allocator *basicAllocator)
1844: d_mutex()
1845, d_notEmptyCondition(clockType)
1846, d_notFullCondition(clockType)
1847, d_monoDeque(begin, end, basicAllocator)
1848, d_highWaterMark(highWaterMark)
1849, d_clockType(clockType)
1850{
1852}
1853
1854template <class TYPE>
1855inline
1857 bslma::Allocator *basicAllocator)
1858: d_mutex()
1859, d_notEmptyCondition()
1860, d_notFullCondition()
1861, d_monoDeque(basicAllocator)
1862, d_highWaterMark(maxSizeT())
1863, d_clockType(original.d_clockType)
1864{
1865 ConstProctor proctor(&original);
1866
1867 d_monoDeque.insert(d_monoDeque.end(), proctor->begin(), proctor->end());
1868}
1869
1870template <class TYPE>
1871inline
1875
1876// MANIPULATORS
1877template <class TYPE>
1878inline
1879void Deque<TYPE>::forcePushBack(const TYPE& item)
1880{
1881 {
1882 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1883
1884 d_monoDeque.push_back(item);
1885 }
1886
1887 d_notEmptyCondition.signal();
1888}
1889
1890template <class TYPE>
1891inline
1893{
1894 {
1895 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1896
1897 d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
1898 }
1899
1900 d_notEmptyCondition.signal();
1901}
1902
1903template <class TYPE>
1904template <class INPUT_ITER>
1905inline
1906void Deque<TYPE>::forcePushBack(INPUT_ITER begin,
1907 INPUT_ITER end)
1908{
1909 size_type growth;
1910 {
1911 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1912
1913 DequeThrowGuard tg(&d_monoDeque);
1914
1915 const size_type initialSize = d_monoDeque.size();
1916 d_monoDeque.insert(d_monoDeque.end(), begin, end);
1917 growth = d_monoDeque.size() - initialSize;
1918
1919 tg.release();
1920 }
1921
1922 for (; growth > 0; --growth) {
1923 d_notEmptyCondition.signal();
1924 }
1925}
1926
1927template <class TYPE>
1928inline
1929void Deque<TYPE>::forcePushFront(const TYPE& item)
1930{
1931 {
1932 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1933
1934 d_monoDeque.push_front(item);
1935 }
1936
1937 d_notEmptyCondition.signal();
1938}
1939
1940template <class TYPE>
1941inline
1943{
1944 {
1945 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1946
1947 d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
1948 }
1949
1950 d_notEmptyCondition.signal();
1951}
1952
1953template <class TYPE>
1954template <class INPUT_ITER>
1955inline
1956void Deque<TYPE>::forcePushFront(INPUT_ITER begin,
1957 INPUT_ITER end)
1958{
1959 size_type growth;
1960 {
1961 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1962
1963 DequeThrowGuard tg(&d_monoDeque);
1964
1965 const size_type initialSize = d_monoDeque.size();
1966 for (; end != begin; ++begin) {
1967 d_monoDeque.push_front(*begin);
1968 }
1969 growth = d_monoDeque.size() - initialSize;
1970
1971 tg.release();
1972 }
1973
1974 for (; growth > 0; --growth) {
1975 d_notEmptyCondition.signal();
1976 }
1977}
1978
1979template <class TYPE>
1981{
1982 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1983
1984 while (d_monoDeque.empty()) {
1985 d_notEmptyCondition.wait(&d_mutex);
1986 }
1987 TYPE ret(bslmf::MovableRefUtil::move(d_monoDeque.back()));
1988 d_monoDeque.pop_back();
1989
1990 const bool shouldSignal = d_monoDeque.size() < d_highWaterMark;
1991 lock.release()->unlock();
1992
1993 if (shouldSignal) {
1994 d_notFullCondition.signal();
1995 }
1996
1997 return ret;
1998}
1999
2000template <class TYPE>
2001void Deque<TYPE>::popBack(TYPE *item)
2002{
2003 bool shouldSignal;
2004
2005 {
2006 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2007
2008 while (d_monoDeque.empty()) {
2009 d_notEmptyCondition.wait(&d_mutex);
2010 }
2011
2012#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
2013 *item = bslmf::MovableRefUtil::move(d_monoDeque.back());
2014#else
2015 *item = d_monoDeque.back();
2016#endif
2017 d_monoDeque.pop_back();
2018 shouldSignal = d_monoDeque.size() < d_highWaterMark;
2019 }
2020
2021 if (shouldSignal) {
2022 d_notFullCondition.signal();
2023 }
2024}
2025
2026template <class TYPE>
2028{
2029 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2030
2031 while (d_monoDeque.empty()) {
2032 d_notEmptyCondition.wait(&d_mutex);
2033 }
2034 TYPE ret(bslmf::MovableRefUtil::move(d_monoDeque.front()));
2035 d_monoDeque.pop_front();
2036
2037 const bool shouldSignal = d_monoDeque.size() < d_highWaterMark;
2038 lock.release()->unlock();
2039
2040 if (shouldSignal) {
2041 d_notFullCondition.signal();
2042 }
2043
2044 return ret;
2045}
2046
2047template <class TYPE>
2049{
2050 bool shouldSignal;
2051 {
2052 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2053
2054 while (d_monoDeque.empty()) {
2055 d_notEmptyCondition.wait(&d_mutex);
2056 }
2057#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
2058 *item = bslmf::MovableRefUtil::move(d_monoDeque.front());
2059#else
2060 *item = d_monoDeque.front();
2061#endif
2062 d_monoDeque.pop_front();
2063
2064 shouldSignal = d_monoDeque.size() < d_highWaterMark;
2065 }
2066
2067 if (shouldSignal) {
2068 d_notFullCondition.signal();
2069 }
2070}
2071
2072template <class TYPE>
2073void Deque<TYPE>::pushBack(const TYPE& item)
2074{
2075 {
2076 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2077
2078 while (d_monoDeque.size() >= d_highWaterMark) {
2079 d_notFullCondition.wait(&d_mutex);
2080 }
2081 d_monoDeque.push_back(item);
2082 }
2083
2084 d_notEmptyCondition.signal();
2085}
2086
2087template <class TYPE>
2089{
2090 {
2091 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2092
2093 while (d_monoDeque.size() >= d_highWaterMark) {
2094 d_notFullCondition.wait(&d_mutex);
2095 }
2096 d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
2097 }
2098
2099 d_notEmptyCondition.signal();
2100}
2101
2102template <class TYPE>
2103void Deque<TYPE>::pushFront(const TYPE& item)
2104{
2105 {
2106 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2107
2108 while (d_monoDeque.size() >= d_highWaterMark) {
2109 d_notFullCondition.wait(&d_mutex);
2110 }
2111 d_monoDeque.push_front(item);
2112 }
2113
2114 d_notEmptyCondition.signal();
2115}
2116
2117template <class TYPE>
2119{
2120 {
2121 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2122
2123 while (d_monoDeque.size() >= d_highWaterMark) {
2124 d_notFullCondition.wait(&d_mutex);
2125 }
2126 d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
2127 }
2128
2129 d_notEmptyCondition.signal();
2130}
2131
2132template <class TYPE>
2133inline
2135{
2136 removeAllImp(static_cast<bsl::vector<TYPE> *>(0));
2137}
2138
2139template <class TYPE>
2140inline
2142{
2143 removeAllImp(buffer);
2144}
2145
2146template <class TYPE>
2147inline
2148void Deque<TYPE>::removeAll(std::vector<TYPE> *buffer)
2149{
2150 removeAllImp(buffer);
2151}
2152
2153#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
2154template <class TYPE>
2155inline
2156void Deque<TYPE>::removeAll(std::pmr::vector<TYPE> *buffer)
2157{
2158 removeAllImp(buffer);
2159}
2160#endif
2161
2162template <class TYPE>
2164 const bsls::TimeInterval& timeout)
2165{
2166 bool shouldSignal;
2167 {
2168 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2169
2170 while (d_monoDeque.empty()) {
2171 if (d_notEmptyCondition.timedWait(&d_mutex, timeout)) {
2172 return 1; // RETURN
2173 }
2174 }
2175#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
2176 *item = bslmf::MovableRefUtil::move(d_monoDeque.back());
2177#else
2178 *item = d_monoDeque.back();
2179#endif
2180 d_monoDeque.pop_back();
2181
2182 shouldSignal = d_monoDeque.size() < d_highWaterMark;
2183 }
2184
2185 if (shouldSignal) {
2186 d_notFullCondition.signal();
2187 }
2188
2189 return 0;
2190}
2191
2192template <class TYPE>
2194 const bsls::TimeInterval& timeout)
2195{
2196 bool shouldSignal;
2197 {
2198 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2199
2200 while (d_monoDeque.empty()) {
2201 if (d_notEmptyCondition.timedWait(&d_mutex, timeout)) {
2202 return 1; // RETURN
2203 }
2204 }
2205#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
2206 *item = bslmf::MovableRefUtil::move(d_monoDeque.front());
2207#else
2208 *item = d_monoDeque.front();
2209#endif
2210 d_monoDeque.pop_front();
2211
2212 shouldSignal = d_monoDeque.size() < d_highWaterMark;
2213 }
2214
2215 if (shouldSignal) {
2216 d_notFullCondition.signal();
2217 }
2218
2219 return 0;
2220}
2221
2222template <class TYPE>
2223int Deque<TYPE>::timedPushBack(const TYPE& item,
2224 const bsls::TimeInterval& timeout)
2225{
2226 {
2227 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2228
2229 while (d_monoDeque.size() >= d_highWaterMark) {
2230 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
2231 return 1; // RETURN
2232 }
2233 }
2234 d_monoDeque.push_back(item);
2235 }
2236
2237 d_notEmptyCondition.signal();
2238
2239 return 0;
2240}
2241
2242template <class TYPE>
2244 const bsls::TimeInterval& timeout)
2245{
2246 {
2247 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2248
2249 while (d_monoDeque.size() >= d_highWaterMark) {
2250 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
2251 return 1; // RETURN
2252 }
2253 }
2254 d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
2255 }
2256
2257 d_notEmptyCondition.signal();
2258
2259 return 0;
2260}
2261
2262template <class TYPE>
2263int Deque<TYPE>::timedPushFront(const TYPE& item,
2264 const bsls::TimeInterval &timeout)
2265{
2266 {
2267 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2268
2269 while (d_monoDeque.size() >= d_highWaterMark) {
2270 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
2271 return 1; // RETURN
2272 }
2273 }
2274 d_monoDeque.push_front(item);
2275 }
2276
2277 d_notEmptyCondition.signal();
2278
2279 return 0;
2280}
2281
2282template <class TYPE>
2284 const bsls::TimeInterval &timeout)
2285{
2286 {
2287 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2288
2289 while (d_monoDeque.size() >= d_highWaterMark) {
2290 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
2291 return 1; // RETURN
2292 }
2293 }
2294 d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
2295 }
2296
2297 d_notEmptyCondition.signal();
2298
2299 return 0;
2300}
2301
2302template <class TYPE>
2304{
2305 bool shouldSignal;
2306 {
2307 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2308
2309 if (d_monoDeque.empty()) {
2310 return 1; // RETURN
2311 }
2312#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
2313 *item = bslmf::MovableRefUtil::move(d_monoDeque.back());
2314#else
2315 *item = d_monoDeque.back();
2316#endif
2317 d_monoDeque.pop_back();
2318
2319 shouldSignal = d_monoDeque.size() < d_highWaterMark;
2320 }
2321
2322 if (shouldSignal) {
2323 d_notFullCondition.signal();
2324 }
2325
2326 return 0;
2327}
2328
2329template <class TYPE>
2330inline
2331void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type maxNumItems)
2332{
2333 tryPopBackImp(maxNumItems, static_cast<bsl::vector<TYPE> *>(0));
2334}
2335
2336template <class TYPE>
2337inline
2338void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type maxNumItems,
2339 bsl::vector<TYPE> *buffer)
2340{
2341 tryPopBackImp(maxNumItems, buffer);
2342}
2343
2344template <class TYPE>
2345inline
2346void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type maxNumItems,
2347 std::vector<TYPE> *buffer)
2348{
2349 tryPopBackImp(maxNumItems, buffer);
2350}
2351
2352#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
2353template <class TYPE>
2354inline
2355void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type maxNumItems,
2356 std::pmr::vector<TYPE> *buffer)
2357{
2358 tryPopBackImp(maxNumItems, buffer);
2359}
2360#endif
2361
2362template <class TYPE>
2364{
2365 bool shouldSignal;
2366 {
2367 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2368
2369 if (d_monoDeque.empty()) {
2370 return 1; // RETURN
2371 }
2372#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
2373 *item = bslmf::MovableRefUtil::move(d_monoDeque.front());
2374#else
2375 *item = d_monoDeque.front();
2376#endif
2377 d_monoDeque.pop_front();
2378
2379 shouldSignal = d_monoDeque.size() < d_highWaterMark;
2380 }
2381
2382 if (shouldSignal) {
2383 d_notFullCondition.signal();
2384 }
2385
2386 return 0;
2387}
2388
2389template <class TYPE>
2390void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type maxNumItems)
2391{
2392 tryPopFrontImp(maxNumItems, static_cast<bsl::vector<TYPE> *>(0));
2393}
2394
2395template <class TYPE>
2396void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type maxNumItems,
2397 bsl::vector<TYPE> *buffer)
2398{
2399 tryPopFrontImp(maxNumItems, buffer);
2400}
2401
2402template <class TYPE>
2403void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type maxNumItems,
2404 std::vector<TYPE> *buffer)
2405{
2406 tryPopFrontImp(maxNumItems, buffer);
2407}
2408
2409#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
2410template <class TYPE>
2411void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type maxNumItems,
2412 std::pmr::vector<TYPE> *buffer)
2413{
2414 tryPopFrontImp(maxNumItems, buffer);
2415}
2416#endif
2417
2418template <class TYPE>
2419int Deque<TYPE>::tryPushBack(const TYPE& item)
2420{
2421 {
2422 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2423
2424 if (d_monoDeque.size() >= d_highWaterMark) {
2425 return 1; // RETURN
2426 }
2427
2428 d_monoDeque.push_back(item);
2429 }
2430
2431 d_notEmptyCondition.signal();
2432
2433 return 0;
2434}
2435
2436template <class TYPE>
2438{
2439 {
2440 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2441
2442 if (d_monoDeque.size() >= d_highWaterMark) {
2443 return 1; // RETURN
2444 }
2445
2446 d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
2447 }
2448
2449 d_notEmptyCondition.signal();
2450
2451 return 0;
2452}
2453
2454template <class TYPE>
2455template <class INPUT_ITER>
2458 INPUT_ITER end)
2459{
2460 size_type growth;
2461 {
2462 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2463
2464 DequeThrowGuard tg(&d_monoDeque);
2465
2466 const size_type startLength = d_monoDeque.size();
2467 size_type length = startLength;
2468
2469 for (; length < d_highWaterMark && end != begin; ++length, ++begin) {
2470 d_monoDeque.push_back(*begin);
2471 }
2472
2473 tg.release();
2474
2475 growth = length - startLength;
2476 }
2477
2478 for (size_type ii = 0; ii < growth; ++ii) {
2479 d_notEmptyCondition.signal();
2480 }
2481
2482 return growth;
2483}
2484
2485template <class TYPE>
2486int Deque<TYPE>::tryPushFront(const TYPE& item)
2487{
2488 {
2489 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2490
2491 if (d_monoDeque.size() >= d_highWaterMark) {
2492 return 1; // RETURN
2493 }
2494
2495 d_monoDeque.push_front(item);
2496 }
2497
2498 d_notEmptyCondition.signal();
2499
2500 return 0;
2501}
2502
2503template <class TYPE>
2505{
2506 {
2507 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2508
2509 if (d_monoDeque.size() >= d_highWaterMark) {
2510 return 1; // RETURN
2511 }
2512
2513 d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
2514 }
2515
2516 d_notEmptyCondition.signal();
2517
2518 return 0;
2519}
2520
2521template <class TYPE>
2522template <class INPUT_ITER>
2525 INPUT_ITER end)
2526{
2527 size_type growth;
2528 {
2529 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2530
2531 DequeThrowGuard tg(&d_monoDeque);
2532
2533 const size_type startLength = d_monoDeque.size();
2534 size_type length = startLength;
2535
2536 for (; length < d_highWaterMark && end != begin; ++length, ++begin) {
2537 d_monoDeque.push_front(*begin);
2538 }
2539
2540 tg.release();
2541
2542 growth = length - startLength;
2543 }
2544
2545 for (size_type ii = 0; ii < growth; ++ii) {
2546 d_notEmptyCondition.signal();
2547 }
2548
2549 return growth;
2550}
2551
2552// ACCESSORS
2553template <class TYPE>
2554inline
2556{
2557 return d_monoDeque.get_allocator().mechanism();
2558}
2559
2560template <class TYPE>
2561inline
2563{
2564 return d_clockType;
2565}
2566
2567template <class TYPE>
2568inline
2570{
2571 // A mutex lock is unnecessary since we decided to make the high water mark
2572 // into a non-malleable property of this container.
2573 //
2574 // bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2575
2576 return d_highWaterMark;
2577}
2578
2579template <class TYPE>
2580inline
2582{
2583 // Note that it is VITAL to lock the mutex here. 'size' on a deque is a
2584 // potentially complex operation as the deque might be managing multiple
2585 // blocks of memory. If 'd_monoDeque' were being modified while we perform
2586 // the 'size' operation, we could potentially dereference pointers to
2587 // freed memory.
2588
2589 // The predessor to this component, @ref bcec_queue , originally had no
2590 // 'length' accessor, and we found that users were very, very frequently
2591 // accessing the underlying thread-unsafe container just to obtain the
2592 // length.
2593
2594 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2595
2596 return d_monoDeque.size();
2597}
2598
2599} // close package namespace
2600
2601namespace bslma {
2602
2603template <class TYPE>
2605{};
2606
2607} // close namespace bslma
2608
2609
2610#endif
2611
2612// ----------------------------------------------------------------------------
2613// Copyright 2018 Bloomberg Finance L.P.
2614//
2615// Licensed under the Apache License, Version 2.0 (the "License");
2616// you may not use this file except in compliance with the License.
2617// You may obtain a copy of the License at
2618//
2619// http://www.apache.org/licenses/LICENSE-2.0
2620//
2621// Unless required by applicable law or agreed to in writing, software
2622// distributed under the License is distributed on an "AS IS" BASIS,
2623// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2624// See the License for the specific language governing permissions and
2625// limitations under the License.
2626// ----------------------------- END-OF-FILE ----------------------------------
2627
2628/** @} */
2629/** @} */
2630/** @} */
Definition bdlcc_deque.h:1238
bool isNull() const
Definition bdlcc_deque.h:1508
void release()
Definition bdlcc_deque.h:1458
const MonoDeque & operator*() const
Definition bdlcc_deque.h:1490
void load(const Deque< TYPE > *container)
Definition bdlcc_deque.h:1445
const TYPE & operator[](size_type position) const
Definition bdlcc_deque.h:1499
const MonoDeque * operator->() const
Definition bdlcc_deque.h:1481
~ConstProctor()
Definition bdlcc_deque.h:1437
Definition bdlcc_deque.h:1053
void release()
Definition bdlcc_deque.h:1579
~DequeThrowGuard()
Definition bdlcc_deque.h:1531
Definition bdlcc_deque.h:1159
void load(Deque< TYPE > *container)
Definition bdlcc_deque.h:1341
MonoDeque & operator*() const
Definition bdlcc_deque.h:1395
bool isNull() const
Return true if this object is not associated with a Deque object.
Definition bdlcc_deque.h:1413
MonoDeque * operator->() const
Definition bdlcc_deque.h:1386
~Proctor()
Definition bdlcc_deque.h:1333
void release()
Definition bdlcc_deque.h:1355
TYPE & operator[](typename MonoDeque::size_type position) const
Definition bdlcc_deque.h:1404
Definition bdlcc_deque.h:541
int timedPopFront(TYPE *item, const bsls::TimeInterval &timeout)
Definition bdlcc_deque.h:2193
bsl::deque< TYPE > MonoDeque
Definition bdlcc_deque.h:553
int tryPushBack(const TYPE &item)
Definition bdlcc_deque.h:2419
TYPE popBack()
Definition bdlcc_deque.h:1980
~Deque()
Definition bdlcc_deque.h:1872
Deque(bslma::Allocator *basicAllocator=0)
Definition bdlcc_deque.h:1736
bslma::Allocator * allocator() const
Return the allocator used by this container for allocating memory.
Definition bdlcc_deque.h:2555
static size_type maxSizeT()
Definition bdlcc_deque.h:1728
void pushBack(const TYPE &item)
Definition bdlcc_deque.h:2073
int timedPushFront(const TYPE &item, const bsls::TimeInterval &timeout)
Definition bdlcc_deque.h:2263
void forcePushFront(const TYPE &item)
Definition bdlcc_deque.h:1929
int timedPopBack(TYPE *item, const bsls::TimeInterval &timeout)
Definition bdlcc_deque.h:2163
int tryPopBack(TYPE *item)
Definition bdlcc_deque.h:2303
void tryPopFront(size_type maxNumItems, bsl::vector< TYPE > *buffer)
int timedPushBack(const TYPE &item, const bsls::TimeInterval &timeout)
Definition bdlcc_deque.h:2223
size_type length() const
Definition bdlcc_deque.h:2581
void tryPopBack(size_type maxNumItems, std::vector< TYPE > *buffer)
void tryPopBack(size_type maxNumItems, bsl::vector< TYPE > *buffer)
void removeAll()
Definition bdlcc_deque.h:2134
int tryPopFront(TYPE *item)
Definition bdlcc_deque.h:2363
TYPE popFront()
Definition bdlcc_deque.h:2027
void forcePushBack(const TYPE &item)
Definition bdlcc_deque.h:1879
MonoDeque::size_type size_type
Definition bdlcc_deque.h:554
void tryPopFront(size_type maxNumItems, std::vector< TYPE > *buffer)
bsls::SystemClockType::Enum clockType() const
Definition bdlcc_deque.h:2562
void tryPopBack(size_type maxNumItems)
size_type highWaterMark() const
Return the high-water mark value for this container.
Definition bdlcc_deque.h:2569
int tryPushFront(const TYPE &item)
Definition bdlcc_deque.h:2486
void pushFront(const TYPE &item)
Definition bdlcc_deque.h:2103
void tryPopFront(size_type maxNumItems)
iterator end() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_deque.h:2107
size_type size() const BSLS_KEYWORD_NOEXCEPT
Return the number of elements contained by this deque.
Definition bslstl_deque.h:2241
iterator begin() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_deque.h:2099
std::size_t size_type
Definition bslstl_deque.h:640
Definition bslstl_deque.h:814
iterator insert(const_iterator position, const VALUE_TYPE &value)
Definition bslstl_deque.h:3956
ConstIterator const_iterator
Definition bslstl_deque.h:865
iterator erase(const_iterator position)
Definition bslstl_deque.h:4195
Iterator iterator
Definition bslstl_deque.h:864
std::size_t size_type
Definition bslstl_deque.h:866
Definition bslstl_vector.h:1120
Definition bslma_allocator.h:545
Definition bslmf_movableref.h:752
Definition bslmt_condition.h:220
Definition bslmt_lockguard.h:234
T * release()
Definition bslmt_lockguard.h:506
Definition bslmt_mutex.h:317
void lock()
Definition bslmt_mutex.h:399
void unlock()
Definition bslmt_mutex.h:417
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_ASSERT_OPT(X)
Definition bsls_assert.h:2045
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.
Definition bdlcc_boundedqueue.h:270
Definition baljsn_encoder_testtypes.h:76
Definition bdlt_iso8601util.h:707
Definition bslmf_issame.h:146
Definition bslma_usesbslmaallocator.h:344
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
Enum
Definition bsls_systemclocktype.h:119