// bslstl_queue.h                                                     -*-C++-*-
#ifndef INCLUDED_BSLSTL_QUEUE
#define INCLUDED_BSLSTL_QUEUE

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

//@PURPOSE: Provide container adapter class template `queue`.
//
//@CLASSES:
//   bsl::queue: class template of a first-in-first-out data structure
//
//@CANONICAL_HEADER: bsl_queue.h
//
//@SEE_ALSO: bslstl_priorityqueue, bslstl_stack
//
//@DESCRIPTION: This component defines a class template, `bsl::queue`, holding
// a container (of a parameterized type `CONTAINER` containing elements of
// another parameterized type `VALUE`), and adapting it to provide a
// first-in-first-out queue data structure.
//
// An instantiation of `queue` is an allocator-aware, value-semantic type whose
// salient attributes are its size (number of elements held) and the sequence
// of values (of held elements) in the order that they were pushed into the
// `queue`.  If `queue` is instantiated with a parameterized type `VALUE` that
// is not itself value-semantic, then it will not retain all of its
// value-semantic qualities.
//
// A queue meets the requirements of a container adaptor as described in the
// C++ standard [queue].  The `queue` implemented here adheres to the C++11
// standard when compiled with a C++11 compiler, and makes the best
// approximation when compiled with a C++03 compiler.  In particular, for C++03
// we emulate move semantics, but limit forwarding (in `emplace`) to `const`
// lvalues, and make no effort to emulate `noexcept` or initializer-lists.
//
///Requirements on `CONTAINER`
///---------------------------
// The `bsl::queue` adapter can accept for its (optional) `CONTAINER` template
// parameter `bsl::deque` (the default), `bsl::vector`, or other container
// classes that support the following types and methods.
//
///Required Types
/// - - - - - - -
// * `value_type`
// * `reference`
// * `const_reference`
// * `size_type`
// * `allocator_type` (if any `queue` constructor taking an allocator is used)
//
///Required Methods, Free Operators, and Free Functions
/// - - - - - - - - - - - - - - - - - - - - - - - - - -
// * `void push_back(const value_type&)` (and variant taking rvalue reference)
// * `void pop_front()`
// * `reference front()`
// * `reference back()`
// * `bool empty() const`
// * `size_type size() const`
// * `const_reference front() const`
// * `const_reference back()  const`
// * `emplace_back`
// * copy-assignment and move-assignment operators
// * free `==`, `!=`, `<`, `>`, `<=`, `>=` operators
// * free `swap` function (found via ADL with `std::swap` in the lookup set)
//
///Requirements on `VALUE`
///-----------------------
// The following term is used to more precisely specify the requirements on
// template parameter types in function-level documentation:
//
// * *equality-comparable*
//   > The type provides an equality-comparison operator that defines an
//   > equivalence relationship and is both reflexive and transitive.
//
///`VALUE` and `CONTAINER::value_type`
///- - - - - - - - - - - - - - - - - -
// When the `CONTAINER` template parameter is omitted the `VALUE` template
// parameter specifies the `value_type` of `bsl::vector`, the default container
// type.  The `VALUE` template has no other role.
//
// For C++17 and later, the behavior is undefined unless:
// ```
// true == bsl::is_same<VALUE, typename CONTAINER::value_type>::value
// ```
// Prior to C++17, `CONTAINER::value_type` determines the contained value type
// and `VALUE` is simply ignored.  The resulting code may work with instances
// of `VALUE` (e.g., `VALUE` is convertible to `CONTAINER::value_type`) or not
// (compiler errors).
//
///Memory Allocation
///-----------------
// The type supplied as `ALLOCATOR` template parameter in some of `queue`
// constructors determines how the held container (of parameterized
// `CONTAINER`) will allocate memory.  A `queue` supports allocators meeting
// the requirements of the C++11 standard [allocator.requirements] as long as
// the held container does.  In addition it supports scoped-allocators derived
// from the `bslma::Allocator` memory allocation protocol.  Clients intending
// to use `bslma` style allocators should use `bsl::allocator` as the
// `ALLOCATOR` template parameter, providing a C++11 standard-compatible
// adapter for a `bslma::Allocator` object.
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Messages Queue
///- - - - - - - - - - - - -
// In this example, we will use the `bsl::queue` container adapter to implement
// a message processor in a server program that receives and displays messages
// from clients.
//
// Suppose we want to write a server program that has two threads: one thread
// (receiving thread) receives messages from clients, passing them to a message
// processor; the other thread (processing thread) runs the message processor,
// printing the messages to the console in the same order as they were
// received.  To accomplish this task, we can use `bsl::queue` in the message
// processor to buffer received, but as yet unprinted, messages.  The message
// processor pushes newly received messages onto the queue in the receiving
// thread, and pops them off the queue in the processing thread.
//
// First, we define a `Message` type:
// ```
// struct Message {
//     int         d_msgId;  // message identifier given by client
//     const char *d_msg_p;  // message content (C-style string, not owned)
// };
// ```
// Then, we define the class `MessageProcessor`, which provides methods to
// receive and process messages:
// ```
// /// This class receives and processes messages from clients.
// class MessageProcessor {
// ```
// Here, we define a private data member of `bsl::queue<Message>` type, which
// is an instantiation of `bsl::queue` that uses `Message` for its `VALUE`
// (template parameter) type and (by default) `bsl::deque<Message>` for its
// `CONTAINER` (template parameter) type:
// ```
//     // DATA
//     bsl::queue<Message> d_msgQueue;  // queue holding received but
//                                      // unprocessed messages
//     // ...
//
//   public:
//     // CREATORS
//
//     /// Create a message processor object.  Optionally specify a
//     /// `basicAllocator` used to supply memory.  If `basicAllocator` is 0,
//     /// the currently installed default allocator is used.
//     explicit MessageProcessor(bslma::Allocator *basicAllocator = 0);
//
//     // MANIPULATORS
//
//     /// Enqueue the specified `message` onto this message processor.
//     void receiveMessage(const Message &message);
//
//     /// Dequeue all messages currently contained by this processor,
//     /// and print them to the console if the specified `verbose` flag
//     /// is not 0.
//     void processMessages(int verbose);
// };
// ```
// Next, we implement the `MessageProcessor` constructor:
// ```
// MessageProcessor::MessageProcessor(bslma::Allocator *basicAllocator)
// : d_msgQueue(basicAllocator)
// {
// }
// ```
// Notice that we pass to the contained `d_msgQueue` object the
// `bslma::Allocator*` supplied to the `MessageProcessor` at construction.
//
// Now, we implement the `receiveMessage` method, which pushes the given
// message onto the queue object:
// ```
// void MessageProcessor::receiveMessage(const Message &message)
// {
//     // ... (some synchronization)
//
//     d_msgQueue.push(message);
//
//     // ...
// }
// ```
// Finally, we implement the `processMessages` method, which pops all messages
// off the queue object:
// ```
// void MessageProcessor::processMessages(int verbose)
// {
//     // ... (some synchronization)
//
//     while (!d_msgQueue.empty()) {
//         const Message& message = d_msgQueue.front();
//         if (verbose) {
//             printf("Msg %d: %s\n", message.d_msgId, message.d_msg_p);
//         }
//         d_msgQueue.pop();
//     }
//
//     // ...
// }
// ```
// Note that the sequence of messages popped from the queue will be in exactly
// the same order in which they were pushed, due to the first-in-first-out
// property of the queue.

