// bdlcc_deque.h                                                      -*-C++-*-
#ifndef INCLUDED_BDLCC_DEQUE
#define INCLUDED_BDLCC_DEQUE

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a fully thread-safe deque container.
//
//@CLASSES:
//  bdlcc::Deque: thread-safe 'bsl::deque' wrapper
//
//@SEE_ALSO: bsl::deque
//
//@DESCRIPTION: This component provides 'bdlcc::Deque<TYPE>', a fully
// thread-safe implementation of an efficient, double-ended queue of
// (template parameter) 'TYPE' values.  'bdlcc::Deque' is effectively a
// thread-safe wrapper for 'bsl::deque', whose interface is also made available
// through proctor types that are nested classes.
//
///Thread Safety
///-------------
// 'bdlcc::Deque' is fully *thread-safe*, meaning that all non-creator
// operations on an object can be safely invoked simultaneously from multiple
// threads.
//
///Exception Safety
///----------------
// Provided the template parameter 'TYPE' provides the following exception
// safety guarantees:
//: 1 The destructor provides the no-throw guarantee.
//: 2 Copy construction and assignment provide the strong guarantee and do not
//:   modify the source.
//: 3 Move construction and assignment where the allocators of the source and
//:   destination match, or if the type is non-allocating, provide the no-throw
//:   guarantee.
//: 4 Move construction and assignment where the allocators of source and
//:   destination do not match behave like non-moving copy construction and
//:   assignment.
// All operations on 'bdlcc::Deque' provide the strong exception guarantee,
// both for the 'bdlcc::Deque's own salient state and the salient state of the
// 'vector', if any, passed to manipulators.  However, the non-salient
// 'capacity' of the underlying 'bsl::deque' and of the passed 'vector' may be
// modified.
//
///Design Rationale for 'bdlcc::Deque'
///-----------------------------------
// The fully thread-safe 'bdlcc::Deque' is similar to 'bsl::deque' in many
// regards, but there are several differences in method behavior and signature
// that arise due to the thread-aware nature of the container and its
// anticipated usage pattern.
//
// A user of 'bsl::deque' is expected to consult the 'size' or 'empty'
// accessors before reading or popping to determine whether elements are
// available in the container to be read or popped.  This won't work in a
// multithreaded context since reading the accessor is a separate operation
// than the read or pop, and another thread may have altered the state of the
// container in between.
//
// So we have eliminated the 'front', 'back' and random-access methods.
// Reading is done from the ends of the container via the 'popFront' and
// 'popBack' methods, which return a 'TYPE' object *by* *value*, rather than
// returning 'void', as 'pop_front' and 'pop_back' in 'bsl::deque' do.
// Moreover, if a 'bdlcc::Deque' object is empty, 'popFront' and 'popBack' will
// block indefinitely until an item is added to the container.
//
///'High-Water Mark' Feature
///-------------------------
// The behaviors of the 'push' methods differ from those of 'bsl::deque' in
// that they can block under certain circumstances.  'bdlcc::Deque' supports
// the notion of a *suggested* maximum capacity known as the *high-water*
// *mark*.  The high-water mark value is supplied at construction, and affects
// some of the various forms of 'push*' methods.  The container is considered
// to be *full* if it contains (at least) the high-water mark number of items,
// and the container has *space* *available* if it is not full.  The high-water
// mark is set at construction and cannot be changed afterward.  If no
// high-water mark is specified, the high-water mark of the container is
// effectively inifinite.  Some of the variants of push operations (described
// below) may fail, and the return status of those operations indicates whether
// the operation succeeded, failed, or partially succeeded (which may happen,
// for example, when pushing a range of values).
//
// 'bdlcc::Deque' supports four variants of the two 'push' methods, whose
// behaviors differ when the container is *full* (i.e. when the push would
// raise the length of the container above the high-water mark).
//
//: 1 *blocking*: ('pushBack', 'pushFront'): If the container is full, block
//:   until space is available, then push, otherwise push immediately.
//:
//: 2 *try* ('tryPushBack', 'tryPushFront'): If the container is full, fail
//:   immediately.  If space is available, succeed immediately.  Note that
//:   partial success is possible in the case of a range try push.
//:
//: 3 *timed* *blocking*: ('timedPushBack', 'timedPushFront'): If the container
//:   is full, block until either space is available or the specified timeout
//:   has been reached.  If space was, or became, available, push and succeed,
//:   otherwise fail.
//:
//: 4 *force*: ('forcePushBack', 'forcePushFront'): If the container is full,
//:   push anyway, increasing the container's size above its high-water mark,
//:   always succeeding immediately.
//
// Note that the availability of force pushes means that the high-water mark is
// a suggestion and not an invariant.
//
// The purpose of a high-water mark is to enable the client to use the
// container as a fixed-length container, where pushes that will grow it above
// a certain size will block.  The purpose of the force pushes is to allow
// high-priority items to be pushed regardless of whether the container is
// full.
//
///Proctor Access
///--------------
// There are public nested classes 'bdlcc::Deque::Proctor' and
// 'bdlcc::Deque::ConstProctor' through which the client can directly access
// the underlying 'bsl::deque' contained in the 'bdlcc::Deque'.  When a proctor
// object is created, it acquires the container's mutex, and allows the client
// to use the overloaded '->' and '*' operators on the proctor object to access
// the underlying 'bsl::deque'.  'operator[]' is also provided for direct
// random access to that deque.  Because the mutex is locked, manipulators of
// 'bdlcc::Deque' called by other threads will block, thus allowing safe access
// to the underlying thread-unsafe container.  When the proctor is destroyed
// (or released via the 'release' method), the proctor signals the thread-aware
// container's condition variables to inform manipulators in other threads of
// new items being available for pops or new space becoming available for
// pushes.
//
///Supported Clock-Types
///---------------------
// The component 'bsls::SystemClockType' supplies the enumeration indicating
// the system clock on which the 'timedPush*' and 'timedPop*' methods should be
// based.  If the clock type indicated at construction is
// 'bsls::SystemClockType::e_REALTIME', time should be expressed as an absolute
// offset since 00:00:00 UTC, January 1, 1970 (which matches the epoch used in
// 'bdlt::SystemTime::now(bsls::SystemClockType::e_REALTIME)'.  If the clock
// type indicated at construction is 'bsls::SystemClockType::e_MONOTONIC', time
// should be expressed as an absolute offset since the epoch of this clock
// (which matches the epoch used in
// 'bsls::SystemTime::now(bsls::SystemClockType::e_MONOTONIC)'.
//
///WARNING: Synchronization Required on Destruction
///------------------------------------------------
// The behavior for the destructor is undefined unless all access or
// modification of the object is completed prior to its destruction.  Some form
// of synchronization, external to the component, is required to ensure this
// precondition on the destructor is met.  For example, if two (or more)
// threads are manipulating a queue, it is *not* safe to anticipate the number
// of elements added to the queue, and destroy that queue immediately after the
// last element is popped (without additional synchronization) because one of
// the corresponding push functions may not have completed (push may, for
// instance, signal waiting threads after the element is considered added to
// the queue).
//
///Tips For Migrating From 'bcec_Queue'
///------------------------------------
//: o 'InitialCapacity' has been eliminated.  Instead, construct your
//:   'bdlcc::Deque' object and then use proctor access to call 'reserve' on
//:   the contained 'bsl::deque' to reserve the desired initial capacity.
//:   (Note that 'deque::reserve' is not part of the C++ standard, though
//:   'bsl::deque' does implement it).
//:
//: o The mutex and condition variables are no longer directly exposed, in
//:   favor of the new proctor access, which gives direct access to the
//:   underlying 'bsl::deque', automatically locking the mutex and updating the
//:   condition variables as necessary.
//:
//: o A new, thread-safe 'length' accessor is provided, eliminating the need to
//:   access the underlying thread-unsafe container to obtain its length.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: A Queue of Work Requests
///- - - - - - - - - - - - - - - - - -
// First, declarer the struct 'WordData'.  Imagine it contains some data one
// wants to process:
//..
//  struct WorkData {
//      // work data...
//  };
//..
// Then, create the function that will produce a 'WorkData' object:
//..
//  bool getWorkData(WorkData *)
//      // Dummy implementation of 'getWorkData' function required by the usage
//      // example.
//  {
//      static bsls::AtomicInt i(1);
//      return ++i < 1000;
//  }
//..
// Next, declare 'WorkRequest', the type of object that will be stored in
// the container:
//..
//  struct WorkRequest {
//      // PUBLIC TYPES
//      enum RequestType {
//          e_WORK = 1,
//          e_STOP = 2
//      };
//
//      // PUBLIC DATA
//      RequestType d_type;
//      WorkData d_data;
//  };
//..
// Then, create the function that will do work on a 'WorkRequest' object:
//..
//  void doWork(WorkData *workData)
//      // Function that pretends to do work on the specified 'workData'.
//  {
//      // do some stuff with '*workData' ...
//
//      (void) workData;
//  }
//..
// Next, create the functor that will be run in the consumer threads:
//..
//  struct ConsumerFunctor {
//      // DATA
//      bdlcc::Deque<WorkRequest> *d_deque_p;
//
//      // CREATORS
//      explicit
//      ConsumerFunctor(bdlcc::Deque<WorkRequest> *container)
//          // Create a ''ConsumerFunctor' object that will consumer work
//          // requests from the specified 'container'.
//      : d_deque_p(container)
//      {}
//
//      // MANIPULATORS
//      void operator()()
//          // Pop work requests off the deque and process them until an
//          // 'e_STOP' request is encountered.
//      {
//          WorkRequest item;
//
//          do {
//              item = d_deque_p->popFront();
//              if (WorkRequest::e_WORK == item.d_type) {
//                  doWork(&item.d_data);
//              }
//          } while (WorkRequest::e_STOP != item.d_type);
//      }
//  };
//..
// Then, create the functor that will be run in the producer threads:
//..
//  struct ProducerFunctor {
//      // DATA
//      bdlcc::Deque<WorkRequest> *d_deque_p;
//
//      // CREATORS
//      explicit
//      ProducerFunctor(bdlcc::Deque<WorkRequest> *container)
//          // Create a 'ProducerFunctor' object that will enqueue work
//          // requests into the specified 'container'.
//      : d_deque_p(container)
//      {}
//
//      // MANIPULATORS
//      void operator()()
//          // Enqueue work requests to the container until 'getWorkData'
//          // returns 'false', then enqueue an 'e_STOP' request.
//      {
//          WorkRequest item;
//          WorkData    workData;
//
//          while (!getWorkData(&workData)) {
//              item.d_type = WorkRequest::e_WORK;
//              item.d_data = workData;
//              d_deque_p->pushBack(item);
//          }
//
//          item.d_type = WorkRequest::e_STOP;
//          d_deque_p->pushBack(item);
//      }
//  };
//..
// Next, in 'main', define the number of consumer and producer threads (these
// numbers must be equal).
//..
//  enum { k_NUM_CONSUMER_THREADS = 10,
//         k_NUM_PRODUCER_THREADS = k_NUM_CONSUMER_THREADS };
//..
// Then, create our container:
//..
//  bdlcc::Deque<WorkRequest> deque;
//..
// Next, create the array of thread handles for the threads we will spawn:
//..
//  bslmt::ThreadUtil::Handle handles[k_NUM_CONSUMER_THREADS +
//                                    k_NUM_PRODUCER_THREADS];
//..
// Now, spawn all the consumers and producers:
//..
//  int ti = 0, rc;
//  while (ti < k_NUM_CONSUMER_THREADS) {
//      rc = bslmt::ThreadUtil::create(&handles[ti++],
//                                     ConsumerFunctor(&deque));
//      assert(0 == rc);
//  }
//  while (ti < k_NUM_CONSUMER_THREADS + k_NUM_PRODUCER_THREADS) {
//      rc = bslmt::ThreadUtil::create(&handles[ti++],
//                                     ProducerFunctor(&deque));
//      assert(0 == rc);
//  }
//..
// Finally, join all the threads after they finish and confirm the container is
// empty afterward:
//..
//  while (ti > 0) {
//      rc = bslmt::ThreadUtil::join(handles[--ti]);
//      assert(0 == rc);
//  }
//  assert(0 == deque.length());
//..
//
///Example 2: A Queue of Events
/// - - - - - - - - - - - - - -
// First, we declare the 'Event' type, that will be contained in our
// 'bdlcc::Deque' object.
//..
//  struct Event {
//      enum EventType {
//          e_IN_PROGRESS   = 1,
//          e_TASK_COMPLETE = 2 };
//
//      EventType   d_type;
//      int         d_workerId;
//      int         d_eventNumber;
//      const char *d_eventText_p;
//  };
//
// Then, we define the number of events each thread will push:
//
//  const int k_NUM_TO_PUSH = 5;
//
// Next, we declare our 'WorkerFunctor' type, that will push 'k_NUM_TO_PUSH'
// events into the deque.
//
//  struct WorkerFunctor {
//      int                  d_workerId;
//      bdlcc::Deque<Event> *d_deque_p;
//      bslmt::Barrier      *d_barrier_p;
//
//      void operator()()
//          // All the threads will block on the same barrier so they all start
//          // at once to maximize concurrency.
//      {
//          d_barrier_p->wait();
//
//          // Loop to push 'k_NUM_TO_PUSH - 1' events onto the deque.
//
//          int evnum = 1;
//          while (evnum < k_NUM_TO_PUSH) {
//              // Yield every loop to maximize concurrency.
//
//              bslmt::ThreadUtil::yield();
//
//              // Create the event object.
//
//              Event ev = {
//                  Event::e_IN_PROGRESS,
//                  d_workerId,
//                  evnum++,
//                  "In-Progress Event"
//              };
//
//              // Push the event object.
//
//              d_deque_p->pushBack(ev);
//          }
//
//          // Create the completing event object.
//
//          Event ev = {
//              Event::e_TASK_COMPLETE,
//              d_workerId,
//              evnum,
//              "Task Complete"
//          };
//
//          // Push the completing event object.
//
//          d_deque_p->pushBack(ev);
//      }
//  };
//..
// Next, in 'main', define the number of threads:
//..
//  const int k_NUM_THREADS = 10;
//..
// Then, declare out 'bdlcc::Deque' object, the set of handles of the
// subthreads, and our barrier object:
//..
//  bdlcc::Deque<Event>       myDeque;
//  bslmt::ThreadUtil::Handle handles[k_NUM_THREADS];
//  bslmt::Barrier            barrier(k_NUM_THREADS + 1);
//..
// Next, spawn the worker threads:
//..
//  for (int ti = 0; ti < k_NUM_THREADS; ++ti) {
//      WorkerFunctor functor = { ti, &myDeque, &barrier };
//
//      bslmt::ThreadUtil::create(&handles[ti], functor);
//  }
//..
// Then, wait on the barrier, that will set all the subthreads running:
//..
//  barrier.wait();
//..
// Now, loop to pop the events off the deque, and keep track of how many
// 'e_COMPLETE' events have been popped.  When this equals the number of
// subthreads, we are done.
//..
//  int numCompleted = 0, numEvents = 0;
//  while (numCompleted < k_NUM_THREADS) {
//      Event ev = myDeque.popFront();
//      ++numEvents;
//      if (verbose) {
//          cout << "[" << ev.d_workerId << "] "
//               << ev.d_eventNumber << ". "
//               << ev.d_eventText_p << endl;
//      }
//      if (Event::e_TASK_COMPLETE == ev.d_type) {
//          ++numCompleted;
//          int rc = bslmt::ThreadUtil::join(handles[ev.d_workerId]);
//          assert(!rc);
//      }
//  }
//..
// Finally, perform some sanity checks:
//..
//  assert(k_NUM_THREADS * k_NUM_TO_PUSH == numEvents);
//  assert(0 == myDeque.length());
//..

