BDE 4.14.0 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 inifinite. 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/// bslmt::ThreadUtil::create(&handles[ti], functor);
452/// }
453/// @endcode
454/// Then, wait on the barrier, that will set all the subthreads running:
455/// @code
456/// barrier.wait();
457/// @endcode
458/// Now, loop to pop the events off the deque, and keep track of how many
459/// `e_COMPLETE` events have been popped. When this equals the number of
460/// subthreads, we are done.
461/// @code
462/// int numCompleted = 0, numEvents = 0;
463/// while (numCompleted < k_NUM_THREADS) {
464/// Event ev = myDeque.popFront();
465/// ++numEvents;
466/// if (verbose) {
467/// cout << "[" << ev.d_workerId << "] "
468/// << ev.d_eventNumber << ". "
469/// << ev.d_eventText_p << endl;
470/// }
471/// if (Event::e_TASK_COMPLETE == ev.d_type) {
472/// ++numCompleted;
473/// int rc = bslmt::ThreadUtil::join(handles[ev.d_workerId]);
474/// assert(!rc);
475/// }
476/// }
477/// @endcode
478/// Finally, perform some sanity checks:
479/// @code
480/// assert(k_NUM_THREADS * k_NUM_TO_PUSH == numEvents);
481/// assert(0 == myDeque.length());
482/// @endcode
483/// @}
484/** @} */
485/** @} */
486
487/** @addtogroup bdl
488 * @{
489 */
490/** @addtogroup bdlcc
491 * @{
492 */
493/** @addtogroup bdlcc_deque
494 * @{
495 */
496
497#include <bdlscm_version.h>
498
499#include <bslmt_condition.h>
500#include <bslmt_lockguard.h>
501#include <bslmt_mutex.h>
502
503#include <bslma_allocator.h>
504
505#include <bslmf_assert.h>
507#include <bslmf_movableref.h>
508
509#include <bsls_assert.h>
510#include <bsls_libraryfeatures.h>
511#include <bsls_review.h>
512#include <bsls_systemclocktype.h>
513#include <bsls_timeinterval.h>
514
515#include <bsl_algorithm.h>
516#include <bsl_deque.h>
517#include <bsl_vector.h>
518#include <bsl_limits.h>
519#include <bsl_cstddef.h>
520#include <bsl_cstdio.h>
521
522#include <vector>
523
524
525namespace bdlcc {
526
527 // ===========
528 // class Deque
529 // ===========
530
531/// This class provides a fully thread-safe implementation of an efficient,
532/// in-place, indexable, double-ended queue of (template parameter) `TYPE`
533/// values. Direct access to the underlying `bsl::deque<TYPE>` object is
534/// provided through the nested `Proctor` and `ConstProctor` classes. While
535/// this class is not value-semantic, the underlying `bsl::deque<TYPE>` class
536/// is.
537///
538/// See @ref bdlcc_deque
539template <class TYPE>
540class Deque {
541
542 // PRIVATE TYPES
543 class DequeThrowGuard;
544 template <class VECTOR>
545 class VectorThrowGuard;
546
547 template <class VECTOR>
548 struct IsVector;
549
550 public:
551 // PUBLIC TYPES
554
555 class Proctor; // defined after this `class`
556 class ConstProctor; // defined after this `class`
557
558 private:
559 // DATA
560 mutable
561 bslmt::Mutex d_mutex; // mutex object used to
562 // synchronize access to the
563 // underlying `deque`.
564
565 bslmt::Condition d_notEmptyCondition; // condition variable used to
566 // signal that new data is
567 // available in the container
568
569 bslmt::Condition d_notFullCondition; // condition variable used to
570 // signal when there is room
571 // available to add new data to
572 // the container
573
574 MonoDeque d_monoDeque; // the underlying deque.
575
576 const size_type d_highWaterMark; // positive maximum number of
577 // items that can be contained
578 // before insertions will be
579 // blocked.
580
582 d_clockType; // clock type used
583
584 private:
585 // NOT IMPLEMENTED
586 Deque<TYPE>& operator=(const Deque<TYPE>&);
587
588 // PRIVATE MANIPULATORS
589
590 /// If the optionally specified `buffer` is non-zero, append all the
591 /// elements from this container to `*buffer` in the same order, then,
592 /// regardless of whether `buffer` is zero, clear this container. Note
593 /// that the previous contents of `*buffer` are not discarded -- the
594 /// removed items are appended to it.
595 template <class VECTOR>
596 void removeAllImp(VECTOR *buffer = 0);
597
598 /// Remove up to the specified `maxNumItems` from the back of this
599 /// container. Optionally specify a `buffer` into which the items
600 /// removed from the container are loaded. If `buffer` is non-null, the
601 /// removed items are appended to it as if by repeated application of
602 /// `buffer->push_back(popBack())` while the container is not empty and
603 /// `maxNumItems` have not yet been removed. Note that the ordering of
604 /// the items in `*buffer` after the call is the reverse of the ordering
605 /// they had in the deque. Also note that `*buffer` is not cleared --
606 /// the popped items are appended after any pre-existing contents.
607 template <class VECTOR>
608 void tryPopBackImp(size_type maxNumItems,
609 VECTOR *buffer);
610
611 /// Remove up to the specified `maxNumItems` from the front of this
612 /// container. Optionally specify a `buffer` into which the items
613 /// removed from the container are appended. If `buffer` is non-null,
614 /// the removed items are appended to it as if by repeated application
615 /// of `buffer->push_back(popFront())` while the const is not empty and
616 /// `maxNumItems` have not yet been removed. Note that `*buffer` is not
617 /// cleared -- the popped items are appended after any pre-existing
618 /// contents.
619 template <class VECTOR>
620 void tryPopFrontImp(size_type maxNumItems,
621 VECTOR *buffer);
622
623 public:
624 // CLASS METHODS
625
626 /// Return the maximum value that can be stored in a veriable of type
627 /// `size_type`. The high water mark defaults to having this value.
628 static
630
631 // CREATORS
632
633 explicit
634 Deque(bslma::Allocator *basicAllocator = 0);
635 /// Create a container of objects of (template parameter) `TYPE`, with no
636 /// high water mark, and use the specified `clockType` to indicate the
637 /// epoch used for all time intervals (see {Supported Clock-Types} in the
638 /// component documentation). If `basicAllocator` is 0, the currently
639 /// installed default allocator is used.
640 explicit
642 bslma::Allocator *basicAllocator = 0);
643
644 explicit
645 Deque(bsl::size_t highWaterMark,
646 bslma::Allocator *basicAllocator = 0);
647 /// Create a container of objects of (template parameter) `TYPE`, with the
648 /// specified `highWaterMark`, and use the specified `clockType` to
649 /// indicate the epoch used for all time intervals (see {Supported
650 /// Clock-Types} in the component documentation). Optionally specify a
651 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0, the
652 /// currently installed default allocator is used. The behavior is
653 /// undefined unless `highWaterMark > 0`.
654 Deque(bsl::size_t highWaterMark,
656 bslma::Allocator *basicAllocator = 0);
657
658 /// Create a container of objects of (template parameter) `TYPE`
659 /// containing the sequence of elements in the specified range
660 /// `[begin .. end)`, having no high water mark, and use the specified
661 /// `clockType` to indicate the epoch used for all time intervals (see
662 /// {Supported Clock-Types} in the component documentation). Optionally
663 /// specify a `basicAllocator` used to supply memory. If
664 /// `basicAllocator` is 0, the currently installed default allocator is
665 /// used. Note that the items in the range are treated as `const`
666 /// objects, copied without being modified.
667 template <class INPUT_ITER>
668 Deque(INPUT_ITER begin,
669 INPUT_ITER end,
670 bslma::Allocator *basicAllocator = 0);
671 template <class INPUT_ITER>
672 Deque(INPUT_ITER begin,
673 INPUT_ITER end,
675 bslma::Allocator *basicAllocator = 0);
676
677 /// Create a container of objects of (template parameter) `TYPE`
678 /// containing the sequence of `TYPE` values in the specified range
679 /// `[begin .. end)` having the specified `highWaterMark`, and use the
680 /// specified `clockType` to indicate the epoch used for all time
681 /// intervals (see {Supported Clock-Types} in the component
682 /// documentation). Optionally specify a `basicAllocator` used to
683 /// supply memory. If `basicAllocator` is 0, the currently installed
684 /// default allocator is used. The behavior is undefined unless
685 /// `highWaterMark > 0`. Note that if the number of elements in the
686 /// range `[begin, end)` exceeds `highWaterMark`, the effect will be the
687 /// same as if the extra elements were added by forced pushes. Also
688 /// note that the items in the range are treated as `const` objects,
689 /// copied without being modified.
690 template <class INPUT_ITER>
691 Deque(INPUT_ITER begin,
692 INPUT_ITER end,
693 bsl::size_t highWaterMark,
694 bslma::Allocator *basicAllocator = 0);
695 template <class INPUT_ITER>
696 Deque(INPUT_ITER begin,
697 INPUT_ITER end,
698 bsl::size_t highWaterMark,
700 bslma::Allocator *basicAllocator = 0);
701
702 /// Create a container having the same value as the specified `original`
703 /// object. Optionally specify a `basicAllocator` used to supply
704 /// memory. If `basicAllocator` is 0, the currently installed default
705 /// allocator is used.
706 Deque(const Deque<TYPE>& original, bslma::Allocator *basicAllocator = 0);
707
708 /// Destroy this container. The behavior is undefined unless all access
709 /// or modification of the container has completed prior to the
710 /// destruction of this object.
711 ~Deque();
712
713 // MANIPULATORS
714
715 /// Append the specified `item` to the back of this container without
716 /// regard for the high-water mark. Note that this method is provided
717 /// to allow high priority items to be inserted when the container is
718 /// full; `pushFront` and `pushBack` should be used for general use.
719 void forcePushBack(const TYPE& item);
720
721 /// Append the specified move-insertable `item` to the back of this
722 /// container without regard for the high-water mark. `item` is left in
723 /// a valid but unspecified state. Note that this method is provided to
724 /// allow high priority items to be inserted when the container is full;
725 /// `pushFront` and `pushBack` should be used for general use.
727
728 /// Append the specified specified range `[begin .. end)` of items to
729 /// the back of this container without regard for the high-water mark.
730 /// Note that the items in the range are treated as `const` objects,
731 /// copied without being modified.
732 template <class INPUT_ITER>
733 void forcePushBack(INPUT_ITER begin,
734 INPUT_ITER end);
735
736 /// Append the specified `item` to the front of this container without
737 /// regard for the high-water mark. Note that this method is provided
738 /// to allow high priority items to be inserted when the container is
739 /// full; `pushFront` and `pushBack` should be used for general use.
740 void forcePushFront(const TYPE& item);
741
742 /// Append the specified move-insertable `item` to the front of this
743 /// container without regard for the high-water mark. `item` is left in
744 /// a valid but unspecified state. Note that this method is provided to
745 /// allow high priority items to be inserted when the container is full;
746 /// `pushFront` and `pushBack` should be used for general use.
748
749 /// Append the specified specified range `[begin .. end)` of items to
750 /// the front of this container without regard for the high-water mark.
751 /// Note that pushed the items will be in the container in the reverse
752 /// of the order in which they occur in the range. Also note that the
753 /// items in the range are treated as `const` objects, copied without
754 /// being modified.
755 template <class INPUT_ITER>
756 void forcePushFront(INPUT_ITER begin,
757 INPUT_ITER end);
758
759 /// Return the last item in this container and remove it. If this
760 /// container is empty, block until an item is available.
761 TYPE popBack();
762
763 /// Remove the last item in this container and load that item into the
764 /// specified `*item`. If this container is empty, block until an item
765 /// is available.
766 void popBack(TYPE *item);
767
768 /// Return the first item in this container and remove it. If this
769 /// container is empty, block until an item is available.
770 TYPE popFront();
771
772 /// Remove the first item in this container and load that item into the
773 /// specified `*item`. If the container is empty, block until an item
774 /// is available.
775 void popFront(TYPE *item);
776
777 /// Block until space in this container becomes available (see
778 /// {`High-Water Mark` Feature}), then append the specified `item` to
779 /// the back of this container.
780 void pushBack(const TYPE& item);
781
782 /// Block until space in this container becomes available (see
783 /// {`High-Water Mark` Feature}), then append the specified
784 /// move-insertable `item` to the back of this container. `item` is
785 /// left in a valid but unspecified state.
787
788 /// Block until space in this container becomes available (see
789 /// {`High-Water Mark` Feature}), then append the specified `item` to
790 /// the front of this container.
791 void pushFront(const TYPE& item);
792
793 /// Block until space in this container becomes available (see
794 /// {`High-Water Mark` Feature}), then append the specified
795 /// move-insertable `item` to the front of this container. `item` is
796 /// left in a valid but unspecified state.
798
799 void removeAll();
800 void removeAll(bsl::vector<TYPE> *buffer);
801 /// If the optionally specified `buffer` is non-zero, append all the
802 /// elements from this container to `*buffer` in the same order, then,
803 /// regardless of whether `buffer` is zero, clear this container. Note
804 /// that the previous contents of `*buffer` are not discarded -- the
805 /// removed items are appended to it.
806 void removeAll(std::vector<TYPE> *buffer);
807#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
808 void removeAll(std::pmr::vector<TYPE> *buffer);
809#endif
810
811 /// Remove the last item in this container and load that item value into
812 /// the specified `*item`. If this container is empty, block until an
813 /// item is available or until the specified `timeout` (expressed as the
814 /// **ABSOLUTE** time from 00:00:00 UTC, January 1, 1970) expires. Return
815 /// 0 on success, and a non-zero value if the call timed out before an
816 /// item was available. Note that this method can block indefinitely if
817 /// another thread has the mutex locked, particularly by a proctor
818 /// object -- there is no guarantee that this method will return after
819 /// `timeout`.
820 int timedPopBack(TYPE *item, const bsls::TimeInterval& timeout);
821
822 /// Remove the first item in this container and load that item value
823 /// into the specified `*item`. If this container is empty, block until
824 /// an item is available or until the specified `timeout` (expressed as
825 /// the **ABSOLUTE** time from 00:00:00 UTC, January 1, 1970) expires.
826 /// Return 0 on success, and a non-zero value if the call timed out
827 /// before an item was available. Note that this method can block
828 /// indefinitely if another thread has the mutex locked, particularly by
829 /// a proctor object -- there is no guarantee that this method will
830 /// return after `timeout`.
831 int timedPopFront(TYPE *item, const bsls::TimeInterval& timeout);
832
833 /// Append the specified `item` to the back of this container if space
834 /// is available, otherwise (if the container is full) block waiting for
835 /// space to become available or until the specified `timeout`
836 /// (expressed as the **ABSOLUTE** time from 00:00:00 UTC, January 1,
837 /// 1970) expires. Return 0 if space was or became available and this
838 /// container was updated, and a non-zero value if the call timed out
839 /// before space became available and this container was left
840 /// unmodified. Note that this method can block indefinitely if another
841 /// thread has the mutex locked, particularly by a proctor object --
842 /// there is no guarantee that this method will return after `timeout`.
843 int timedPushBack(const TYPE& item,
844 const bsls::TimeInterval& timeout);
845
846 /// Append the specified move-insertable `item` to the back of this
847 /// container if space is available, otherwise (if the container is
848 /// full) block waiting for space to become available or until the
849 /// specified `timeout` (expressed as the **ABSOLUTE** time from 00:00:00
850 /// UTC, January 1, 1970) expires. If the container is modified, `item`
851 /// is left in a valid but unspecified state, otherwise `item` is
852 /// unchanged. Return 0 if space was or became available and this
853 /// container was updated, and a non-zero value if the call timed out
854 /// before space became available and this container was left
855 /// unmodified. Note that this method can block indefinitely if another
856 /// thread has the mutex locked, particularly by a proctor object --
857 /// there is no guarantee that this method will return after `timeout`.
859 const bsls::TimeInterval& timeout);
860
861 /// Append the specified `item` to the front of this container if space
862 /// is available, otherwise (if the container is full) block waiting for
863 /// space to become available or until the specified `timeout`
864 /// (expressed as the **ABSOLUTE** time from 00:00:00 UTC, January 1,
865 /// 1970) expires. Return 0 if space was or became available and this
866 /// container was updated, and a non-zero value if the call timed out
867 /// before space became available and this container was left
868 /// unmodified. Note that this method can block indefinitely if another
869 /// thread has the mutex locked, particularly by a proctor object --
870 /// there is no guarantee that this method will return after `timeout`.
871 int timedPushFront(const TYPE& item,
872 const bsls::TimeInterval& timeout);
873
874 /// Append the specified move-insertable `item` to the front of this
875 /// container if space is available, otherwise (if the container is
876 /// full) block waiting for space to become available or until the
877 /// specified `timeout` (expressed as the **ABSOLUTE** time from 00:00:00
878 /// UTC, January 1, 1970) expires. If the container is modified,`item`
879 /// is left in a valid but unspecified state, otherwise `item` is left
880 /// unchanged. Return 0 if space was or became available and this
881 /// container was updated, and a non-zero value if the call timed out
882 /// before space became available and this container was left
883 /// unmodified. Note that this method can block indefinitely if another
884 /// thread has the mutex locked, particularly by a proctor object --
885 /// there is no guarantee that this method will return after `timeout`.
887 const bsls::TimeInterval& timeout);
888
889 /// If this container is non-empty, remove the last item, load that item
890 /// into the specified `*item`, and return 0 indicating success. If
891 /// this container is empty, return a non-zero value with no effect on
892 /// `item` or the state of this container.
893 int tryPopBack(TYPE *item);
894
895 /// Remove up to the specified `maxNumItems` from the back of this
896 /// container. Optionally specify a `buffer` into which the items
897 /// removed from the container are loaded. If `buffer` is non-null, the
898 /// removed items are appended to it as if by repeated application of
899 /// `buffer->push_back(popBack())` while the container is not empty and
900 /// `maxNumItems` have not yet been removed. Note that the ordering of
901 /// the items in `*buffer` after the call is the reverse of the ordering
902 /// they had in the deque. Also note that `*buffer` is not cleared --
903 /// the popped items are appended after any pre-existing contents.
904 ///
905 void tryPopBack(size_type maxNumItems);
906 void tryPopBack(size_type maxNumItems,
907 bsl::vector<TYPE> *buffer);
908 /// Also note that to transfer the entire contents of a `Deque` `d` to a
909 /// vector `v`, use `d.removeAll(&v);`.
910 void tryPopBack(size_type maxNumItems,
911 std::vector<TYPE> *buffer);
912#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
913 void tryPopBack(size_type maxNumItems,
914 std::pmr::vector<TYPE> *buffer);
915#endif
916
917 /// If this container is non-empty, remove the first item, load that
918 /// item into the specified `*item`, and return 0 indicating success.
919 /// If this container is empty, return a non-zero value with no effect
920 /// on `*item` or the state of this container.
921 int tryPopFront(TYPE *item);
922
923 /// Remove up to the specified `maxNumItems` from the front of this
924 /// container. Optionally specify a `buffer` into which the items
925 /// removed from the container are appended. If `buffer` is non-null,
926 /// the removed items are appended to it as if by repeated application
927 /// of `buffer->push_back(popFront())` while the const is not empty and
928 /// `maxNumItems` have not yet been removed. Note that `*buffer` is not
929 /// cleared -- the popped items are appended after any pre-existing
930 /// contents.
931 ///
932 void tryPopFront(size_type maxNumItems);
933 void tryPopFront(size_type maxNumItems,
934 bsl::vector<TYPE> *buffer);
935 /// Also note that to transfer the entire contents of a `Deque` `d` to a
936 /// vector `v`, use `d.removeAll(&v);`.
937 void tryPopFront(size_type maxNumItems,
938 std::vector<TYPE> *buffer);
939#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
940 void tryPopFront(size_type maxNumItems,
941 std::pmr::vector<TYPE> *buffer);
942#endif
943
944 /// If the container is not full (see {`High-Water Mark` Feature}),
945 /// append the specified `item` to the back of the container, otherwise
946 /// leave the container unchanged. Return 0 if the container was
947 /// updated and a non-zero value otherwise.
948 int tryPushBack(const TYPE& item);
949
950 /// If the container is not full (see {`High-Water Mark` Feature}),
951 /// append the specified move-insertable `item` to the back of the
952 /// container, otherwise leave the container unchanged. If the
953 /// container is modified, `item` is left in a valid but unspecified
954 /// state, otherwise `item` is unchanged. Return 0 if the container was
955 /// updated and a non-zero value otherwise.
957
958 /// Push as many of the items in the specified range `[begin .. end)` as
959 /// there is space available for (see {`High-Water Mark` Feature}) to
960 /// the back of the container, stopping if the container high-water mark
961 /// is reached. Return the number of items pushed. Note that the items
962 /// in the range are treated as `const` objects, copied without being
963 /// modified.
964 template <class INPUT_ITER>
965 size_type tryPushBack(INPUT_ITER begin,
966 INPUT_ITER end);
967
968 /// If the container is not full (see {`High-Water Mark` Feature}),
969 /// append the specified `item` to the front 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 tryPushFront(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 front 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 front of the container, stopping if the container high-water
985 /// mark is reached. Return the number of items pushed. Note that the
986 /// pushed items will be in the container in the reverse of the order in
987 /// which they occur in the range. Also note that the items in the
988 /// range are treated as `const` objects, copied without being modified.
989 template <class INPUT_ITER>
990 size_type tryPushFront(INPUT_ITER begin,
991 INPUT_ITER end);
992
993 // ACCESSORS
994
995 /// Return the allocator used by this container for allocating memory.
997
998 /// Return the system clock type used for timing `timed*` operations on
999 /// this object (see {Supported Clock-Types} in the component
1000 /// documentation).
1002
1003 /// Return the high-water mark value for this container.
1004 size_type highWaterMark() const;
1005
1006 /// Return the number of elements contained in this container. Note
1007 /// that this method temporarily acquires the mutex, so that this method
1008 /// must not be called while a proctor in the same thread has this
1009 /// container locked, and the value returned is potentially obsolete
1010 /// before it is returned if any other threads are simultaneously
1011 /// modifying this container. To find the length while a proctor has
1012 /// the container locked, call `proctor->size()`.
1013 size_type length() const;
1014};
1015
1016/// This private `class` is used to manage a `bsl::deque`, during the course of
1017/// an operation by a `bdlcc::Deque`. Because it has a `release` method, it is
1018/// actually a proctor, but we call it a `guard` to avoid having clients
1019/// confuse it with this component's `Proctor` and `ConstProctor` types. A
1020/// `deque` that is being managed may only grow, and only on one end or the
1021/// other. If a throw happens during the course of the operation and this
1022/// guard's destructor is called while still managing the object, it will
1023/// restore the managed object to its initial state via operations that are
1024/// guaranteed not to throw.
1025template <class TYPE>
1027
1028 // PRIVATE TYPES
1030 typedef typename MonoDeque::size_type size_type;
1031 typedef typename MonoDeque::const_iterator MDCIter;
1032
1033 // DATA
1034 MonoDeque *d_monoDeque_p;
1035 const MDCIter d_mdBegin;
1036 const MDCIter d_mdEnd;
1037 const bool d_mdWasEmpty;
1038
1039 private:
1040 // NOT IMPLEMENTED
1042 DequeThrowGuard& operator=(const DequeThrowGuard&);
1043
1044 public:
1045 // CREATORS
1046
1047 /// Create a `Deque_DequeThrowGuard` object that will manage the
1048 /// specified `*monoDeque_p`. The behavior is undefined if
1049 /// `0 == monoDeque_p`.
1050 explicit
1051 DequeThrowGuard(MonoDeque *monoDeque_p);
1052
1053 /// If a `MonoDeque` is being managed by this `ThrowGuard`, restore it
1054 /// to the state it was in when this object was created.
1056
1057 // MANIPULATOR
1058
1059 /// Release the monitored `MonoDeque` from management by this
1060 /// `Deque_DequeThrowGuard` object.
1061 void release();
1062};
1063
1064/// This private `class` is used to manage one `vector` object during the
1065/// course of an operation by a `bdlcc::Deque`. Because it has a `release`
1066/// method, it is actually a proctor, but we call it a `guard` to avoid having
1067/// clients confuse it with the `Proctor` and `ConstProctor` types. The vector
1068/// may only grow by having objects appended to it. If a throw happens during
1069/// the course of the operation and the guard's destructor is called while
1070/// still managing the object, it will restore the managed object to its
1071/// initial state via operations that are guaranteed not to throw.
1072template <class TYPE>
1073template <class VECTOR>
1074class Deque<TYPE>::VectorThrowGuard {
1075
1076 // PRIVATE TYPES
1077 typedef typename VECTOR::size_type VSize;
1078
1079 // DATA
1080 VECTOR *d_vector_p;
1081 const VSize d_vSize;
1082
1083 private:
1084 // NOT IMPLEMENTED
1085 VectorThrowGuard(const VectorThrowGuard&);
1086 VectorThrowGuard& operator=(const VectorThrowGuard&);
1087
1088 public:
1089 // CREATORS
1090
1091 /// Create a `VectorThrowGuard` object that will manage the specified
1092 /// `*vector_p`. Note that the case where `0 == vector_p` is explicitly
1093 /// permitted, in which case this object will not manage anything.
1094 explicit
1095 VectorThrowGuard(VECTOR *vector_p);
1096
1097 /// If a `vector` is being managed by this `VectorThrowGuard`, restore
1098 /// it to the state it was in when this object was created.
1099 ~VectorThrowGuard();
1100
1101 // MANIPULATOR
1102
1103 /// Release the monitored `vector` from management by this
1104 /// `VectorThrowGuard` object.
1105 void release();
1106};
1107
1108/// This `struct` has a `value` that evaluates to `true` if the specified
1109/// `VECTOR` is a `bsl`, `std`, or `std::pmr` `vector<VALUE>`.
1110template <class TYPE>
1111template <class VECTOR>
1112struct Deque<TYPE>::IsVector {
1113
1114 static const bool value =
1115 bsl::is_same<bsl::vector<TYPE>, VECTOR>::value
1116#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1117 || bsl::is_same<std::pmr::vector<TYPE>, VECTOR>::value
1118#endif
1119 || bsl::is_same<std::vector<TYPE>, VECTOR>::value;
1120};
1121
1122 // ====================
1123 // class Deque::Proctor
1124 // ====================
1125
1126/// This class defines a proctor type that provides direct access to the
1127/// underlying `bsl::deque` contained in a `Deque`. Creation of a `Proctor`
1128/// object locks the mutex of the `Deque`, and destruction unlocks it.
1129template <class TYPE>
1130class Deque<TYPE>::Proctor {
1131
1132 // PRIVATE TYPES
1134 typedef typename MonoDeque::size_type size_type;
1135
1136 // DATA
1137 Deque<TYPE> *d_container_p;
1138 size_type d_startLength; // If '!d_container_p', this field may
1139 // be left uninitialized.
1140
1141 private:
1142 // NOT IMPLEMENTED
1143 Proctor(const Proctor&);
1144 Proctor& operator=(const Proctor&);
1145
1146 public:
1147 // CREATORS
1148
1149 /// Create a `Proctor` object to provide access to the underlying
1150 /// `bsl::deque` contained in the optionally specified `*container`,
1151 /// locking `container`s mutex. If no `container` is specified, this
1152 /// object will be null.
1153 explicit
1154 Proctor(Deque<TYPE> *container = 0);
1155
1156 /// Release the lock on the mutex of the `Deque` that was provided at
1157 /// contstuction and destroy this `Proctor` object. Signal the conditions
1158 /// on the `Deque` that was supplied to this object at construction to
1159 /// reflect any changes that have been made to its contents since
1160 /// construction.
1161 ~Proctor();
1162
1163 // MANIPULATORS
1164
1165 /// In the case where this `Proctor` has been released, attach this
1166 /// object to the specified `container`. If this object is already
1167 /// attached, release the previous object first. The behavior is
1168 /// undefined if `0 == container`.
1169 void load(Deque<TYPE> *container);
1170
1171 /// Release this proctor without destroying it. Afterward the
1172 /// destructor will have no effect. This may be called multiple times;
1173 /// only the first call has any effect.
1174 void release();
1175
1176 // ACCESSORS
1177
1178 /// Return a pointer to the `bsl::deque` contained in the `Deque`
1179 /// managed by this `Proctor` object'. The behavior is undefined if
1180 /// this `Proctor` has been released.
1181 MonoDeque *operator->() const;
1182
1183 /// Return a reference to the `bsl::deque` managed by this `Proctor`
1184 /// object. The behavior is undefined if this `Proctor` has been
1185 /// released.
1186 MonoDeque& operator*() const;
1187
1188 /// Return a reference providing modifiable access to the element at the
1189 /// specified `position` in the `bsl::deque` held by this proctor. The
1190 /// behavior is undefined unless `position < size` where `size` is the
1191 /// the number of elements in that deque.
1192 TYPE& operator[](typename MonoDeque::size_type position) const;
1193
1194 /// Return `true` if this object is not associated with a `Deque` object.
1195 bool isNull() const;
1196};
1197
1198 // =========================
1199 // class Deque::ConstProctor
1200 // =========================
1201
1202/// This class defines a proctor type that provides direct const access to the
1203/// underlying `bsl::deque` contained in a `Deque`.
1204template <class TYPE>
1205class Deque<TYPE>::ConstProctor {
1206
1207 // PRIVATE TYPES
1209 typedef typename MonoDeque::size_type size_type;
1210
1211 // DATA
1212 const Deque<TYPE> *d_container_p;
1213 size_type d_startLength; // If '!d_container_p', this field may
1214 // be left uninitialized.
1215
1216 private:
1217 // NOT IMPLEMENTED
1218 ConstProctor(const ConstProctor&);
1219 ConstProctor& operator=(const ConstProctor&);
1220
1221 public:
1222 // CREATORS
1223
1224 /// Create a `ConstProctor` object to provide const access to the
1225 /// underlying `bsl::deque` contained in the optionally specified
1226 /// `*container`, locking `container`s mutex. If no `container` is
1227 /// specified, this object will be null.
1228 explicit
1229 ConstProctor(const Deque<TYPE> *container = 0);
1230
1231 /// Release the lock on the mutex of the `Deque` that was provided at
1232 /// contstuction and destroy this `Proctor` object. The behavior is
1233 /// undefined if the `Deque` has been modified since the construction of
1234 /// this object.
1235 ~ConstProctor();
1236
1237 // MANIPULATORS
1238
1239 /// In the case where this `Proctor` has been released, attach this
1240 /// object to the specified `container`. If this object is already
1241 /// attached, release the previous object first. The behavior is
1242 /// undefined if `0 == container`.
1243 void load(const Deque<TYPE> *container);
1244
1245 /// Release this proctor without destroying it. Afterward the
1246 /// destructor will have no effect. This may be called multiple times;
1247 /// only the first call has any effect;
1248 void release();
1249
1250 // ACCESSORS
1251
1252 /// Return a pointer to the `bsl::deque` contained in the `Deque`
1253 /// managed by this object. The behavior is undefined if this
1254 /// `ConstProctor` has been released.
1255 const MonoDeque *operator->() const;
1256
1257 /// Return a reference to the `bsl::deque` managed by this `Proctor`
1258 /// object. The behavior is undefined if this `ConstProctor` has been
1259 /// released.
1260 const MonoDeque& operator*() const;
1261
1262 /// Return a reference providing non-modifiable access to the element at
1263 /// the specified `position` in the `bsl::deque` held by this proctor.
1264 /// The behavior is undefined unless `position < size` where `size` is
1265 /// the number of elements in that deque.
1266 const TYPE& operator[](size_type position) const;
1267
1268 /// Return `true` if this object is not associated with a `Deque`
1269 /// object.
1270 bool isNull() const;
1271};
1272
1273// ============================================================================
1274// INLINE DEFINITIONS
1275// ============================================================================
1276
1277 // ---------------------
1278 // bdlcc::Deque::Proctor
1279 // ---------------------
1280
1281// CREATORS
1282template <class TYPE>
1283inline
1285: d_container_p(0)
1286{
1287 if (container) {
1288 this->load(container);
1289 }
1290
1291 // If '0 == container', leave 'd_startLength' uninitialized.
1292}
1293
1294template <class TYPE>
1295inline
1297{
1298 this->release();
1299}
1300
1301// MANIPULATORS
1302template <class TYPE>
1303inline
1305{
1306 BSLS_ASSERT(0 != container);
1307
1308 if (0 != d_container_p) {
1309 this->release();
1310 }
1311
1312 container->d_mutex.lock();
1313 d_container_p = container;
1314 d_startLength = d_container_p->d_monoDeque.size();
1315}
1316
1317template <class TYPE>
1319{
1320 if (0 == d_container_p) {
1321 return; // RETURN
1322 }
1323
1324 const size_type sz = d_container_p->d_monoDeque.size();
1325 size_type ii = d_startLength;
1326
1327 d_container_p->d_mutex.unlock();
1328
1329 if (ii < sz) {
1330 do {
1331 d_container_p->d_notEmptyCondition.signal();
1332 } while (++ii < sz);
1333 }
1334 else {
1335 if (d_container_p->d_highWaterMark < ii) {
1336 ii = d_container_p->d_highWaterMark;
1337 }
1338 for (; ii > sz; --ii) {
1339 d_container_p->d_notFullCondition.signal();
1340 }
1341 }
1342
1343 d_container_p = 0;
1344}
1345
1346// ACCESSORS
1347template <class TYPE>
1348inline
1350{
1351 BSLS_ASSERT(d_container_p);
1352
1353 return &d_container_p->d_monoDeque;
1354}
1355
1356template <class TYPE>
1357inline
1359{
1360 BSLS_ASSERT(d_container_p);
1361
1362 return d_container_p->d_monoDeque;
1363}
1364
1365template <class TYPE>
1366inline
1367TYPE& Deque<TYPE>::Proctor::operator[](size_type position) const
1368{
1369 BSLS_ASSERT(position < d_container_p->d_monoDeque.size());
1370
1371 return d_container_p->d_monoDeque[position];
1372}
1373
1374template <class TYPE>
1375inline
1377{
1378 return 0 == d_container_p;
1379}
1380
1381 // --------------------------
1382 // bdlcc::Deque::ConstProctor
1383 // --------------------------
1384
1385
1386// CREATORS
1387template <class TYPE>
1388inline
1390: d_container_p(0)
1391{
1392 if (container) {
1393 this->load(container);
1394 }
1395
1396 // If '0 == container', leave 'd_startLength' uninitialized.
1397}
1398
1399template <class TYPE>
1400inline
1402{
1403 this->release();
1404}
1405
1406// MANIPULATORS
1407template <class TYPE>
1408inline
1410{
1411 BSLS_ASSERT(0 != container);
1412
1413 this->release();
1414
1415 container->d_mutex.lock();
1416 d_container_p = container;
1417 d_startLength = d_container_p->d_monoDeque.size();
1418}
1419
1420template <class TYPE>
1421inline
1423{
1424 // It is important that nobody did a const_cast and modified the underlying
1425 // 'bsls::deque' since this destructor won't signal the appropriate
1426 // condtions in the 'Deque' in that case. If they wanted to modify the
1427 // 'bsl::deque' they should have used a 'Proctor' instead of a
1428 // 'ConstProctor'.
1429
1430 if (0 == d_container_p) {
1431 return; // RETURN
1432 }
1433
1434 BSLS_ASSERT_OPT(d_container_p->d_monoDeque.size() == d_startLength &&
1435 "Underlying 'bsl::deque' modified through ConstProcter.");
1436
1437 bslmt::Mutex *mutex = &d_container_p->d_mutex;
1438 d_container_p = 0;
1439 mutex->unlock();
1440}
1441
1442// ACCESSORS
1443template <class TYPE>
1444inline
1446{
1447 BSLS_ASSERT(d_container_p);
1448
1449 return &d_container_p->d_monoDeque;
1450}
1451
1452template <class TYPE>
1453inline
1455{
1456 BSLS_ASSERT(d_container_p);
1457
1458 return d_container_p->d_monoDeque;
1459}
1460
1461template <class TYPE>
1462inline
1463const TYPE& Deque<TYPE>::ConstProctor::operator[](size_type position) const
1464{
1465 BSLS_ASSERT(position < d_container_p->d_monoDeque.size());
1466
1467 return d_container_p->d_monoDeque[position];
1468}
1469
1470template <class TYPE>
1471inline
1473{
1474 return 0 == d_container_p;
1475}
1476
1477 // -----------------------------------
1478 // bdlcc::Deque<TYPE>::DequeThrowGuard
1479 // -----------------------------------
1480
1481// CREATORS
1482template <class TYPE>
1483inline
1485: d_monoDeque_p(monoDeque_p)
1486, d_mdBegin( monoDeque_p->cbegin())
1487, d_mdEnd( monoDeque_p->cend())
1488, d_mdWasEmpty(monoDeque_p->empty())
1489{
1490 BSLS_ASSERT(0 != monoDeque_p);
1491}
1492
1493template <class TYPE>
1494inline
1496{
1497 if (d_monoDeque_p) {
1498 if (d_mdWasEmpty) {
1499 // In the case where the mono deque started out empty, pushing to
1500 // it can invalidate the iterators that were copied to 'd_mdBegin'
1501 // and 'd_mdEnd' when it was empty, so comparisons between
1502 // 'newBegin' & 'newEnd' and the old iterators will yield undefined
1503 // results. So we kept a separate boolean, 'd_mdWasEmpty', to
1504 // track that case, which we handle specially here.
1505
1506 d_monoDeque_p->clear();
1507
1508 return; // RETURN
1509 }
1510
1511 const MDCIter newBegin = d_monoDeque_p->cbegin();
1512 const MDCIter newEnd = d_monoDeque_p->cend();
1513
1514 // While range-based 'erase' of 'bsl::deque' does not always provide
1515 // the no-throw guarantee, all the erasing here is done at the ends of
1516 // the 'bsl::deque', so no items have to be copied around, so no
1517 // throwing should occur.
1518
1519 // The 'MonoDeque' may have been pushed to, but only on one end or the
1520 // other. It should never have been deleted from.
1521
1522 if (newBegin < d_mdBegin) {
1523 BSLS_ASSERT(d_mdEnd == newEnd);
1524
1525 d_monoDeque_p->erase(newBegin, d_mdBegin);
1526 }
1527 else {
1528 BSLS_ASSERT(newBegin == d_mdBegin);
1529
1530 if (d_mdEnd < newEnd) {
1531 d_monoDeque_p->erase(d_mdEnd, newEnd);
1532 }
1533 else {
1534 BSLS_ASSERT(d_mdEnd == newEnd);
1535 }
1536 }
1537 }
1538}
1539
1540// MANIPULATOR
1541template <class TYPE>
1542inline
1544{
1545 d_monoDeque_p = 0;
1546}
1547
1548 // --------------------------------------------
1549 // bdlcc::Deque<TYPE>::VectorThrowGuard<VECTOR>
1550 // --------------------------------------------
1551
1552// CREATORS
1553template <class TYPE>
1554template <class VECTOR>
1555inline
1557: d_vector_p(vector_p)
1558, d_vSize(vector_p ? vector_p->size() : 0)
1559{
1560}
1561
1562template <class TYPE>
1563template <class VECTOR>
1564inline
1566{
1567 if (d_vector_p) {
1568 const VSize newSize = d_vector_p->size();
1569
1570 // While 'vector::resize' does not always provide the no-throw
1571 // guarantee, here we are always shrinking the vector, so it should not
1572 // throw.
1573
1574 // The vector may have grown, it should never have been shrunk.
1575
1576 if (d_vSize < newSize) {
1577 d_vector_p->resize(d_vSize);
1578 }
1579 else {
1580 BSLS_ASSERT(d_vSize == newSize);
1581 }
1582 }
1583}
1584
1585// MANIPULATOR
1586template <class TYPE>
1587template <class VECTOR>
1588inline
1589void Deque<TYPE>::VectorThrowGuard<VECTOR>::release()
1590{
1591 d_vector_p = 0;
1592}
1593
1594 // ------------
1595 // bdlcc::Deque
1596 // ------------
1597
1598// PRIVATE MANIPULATORS
1599template <class TYPE>
1600template <class VECTOR>
1601inline
1602void Deque<TYPE>::removeAllImp(VECTOR *buffer)
1603{
1604 BSLMF_ASSERT(IsVector<VECTOR>::value);
1605
1606 Proctor proctor(this);
1607
1608 VectorThrowGuard<VECTOR> tg(buffer);
1609
1610 if (buffer) {
1611 const size_type size = d_monoDeque.size();
1612 buffer->reserve(buffer->size() + size);
1613
1614 for (size_type ii = 0; ii < size; ++ii) {
1615 buffer->push_back(bslmf::MovableRefUtil::move(d_monoDeque[ii]));
1616 }
1617 }
1618
1619 proctor->clear();
1620
1621 tg.release();
1622}
1623
1624
1625template <class TYPE>
1626template <class VECTOR>
1628 VECTOR *buffer)
1629{
1630 BSLMF_ASSERT(IsVector<VECTOR>::value);
1631
1632 Proctor proctor(this);
1633 VectorThrowGuard<VECTOR> tg(buffer);
1634
1635 // First, calculate 'toMove', which drives how the rest of the function
1636 // behaves.
1637
1638 const size_type size = d_monoDeque.size();
1639 const size_type toMove = bsl::min(size, maxNumItems);
1640
1641 if (buffer) {
1642 buffer->reserve(buffer->size() + toMove);
1643
1644 const size_type lastMovedIdx = size - toMove;
1645 for (size_type ii = size; lastMovedIdx < ii--; ) {
1646 buffer->push_back(bslmf::MovableRefUtil::move(d_monoDeque[ii]));
1647 }
1648 }
1649 d_monoDeque.erase(d_monoDeque.end() - toMove, d_monoDeque.end());
1650
1651 tg.release();
1652
1653 // Signalling will happen automatically when proctor is destroyed.
1654}
1655
1656template <class TYPE>
1657template <class VECTOR>
1659 VECTOR *buffer)
1660{
1661 BSLMF_ASSERT(IsVector<VECTOR>::value);
1662
1663 typedef typename MonoDeque::iterator Iterator;
1664
1665 Proctor proctor(this);
1666 VectorThrowGuard<VECTOR> tg(buffer);
1667
1668 // First, calculate 'toMove', which drives how the rest of the function
1669 // behaves.
1670
1671 const size_type toMove = bsl::min(d_monoDeque.size(), maxNumItems);
1672 const Iterator beginRange = d_monoDeque.begin();
1673 const Iterator endRange = beginRange + toMove;
1674
1675 if (buffer) {
1676 buffer->reserve(buffer->size() + toMove);
1677
1678 for (size_type ii = 0; ii < toMove; ++ii) {
1679 buffer->push_back(bslmf::MovableRefUtil::move(d_monoDeque[ii]));
1680 }
1681 }
1682 proctor->erase(beginRange, endRange);
1683
1684 tg.release();
1685
1686 // Signalling will happen automatically when proctor is destroyed.
1687}
1688
1689// CLASS METHODS
1690template <class TYPE>
1691inline
1693{
1694 return bsl::numeric_limits<size_type>::max();
1695}
1696
1697// CREATORS
1698template <class TYPE>
1699inline
1701: d_mutex()
1702, d_notEmptyCondition()
1703, d_notFullCondition()
1704, d_monoDeque(basicAllocator)
1705, d_highWaterMark(maxSizeT())
1706, d_clockType(bsls::SystemClockType::e_REALTIME)
1707{
1708}
1709
1710template <class TYPE>
1711inline
1713 bslma::Allocator *basicAllocator)
1714: d_mutex()
1715, d_notEmptyCondition(clockType)
1716, d_notFullCondition(clockType)
1717, d_monoDeque(basicAllocator)
1718, d_highWaterMark(maxSizeT())
1719, d_clockType(clockType)
1720{
1721}
1722
1723template <class TYPE>
1724inline
1725Deque<TYPE>::Deque(bsl::size_t highWaterMark,
1726 bslma::Allocator *basicAllocator)
1727: d_mutex()
1728, d_notEmptyCondition()
1729, d_notFullCondition()
1730, d_monoDeque(basicAllocator)
1731, d_highWaterMark(highWaterMark)
1732, d_clockType(bsls::SystemClockType::e_REALTIME)
1733{
1735}
1736
1737template <class TYPE>
1738inline
1739Deque<TYPE>::Deque(bsl::size_t highWaterMark,
1741 bslma::Allocator *basicAllocator)
1742: d_mutex()
1743, d_notEmptyCondition(clockType)
1744, d_notFullCondition(clockType)
1745, d_monoDeque(basicAllocator)
1746, d_highWaterMark(highWaterMark)
1747, d_clockType(clockType)
1748{
1750}
1751
1752template <class TYPE>
1753template <class INPUT_ITER>
1754inline
1755Deque<TYPE>::Deque(INPUT_ITER begin,
1756 INPUT_ITER end,
1757 bslma::Allocator *basicAllocator)
1758: d_mutex()
1759, d_notEmptyCondition()
1760, d_notFullCondition()
1761, d_monoDeque(begin, end, basicAllocator)
1762, d_highWaterMark(maxSizeT())
1763, d_clockType(bsls::SystemClockType::e_REALTIME)
1764{
1765}
1766
1767template <class TYPE>
1768template <class INPUT_ITER>
1769inline
1770Deque<TYPE>::Deque(INPUT_ITER begin,
1771 INPUT_ITER end,
1773 bslma::Allocator *basicAllocator)
1774: d_mutex()
1775, d_notEmptyCondition(clockType)
1776, d_notFullCondition(clockType)
1777, d_monoDeque(begin, end, basicAllocator)
1778, d_highWaterMark(maxSizeT())
1779, d_clockType(clockType)
1780{
1781}
1782
1783template <class TYPE>
1784template <class INPUT_ITER>
1785inline
1786Deque<TYPE>::Deque(INPUT_ITER begin,
1787 INPUT_ITER end,
1788 bsl::size_t highWaterMark,
1789 bslma::Allocator *basicAllocator)
1790: d_mutex()
1791, d_notEmptyCondition()
1792, d_notFullCondition()
1793, d_monoDeque(begin, end, basicAllocator)
1794, d_highWaterMark(highWaterMark)
1795, d_clockType(bsls::SystemClockType::e_REALTIME)
1796{
1798}
1799
1800template <class TYPE>
1801template <class INPUT_ITER>
1802inline
1803Deque<TYPE>::Deque(INPUT_ITER begin,
1804 INPUT_ITER end,
1805 bsl::size_t highWaterMark,
1807 bslma::Allocator *basicAllocator)
1808: d_mutex()
1809, d_notEmptyCondition(clockType)
1810, d_notFullCondition(clockType)
1811, d_monoDeque(begin, end, basicAllocator)
1812, d_highWaterMark(highWaterMark)
1813, d_clockType(clockType)
1814{
1816}
1817
1818template <class TYPE>
1819inline
1821 bslma::Allocator *basicAllocator)
1822: d_mutex()
1823, d_notEmptyCondition()
1824, d_notFullCondition()
1825, d_monoDeque(basicAllocator)
1826, d_highWaterMark(maxSizeT())
1827, d_clockType(original.d_clockType)
1828{
1829 ConstProctor proctor(&original);
1830
1831 d_monoDeque.insert(d_monoDeque.end(), proctor->begin(), proctor->end());
1832}
1833
1834template <class TYPE>
1835inline
1839
1840// MANIPULATORS
1841template <class TYPE>
1842inline
1843void Deque<TYPE>::forcePushBack(const TYPE& item)
1844{
1845 {
1846 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1847
1848 d_monoDeque.push_back(item);
1849 }
1850
1851 d_notEmptyCondition.signal();
1852}
1853
1854template <class TYPE>
1855inline
1857{
1858 {
1859 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1860
1861 d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
1862 }
1863
1864 d_notEmptyCondition.signal();
1865}
1866
1867template <class TYPE>
1868template <class INPUT_ITER>
1869inline
1870void Deque<TYPE>::forcePushBack(INPUT_ITER begin,
1871 INPUT_ITER end)
1872{
1873 size_type growth;
1874 {
1875 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1876
1877 DequeThrowGuard tg(&d_monoDeque);
1878
1879 const size_type initialSize = d_monoDeque.size();
1880 d_monoDeque.insert(d_monoDeque.end(), begin, end);
1881 growth = d_monoDeque.size() - initialSize;
1882
1883 tg.release();
1884 }
1885
1886 for (; growth > 0; --growth) {
1887 d_notEmptyCondition.signal();
1888 }
1889}
1890
1891template <class TYPE>
1892inline
1893void Deque<TYPE>::forcePushFront(const TYPE& item)
1894{
1895 {
1896 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1897
1898 d_monoDeque.push_front(item);
1899 }
1900
1901 d_notEmptyCondition.signal();
1902}
1903
1904template <class TYPE>
1905inline
1907{
1908 {
1909 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1910
1911 d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
1912 }
1913
1914 d_notEmptyCondition.signal();
1915}
1916
1917template <class TYPE>
1918template <class INPUT_ITER>
1919inline
1920void Deque<TYPE>::forcePushFront(INPUT_ITER begin,
1921 INPUT_ITER end)
1922{
1923 size_type growth;
1924 {
1925 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1926
1927 DequeThrowGuard tg(&d_monoDeque);
1928
1929 const size_type initialSize = d_monoDeque.size();
1930 for (; end != begin; ++begin) {
1931 d_monoDeque.push_front(*begin);
1932 }
1933 growth = d_monoDeque.size() - initialSize;
1934
1935 tg.release();
1936 }
1937
1938 for (; growth > 0; --growth) {
1939 d_notEmptyCondition.signal();
1940 }
1941}
1942
1943template <class TYPE>
1945{
1946 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1947
1948 while (d_monoDeque.empty()) {
1949 d_notEmptyCondition.wait(&d_mutex);
1950 }
1951 TYPE ret(bslmf::MovableRefUtil::move(d_monoDeque.back()));
1952 d_monoDeque.pop_back();
1953
1954 const bool shouldSignal = d_monoDeque.size() < d_highWaterMark;
1955 lock.release()->unlock();
1956
1957 if (shouldSignal) {
1958 d_notFullCondition.signal();
1959 }
1960
1961 return ret;
1962}
1963
1964template <class TYPE>
1965void Deque<TYPE>::popBack(TYPE *item)
1966{
1967 bool shouldSignal;
1968
1969 {
1970 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1971
1972 while (d_monoDeque.empty()) {
1973 d_notEmptyCondition.wait(&d_mutex);
1974 }
1975
1976#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
1977 *item = bslmf::MovableRefUtil::move(d_monoDeque.back());
1978#else
1979 *item = d_monoDeque.back();
1980#endif
1981 d_monoDeque.pop_back();
1982 shouldSignal = d_monoDeque.size() < d_highWaterMark;
1983 }
1984
1985 if (shouldSignal) {
1986 d_notFullCondition.signal();
1987 }
1988}
1989
1990template <class TYPE>
1992{
1993 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1994
1995 while (d_monoDeque.empty()) {
1996 d_notEmptyCondition.wait(&d_mutex);
1997 }
1998 TYPE ret(bslmf::MovableRefUtil::move(d_monoDeque.front()));
1999 d_monoDeque.pop_front();
2000
2001 const bool shouldSignal = d_monoDeque.size() < d_highWaterMark;
2002 lock.release()->unlock();
2003
2004 if (shouldSignal) {
2005 d_notFullCondition.signal();
2006 }
2007
2008 return ret;
2009}
2010
2011template <class TYPE>
2013{
2014 bool shouldSignal;
2015 {
2016 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2017
2018 while (d_monoDeque.empty()) {
2019 d_notEmptyCondition.wait(&d_mutex);
2020 }
2021#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
2022 *item = bslmf::MovableRefUtil::move(d_monoDeque.front());
2023#else
2024 *item = d_monoDeque.front();
2025#endif
2026 d_monoDeque.pop_front();
2027
2028 shouldSignal = d_monoDeque.size() < d_highWaterMark;
2029 }
2030
2031 if (shouldSignal) {
2032 d_notFullCondition.signal();
2033 }
2034}
2035
2036template <class TYPE>
2037void Deque<TYPE>::pushBack(const TYPE& item)
2038{
2039 {
2040 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2041
2042 while (d_monoDeque.size() >= d_highWaterMark) {
2043 d_notFullCondition.wait(&d_mutex);
2044 }
2045 d_monoDeque.push_back(item);
2046 }
2047
2048 d_notEmptyCondition.signal();
2049}
2050
2051template <class TYPE>
2053{
2054 {
2055 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2056
2057 while (d_monoDeque.size() >= d_highWaterMark) {
2058 d_notFullCondition.wait(&d_mutex);
2059 }
2060 d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
2061 }
2062
2063 d_notEmptyCondition.signal();
2064}
2065
2066template <class TYPE>
2067void Deque<TYPE>::pushFront(const TYPE& item)
2068{
2069 {
2070 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2071
2072 while (d_monoDeque.size() >= d_highWaterMark) {
2073 d_notFullCondition.wait(&d_mutex);
2074 }
2075 d_monoDeque.push_front(item);
2076 }
2077
2078 d_notEmptyCondition.signal();
2079}
2080
2081template <class TYPE>
2083{
2084 {
2085 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2086
2087 while (d_monoDeque.size() >= d_highWaterMark) {
2088 d_notFullCondition.wait(&d_mutex);
2089 }
2090 d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
2091 }
2092
2093 d_notEmptyCondition.signal();
2094}
2095
2096template <class TYPE>
2097inline
2099{
2100 removeAllImp(static_cast<bsl::vector<TYPE> *>(0));
2101}
2102
2103template <class TYPE>
2104inline
2106{
2107 removeAllImp(buffer);
2108}
2109
2110template <class TYPE>
2111inline
2112void Deque<TYPE>::removeAll(std::vector<TYPE> *buffer)
2113{
2114 removeAllImp(buffer);
2115}
2116
2117#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
2118template <class TYPE>
2119inline
2120void Deque<TYPE>::removeAll(std::pmr::vector<TYPE> *buffer)
2121{
2122 removeAllImp(buffer);
2123}
2124#endif
2125
2126template <class TYPE>
2128 const bsls::TimeInterval& timeout)
2129{
2130 bool shouldSignal;
2131 {
2132 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2133
2134 while (d_monoDeque.empty()) {
2135 if (d_notEmptyCondition.timedWait(&d_mutex, timeout)) {
2136 return 1; // RETURN
2137 }
2138 }
2139#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
2140 *item = bslmf::MovableRefUtil::move(d_monoDeque.back());
2141#else
2142 *item = d_monoDeque.back();
2143#endif
2144 d_monoDeque.pop_back();
2145
2146 shouldSignal = d_monoDeque.size() < d_highWaterMark;
2147 }
2148
2149 if (shouldSignal) {
2150 d_notFullCondition.signal();
2151 }
2152
2153 return 0;
2154}
2155
2156template <class TYPE>
2158 const bsls::TimeInterval& timeout)
2159{
2160 bool shouldSignal;
2161 {
2162 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2163
2164 while (d_monoDeque.empty()) {
2165 if (d_notEmptyCondition.timedWait(&d_mutex, timeout)) {
2166 return 1; // RETURN
2167 }
2168 }
2169#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
2170 *item = bslmf::MovableRefUtil::move(d_monoDeque.front());
2171#else
2172 *item = d_monoDeque.front();
2173#endif
2174 d_monoDeque.pop_front();
2175
2176 shouldSignal = d_monoDeque.size() < d_highWaterMark;
2177 }
2178
2179 if (shouldSignal) {
2180 d_notFullCondition.signal();
2181 }
2182
2183 return 0;
2184}
2185
2186template <class TYPE>
2187int Deque<TYPE>::timedPushBack(const TYPE& item,
2188 const bsls::TimeInterval& timeout)
2189{
2190 {
2191 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2192
2193 while (d_monoDeque.size() >= d_highWaterMark) {
2194 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
2195 return 1; // RETURN
2196 }
2197 }
2198 d_monoDeque.push_back(item);
2199 }
2200
2201 d_notEmptyCondition.signal();
2202
2203 return 0;
2204}
2205
2206template <class TYPE>
2208 const bsls::TimeInterval& timeout)
2209{
2210 {
2211 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2212
2213 while (d_monoDeque.size() >= d_highWaterMark) {
2214 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
2215 return 1; // RETURN
2216 }
2217 }
2218 d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
2219 }
2220
2221 d_notEmptyCondition.signal();
2222
2223 return 0;
2224}
2225
2226template <class TYPE>
2227int Deque<TYPE>::timedPushFront(const TYPE& item,
2228 const bsls::TimeInterval &timeout)
2229{
2230 {
2231 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2232
2233 while (d_monoDeque.size() >= d_highWaterMark) {
2234 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
2235 return 1; // RETURN
2236 }
2237 }
2238 d_monoDeque.push_front(item);
2239 }
2240
2241 d_notEmptyCondition.signal();
2242
2243 return 0;
2244}
2245
2246template <class TYPE>
2248 const bsls::TimeInterval &timeout)
2249{
2250 {
2251 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2252
2253 while (d_monoDeque.size() >= d_highWaterMark) {
2254 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
2255 return 1; // RETURN
2256 }
2257 }
2258 d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
2259 }
2260
2261 d_notEmptyCondition.signal();
2262
2263 return 0;
2264}
2265
2266template <class TYPE>
2268{
2269 bool shouldSignal;
2270 {
2271 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2272
2273 if (d_monoDeque.empty()) {
2274 return 1; // RETURN
2275 }
2276#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
2277 *item = bslmf::MovableRefUtil::move(d_monoDeque.back());
2278#else
2279 *item = d_monoDeque.back();
2280#endif
2281 d_monoDeque.pop_back();
2282
2283 shouldSignal = d_monoDeque.size() < d_highWaterMark;
2284 }
2285
2286 if (shouldSignal) {
2287 d_notFullCondition.signal();
2288 }
2289
2290 return 0;
2291}
2292
2293template <class TYPE>
2294inline
2295void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type maxNumItems)
2296{
2297 tryPopBackImp(maxNumItems, static_cast<bsl::vector<TYPE> *>(0));
2298}
2299
2300template <class TYPE>
2301inline
2302void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type maxNumItems,
2303 bsl::vector<TYPE> *buffer)
2304{
2305 tryPopBackImp(maxNumItems, buffer);
2306}
2307
2308template <class TYPE>
2309inline
2310void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type maxNumItems,
2311 std::vector<TYPE> *buffer)
2312{
2313 tryPopBackImp(maxNumItems, buffer);
2314}
2315
2316#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
2317template <class TYPE>
2318inline
2319void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type maxNumItems,
2320 std::pmr::vector<TYPE> *buffer)
2321{
2322 tryPopBackImp(maxNumItems, buffer);
2323}
2324#endif
2325
2326template <class TYPE>
2328{
2329 bool shouldSignal;
2330 {
2331 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2332
2333 if (d_monoDeque.empty()) {
2334 return 1; // RETURN
2335 }
2336#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
2337 *item = bslmf::MovableRefUtil::move(d_monoDeque.front());
2338#else
2339 *item = d_monoDeque.front();
2340#endif
2341 d_monoDeque.pop_front();
2342
2343 shouldSignal = d_monoDeque.size() < d_highWaterMark;
2344 }
2345
2346 if (shouldSignal) {
2347 d_notFullCondition.signal();
2348 }
2349
2350 return 0;
2351}
2352
2353template <class TYPE>
2354void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type maxNumItems)
2355{
2356 tryPopFrontImp(maxNumItems, static_cast<bsl::vector<TYPE> *>(0));
2357}
2358
2359template <class TYPE>
2360void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type maxNumItems,
2361 bsl::vector<TYPE> *buffer)
2362{
2363 tryPopFrontImp(maxNumItems, buffer);
2364}
2365
2366template <class TYPE>
2367void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type maxNumItems,
2368 std::vector<TYPE> *buffer)
2369{
2370 tryPopFrontImp(maxNumItems, buffer);
2371}
2372
2373#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
2374template <class TYPE>
2375void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type maxNumItems,
2376 std::pmr::vector<TYPE> *buffer)
2377{
2378 tryPopFrontImp(maxNumItems, buffer);
2379}
2380#endif
2381
2382template <class TYPE>
2383int Deque<TYPE>::tryPushBack(const TYPE& item)
2384{
2385 {
2386 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2387
2388 if (d_monoDeque.size() >= d_highWaterMark) {
2389 return 1; // RETURN
2390 }
2391
2392 d_monoDeque.push_back(item);
2393 }
2394
2395 d_notEmptyCondition.signal();
2396
2397 return 0;
2398}
2399
2400template <class TYPE>
2402{
2403 {
2404 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2405
2406 if (d_monoDeque.size() >= d_highWaterMark) {
2407 return 1; // RETURN
2408 }
2409
2410 d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
2411 }
2412
2413 d_notEmptyCondition.signal();
2414
2415 return 0;
2416}
2417
2418template <class TYPE>
2419template <class INPUT_ITER>
2422 INPUT_ITER end)
2423{
2424 size_type growth;
2425 {
2426 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2427
2428 DequeThrowGuard tg(&d_monoDeque);
2429
2430 const size_type startLength = d_monoDeque.size();
2431 size_type length = startLength;
2432
2433 for (; length < d_highWaterMark && end != begin; ++length, ++begin) {
2434 d_monoDeque.push_back(*begin);
2435 }
2436
2437 tg.release();
2438
2439 growth = length - startLength;
2440 }
2441
2442 for (size_type ii = 0; ii < growth; ++ii) {
2443 d_notEmptyCondition.signal();
2444 }
2445
2446 return growth;
2447}
2448
2449template <class TYPE>
2450int Deque<TYPE>::tryPushFront(const TYPE& item)
2451{
2452 {
2453 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2454
2455 if (d_monoDeque.size() >= d_highWaterMark) {
2456 return 1; // RETURN
2457 }
2458
2459 d_monoDeque.push_front(item);
2460 }
2461
2462 d_notEmptyCondition.signal();
2463
2464 return 0;
2465}
2466
2467template <class TYPE>
2469{
2470 {
2471 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2472
2473 if (d_monoDeque.size() >= d_highWaterMark) {
2474 return 1; // RETURN
2475 }
2476
2477 d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
2478 }
2479
2480 d_notEmptyCondition.signal();
2481
2482 return 0;
2483}
2484
2485template <class TYPE>
2486template <class INPUT_ITER>
2489 INPUT_ITER end)
2490{
2491 size_type growth;
2492 {
2493 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2494
2495 DequeThrowGuard tg(&d_monoDeque);
2496
2497 const size_type startLength = d_monoDeque.size();
2498 size_type length = startLength;
2499
2500 for (; length < d_highWaterMark && end != begin; ++length, ++begin) {
2501 d_monoDeque.push_front(*begin);
2502 }
2503
2504 tg.release();
2505
2506 growth = length - startLength;
2507 }
2508
2509 for (size_type ii = 0; ii < growth; ++ii) {
2510 d_notEmptyCondition.signal();
2511 }
2512
2513 return growth;
2514}
2515
2516// ACCESSORS
2517template <class TYPE>
2518inline
2520{
2521 return d_monoDeque.get_allocator().mechanism();
2522}
2523
2524template <class TYPE>
2525inline
2527{
2528 return d_clockType;
2529}
2530
2531template <class TYPE>
2532inline
2534{
2535 // A mutex lock is unnecessary since we decided to make the high water mark
2536 // into a non-malleable property of this container.
2537 //
2538 // bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2539
2540 return d_highWaterMark;
2541}
2542
2543template <class TYPE>
2544inline
2546{
2547 // Note that it is VITAL to lock the mutex here. 'size' on a deque is a
2548 // potentially complex operation as the deque might be managing multiple
2549 // blocks of memory. If 'd_monoDeque' were being modified while we perform
2550 // the 'size' operation, we could potentially dereference pointers to
2551 // freed memory.
2552
2553 // The predessor to this component, @ref bcec_queue , originally had no
2554 // 'length' accessor, and we found that users were very, very frequently
2555 // accessing the underlying thread-unsafe container just to obtain the
2556 // length.
2557
2558 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
2559
2560 return d_monoDeque.size();
2561}
2562
2563} // close package namespace
2564
2565namespace bslma {
2566
2567template <class TYPE>
2569{};
2570
2571} // close namespace bslma
2572
2573
2574#endif
2575
2576// ----------------------------------------------------------------------------
2577// Copyright 2018 Bloomberg Finance L.P.
2578//
2579// Licensed under the Apache License, Version 2.0 (the "License");
2580// you may not use this file except in compliance with the License.
2581// You may obtain a copy of the License at
2582//
2583// http://www.apache.org/licenses/LICENSE-2.0
2584//
2585// Unless required by applicable law or agreed to in writing, software
2586// distributed under the License is distributed on an "AS IS" BASIS,
2587// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2588// See the License for the specific language governing permissions and
2589// limitations under the License.
2590// ----------------------------- END-OF-FILE ----------------------------------
2591
2592/** @} */
2593/** @} */
2594/** @} */
Definition bdlcc_deque.h:1205
bool isNull() const
Definition bdlcc_deque.h:1472
void release()
Definition bdlcc_deque.h:1422
const MonoDeque & operator*() const
Definition bdlcc_deque.h:1454
void load(const Deque< TYPE > *container)
Definition bdlcc_deque.h:1409
const TYPE & operator[](size_type position) const
Definition bdlcc_deque.h:1463
const MonoDeque * operator->() const
Definition bdlcc_deque.h:1445
~ConstProctor()
Definition bdlcc_deque.h:1401
Definition bdlcc_deque.h:1026
void release()
Definition bdlcc_deque.h:1543
~DequeThrowGuard()
Definition bdlcc_deque.h:1495
Definition bdlcc_deque.h:1130
void load(Deque< TYPE > *container)
Definition bdlcc_deque.h:1304
MonoDeque & operator*() const
Definition bdlcc_deque.h:1358
bool isNull() const
Return true if this object is not associated with a Deque object.
Definition bdlcc_deque.h:1376
MonoDeque * operator->() const
Definition bdlcc_deque.h:1349
~Proctor()
Definition bdlcc_deque.h:1296
void release()
Definition bdlcc_deque.h:1318
TYPE & operator[](typename MonoDeque::size_type position) const
Definition bdlcc_deque.h:1367
Definition bdlcc_deque.h:540
int timedPopFront(TYPE *item, const bsls::TimeInterval &timeout)
Definition bdlcc_deque.h:2157
bsl::deque< TYPE > MonoDeque
Definition bdlcc_deque.h:552
int tryPushBack(const TYPE &item)
Definition bdlcc_deque.h:2383
TYPE popBack()
Definition bdlcc_deque.h:1944
~Deque()
Definition bdlcc_deque.h:1836
Deque(bslma::Allocator *basicAllocator=0)
Definition bdlcc_deque.h:1700
bslma::Allocator * allocator() const
Return the allocator used by this container for allocating memory.
Definition bdlcc_deque.h:2519
static size_type maxSizeT()
Definition bdlcc_deque.h:1692
void pushBack(const TYPE &item)
Definition bdlcc_deque.h:2037
int timedPushFront(const TYPE &item, const bsls::TimeInterval &timeout)
Definition bdlcc_deque.h:2227
void forcePushFront(const TYPE &item)
Definition bdlcc_deque.h:1893
int timedPopBack(TYPE *item, const bsls::TimeInterval &timeout)
Definition bdlcc_deque.h:2127
int tryPopBack(TYPE *item)
Definition bdlcc_deque.h:2267
void tryPopFront(size_type maxNumItems, bsl::vector< TYPE > *buffer)
int timedPushBack(const TYPE &item, const bsls::TimeInterval &timeout)
Definition bdlcc_deque.h:2187
size_type length() const
Definition bdlcc_deque.h:2545
void tryPopBack(size_type maxNumItems, std::vector< TYPE > *buffer)
void tryPopBack(size_type maxNumItems, bsl::vector< TYPE > *buffer)
void removeAll()
Definition bdlcc_deque.h:2098
int tryPopFront(TYPE *item)
Definition bdlcc_deque.h:2327
TYPE popFront()
Definition bdlcc_deque.h:1991
void forcePushBack(const TYPE &item)
Definition bdlcc_deque.h:1843
MonoDeque::size_type size_type
Definition bdlcc_deque.h:553
void tryPopFront(size_type maxNumItems, std::vector< TYPE > *buffer)
bsls::SystemClockType::Enum clockType() const
Definition bdlcc_deque.h:2526
void tryPopBack(size_type maxNumItems)
size_type highWaterMark() const
Return the high-water mark value for this container.
Definition bdlcc_deque.h:2533
int tryPushFront(const TYPE &item)
Definition bdlcc_deque.h:2450
void pushFront(const TYPE &item)
Definition bdlcc_deque.h:2067
void tryPopFront(size_type maxNumItems)
iterator end() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_deque.h:1940
size_type size() const BSLS_KEYWORD_NOEXCEPT
Return the number of elements contained by this deque.
Definition bslstl_deque.h:2074
iterator begin() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_deque.h:1932
std::size_t size_type
Definition bslstl_deque.h:606
Definition bslstl_deque.h:772
iterator insert(const_iterator position, const VALUE_TYPE &value)
Definition bslstl_deque.h:3671
ConstIterator const_iterator
Definition bslstl_deque.h:823
iterator erase(const_iterator position)
Definition bslstl_deque.h:3897
Iterator iterator
Definition bslstl_deque.h:822
std::size_t size_type
Definition bslstl_deque.h:824
Definition bslstl_vector.h:1025
Definition bslma_allocator.h:457
Definition bslmf_movableref.h:751
Definition bslmt_condition.h:220
Definition bslmt_lockguard.h:234
T * release()
Definition bslmt_lockguard.h:493
Definition bslmt_mutex.h:315
void lock()
Definition bslmt_mutex.h:392
void unlock()
Definition bslmt_mutex.h:410
Definition bsls_timeinterval.h:301
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_ASSERT_OPT(X)
Definition bsls_assert.h:1856
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.
Definition bdlcc_boundedqueue.h:270
Definition balxml_encoderoptions.h:68
Definition bdlt_iso8601util.h:691
Definition bslmf_issame.h:146
Definition bslma_usesbslmaallocator.h:343
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060
Enum
Definition bsls_systemclocktype.h:117