#include <bslscm_version.h>

#include <bslstl_compare.h>
#include <bslstl_deque.h>
#include <bslstl_iterator.h>
#include <bslstl_iteratorutil.h>
#include <bslstl_ranges.h>

#include <bslalg_swaputil.h>

#include <bslma_isstdallocator.h>
#include <bslma_usesbslmaallocator.h>

#include <bslmf_assert.h>
#include <bslmf_containercompatiblerange.h>
#include <bslmf_enableif.h>
#include <bslmf_isconvertible.h>
#include <bslmf_issame.h>
#include <bslmf_movableref.h>
#include <bslmf_nestedtraitdeclaration.h>
#include <bslmf_usesallocator.h>
#include <bslmf_util.h>    // 'forward(V)'

#include <bsls_compilerfeatures.h>
#include <bsls_libraryfeatures.h>
#include <bsls_keyword.h>
#include <bsls_platform.h>
#include <bsls_util.h>     // 'forward<T>(V)'

#if defined(BSLS_LIBRARYFEATURES_HAS_CPP20_CONCEPTS) \
 && defined(BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES)
# define BSLSTL_QUEUE_REQUIRES_CONTAINER_COMPATIBLE_RANGE(R, T) \
                  requires ::BloombergLP::bslmf::ContainerCompatibleRange<R, T>
#else
# define BSLSTL_QUEUE_REQUIRES_CONTAINER_COMPATIBLE_RANGE(R, T)
#endif

#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
// clang-format off
// Include version that can be compiled with C++03
// Generated on Mon Jan 13 08:31:39 2025
// Command line: sim_cpp11_features.pl bslstl_queue.h

# define COMPILING_BSLSTL_QUEUE_H
# include <bslstl_queue_cpp03.h>
# undef COMPILING_BSLSTL_QUEUE_H

// clang-format on
#else

namespace bsl {

                             // ===========
                             // class queue
                             // ===========

/// This class is a value-semantic class template, having a container of the
/// parameterized `CONTAINER` type that holds elements of the parameterized
/// `VALUE` type, to provide a first-in-first-out queue data structure.  The
/// container object held by a `queue` class object is referenced as `c` in
/// the following function-level documentation.
template <class VALUE, class CONTAINER = deque<VALUE> >
class queue {

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY
    // STATIC CHECK: Type mismatch is UB per C++17
    BSLMF_ASSERT((is_same<VALUE, typename CONTAINER::value_type>::value));
#endif