#include <bdlscm_version.h>

#include <bslmt_condition.h>
#include <bslmt_lockguard.h>
#include <bslmt_mutex.h>

#include <bslma_allocator.h>

#include <bslmf_assert.h>
#include <bslmf_integralconstant.h>
#include <bslmf_movableref.h>

#include <bsls_assert.h>
#include <bsls_libraryfeatures.h>
#include <bsls_review.h>
#include <bsls_systemclocktype.h>
#include <bsls_timeinterval.h>

#include <bsl_algorithm.h>
#include <bsl_deque.h>
#include <bsl_vector.h>
#include <bsl_limits.h>
#include <bsl_cstddef.h>
#include <bsl_cstdio.h>

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
# include <memory_resource>
#endif

#include <vector>

namespace BloombergLP {
namespace bdlcc {

                                 // ===========
                                 // class Deque
                                 // ===========

template <class TYPE>
class Deque {
    // This class provides a fully thread-safe implementation of an efficient,
    // in-place, indexable, double-ended queue of (template parameter) 'TYPE'
    // values.  Direct access to the underlying 'bsl::deque<TYPE>' object is
    // provided through the nested 'Proctor' and 'ConstProctor' classes.  While
    // this class is not value-semantic, the underlying 'bsl::deque<TYPE>'
    // class is.

    // PRIVATE TYPES
    class DequeThrowGuard;
    template <class VECTOR>
    class VectorThrowGuard;

    template <class VECTOR>
    struct IsVector;

  public:
    // PUBLIC TYPES
    typedef bsl::deque<TYPE>               MonoDeque;
    typedef typename MonoDeque::size_type  size_type;

    class Proctor;            // defined after this 'class'
    class ConstProctor;       // defined after this 'class'

  private:
    // DATA
    mutable
    bslmt::Mutex       d_mutex;              // mutex object used to
                                             // synchronize access to the
                                             // underlying 'deque'.

    bslmt::Condition   d_notEmptyCondition;  // condition variable used to
                                             // signal that new data is
                                             // available in the container

    bslmt::Condition   d_notFullCondition;   // condition variable used to
                                             // signal when there is room
                                             // available to add new data to
                                             // the container

    MonoDeque          d_monoDeque;          // the underlying deque.

    const size_type    d_highWaterMark;      // positive maximum number of
                                             // items that can be contained
                                             // before insertions will be
                                             // blocked.

    bsls::SystemClockType::Enum
                       d_clockType;          // clock type used

  private:
    // NOT IMPLEMENTED
    Deque<TYPE>& operator=(const Deque<TYPE>&);

    // PRIVATE MANIPULATORS
    template <class VECTOR>
    void removeAllImp(VECTOR *buffer = 0);
        // If the optionally specified 'buffer' is non-zero, append all the
        // elements from this container to '*buffer' in the same order, then,
        // regardless of whether 'buffer' is zero, clear this container.  Note
        // that the previous contents of '*buffer' are not discarded -- the
        // removed items are appended to it.

    template <class VECTOR>
    void tryPopBackImp(size_type  maxNumItems,
                       VECTOR    *buffer);
        // Remove up to the specified 'maxNumItems' from the back of this
        // container.  Optionally specify a 'buffer' into which the items
        // removed from the container are loaded.  If 'buffer' is non-null, the
        // removed items are appended to it as if by repeated application of
        // 'buffer->push_back(popBack())' while the container is not empty and
        // 'maxNumItems' have not yet been removed.  Note that the ordering of
        // the items in '*buffer' after the call is the reverse of the ordering
        // they had in the deque.  Also note that '*buffer' is not cleared --
        // the popped items are appended after any pre-existing contents.