    // FRIENDS
    template <class VALUE2, class CONTAINER2>
    friend bool operator==(const queue<VALUE2, CONTAINER2>&,
                           const queue<VALUE2, CONTAINER2>&);

    template <class VALUE2, class CONTAINER2>
    friend bool operator!=(const queue<VALUE2, CONTAINER2>&,
                           const queue<VALUE2, CONTAINER2>&);

    template <class VALUE2, class CONTAINER2>
    friend bool operator< (const queue<VALUE2, CONTAINER2>&,
                           const queue<VALUE2, CONTAINER2>&);

    template <class VALUE2, class CONTAINER2>
    friend bool operator> (const queue<VALUE2, CONTAINER2>&,
                           const queue<VALUE2, CONTAINER2>&);

    template <class VALUE2, class CONTAINER2>
    friend bool operator<=(const queue<VALUE2, CONTAINER2>&,
                           const queue<VALUE2, CONTAINER2>&);

    template <class VALUE2, class CONTAINER2>
    friend bool operator>=(const queue<VALUE2, CONTAINER2>&,
                           const queue<VALUE2, CONTAINER2>&);

#if defined BSLS_COMPILERFEATURES_SUPPORT_THREE_WAY_COMPARISON \
 && defined BSLS_LIBRARYFEATURES_HAS_CPP20_CONCEPTS
    template <class VALUE2, three_way_comparable CONTAINER2>
    friend compare_three_way_result_t<CONTAINER2>
    operator<=>(const queue<VALUE2, CONTAINER2>&,
                const queue<VALUE2, CONTAINER2>&);
#endif

    // PRIVATE TYPES

    /// This `typedef` is a convenient alias for the utility associated with
    /// movable references.
    typedef BloombergLP::bslmf::MovableRefUtil  MoveUtil;

    // PRIVATE MANIPULATORS

    /// Push onto the back of this queue the elements of the specified
    /// `[first, last)` range.
    template <class INPUT_ITER, class SENTINEL>
    void privatePushRange(INPUT_ITER first, SENTINEL last);

  public:
    // PUBLIC TYPES
    typedef typename CONTAINER::value_type      value_type;
    typedef typename CONTAINER::reference       reference;
    typedef typename CONTAINER::const_reference const_reference;
    typedef typename CONTAINER::size_type       size_type;
    typedef          CONTAINER                  container_type;

  protected:
    // PROTECTED DATA
    CONTAINER c;  // Contains the elements of this queue.
                  // 'protected' and named ('c') per the C++11 standard.

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(
        queue,
        BloombergLP::bslma::UsesBslmaAllocator,
        BloombergLP::bslma::UsesBslmaAllocator<container_type>::value);

    // CREATORS

    /// Create an empty queue having a container of the parameterized
    /// `CONTAINER` type.
    explicit queue();

    /// Create a queue having the value of the specified `original`.
    queue(const queue& original);

    /// Create a queue having the value of the specified `original`.  The
    /// allocator associated with `original` (if any) is propagated for use
    /// in the new queue.  `original` is left in valid but unspecified
    /// state.
    queue(BloombergLP::bslmf::MovableRef<queue> container);

    /// Create a queue having the specified `container` that holds elements
    /// of the parameterized `VALUE` type.
    explicit queue(const CONTAINER& container);

    /// Create a queue having the same sequence of values as the specified
    /// `container`.  The allocator associated with `container` (if any) is
    /// propagated for use in the new queue.  `container` is left in valid
    /// but unspecified state.
    explicit queue(BloombergLP::bslmf::MovableRef<CONTAINER> container);

    /// Create an empty queue.  This queue object uses the specified
    /// `basicAllocator` to supply memory.  Note that the `ALLOCATOR`
    /// parameter type has to be convertible to the allocator of the
    /// `CONTAINER` parameter type, `CONTAINER::allocator_type`; otherwise,
    /// this constructor is disabled.
    template <class ALLOCATOR>
    explicit
    queue(const ALLOCATOR& basicAllocator,
          typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                             ALLOCATOR>::type * = 0);

    /// Create a queue having the same sequence of values as the specified
    /// `container`.  The queue object uses the specified `basicAllocator`
    /// to obtain memory.  Note that the `ALLOCATOR` parameter type has to
    /// be convertible to the allocator of the `CONTAINER` parameter type,
    /// `CONTAINER::allocator_type`; otherwise, this constructor is
    /// disabled.
    template <class ALLOCATOR>
    queue(const CONTAINER& container,
          const ALLOCATOR& basicAllocator,
          typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                             ALLOCATOR>::type * = 0);

    /// Create a queue having the value of the specified `original` that
    /// will use the specified `basicAllocator` to supply memory.  Note that
    /// the `ALLOCATOR` parameter type has to be convertible to the
    /// allocator of the `CONTAINER` parameter type,
    /// `CONTAINER::allocator_type`.  Otherwise this constructor is
    /// disabled.
    template <class ALLOCATOR>
    queue(const queue&     original,
          const ALLOCATOR& basicAllocator,
          typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                             ALLOCATOR>::type * = 0);

    /// Create a queue whose underlying container has the value of the
    /// specified `container` (on entry) and uses `basicAllocator` to supply
    /// memory.  The allocated-extended move constructor of `CONTAINER` is
    /// used to create the new queue.  `container` is left in a valid but
    /// unspecified state.  Note that a `bslma::Allocator *` can be supplied
    /// for `basicAllocator` if the (template parameter) `ALLOCATOR` is
    /// `bsl::allocator` (the default).  Also note that this method assumes
    /// that `CONTAINER` has a move constructor.  Also note that if
    /// `CONTAINER::allocator_type` does not exist, this constructor is
    /// disabled.
    template <class ALLOCATOR>
    queue(BloombergLP::bslmf::MovableRef<CONTAINER> container,
          const ALLOCATOR&                          basicAllocator,
          typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                             ALLOCATOR>::type * = 0);

    /// Create a queue having the value of the specified `original` (on
    /// entry), that uses `basicAllocator` to supply memory.  The
    /// allocator-extended move constructor of `CONTAINER` is used to create
    /// the new queue.  `original` is left in a valid but unspecified state.
    /// Note that a `bslma::Allocator *` can be supplied for
    /// `basicAllocator` if the (template parameter) `ALLOCATOR` is
    /// `bsl::allocator` (the default).  Also note that this method assumes
    /// that `CONTAINER` has a move constructor.  Also note that if
    /// `CONTAINER::allocator_type` does not exist, this constructor is
    /// disabled.
    template <class ALLOCATOR>
    queue(BloombergLP::bslmf::MovableRef<queue> original,
          const ALLOCATOR&                      basicAllocator,
          typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                             ALLOCATOR>::type * = 0);

    /// Create a queue passing the specified `first` and `last` to the
    /// constructor of the underlying container.  Optionally specify an
    /// `allocator` used to supply memory.  If `allocator` is not specified, a
    /// default-constructed object of the (template parameter) type `ALLOCATOR`
    /// is used.
    template <class INPUT_ITER>
    queue(INPUT_ITER first, INPUT_ITER last);
    template <class INPUT_ITER, class ALLOCATOR>
    queue(INPUT_ITER       first,
          INPUT_ITER       last,
          const ALLOCATOR& allocator,
          typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                             ALLOCATOR>::type * = 0);

    /// Create a queue from the elements of the specifed `range`.  Optionally
    /// specify an `allocator` used to supply memory.  If `allocator` is not
    /// specified, a default-constructed object of the (template parameter)
    /// type `t_ALLOCATOR` is used.  Note that `range` must meet the
    /// requirements of an input range and the values from `range` must have a
    /// type matching or convertible to (template parameter) `VALUE`.
    template <class t_RANGE>
    BSLSTL_QUEUE_REQUIRES_CONTAINER_COMPATIBLE_RANGE(t_RANGE, VALUE)
    queue(from_range_t, BSLS_COMPILERFEATURES_FORWARD_REF(t_RANGE) range);
    template <class t_RANGE, class t_ALLOCATOR>
    BSLSTL_QUEUE_REQUIRES_CONTAINER_COMPATIBLE_RANGE(t_RANGE, VALUE)
    queue(from_range_t                               ,
          BSLS_COMPILERFEATURES_FORWARD_REF(t_RANGE) range,
          const t_ALLOCATOR&                         allocator,
          typename enable_if<bsl::uses_allocator<CONTAINER,t_ALLOCATOR>::value,
                             t_ALLOCATOR>::type * = 0);

    // MANIPULATORS

    /// Assign to this queue the value of the specified `rhs`, and return a
    /// reference providing modifiable access to this queue.
    queue& operator=(const queue& rhs);

    /// Assign to this queue the value as the specified `rhs` and return a
    /// reference providing modifiable access to this queue.  The
    /// move-assignment operator of `CONTAINER` is used to set the value of
    /// this queue.  `rhs` is left in a valid but unspecified state, and if
    /// an exception is thrown, `*this` is left in a valid but unspecified
    /// state.
    queue& operator=(BloombergLP::bslmf::MovableRef<queue> rhs);

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
    /// Push onto this queue a newly created `value_type` object constructed
    /// by forwarding `get_allocator()` (if required) and the specified
    /// (variable number of) `args` to the corresponding constructor of
    /// `value_type`.  Return a reference providing modifiable access to the
    /// inserted element.
    template <class... Args>
    reference emplace(Args&&... args);
#endif

    /// Push onto the back of this queue a `value_type` object having the
    /// specified `value`.
    void push(const value_type& value);