    template <class VECTOR>
    void tryPopFrontImp(size_type  maxNumItems,
                        VECTOR    *buffer);
        // Remove up to the specified 'maxNumItems' from the front of this
        // container.  Optionally specify a 'buffer' into which the items
        // removed from the container are appended.  If 'buffer' is non-null,
        // the removed items are appended to it as if by repeated application
        // of 'buffer->push_back(popFront())' while the const is not empty and
        // 'maxNumItems' have not yet been removed.  Note that '*buffer' is not
        // cleared -- the popped items are appended after any pre-existing
        // contents.

  public:
    // CLASS METHODS
    static
    size_type maxSizeT();
        // Return the maximum value that can be stored in a veriable of type
        // 'size_type'.  The high water mark defaults to having this value.

    // CREATORS
    explicit
    Deque(bslma::Allocator            *basicAllocator = 0);
    explicit
    Deque(bsls::SystemClockType::Enum  clockType,
          bslma::Allocator            *basicAllocator = 0);
        // Create a container of objects of (template parameter) 'TYPE', with
        // no high water mark, and use the specified 'clockType' to indicate
        // the epoch used for all time intervals (see {Supported Clock-Types}
        // in the component documentation).  If 'basicAllocator' is 0, the
        // currently installed default allocator is used.

    explicit
    Deque(bsl::size_t                  highWaterMark,
          bslma::Allocator            *basicAllocator = 0);
    Deque(bsl::size_t                  highWaterMark,
          bsls::SystemClockType::Enum  clockType,
          bslma::Allocator            *basicAllocator = 0);
        // Create a container of objects of (template parameter) 'TYPE', with
        // the specified 'highWaterMark', and use the specified 'clockType' to
        // indicate the epoch used for all time intervals (see {Supported
        // Clock-Types} in the component documentation).  Optionally specify a
        // 'basicAllocator' used to supply memory.  If 'basicAllocator' is 0,
        // the currently installed default allocator is used.  The behavior is
        // undefined unless 'highWaterMark > 0'.

    template <class INPUT_ITER>
    Deque(INPUT_ITER                   begin,
          INPUT_ITER                   end,
          bslma::Allocator            *basicAllocator = 0);
    template <class INPUT_ITER>
    Deque(INPUT_ITER                   begin,
          INPUT_ITER                   end,
          bsls::SystemClockType::Enum  clockType,
          bslma::Allocator            *basicAllocator = 0);
        // Create a container of objects of (template parameter) 'TYPE'
        // containing the sequence of elements in the specified range
        // '[begin .. end)', having no high water mark, and use the specified
        // 'clockType' to indicate the epoch used for all time intervals (see
        // {Supported Clock-Types} in the component documentation).  Optionally
        // specify a 'basicAllocator' used to supply memory.  If
        // 'basicAllocator' is 0, the currently installed default allocator is
        // used.  Note that the items in the range are treated as 'const'
        // objects, copied without being modified.

    template <class INPUT_ITER>
    Deque(INPUT_ITER                   begin,
          INPUT_ITER                   end,
          bsl::size_t                  highWaterMark,
          bslma::Allocator            *basicAllocator = 0);
    template <class INPUT_ITER>
    Deque(INPUT_ITER                   begin,
          INPUT_ITER                   end,
          bsl::size_t                  highWaterMark,
          bsls::SystemClockType::Enum  clockType,
          bslma::Allocator            *basicAllocator = 0);
        // Create a container of objects of (template parameter) 'TYPE'
        // containing the sequence of 'TYPE' values in the specified range
        // '[begin .. end)' having the specified 'highWaterMark', and use the
        // specified 'clockType' to indicate the epoch used for all time
        // intervals (see {Supported Clock-Types} in the component
        // documentation).  Optionally specify a 'basicAllocator' used to
        // supply memory.  If 'basicAllocator' is 0, the currently installed
        // default allocator is used.  The behavior is undefined unless
        // 'highWaterMark > 0'.  Note that if the number of elements in the
        // range '[begin, end)' exceeds 'highWaterMark', the effect will be the
        // same as if the extra elements were added by forced pushes.  Also
        // note that the items in the range are treated as 'const' objects,
        // copied without being modified.

    Deque(const Deque<TYPE>& original, bslma::Allocator *basicAllocator = 0);
        // Create a container having the same value as the specified 'original'
        // object.  Optionally specify a 'basicAllocator' used to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.

    ~Deque();
        // Destroy this container.  The behavior is undefined unless all access
        // or modification of the container has completed prior to the
        // destruction of this object.

    // MANIPULATORS
    void forcePushBack(const TYPE&             item);
        // Append the specified 'item' to the back of this container without
        // regard for the high-water mark.  Note that this method is provided
        // to allow high priority items to be inserted when the container is
        // full; 'pushFront' and 'pushBack' should be used for general use.

    void forcePushBack(bslmf::MovableRef<TYPE> item);
        // Append the specified move-insertable 'item' to the back of this
        // container without regard for the high-water mark.  'item' is left in
        // a valid but unspecified state.  Note that this method is provided to
        // allow high priority items to be inserted when the container is full;
        // 'pushFront' and 'pushBack' should be used for general use.

    template <class INPUT_ITER>
    void forcePushBack(INPUT_ITER begin,
                       INPUT_ITER end);
        // Append the specified specified range '[begin .. end)' of items to
        // the back of this container without regard for the high-water mark.
        // Note that the items in the range are treated as 'const' objects,
        // copied without being modified.

    void forcePushFront(const TYPE&             item);
        // Append the specified 'item' to the front of this container without
        // regard for the high-water mark.  Note that this method is provided
        // to allow high priority items to be inserted when the container is
        // full; 'pushFront' and 'pushBack' should be used for general use.

    void forcePushFront(bslmf::MovableRef<TYPE> item);
        // Append the specified move-insertable 'item' to the front of this
        // container without regard for the high-water mark.  'item' is left in
        // a valid but unspecified state.  Note that this method is provided to
        // allow high priority items to be inserted when the container is full;
        // 'pushFront' and 'pushBack' should be used for general use.

    template <class INPUT_ITER>
    void forcePushFront(INPUT_ITER begin,
                        INPUT_ITER end);
        // Append the specified specified range '[begin .. end)' of items to
        // the front of this container without regard for the high-water mark.
        // Note that pushed the items will be in the container in the reverse
        // of the order in which they occur in the range.  Also note that the
        // items in the range are treated as 'const' objects, copied without
        // being modified.

    TYPE popBack();
        // Return the last item in this container and remove it.  If this
        // container is empty, block until an item is available.

    void popBack(TYPE *item);
        // Remove the last item in this container and load that item into the
        // specified '*item'.  If this container is empty, block until an item
        // is available.

    TYPE popFront();
        // Return the first item in this container and remove it.  If this
        // container is empty, block until an item is available.

    void popFront(TYPE *item);
        // Remove the first item in this container and load that item into the
        // specified '*item'.  If the container is empty, block until an item
        // is available.

    void pushBack(const TYPE&             item);
        // Block until space in this container becomes available (see
        // {'High-Water Mark' Feature}), then append the specified 'item' to
        // the back of this container.

    void pushBack(bslmf::MovableRef<TYPE> item);
        // Block until space in this container becomes available (see
        // {'High-Water Mark' Feature}), then append the specified
        // move-insertable 'item' to the back of this container.  'item' is
        // left in a valid but unspecified state.

    void pushFront(const TYPE&             item);
        // Block until space in this container becomes available (see
        // {'High-Water Mark' Feature}), then append the specified 'item' to
        // the front of this container.

    void pushFront(bslmf::MovableRef<TYPE> item);
        // Block until space in this container becomes available (see
        // {'High-Water Mark' Feature}), then append the specified
        // move-insertable 'item' to the front of this container.  'item' is
        // left in a valid but unspecified state.

    void removeAll();
    void removeAll(bsl::vector<TYPE>      *buffer);
    void removeAll(std::vector<TYPE>      *buffer);
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
    void removeAll(std::pmr::vector<TYPE> *buffer);
#endif
        // If the optionally specified 'buffer' is non-zero, append all the
        // elements from this container to '*buffer' in the same order, then,
        // regardless of whether 'buffer' is zero, clear this container.  Note
        // that the previous contents of '*buffer' are not discarded -- the
        // removed items are appended to it.

    int timedPopBack(TYPE *item, const bsls::TimeInterval& timeout);
        // Remove the last item in this container and load that item value into
        // the specified '*item'.  If this container is empty, block until an
        // item is available or until the specified 'timeout' (expressed as the
        // !ABSOLUTE! time from 00:00:00 UTC, January 1, 1970) expires.  Return
        // 0 on success, and a non-zero value if the call timed out before an
        // item was available.  Note that this method can block indefinitely if
        // another thread has the mutex locked, particularly by a proctor
        // object -- there is no guarantee that this method will return after
        // 'timeout'.

    int timedPopFront(TYPE *item, const bsls::TimeInterval& timeout);
        // Remove the first item in this container and load that item value
        // into the specified '*item'.  If this container is empty, block until
        // an item is available or until the specified 'timeout' (expressed as
        // the !ABSOLUTE! time from 00:00:00 UTC, January 1, 1970) expires.
        // Return 0 on success, and a non-zero value if the call timed out
        // before an item was available.  Note that this method can block
        // indefinitely if another thread has the mutex locked, particularly by
        // a proctor object -- there is no guarantee that this method will
        // return after 'timeout'.