    /// Push onto the back of this queue a `value_type` object having the
    /// value of the specified `value` (on entry) by moving the
    /// contents of `value` to the new object on this queue.  `value` is
    /// left in a valid but unspecified state.
    void push(BloombergLP::bslmf::MovableRef<value_type> value);

    /// Push onto the back of this queue the elements of the specified `range`.
    /// Note that `range` must meet the requirements of an input range and the
    /// values from `range` must have a type matching or convertible to
    /// (template parameter) `VALUE`.
    template <class t_RANGE>
    BSLSTL_QUEUE_REQUIRES_CONTAINER_COMPATIBLE_RANGE(t_RANGE, VALUE)
    void push_range(BSLS_COMPILERFEATURES_FORWARD_REF(t_RANGE) range);

    /// Remove the front (the earliest pushed) element from this `queue`
    /// object.
    void pop();

    /// Efficiently exchange the value of this object with the value of the
    /// specified `other` object.  In effect, performs
    /// `using bsl::swap; swap(c, other.c);`.
    void swap(queue& other) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                                  bsl::is_nothrow_swappable<CONTAINER>::value);

    /// Return a reference providing modifiable access to the front (the
    /// earliest pushed) element from this `queue` object.
    reference front();

    /// Return a reference providing modifiable access to the back (the
    /// latest pushed) element of this `queue` object.
    reference back();

    // ACCESSORS

    /// Return `true` if this `queue` object contains no elements, and
    /// `false` otherwise.  In effect, performs `return c.empty();`.
    bool empty() const;

    /// Return the number of elements in this queue.  In effect, performs
    /// `return c.size();`.
    size_type size() const;

    /// Return the immutable front (the earliest pushed) element from this
    /// `queue` object.  In effect, performs `c.front()`.
    const_reference front() const;

    /// Return the immutable back (the latest pushed) element from this
    /// `queue` object.  In effect, performs `c.back()`.
    const_reference back() const;
};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
// CLASS TEMPLATE DEDUCTION GUIDES

/// Deduce the template parameters `VALUE` and `CONTAINER` from the
/// parameters supplied to the constructor of `queue`.  This deduction guide
/// does not participate if the parameter meets the requirements for a
/// standard allocator.
template<class CONTAINER,
         class = bsl::enable_if_t<!bsl::IsStdAllocator_v<CONTAINER>>
        >
queue(CONTAINER) -> queue<typename CONTAINER::value_type, CONTAINER>;

/// Deduce the template parameters `VALUE` and `CONTAINER` from the
/// parameters supplied to the constructor of `queue`.  This deduction
/// guide does not participate unless the supplied allocator is convertible
/// to the underlying container's `allocator_type`.
template<
    class CONTAINER,
    class ALLOCATOR,
    class = bsl::enable_if_t<bsl::uses_allocator_v<CONTAINER, ALLOCATOR>>
    >
queue(CONTAINER, ALLOCATOR) -> queue<typename CONTAINER::value_type, CONTAINER>;

/// Deduce the template parameter `VALUE` from the parameters supplied to the
/// constructor of `queue`.
template <class INPUT_ITER,
          class TYPE = BloombergLP::bslstl::IteratorUtil::
                                                         IterVal_t<INPUT_ITER>>
queue(INPUT_ITER, INPUT_ITER) -> queue<TYPE>;

/// Deduce the template parameters `VALUE` and `CONTAINER` from the parameters
/// supplied to the constructor of `queue`.  This deduction guide does not
/// participate unless the `ALLOCATOR` parameter meets the requirements for a
/// standard allocator.
template <class INPUT_ITER,
          class ALLOCATOR,
          class TYPE = BloombergLP::bslstl::IteratorUtil::
                                                         IterVal_t<INPUT_ITER>,
          class = enable_if_t<IsStdAllocator_v<ALLOCATOR>>>
queue(INPUT_ITER, INPUT_ITER, ALLOCATOR)-> queue<TYPE, deque<TYPE, ALLOCATOR>>;

#if defined(BSLS_LIBRARYFEATURES_HAS_CPP20_CONCEPTS) \
 && defined(BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES)
/// Deduce the template parameter `VALUE` from the parameters supplied to the
/// constructor of `queue`.
template <ranges::input_range t_RANGE>
queue(from_range_t, t_RANGE&&) -> queue<ranges::range_value_t<t_RANGE>>;

/// Deduce the template parameters `VALUE` and `ALLOCATOR` from the parameters
/// supplied to the constructor of `queue`.  This deduction guide does not
/// participate unless the `t_ALLOCATOR` parameter meets the requirements for a
/// standard allocator.
template <ranges::input_range t_RANGE,
          class               t_ALLOCATOR,
          class               t_TYPE = ranges::range_value_t<t_RANGE>>
requires IsStdAllocator_v<t_ALLOCATOR>
queue(from_range_t, t_RANGE&&, t_ALLOCATOR)
-> queue<t_TYPE, deque<t_TYPE, t_ALLOCATOR>>;
#endif
#endif

// FREE OPERATORS

/// Return `true` if the specified `lhs` and `rhs` objects have the same
/// value, and `false` otherwise.  Two `queue` objects `lhs` and `rhs` have
/// the same value if they have the same number of elements, and each
/// element in the ordered sequence of elements of `lhs` has the same value
/// as the corresponding element in the ordered sequence of elements of
/// `rhs`.  This method requires that the (template parameter) type `VALUE`
/// be `equality-comparable` (see {Requirements on `VALUE`}).
template <class VALUE, class CONTAINER>
bool operator==(const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs);

/// Return `true` if the specified `lhs` and `rhs` objects do not have the
/// same value, and `false` otherwise.  Two `queue` objects `lhs` and `rhs`
/// do not have the same value if they do not have the same number of
/// elements, or some element in the ordered sequence of elements of `lhs`
/// does not have the same value as the corresponding element in the ordered
/// sequence of elements of `rhs`.  This method requires that the (template
/// parameter) type `VALUE` be `equality-comparable` (see {Requirements on
/// `VALUE`}).
template <class VALUE, class CONTAINER>
bool operator!=(const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs);

/// Return `true` if the value of the specified `lhs` queue is
/// lexicographically less than that of the specified `rhs` queue, and
/// `false` otherwise.  Given iterators `i` and `j` over the respective
/// sequences `[lhs.begin() .. lhs.end())` and `[rhs.begin() .. rhs.end())`,
/// the value of queue `lhs` is lexicographically less than that of queue
/// `rhs` if `true == *i < *j` for the first pair of corresponding iterator
/// positions where `*i < *j` and `*j < *i` are not both `false`.  If no
/// such corresponding iterator position exists, the value of `lhs` is
/// lexicographically less than that of `rhs` if `lhs.size() < rhs.size()`.
/// This method requires that `operator<`, inducing a total order, be
/// defined for `value_type`.
template <class VALUE, class CONTAINER>
bool operator< (const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs);

/// Return `true` if the value of the specified `lhs` queue is
/// lexicographically greater than that of the specified `rhs` queue, and
/// `false` otherwise.  The value of queue `lhs` is lexicographically
/// greater than that of queue `rhs` if `rhs` is lexicographically less than
/// `lhs` (see `operator<`).  This method requires that `operator<`,
/// inducing a total order, be defined for `value_type`.  Note that this
/// operator returns `rhs < lhs`.
template <class VALUE, class CONTAINER>
bool operator> (const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs);

/// Return `true` if the value of the specified `lhs` queue is
/// lexicographically less than or equal to that of the specified `rhs`
/// queue, and `false` otherwise.  The value of queue `lhs` is
/// lexicographically less than or equal to that of queue `rhs` if `rhs` is
/// not lexicographically less than `lhs` (see `operator<`).  This method
/// requires that `operator<`, inducing a total order, be defined for
/// `value_type`.  Note that this operator returns `!(rhs < lhs)`.
template <class VALUE, class CONTAINER>
bool operator<=(const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs);

/// Return `true` if the value of the specified `lhs` queue is
/// lexicographically greater than or equal to that of the specified `rhs`
/// queue, and `false` otherwise.  The value of queue `lhs` is
/// lexicographically greater than or equal to that of queue `rhs` if `lhs`
/// is not lexicographically less than `rhs` (see `operator<`).  This method
/// requires that `operator<`, inducing a total order, be defined for
/// `value_type`.  Note that this operator returns `!(lhs < rhs)`.
template <class VALUE, class CONTAINER>
bool operator>=(const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs);

// FREE FUNCTIONS

/// Swap the value of the specified `lhs` queue with the value of the
/// specified `rhs` queue.
template <class VALUE, class CONTAINER>
void swap(queue<VALUE, CONTAINER>& lhs,
          queue<VALUE, CONTAINER>& rhs)
                                    BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(false);

// ============================================================================
//                  TEMPLATE AND INLINE FUNCTION DEFINITIONS
// ============================================================================

                              // -----------
                              // class queue
                              // -----------

// CREATORS
template <class VALUE, class CONTAINER>
inline
queue<VALUE, CONTAINER>::queue()
{
}

template <class VALUE, class CONTAINER>
inline
queue<VALUE, CONTAINER>::queue(const queue& original)
: c(original.c)
{
}

template <class VALUE, class CONTAINER>
inline
queue<VALUE, CONTAINER>::queue(BloombergLP::bslmf::MovableRef<queue> original)
: c(MoveUtil::move(MoveUtil::access(original).c))
{
}

template <class VALUE, class CONTAINER>
inline
queue<VALUE, CONTAINER>::queue(const CONTAINER& container)
: c(container)
{
}