    int timedPushBack(const TYPE&               item,
                      const bsls::TimeInterval& timeout);
        // Append the specified 'item' to the back of this container if space
        // is available, otherwise (if the container is full) block waiting for
        // space to become available or until the specified 'timeout'
        // (expressed as the !ABSOLUTE! time from 00:00:00 UTC, January 1,
        // 1970) expires.  Return 0 if space was or became available and this
        // container was updated, and a non-zero value if the call timed out
        // before space became available and this container was left
        // unmodified.  Note that this method can block indefinitely if another
        // thread has the mutex locked, particularly by a proctor object --
        // there is no guarantee that this method will return after 'timeout'.

    int timedPushBack(bslmf::MovableRef<TYPE>   item,
                      const bsls::TimeInterval& timeout);
        // Append the specified move-insertable 'item' to the back of this
        // container if space is available, otherwise (if the container is
        // full) block waiting for space to become available or until the
        // specified 'timeout' (expressed as the !ABSOLUTE! time from 00:00:00
        // UTC, January 1, 1970) expires.  If the container is modified, 'item'
        // is left in a valid but unspecified state, otherwise 'item' is
        // unchanged.  Return 0 if space was or became available and this
        // container was updated, and a non-zero value if the call timed out
        // before space became available and this container was left
        // unmodified.  Note that this method can block indefinitely if another
        // thread has the mutex locked, particularly by a proctor object --
        // there is no guarantee that this method will return after 'timeout'.

    int timedPushFront(const TYPE&               item,
                       const bsls::TimeInterval& timeout);
        // Append the specified 'item' to the front of this container if space
        // is available, otherwise (if the container is full) block waiting for
        // space to become available or until the specified 'timeout'
        // (expressed as the !ABSOLUTE! time from 00:00:00 UTC, January 1,
        // 1970) expires.  Return 0 if space was or became available and this
        // container was updated, and a non-zero value if the call timed out
        // before space became available and this container was left
        // unmodified.  Note that this method can block indefinitely if another
        // thread has the mutex locked, particularly by a proctor object --
        // there is no guarantee that this method will return after 'timeout'.

    int timedPushFront(bslmf::MovableRef<TYPE>   item,
                       const bsls::TimeInterval& timeout);
        // Append the specified move-insertable 'item' to the front of this
        // container if space is available, otherwise (if the container is
        // full) block waiting for space to become available or until the
        // specified 'timeout' (expressed as the !ABSOLUTE! time from 00:00:00
        // UTC, January 1, 1970) expires.  If the container is modified,'item'
        // is left in a valid but unspecified state, otherwise 'item' is left
        // unchanged.  Return 0 if space was or became available and this
        // container was updated, and a non-zero value if the call timed out
        // before space became available and this container was left
        // unmodified.  Note that this method can block indefinitely if another
        // thread has the mutex locked, particularly by a proctor object --
        // there is no guarantee that this method will return after 'timeout'.

    int tryPopBack(TYPE *item);
        // If this container is non-empty, remove the last item, load that item
        // into the specified '*item', and return 0 indicating success.  If
        // this container is empty, return a non-zero value with no effect on
        // 'item' or the state of this container.

    void tryPopBack(size_type               maxNumItems);
    void tryPopBack(size_type               maxNumItems,
                    bsl::vector<TYPE>      *buffer);
    void tryPopBack(size_type               maxNumItems,
                    std::vector<TYPE>      *buffer);
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
    void tryPopBack(size_type               maxNumItems,
                    std::pmr::vector<TYPE> *buffer);
#endif
        // Remove up to the specified 'maxNumItems' from the back of this
        // container.  Optionally specify a 'buffer' into which the items
        // removed from the container are loaded.  If 'buffer' is non-null, the
        // removed items are appended to it as if by repeated application of
        // 'buffer->push_back(popBack())' while the container is not empty and
        // 'maxNumItems' have not yet been removed.  Note that the ordering of
        // the items in '*buffer' after the call is the reverse of the ordering
        // they had in the deque.  Also note that '*buffer' is not cleared --
        // the popped items are appended after any pre-existing contents.
        //
        // Also note that to transfer the entire contents of a 'Deque' 'd' to a
        // vector 'v', use 'd.removeAll(&v);'.

    int tryPopFront(TYPE *item);
        // If this container is non-empty, remove the first item, load that
        // item into the specified '*item', and return 0 indicating success.
        // If this container is empty, return a non-zero value with no effect
        // on '*item' or the state of this container.

    void tryPopFront(size_type               maxNumItems);
    void tryPopFront(size_type               maxNumItems,
                     bsl::vector<TYPE>      *buffer);
    void tryPopFront(size_type               maxNumItems,
                     std::vector<TYPE>      *buffer);
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
    void tryPopFront(size_type               maxNumItems,
                     std::pmr::vector<TYPE> *buffer);
#endif
        // Remove up to the specified 'maxNumItems' from the front of this
        // container.  Optionally specify a 'buffer' into which the items
        // removed from the container are appended.  If 'buffer' is non-null,
        // the removed items are appended to it as if by repeated application
        // of 'buffer->push_back(popFront())' while the const is not empty and
        // 'maxNumItems' have not yet been removed.  Note that '*buffer' is not
        // cleared -- the popped items are appended after any pre-existing
        // contents.
        //
        // Also note that to transfer the entire contents of a 'Deque' 'd' to a
        // vector 'v', use 'd.removeAll(&v);'.

    int tryPushBack(const TYPE&             item);
        // If the container is not full (see {'High-Water Mark' Feature}),
        // append the specified 'item' to the back of the container, otherwise
        // leave the container unchanged.  Return 0 if the container was
        // updated and a non-zero value otherwise.

    int tryPushBack(bslmf::MovableRef<TYPE> item);
        // If the container is not full (see {'High-Water Mark' Feature}),
        // append the specified move-insertable 'item' to the back of the
        // container, otherwise leave the container unchanged.  If the
        // container is modified, 'item' is left in a valid but unspecified
        // state, otherwise 'item' is unchanged.  Return 0 if the container was
        // updated and a non-zero value otherwise.

    template <class INPUT_ITER>
    size_type tryPushBack(INPUT_ITER begin,
                          INPUT_ITER end);
        // Push as many of the items in the specified range '[begin .. end)' as
        // there is space available for (see {'High-Water Mark' Feature}) to
        // the back of the container, stopping if the container high-water mark
        // is reached.  Return the number of items pushed.  Note that the items
        // in the range are treated as 'const' objects, copied without being
        // modified.

    int tryPushFront(const TYPE&             item);
        // If the container is not full (see {'High-Water Mark' Feature}),
        // append the specified 'item' to the front of the container, otherwise
        // leave the container unchanged.  Return 0 if the container was
        // updated and a non-zero value otherwise.

    int tryPushFront(bslmf::MovableRef<TYPE> item);
        // If the container is not full (see {'High-Water Mark' Feature}),
        // append the specified move-insertable 'item' to the front of the
        // container, otherwise leave the container unchanged.  If the
        // container is modified, 'item' is left in a valid but unspecified
        // state, otherwise 'item' is unchanged.  Return 0 if the container was
        // updated and a non-zero value otherwise.

    template <class INPUT_ITER>
    size_type tryPushFront(INPUT_ITER begin,
                           INPUT_ITER end);
        // Push as many of the items in the specified range '[begin .. end)' as
        // there is space available for (see {'High-Water Mark' Feature}) to
        // the front of the container, stopping if the container high-water
        // mark is reached.  Return the number of items pushed.  Note that the
        // pushed items will be in the container in the reverse of the order in
        // which they occur in the range.  Also note that the items in the
        // range are treated as 'const' objects, copied without being modified.

    // ACCESSORS
    bslma::Allocator *allocator() const;
        // Return the allocator used by this container for allocating memory.

    bsls::SystemClockType::Enum clockType() const;
        // Return the system clock type used for timing 'timed*' operations on
        // this object (see {Supported Clock-Types} in the component
        // documentation).

    size_type highWaterMark() const;
        // Return the high-water mark value for this container.

    size_type length() const;
        // Return the number of elements contained in this container.  Note
        // that this method temporarily acquires the mutex, so that this method
        // must not be called while a proctor in the same thread has this
        // container locked, and the value returned is potentially obsolete
        // before it is returned if any other threads are simultaneously
        // modifying this container.  To find the length while a proctor has
        // the container locked, call 'proctor->size()'.
};

template <class TYPE>
class Deque<TYPE>::DequeThrowGuard {
    // This private 'class' is used to manage a 'bsl::deque', during the course
    // of an operation by a 'bdlcc::Deque'.  Because it has a 'release' method,
    // it is actually a proctor, but we call it a 'guard' to avoid having
    // clients confuse it with this component's 'Proctor' and 'ConstProctor'
    // types.  A 'deque' that is being managed may only grow, and only on one
    // end or the other.  If a throw happens during the course of the operation
    // and this guard's destructor is called while still managing the object,
    // it will restore the managed object to its initial state via operations
    // that are guaranteed not to throw.

    // PRIVATE TYPES
    typedef bsl::deque<TYPE>                      MonoDeque;
    typedef typename MonoDeque::size_type         size_type;
    typedef typename MonoDeque::const_iterator    MDCIter;

    // DATA
    MonoDeque          *d_monoDeque_p;
    const MDCIter       d_mdBegin;
    const MDCIter       d_mdEnd;
    const bool          d_mdWasEmpty;

  private:
    // NOT IMPLEMENTED
    DequeThrowGuard(const DequeThrowGuard&);
    DequeThrowGuard& operator=(const DequeThrowGuard&);