template <class VALUE, class CONTAINER>
template <class ALLOCATOR>
inline
queue<VALUE, CONTAINER>::queue(
           const ALLOCATOR& basicAllocator,
           typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                              ALLOCATOR>::type *)
: c(basicAllocator)
{
}

template <class VALUE, class CONTAINER>
template <class ALLOCATOR>
inline
queue<VALUE, CONTAINER>::queue(
           const CONTAINER& container,
           const ALLOCATOR& basicAllocator,
           typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                              ALLOCATOR>::type *)
: c(container, basicAllocator)
{
}

template <class VALUE, class CONTAINER>
template <class ALLOCATOR>
inline
queue<VALUE, CONTAINER>::queue(
           const queue&     queue,
           const ALLOCATOR& basicAllocator,
           typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                              ALLOCATOR>::type *)
: c(queue.c, basicAllocator)
{
}

template <class VALUE, class CONTAINER>
inline
queue<VALUE, CONTAINER>::queue(BloombergLP::bslmf::MovableRef<CONTAINER>
                                                                     container)
: c(MoveUtil::move(container))
{
}

template <class VALUE, class CONTAINER>
template <class ALLOCATOR>
inline
queue<VALUE, CONTAINER>::queue(
           BloombergLP::bslmf::MovableRef<CONTAINER> container,
           const ALLOCATOR&                          basicAllocator,
           typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                              ALLOCATOR>::type *)
: c(MoveUtil::move(container), basicAllocator)
{
}

template <class VALUE, class CONTAINER>
template <class ALLOCATOR>
inline
queue<VALUE, CONTAINER>::queue(
           BloombergLP::bslmf::MovableRef<queue> original,
           const ALLOCATOR&                      basicAllocator,
           typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                              ALLOCATOR>::type *)
: c(MoveUtil::move(MoveUtil::access(original).c), basicAllocator)
{
}

template <class VALUE, class CONTAINER>
template <class INPUT_ITER>
inline
queue<VALUE, CONTAINER>::queue(INPUT_ITER first, INPUT_ITER last)
: c(first, last)
{
}

template <class VALUE, class CONTAINER>
template <class INPUT_ITER, class ALLOCATOR>
inline
queue<VALUE, CONTAINER>::queue(
           INPUT_ITER       first,
           INPUT_ITER       last,
           const ALLOCATOR& allocator,
           typename enable_if<bsl::uses_allocator<CONTAINER, ALLOCATOR>::value,
                              ALLOCATOR>::type *)
: c(first, last, allocator)
{
}

template <class VALUE, class CONTAINER>
template <class t_RANGE>
BSLSTL_QUEUE_REQUIRES_CONTAINER_COMPATIBLE_RANGE(t_RANGE, VALUE)
inline
queue<VALUE, CONTAINER>::queue(
                              from_range_t                               ,
                              BSLS_COMPILERFEATURES_FORWARD_REF(t_RANGE) range)
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_TO_CONTAINER
: c(ranges::to<CONTAINER>(std::forward<t_RANGE>(range)))
#else
: c(bsl::from_range, BSLS_COMPILERFEATURES_FORWARD(t_RANGE, range))
#endif
{
}

template <class VALUE, class CONTAINER>
template <class t_RANGE, class t_ALLOCATOR>
BSLSTL_QUEUE_REQUIRES_CONTAINER_COMPATIBLE_RANGE(t_RANGE, VALUE)
inline
queue<VALUE, CONTAINER>::queue(
                          from_range_t                               ,
                          BSLS_COMPILERFEATURES_FORWARD_REF(t_RANGE) range,
                          const t_ALLOCATOR&                         allocator,
                          typename enable_if<
                             bsl::uses_allocator<CONTAINER,t_ALLOCATOR>::value,
                             t_ALLOCATOR>::type *)
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_TO_CONTAINER
: c(ranges::to<CONTAINER>(std::forward<t_RANGE>(range), allocator))
#else
: c(bsl::from_range, BSLS_COMPILERFEATURES_FORWARD(t_RANGE, range), allocator)
#endif
{
}

// PRIVATE MANIPULATORS
template <class VALUE, class CONTAINER>
template <class INPUT_ITER, class SENTINEL>
inline
void queue<VALUE, CONTAINER>::privatePushRange(INPUT_ITER first,
                                               SENTINEL   last)
{
    while (first != last) {
        push(*first);
        ++first;
    }
}

// MANIPULATORS
template <class VALUE, class CONTAINER>
inline
queue<VALUE, CONTAINER>& queue<VALUE, CONTAINER>::operator=(const queue& rhs)
{
    c = rhs.c;
    return *this;
}

template <class VALUE, class CONTAINER>
inline
queue<VALUE, CONTAINER>& queue<VALUE, CONTAINER>::operator=(
                                     BloombergLP::bslmf::MovableRef<queue> rhs)
{
    c = MoveUtil::move(MoveUtil::access(rhs).c);
    return *this;
}

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
template <class VALUE, class CONTAINER>
template <class... Args>
inline
typename queue<VALUE, CONTAINER>::reference
queue<VALUE, CONTAINER>::emplace(Args&&... args)
{
    c.emplace_back(BSLS_COMPILERFEATURES_FORWARD(Args,args)...);
    return back();
}
#endif