  public:
    // CREATORS
    explicit
    DequeThrowGuard(MonoDeque *monoDeque_p);
        // Create a 'Deque_DequeThrowGuard' object that will manage the
        // specified '*monoDeque_p'.  The behavior is undefined if
        // '0 == monoDeque_p'.

    ~DequeThrowGuard();
        // If a 'MonoDeque' is being managed by this 'ThrowGuard', restore it
        // to the state it was in when this object was created.

    // MANIPULATOR
    void release();
        // Release the monitored 'MonoDeque' from management by this
        // 'Deque_DequeThrowGuard' object.
};

template <class TYPE>
template <class VECTOR>
class Deque<TYPE>::VectorThrowGuard {
    // This private 'class' is used to manage one 'vector' object during the
    // course of an operation by a 'bdlcc::Deque'.  Because it has a 'release'
    // method, it is actually a proctor, but we call it a 'guard' to avoid
    // having clients confuse it with the 'Proctor' and 'ConstProctor' types.
    // The vector may only grow by having objects appended to it.  If a throw
    // happens during the course of the operation and the guard's destructor is
    // called while still managing the object, it will restore the managed
    // object to its initial state via operations that are guaranteed not to
    // throw.

    // PRIVATE TYPES
    typedef typename VECTOR::size_type VSize;

    // DATA
    VECTOR         *d_vector_p;
    const VSize     d_vSize;

  private:
    // NOT IMPLEMENTED
    VectorThrowGuard(const VectorThrowGuard&);
    VectorThrowGuard& operator=(const VectorThrowGuard&);

  public:
    // CREATORS
    explicit
    VectorThrowGuard(VECTOR *vector_p);
        // Create a 'VectorThrowGuard' object that will manage the specified
        // '*vector_p'.  Note that the case where '0 == vector_p' is explicitly
        // permitted, in which case this object will not manage anything.

    ~VectorThrowGuard();
        // If a 'vector' is being managed by this 'VectorThrowGuard', restore
        // it to the state it was in when this object was created.

    // MANIPULATOR
    void release();
        // Release the monitored 'vector' from management by this
        // 'VectorThrowGuard' object.
};

template <class TYPE>
template <class VECTOR>
struct Deque<TYPE>::IsVector {
    // This 'struct' has a 'value' that evaluates to 'true' if the specified
    // 'VECTOR' is a 'bsl', 'std', or 'std::pmr' 'vector<VALUE>'.

    static const bool value =
                            bsl::is_same<bsl::vector<TYPE>, VECTOR>::value
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
                         || bsl::is_same<std::pmr::vector<TYPE>, VECTOR>::value
#endif
                         || bsl::is_same<std::vector<TYPE>, VECTOR>::value;
};

                              // ====================
                              // class Deque::Proctor
                              // ====================

template <class TYPE>
class Deque<TYPE>::Proctor {
    // This class defines a proctor type that provides direct access to the
    // underlying 'bsl::deque' contained in a 'Deque'.  Creation of a 'Proctor'
    // object locks the mutex of the 'Deque', and destruction unlocks it.

    // PRIVATE TYPES
    typedef bsl::deque<TYPE>              MonoDeque;
    typedef typename MonoDeque::size_type size_type;

    // DATA
    Deque<TYPE>    *d_container_p;
    size_type       d_startLength;      // If '!d_container_p', this field may
                                        // be left uninitialized.

  private:
    // NOT IMPLEMENTED
    Proctor(const Proctor&);
    Proctor& operator=(const Proctor&);

  public:
    // CREATORS
    explicit
    Proctor(Deque<TYPE> *container = 0);
        // Create a 'Proctor' object to provide access to the underlying
        // 'bsl::deque' contained in the optionally specified '*container',
        // locking 'container's mutex.  If no 'container' is specified, this
        // object will be null.

    ~Proctor();
        // Release the lock on the mutex of the 'Deque' that was provided at
        // contstuction and destroy this 'Proctor' object.  Signal the
        // conditions on the 'Deque' that was supplied to this object at
        // construction to reflect any changes that have been made to its
        // contents since construction.

    // MANIPULATORS
    void load(Deque<TYPE> *container);
        // In the case where this 'Proctor' has been released, attach this
        // object to the specified 'container'.  If this object is already
        // attached, release the previous object first.  The behavior is
        // undefined if '0 == container'.

    void release();
        // Release this proctor without destroying it.  Afterward the
        // destructor will have no effect.  This may be called multiple times;
        // only the first call has any effect.

    // ACCESSORS
    MonoDeque *operator->() const;
        // Return a pointer to the 'bsl::deque' contained in the 'Deque'
        // managed by this 'Proctor' object'.  The behavior is undefined if
        // this 'Proctor' has been released.

    MonoDeque& operator*() const;
        // Return a reference to the 'bsl::deque' managed by this 'Proctor'
        // object.  The behavior is undefined if this 'Proctor' has been
        // released.

    TYPE& operator[](typename MonoDeque::size_type position) const;
        // Return a reference providing modifiable access to the element at the
        // specified 'position' in the 'bsl::deque' held by this proctor.  The
        // behavior is undefined unless 'position < size' where 'size' is the
        // the number of elements in that deque.

    bool isNull() const;
        // Return 'true' if this object is not associated with a 'Deque'
        // object.
};

                            // =========================
                            // class Deque::ConstProctor
                            // =========================

template <class TYPE>
class Deque<TYPE>::ConstProctor {
    // This class defines a proctor type that provides direct const access to
    // the underlying 'bsl::deque' contained in a 'Deque'.

    // PRIVATE TYPES
    typedef bsl::deque<TYPE>              MonoDeque;
    typedef typename MonoDeque::size_type size_type;

    // DATA
    const Deque<TYPE>  *d_container_p;
    size_type           d_startLength;  // If '!d_container_p', this field may
                                        // be left uninitialized.

  private:
    // NOT IMPLEMENTED
    ConstProctor(const ConstProctor&);
    ConstProctor& operator=(const ConstProctor&);

  public:
    // CREATORS
    explicit
    ConstProctor(const Deque<TYPE> *container = 0);
        // Create a 'ConstProctor' object to provide const access to the
        // underlying 'bsl::deque' contained in the optionally specified
        // '*container', locking 'container's mutex.  If no 'container' is
        // specified, this object will be null.

    ~ConstProctor();
        // Release the lock on the mutex of the 'Deque' that was provided at
        // contstuction and destroy this 'Proctor' object.  The behavior is
        // undefined if the 'Deque' has been modified since the construction of
        // this object.

    // MANIPULATORS
    void load(const Deque<TYPE> *container);
        // In the case where this 'Proctor' has been released, attach this
        // object to the specified 'container'.  If this object is already
        // attached, release the previous object first.  The behavior is
        // undefined if '0 == container'.

    void release();
        // Release this proctor without destroying it.  Afterward the
        // destructor will have no effect.  This may be called multiple times;
        // only the first call has any effect;

    // ACCESSORS
    const MonoDeque *operator->() const;
        // Return a pointer to the 'bsl::deque' contained in the 'Deque'
        // managed by this object.  The behavior is undefined if this
        // 'ConstProctor' has been released.

    const MonoDeque& operator*() const;
        // Return a reference to the 'bsl::deque' managed by this 'Proctor'
        // object.  The behavior is undefined if this 'ConstProctor' has been
        // released.

    const TYPE& operator[](size_type position) const;
        // Return a reference providing non-modifiable access to the element at
        // the specified 'position' in the 'bsl::deque' held by this proctor.
        // The behavior is undefined unless 'position < size' where 'size' is
        // the number of elements in that deque.

    bool isNull() const;
        // Return 'true' if this object is not associated with a 'Deque'
        // object.
};

// ============================================================================
//                             INLINE DEFINITIONS
// ============================================================================

                            // ---------------------
                            // bdlcc::Deque::Proctor
                            // ---------------------

// CREATORS
template <class TYPE>
inline
Deque<TYPE>::Proctor::Proctor(Deque<TYPE> *container)
: d_container_p(0)
{
    if (container) {
        this->load(container);
    }

    // If '0 == container', leave 'd_startLength' uninitialized.
}

template <class TYPE>
inline
Deque<TYPE>::Proctor::~Proctor()
{
    this->release();
}

// MANIPULATORS
template <class TYPE>
inline
void Deque<TYPE>::Proctor::load(Deque<TYPE> *container)
{
    BSLS_ASSERT(0 != container);

    if (0 != d_container_p) {
        this->release();
    }

    container->d_mutex.lock();
    d_container_p = container;
    d_startLength = d_container_p->d_monoDeque.size();
}

template <class TYPE>
void Deque<TYPE>::Proctor::release()
{
    if (0 == d_container_p) {
        return;                                                       // RETURN
    }

    const size_type sz = d_container_p->d_monoDeque.size();
    size_type       ii = d_startLength;

    d_container_p->d_mutex.unlock();

    if (ii < sz) {
        do {
            d_container_p->d_notEmptyCondition.signal();
        } while (++ii < sz);
    }
    else {
        if (d_container_p->d_highWaterMark < ii) {
            ii = d_container_p->d_highWaterMark;
        }
        for (; ii > sz; --ii) {
            d_container_p->d_notFullCondition.signal();
        }
    }

    d_container_p = 0;
}

// ACCESSORS
template <class TYPE>
inline
bsl::deque<TYPE> *Deque<TYPE>::Proctor::operator->() const
{
    BSLS_ASSERT(d_container_p);

    return &d_container_p->d_monoDeque;
}

template <class TYPE>
inline
bsl::deque<TYPE>& Deque<TYPE>::Proctor::operator*() const
{
    BSLS_ASSERT(d_container_p);

    return d_container_p->d_monoDeque;
}

template <class TYPE>
inline
TYPE& Deque<TYPE>::Proctor::operator[](size_type position) const
{
    BSLS_ASSERT(position < d_container_p->d_monoDeque.size());

    return d_container_p->d_monoDeque[position];
}

template <class TYPE>
inline
bool Deque<TYPE>::Proctor::isNull() const
{
    return 0 == d_container_p;
}