template <class VALUE, class CONTAINER>
inline
void queue<VALUE, CONTAINER>::push(const value_type& value)
{
    c.push_back(value);
}

template <class VALUE, class CONTAINER>
inline
void queue<VALUE, CONTAINER>::push(BloombergLP::bslmf::MovableRef<value_type>
                                                                         value)
{
    c.push_back(MoveUtil::move(value));
}

template <class VALUE, class CONTAINER>
template <class t_RANGE>
BSLSTL_QUEUE_REQUIRES_CONTAINER_COMPATIBLE_RANGE(t_RANGE, VALUE)
void queue<VALUE, CONTAINER>::push_range(
                              BSLS_COMPILERFEATURES_FORWARD_REF(t_RANGE) range)
{
#if defined(BSLS_LIBRARYFEATURES_HAS_CPP20_CONCEPTS) \
 && defined(BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES)
    if constexpr (requires{ c.append_range(std::forward<t_RANGE>(range)); }) {
        c.append_range(std::forward<t_RANGE>(range));
    }
    else {
        ranges::copy(range, back_inserter(c));
    }
#else
    privatePushRange(bsl::begin(range), bsl::end(range));
#endif
}

template <class VALUE, class CONTAINER>
inline
void queue<VALUE, CONTAINER>::pop()
{
    c.pop_front();
}

template <class VALUE, class CONTAINER>
inline
void queue<VALUE, CONTAINER>::swap(queue& other)
    BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                                   bsl::is_nothrow_swappable<CONTAINER>::value)
{
    BloombergLP::bslalg::SwapUtil::swap(&c, &other.c);
}

// ACCESSORS
template <class VALUE, class CONTAINER>
inline
bool queue<VALUE, CONTAINER>::empty() const
{
    return c.empty();
}

template <class VALUE, class CONTAINER>
inline
typename queue<VALUE, CONTAINER>::size_type
queue<VALUE, CONTAINER>::size() const
{
    return c.size();
}

template <class VALUE, class CONTAINER>
inline
typename queue<VALUE, CONTAINER>::reference
queue<VALUE, CONTAINER>::front()
{
    return c.front();
}

template <class VALUE, class CONTAINER>
inline
typename queue<VALUE, CONTAINER>::const_reference
queue<VALUE, CONTAINER>::front() const
{
    return c.front();
}

template <class VALUE, class CONTAINER>
inline
typename queue<VALUE, CONTAINER>::reference
queue<VALUE, CONTAINER>::back()
{
    return c.back();
}

template <class VALUE, class CONTAINER>
inline
typename queue<VALUE, CONTAINER>::const_reference
queue<VALUE, CONTAINER>::back() const
{
    return c.back();
}

// FREE OPERATORS
template <class VALUE, class CONTAINER>
inline
bool operator==(const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs)
{
    return lhs.c == rhs.c;
}

template <class VALUE, class CONTAINER>
inline
bool operator!=(const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs)
{
    return lhs.c != rhs.c;
}

template <class VALUE, class CONTAINER>
inline
bool operator< (const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs)
{
    return lhs.c < rhs.c;
}

template <class VALUE, class CONTAINER>
inline
bool operator> (const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs)
{
    return lhs.c > rhs.c;
}

template <class VALUE, class CONTAINER>
inline
bool operator<=(const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs)
{
    return lhs.c <= rhs.c;
}

template <class VALUE, class CONTAINER>
inline
bool operator>=(const queue<VALUE, CONTAINER>& lhs,
                const queue<VALUE, CONTAINER>& rhs)
{
    return lhs.c >= rhs.c;
}

#if defined BSLS_COMPILERFEATURES_SUPPORT_THREE_WAY_COMPARISON \
 && defined BSLS_LIBRARYFEATURES_HAS_CPP20_CONCEPTS
template <class VALUE, three_way_comparable CONTAINER>
inline compare_three_way_result_t<CONTAINER>
operator<=>(const queue<VALUE, CONTAINER>& lhs,
            const queue<VALUE, CONTAINER>& rhs)
{
    return lhs.c <=> rhs.c;
}
#endif

// FREE FUNCTIONS
template <class VALUE, class CONTAINER>
inline
void swap(queue<VALUE, CONTAINER>& lhs,
          queue<VALUE, CONTAINER>& rhs)
                                     BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(false)
{
    lhs.swap(rhs);
}

}  // close namespace bsl

#endif // End C++11 code

#undef BSLSTL_QUEUE_REQUIRES_CONTAINER_COMPATIBLE_RANGE

#endif

// ----------------------------------------------------------------------------
// Copyright 2016 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 ----------------------------------