                        // --------------------------
                        // bdlcc::Deque::ConstProctor
                        // --------------------------


// CREATORS
template <class TYPE>
inline
Deque<TYPE>::ConstProctor::ConstProctor(const Deque<TYPE> *container)
: d_container_p(0)
{
    if (container) {
        this->load(container);
    }

    // If '0 == container', leave 'd_startLength' uninitialized.
}

template <class TYPE>
inline
Deque<TYPE>::ConstProctor::~ConstProctor()
{
    this->release();
}

// MANIPULATORS
template <class TYPE>
inline
void Deque<TYPE>::ConstProctor::load(const Deque<TYPE> *container)
{
    BSLS_ASSERT(0 != container);

    this->release();

    container->d_mutex.lock();
    d_container_p = container;
    d_startLength = d_container_p->d_monoDeque.size();
}

template <class TYPE>
inline
void Deque<TYPE>::ConstProctor::release()
{
    // It is important that nobody did a const_cast and modified the underlying
    // 'bsls::deque' since this destructor won't signal the appropriate
    // condtions in the 'Deque' in that case.  If they wanted to modify the
    // 'bsl::deque' they should have used a 'Proctor' instead of a
    // 'ConstProctor'.

    if (0 == d_container_p) {
        return;                                                       // RETURN
    }

    BSLS_ASSERT_OPT(d_container_p->d_monoDeque.size() == d_startLength &&
                     "Underlying 'bsl::deque' modified through ConstProcter.");

    bslmt::Mutex *mutex = &d_container_p->d_mutex;
    d_container_p = 0;
    mutex->unlock();
}

// ACCESSORS
template <class TYPE>
inline
const bsl::deque<TYPE> *Deque<TYPE>::ConstProctor::operator->() const
{
    BSLS_ASSERT(d_container_p);

    return &d_container_p->d_monoDeque;
}

template <class TYPE>
inline
const bsl::deque<TYPE>& Deque<TYPE>::ConstProctor::operator*() const
{
    BSLS_ASSERT(d_container_p);

    return d_container_p->d_monoDeque;
}

template <class TYPE>
inline
const TYPE& Deque<TYPE>::ConstProctor::operator[](size_type position) const
{
    BSLS_ASSERT(position < d_container_p->d_monoDeque.size());

    return d_container_p->d_monoDeque[position];
}

template <class TYPE>
inline
bool Deque<TYPE>::ConstProctor::isNull() const
{
    return 0 == d_container_p;
}

                      // -----------------------------------
                      // bdlcc::Deque<TYPE>::DequeThrowGuard
                      // -----------------------------------

// CREATORS
template <class TYPE>
inline
Deque<TYPE>::DequeThrowGuard::DequeThrowGuard(bsl::deque<TYPE> *monoDeque_p)
: d_monoDeque_p(monoDeque_p)
, d_mdBegin(   monoDeque_p->cbegin())
, d_mdEnd(     monoDeque_p->cend())
, d_mdWasEmpty(monoDeque_p->empty())
{
    BSLS_ASSERT(0 != monoDeque_p);
}

template <class TYPE>
inline
Deque<TYPE>::DequeThrowGuard::~DequeThrowGuard()
{
    if (d_monoDeque_p)  {
        if (d_mdWasEmpty) {
            // In the case where the mono deque started out empty, pushing to
            // it can invalidate the iterators that were copied to 'd_mdBegin'
            // and 'd_mdEnd' when it was empty, so comparisons between
            // 'newBegin' & 'newEnd' and the old iterators will yield undefined
            // results.  So we kept a separate boolean, 'd_mdWasEmpty', to
            // track that case, which we handle specially here.

            d_monoDeque_p->clear();

            return;                                                   // RETURN
        }

        const MDCIter newBegin = d_monoDeque_p->cbegin();
        const MDCIter newEnd   = d_monoDeque_p->cend();

        // While range-based 'erase' of 'bsl::deque' does not always provide
        // the no-throw guarantee, all the erasing here is done at the ends of
        // the 'bsl::deque', so no items have to be copied around, so no
        // throwing should occur.

        // The 'MonoDeque' may have been pushed to, but only on one end or the
        // other.  It should never have been deleted from.

        if (newBegin < d_mdBegin) {
            BSLS_ASSERT(d_mdEnd == newEnd);

            d_monoDeque_p->erase(newBegin, d_mdBegin);
        }
        else {
            BSLS_ASSERT(newBegin == d_mdBegin);

            if (d_mdEnd < newEnd) {
                d_monoDeque_p->erase(d_mdEnd, newEnd);
            }
            else {
                BSLS_ASSERT(d_mdEnd == newEnd);
            }
        }
    }
}

// MANIPULATOR
template <class TYPE>
inline
void Deque<TYPE>::DequeThrowGuard::release()
{
    d_monoDeque_p = 0;
}

                  // --------------------------------------------
                  // bdlcc::Deque<TYPE>::VectorThrowGuard<VECTOR>
                  // --------------------------------------------

// CREATORS
template <class TYPE>
template <class VECTOR>
inline
Deque<TYPE>::VectorThrowGuard<VECTOR>::VectorThrowGuard(VECTOR *vector_p)
: d_vector_p(vector_p)
, d_vSize(vector_p ? vector_p->size() : 0)
{
}

template <class TYPE>
template <class VECTOR>
inline
Deque<TYPE>::VectorThrowGuard<VECTOR>::~VectorThrowGuard()
{
    if (d_vector_p) {
        const VSize newSize = d_vector_p->size();

        // While 'vector::resize' does not always provide the no-throw
        // guarantee, here we are always shrinking the vector, so it should not
        // throw.

        // The vector may have grown, it should never have been shrunk.

        if (d_vSize < newSize) {
            d_vector_p->resize(d_vSize);
        }
        else {
            BSLS_ASSERT(d_vSize == newSize);
        }
    }
}

// MANIPULATOR
template <class TYPE>
template <class VECTOR>
inline
void Deque<TYPE>::VectorThrowGuard<VECTOR>::release()
{
    d_vector_p = 0;
}

                                  // ------------
                                  // bdlcc::Deque
                                  // ------------

// PRIVATE MANIPULATORS
template <class TYPE>
template <class VECTOR>
inline
void Deque<TYPE>::removeAllImp(VECTOR *buffer)
{
    BSLMF_ASSERT(IsVector<VECTOR>::value);

    Proctor proctor(this);

    VectorThrowGuard<VECTOR> tg(buffer);

    if (buffer) {
        const size_type size = d_monoDeque.size();
        buffer->reserve(buffer->size() + size);

        for (size_type ii = 0; ii < size; ++ii) {
            buffer->push_back(bslmf::MovableRefUtil::move(d_monoDeque[ii]));
        }
    }

    proctor->clear();

    tg.release();
}


template <class TYPE>
template <class VECTOR>
void Deque<TYPE>::tryPopBackImp(typename Deque<TYPE>::size_type  maxNumItems,
                                VECTOR                          *buffer)
{
    BSLMF_ASSERT(IsVector<VECTOR>::value);

    Proctor proctor(this);
    VectorThrowGuard<VECTOR> tg(buffer);

    // First, calculate 'toMove', which drives how the rest of the function
    // behaves.

    const size_type size   = d_monoDeque.size();
    const size_type toMove = bsl::min(size, maxNumItems);

    if (buffer) {
        buffer->reserve(buffer->size() + toMove);

        const size_type lastMovedIdx = size - toMove;
        for (size_type ii = size; lastMovedIdx < ii--; ) {
            buffer->push_back(bslmf::MovableRefUtil::move(d_monoDeque[ii]));
        }
    }
    d_monoDeque.erase(d_monoDeque.end() - toMove, d_monoDeque.end());

    tg.release();

    // Signalling will happen automatically when proctor is destroyed.
}

template <class TYPE>
template <class VECTOR>
void Deque<TYPE>::tryPopFrontImp(typename Deque<TYPE>::size_type  maxNumItems,
                                 VECTOR                          *buffer)
{
    BSLMF_ASSERT(IsVector<VECTOR>::value);

    typedef typename MonoDeque::iterator Iterator;

    Proctor proctor(this);
    VectorThrowGuard<VECTOR> tg(buffer);

    // First, calculate 'toMove', which drives how the rest of the function
    // behaves.

    const size_type toMove     = bsl::min(d_monoDeque.size(), maxNumItems);
    const Iterator  beginRange = d_monoDeque.begin();
    const Iterator  endRange   = beginRange + toMove;

    if (buffer) {
        buffer->reserve(buffer->size() + toMove);

        for (size_type ii = 0; ii < toMove; ++ii) {
            buffer->push_back(bslmf::MovableRefUtil::move(d_monoDeque[ii]));
        }
    }
    proctor->erase(beginRange, endRange);

    tg.release();

    // Signalling will happen automatically when proctor is destroyed.
}

// CLASS METHODS
template <class TYPE>
inline
typename Deque<TYPE>::size_type Deque<TYPE>::maxSizeT()
{
    return bsl::numeric_limits<size_type>::max();
}

// CREATORS
template <class TYPE>
inline
Deque<TYPE>::Deque(bslma::Allocator *basicAllocator)
: d_mutex()
, d_notEmptyCondition()
, d_notFullCondition()
, d_monoDeque(basicAllocator)
, d_highWaterMark(maxSizeT())
, d_clockType(bsls::SystemClockType::e_REALTIME)
{
}

template <class TYPE>
inline
Deque<TYPE>::Deque(bsls::SystemClockType::Enum  clockType,
                   bslma::Allocator            *basicAllocator)
: d_mutex()
, d_notEmptyCondition(clockType)
, d_notFullCondition(clockType)
, d_monoDeque(basicAllocator)
, d_highWaterMark(maxSizeT())
, d_clockType(clockType)
{
}

template <class TYPE>
inline
Deque<TYPE>::Deque(bsl::size_t       highWaterMark,
                   bslma::Allocator *basicAllocator)
: d_mutex()
, d_notEmptyCondition()
, d_notFullCondition()
, d_monoDeque(basicAllocator)
, d_highWaterMark(highWaterMark)
, d_clockType(bsls::SystemClockType::e_REALTIME)
{
    BSLS_ASSERT(highWaterMark > 0);
}

template <class TYPE>
inline
Deque<TYPE>::Deque(bsl::size_t                  highWaterMark,
                   bsls::SystemClockType::Enum  clockType,
                   bslma::Allocator            *basicAllocator)
: d_mutex()
, d_notEmptyCondition(clockType)
, d_notFullCondition(clockType)
, d_monoDeque(basicAllocator)
, d_highWaterMark(highWaterMark)
, d_clockType(clockType)
{
    BSLS_ASSERT(highWaterMark > 0);
}

template <class TYPE>
template <class INPUT_ITER>
inline
Deque<TYPE>::Deque(INPUT_ITER        begin,
                   INPUT_ITER        end,
                   bslma::Allocator *basicAllocator)
: d_mutex()
, d_notEmptyCondition()
, d_notFullCondition()
, d_monoDeque(begin, end, basicAllocator)
, d_highWaterMark(maxSizeT())
, d_clockType(bsls::SystemClockType::e_REALTIME)
{
}

template <class TYPE>
template <class INPUT_ITER>
inline
Deque<TYPE>::Deque(INPUT_ITER                   begin,
                   INPUT_ITER                   end,
                   bsls::SystemClockType::Enum  clockType,
                   bslma::Allocator            *basicAllocator)
: d_mutex()
, d_notEmptyCondition(clockType)
, d_notFullCondition(clockType)
, d_monoDeque(begin, end, basicAllocator)
, d_highWaterMark(maxSizeT())
, d_clockType(clockType)
{
}

template <class TYPE>
template <class INPUT_ITER>
inline
Deque<TYPE>::Deque(INPUT_ITER        begin,
                   INPUT_ITER        end,
                   bsl::size_t       highWaterMark,
                   bslma::Allocator *basicAllocator)
: d_mutex()
, d_notEmptyCondition()
, d_notFullCondition()
, d_monoDeque(begin, end, basicAllocator)
, d_highWaterMark(highWaterMark)
, d_clockType(bsls::SystemClockType::e_REALTIME)
{
    BSLS_ASSERT(highWaterMark > 0);
}

template <class TYPE>
template <class INPUT_ITER>
inline
Deque<TYPE>::Deque(INPUT_ITER                   begin,
                   INPUT_ITER                   end,
                   bsl::size_t                  highWaterMark,
                   bsls::SystemClockType::Enum  clockType,
                   bslma::Allocator            *basicAllocator)
: d_mutex()
, d_notEmptyCondition(clockType)
, d_notFullCondition(clockType)
, d_monoDeque(begin, end, basicAllocator)
, d_highWaterMark(highWaterMark)
, d_clockType(clockType)
{
    BSLS_ASSERT(highWaterMark > 0);
}

template <class TYPE>
inline
Deque<TYPE>::Deque(const Deque<TYPE>&  original,
                   bslma::Allocator   *basicAllocator)
: d_mutex()
, d_notEmptyCondition()
, d_notFullCondition()
, d_monoDeque(basicAllocator)
, d_highWaterMark(maxSizeT())
, d_clockType(original.d_clockType)
{
    ConstProctor proctor(&original);

    d_monoDeque.insert(d_monoDeque.end(), proctor->begin(), proctor->end());
}

template <class TYPE>
inline
Deque<TYPE>::~Deque()
{
}

// MANIPULATORS
template <class TYPE>
inline
void Deque<TYPE>::forcePushBack(const TYPE& item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        d_monoDeque.push_back(item);
    }

    d_notEmptyCondition.signal();
}

template <class TYPE>
inline
void Deque<TYPE>::forcePushBack(bslmf::MovableRef<TYPE> item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
    }

    d_notEmptyCondition.signal();
}

template <class TYPE>
template <class INPUT_ITER>
inline
void Deque<TYPE>::forcePushBack(INPUT_ITER begin,
                                INPUT_ITER end)
{
    size_type growth;
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        DequeThrowGuard tg(&d_monoDeque);

        const size_type initialSize = d_monoDeque.size();
        d_monoDeque.insert(d_monoDeque.end(), begin, end);
        growth = d_monoDeque.size() - initialSize;

        tg.release();
    }

    for (; growth > 0; --growth) {
        d_notEmptyCondition.signal();
    }
}

template <class TYPE>
inline
void Deque<TYPE>::forcePushFront(const TYPE& item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        d_monoDeque.push_front(item);
    }

    d_notEmptyCondition.signal();
}

template <class TYPE>
inline
void Deque<TYPE>::forcePushFront(bslmf::MovableRef<TYPE> item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
    }

    d_notEmptyCondition.signal();
}

template <class TYPE>
template <class INPUT_ITER>
inline
void Deque<TYPE>::forcePushFront(INPUT_ITER begin,
                                 INPUT_ITER end)
{
    size_type growth;
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        DequeThrowGuard tg(&d_monoDeque);

        const size_type initialSize = d_monoDeque.size();
        for (; end != begin; ++begin) {
            d_monoDeque.push_front(*begin);
        }
        growth = d_monoDeque.size() - initialSize;

        tg.release();
    }

    for (; growth > 0; --growth) {
        d_notEmptyCondition.signal();
    }
}

template <class TYPE>
TYPE Deque<TYPE>::popBack()
{
    bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

    while (d_monoDeque.empty()) {
        d_notEmptyCondition.wait(&d_mutex);
    }
    TYPE ret(bslmf::MovableRefUtil::move(d_monoDeque.back()));
    d_monoDeque.pop_back();

    const bool shouldSignal = d_monoDeque.size() < d_highWaterMark;
    lock.release()->unlock();

    if (shouldSignal) {
        d_notFullCondition.signal();
    }

    return ret;
}

template <class TYPE>
void Deque<TYPE>::popBack(TYPE *item)
{
    bool shouldSignal;

    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.empty()) {
            d_notEmptyCondition.wait(&d_mutex);
        }

#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
        *item = bslmf::MovableRefUtil::move(d_monoDeque.back());
#else
        *item = d_monoDeque.back();
#endif
        d_monoDeque.pop_back();
        shouldSignal = d_monoDeque.size() < d_highWaterMark;
    }

    if (shouldSignal) {
        d_notFullCondition.signal();
    }
}

template <class TYPE>
TYPE Deque<TYPE>::popFront()
{
    bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

    while (d_monoDeque.empty()) {
        d_notEmptyCondition.wait(&d_mutex);
    }
    TYPE ret(bslmf::MovableRefUtil::move(d_monoDeque.front()));
    d_monoDeque.pop_front();

    const bool shouldSignal = d_monoDeque.size() < d_highWaterMark;
    lock.release()->unlock();

    if (shouldSignal) {
        d_notFullCondition.signal();
    }

    return ret;
}

template <class TYPE>
void Deque<TYPE>::popFront(TYPE *item)
{
    bool shouldSignal;
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.empty()) {
            d_notEmptyCondition.wait(&d_mutex);
        }
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
        *item = bslmf::MovableRefUtil::move(d_monoDeque.front());
#else
        *item = d_monoDeque.front();
#endif
        d_monoDeque.pop_front();

        shouldSignal = d_monoDeque.size() < d_highWaterMark;
    }

    if (shouldSignal) {
        d_notFullCondition.signal();
    }
}

template <class TYPE>
void Deque<TYPE>::pushBack(const TYPE& item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.size() >= d_highWaterMark) {
            d_notFullCondition.wait(&d_mutex);
        }
        d_monoDeque.push_back(item);
    }

    d_notEmptyCondition.signal();
}

template <class TYPE>
void Deque<TYPE>::pushBack(bslmf::MovableRef<TYPE> item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.size() >= d_highWaterMark) {
            d_notFullCondition.wait(&d_mutex);
        }
        d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
    }

    d_notEmptyCondition.signal();
}

template <class TYPE>
void Deque<TYPE>::pushFront(const TYPE& item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.size() >= d_highWaterMark) {
            d_notFullCondition.wait(&d_mutex);
        }
        d_monoDeque.push_front(item);
    }

    d_notEmptyCondition.signal();
}

template <class TYPE>
void Deque<TYPE>::pushFront(bslmf::MovableRef<TYPE> item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.size() >= d_highWaterMark) {
            d_notFullCondition.wait(&d_mutex);
        }
        d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
    }

    d_notEmptyCondition.signal();
}

template <class TYPE>
inline
void Deque<TYPE>::removeAll()
{
    removeAllImp(static_cast<bsl::vector<TYPE> *>(0));
}

template <class TYPE>
inline
void Deque<TYPE>::removeAll(bsl::vector<TYPE> *buffer)
{
    removeAllImp(buffer);
}

template <class TYPE>
inline
void Deque<TYPE>::removeAll(std::vector<TYPE> *buffer)
{
    removeAllImp(buffer);
}

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
template <class TYPE>
inline
void Deque<TYPE>::removeAll(std::pmr::vector<TYPE> *buffer)
{
    removeAllImp(buffer);
}
#endif

template <class TYPE>
int Deque<TYPE>::timedPopBack(TYPE                      *item,
                              const bsls::TimeInterval&  timeout)
{
    bool shouldSignal;
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.empty()) {
            if (d_notEmptyCondition.timedWait(&d_mutex, timeout)) {
                return 1;                                             // RETURN
            }
        }
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
        *item = bslmf::MovableRefUtil::move(d_monoDeque.back());
#else
        *item = d_monoDeque.back();
#endif
        d_monoDeque.pop_back();

        shouldSignal = d_monoDeque.size() < d_highWaterMark;
    }

    if (shouldSignal) {
        d_notFullCondition.signal();
    }

    return 0;
}

template <class TYPE>
int Deque<TYPE>::timedPopFront(TYPE                      *item,
                               const bsls::TimeInterval&  timeout)
{
    bool shouldSignal;
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.empty()) {
            if (d_notEmptyCondition.timedWait(&d_mutex, timeout)) {
                return 1;                                             // RETURN
            }
        }
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
        *item = bslmf::MovableRefUtil::move(d_monoDeque.front());
#else
        *item = d_monoDeque.front();
#endif
        d_monoDeque.pop_front();

        shouldSignal = d_monoDeque.size() < d_highWaterMark;
    }

    if (shouldSignal) {
        d_notFullCondition.signal();
    }

    return 0;
}

template <class TYPE>
int Deque<TYPE>::timedPushBack(const TYPE&               item,
                               const bsls::TimeInterval& timeout)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.size() >= d_highWaterMark) {
            if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
                return 1;                                             // RETURN
            }
        }
        d_monoDeque.push_back(item);
    }

    d_notEmptyCondition.signal();

    return 0;
}

template <class TYPE>
int Deque<TYPE>::timedPushBack(bslmf::MovableRef<TYPE>   item,
                               const bsls::TimeInterval& timeout)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.size() >= d_highWaterMark) {
            if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
                return 1;                                             // RETURN
            }
        }
        d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
    }

    d_notEmptyCondition.signal();

    return 0;
}

template <class TYPE>
int Deque<TYPE>::timedPushFront(const TYPE&               item,
                                const bsls::TimeInterval &timeout)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.size() >= d_highWaterMark) {
            if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
                return 1;                                             // RETURN
            }
        }
        d_monoDeque.push_front(item);
    }

    d_notEmptyCondition.signal();

    return 0;
}

template <class TYPE>
int Deque<TYPE>::timedPushFront(bslmf::MovableRef<TYPE>   item,
                                const bsls::TimeInterval &timeout)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        while (d_monoDeque.size() >= d_highWaterMark) {
            if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
                return 1;                                             // RETURN
            }
        }
        d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
    }

    d_notEmptyCondition.signal();

    return 0;
}

template <class TYPE>
int Deque<TYPE>::tryPopBack(TYPE *item)
{
    bool shouldSignal;
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        if (d_monoDeque.empty()) {
            return 1;                                                 // RETURN
        }
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
        *item = bslmf::MovableRefUtil::move(d_monoDeque.back());
#else
        *item = d_monoDeque.back();
#endif
        d_monoDeque.pop_back();

        shouldSignal = d_monoDeque.size() < d_highWaterMark;
    }

    if (shouldSignal) {
        d_notFullCondition.signal();
    }

    return 0;
}

template <class TYPE>
inline
void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type  maxNumItems)
{
    tryPopBackImp(maxNumItems, static_cast<bsl::vector<TYPE> *>(0));
}

template <class TYPE>
inline
void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type  maxNumItems,
                             bsl::vector<TYPE>               *buffer)
{
    tryPopBackImp(maxNumItems, buffer);
}

template <class TYPE>
inline
void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type  maxNumItems,
                             std::vector<TYPE>               *buffer)
{
    tryPopBackImp(maxNumItems, buffer);
}

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
template <class TYPE>
inline
void Deque<TYPE>::tryPopBack(typename Deque<TYPE>::size_type  maxNumItems,
                             std::pmr::vector<TYPE>          *buffer)
{
    tryPopBackImp(maxNumItems, buffer);
}
#endif

template <class TYPE>
int Deque<TYPE>::tryPopFront(TYPE *item)
{
    bool shouldSignal;
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        if (d_monoDeque.empty()) {
            return 1;                                                 // RETURN
        }
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
        *item = bslmf::MovableRefUtil::move(d_monoDeque.front());
#else
        *item = d_monoDeque.front();
#endif
        d_monoDeque.pop_front();

        shouldSignal = d_monoDeque.size() < d_highWaterMark;
    }

    if (shouldSignal) {
        d_notFullCondition.signal();
    }

    return 0;
}

template <class TYPE>
void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type  maxNumItems)
{
    tryPopFrontImp(maxNumItems, static_cast<bsl::vector<TYPE> *>(0));
}

template <class TYPE>
void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type  maxNumItems,
                              bsl::vector<TYPE>               *buffer)
{
    tryPopFrontImp(maxNumItems, buffer);
}

template <class TYPE>
void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type  maxNumItems,
                              std::vector<TYPE>               *buffer)
{
    tryPopFrontImp(maxNumItems, buffer);
}

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
template <class TYPE>
void Deque<TYPE>::tryPopFront(typename Deque<TYPE>::size_type  maxNumItems,
                              std::pmr::vector<TYPE>          *buffer)
{
    tryPopFrontImp(maxNumItems, buffer);
}
#endif

template <class TYPE>
int Deque<TYPE>::tryPushBack(const TYPE& item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        if (d_monoDeque.size() >= d_highWaterMark) {
            return 1;                                                 // RETURN
        }

        d_monoDeque.push_back(item);
    }

    d_notEmptyCondition.signal();

    return 0;
}

template <class TYPE>
int Deque<TYPE>::tryPushBack(bslmf::MovableRef<TYPE> item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        if (d_monoDeque.size() >= d_highWaterMark) {
            return 1;                                                 // RETURN
        }

        d_monoDeque.push_back(bslmf::MovableRefUtil::move(item));
    }

    d_notEmptyCondition.signal();

    return 0;
}

template <class TYPE>
template <class INPUT_ITER>
typename Deque<TYPE>::size_type
Deque<TYPE>::tryPushBack(INPUT_ITER begin,
                         INPUT_ITER end)
{
    size_type growth;
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        DequeThrowGuard tg(&d_monoDeque);

        const size_type startLength = d_monoDeque.size();
        size_type       length      = startLength;

        for (; length < d_highWaterMark && end != begin; ++length, ++begin) {
            d_monoDeque.push_back(*begin);
        }

        tg.release();

        growth = length - startLength;
    }

    for (size_type ii = 0; ii < growth; ++ii) {
        d_notEmptyCondition.signal();
    }

    return growth;
}

template <class TYPE>
int Deque<TYPE>::tryPushFront(const TYPE& item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        if (d_monoDeque.size() >= d_highWaterMark) {
            return 1;                                                 // RETURN
        }

        d_monoDeque.push_front(item);
    }

    d_notEmptyCondition.signal();

    return 0;
}

template <class TYPE>
int Deque<TYPE>::tryPushFront(bslmf::MovableRef<TYPE> item)
{
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        if (d_monoDeque.size() >= d_highWaterMark) {
            return 1;                                                 // RETURN
        }

        d_monoDeque.push_front(bslmf::MovableRefUtil::move(item));
    }

    d_notEmptyCondition.signal();

    return 0;
}

template <class TYPE>
template <class INPUT_ITER>
typename Deque<TYPE>::size_type
Deque<TYPE>::tryPushFront(INPUT_ITER begin,
                          INPUT_ITER end)
{
    size_type growth;
    {
        bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

        DequeThrowGuard tg(&d_monoDeque);

        const size_type startLength = d_monoDeque.size();
        size_type       length      = startLength;

        for (; length < d_highWaterMark && end != begin; ++length, ++begin) {
            d_monoDeque.push_front(*begin);
        }

        tg.release();

        growth = length - startLength;
    }

    for (size_type ii = 0; ii < growth; ++ii) {
        d_notEmptyCondition.signal();
    }

    return growth;
}

// ACCESSORS
template <class TYPE>
inline
bslma::Allocator *Deque<TYPE>::allocator() const
{
    return d_monoDeque.get_allocator().mechanism();
}

template <class TYPE>
inline
bsls::SystemClockType::Enum Deque<TYPE>::clockType() const
{
    return d_clockType;
}

template <class TYPE>
inline
typename Deque<TYPE>::size_type Deque<TYPE>::highWaterMark() const
{
    // A mutex lock is unnecessary since we decided to make the high water mark
    // into a non-malleable property of this container.
    //
    // bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

    return d_highWaterMark;
}

template <class TYPE>
inline
typename Deque<TYPE>::size_type Deque<TYPE>::length() const
{
    // Note that it is VITAL to lock the mutex here.  'size' on a deque is a
    // potentially complex operation as the deque might be managing multiple
    // blocks of memory.  If 'd_monoDeque' were being modified while we perform
    // the 'size' operation, we could potentially dereference pointers to
    // freed memory.

    // The predessor to this component, 'bcec_queue', originally had no
    // 'length' accessor, and we found that users were very, very frequently
    // accessing the underlying thread-unsafe container just to obtain the
    // length.

    bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);

    return d_monoDeque.size();
}

}  // close package namespace

namespace bslma {

template <class TYPE>
struct UsesBslmaAllocator<bdlcc::Deque<TYPE> > : bsl::true_type
{};

}  // close namespace bslma
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2018 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------