// queue standard header -*-c++-*-
// Copyright 2009-2017 IAR Systems AB.
#ifndef _QUEUE_
#define _QUEUE_

#ifndef _SYSTEM_BUILD
#pragma system_include
#endif

#include <algorithm>
#include <deque>
#include <vector>

namespace std {

// TEMPLATE CLASS queue
template<class _Ty,
         class _Container = deque<_Ty> >
class queue
{       // FIFO queue implemented with a container
public:
  typedef queue<_Ty, _Container> _Myt;
  typedef _Container container_type;
  typedef typename _Container::value_type value_type;
  typedef typename _Container::size_type size_type;
  typedef typename _Container::reference reference;
  typedef typename _Container::const_reference const_reference;

  static_assert((is_same<_Ty, value_type>::value),
                "mismatch between value_type of queue and underlying container");

  queue()
    : c()
  {       // construct with empty container
  }

  queue(const _Myt& _Right)
    : c(_Right.c)
  {       // construct by copying _Right container
  }

  explicit queue(const _Container& _Cont)
    : c(_Cont)
  {       // construct by copying specified container
  }

  _Myt& operator=(const _Myt& _Right)
  {       // assign by copying _Right
    c = _Right.c;
    return *this;
  }

  template<class _Alloc,
           class = typename enable_if<uses_allocator<_Container,
                                                     _Alloc>::value,
                                      void>::type>
  explicit queue(const _Alloc& _Al)
    : c(_Al)
  {       // construct with empty container, allocator
  }

  template<class _Alloc,
           class = typename enable_if<uses_allocator<_Container,
                                                     _Alloc>::value,
                                      void>::type>
  queue(const _Container& _Cont, const _Alloc& _Al)
    : c(_Cont, _Al)
  {       // construct by copying specified container, allocator
  }

  template<class _Alloc,
           class = typename enable_if<uses_allocator<_Container,
                                                     _Alloc>::value,
                                      void>::type>
  queue(const _Myt& _Right, const _Alloc& _Al)
    : c(_Right.c, _Al)
  {       // construct by copying _Right container, allocator
  }

  queue(_Myt&& _Right)
  _NOEXCEPT_OP(is_nothrow_move_constructible<_Container>::value)
  : c(std::move(_Right.c))
  {       // construct by moving _Right
  }

  explicit queue(_Container&& _Cont)
    : c(std::move(_Cont))
  {       // construct by moving specified container
  }

  template<class _Alloc,
           class = typename enable_if<uses_allocator<_Container,
                                                     _Alloc>::value,
                                      void>::type>
  queue(_Container&& _Cont, const _Alloc& _Al)
    : c(std::move(_Cont), _Al)
  {       // construct by moving specified container, allocator
  }

  template<class _Alloc,
           class = typename enable_if<uses_allocator<_Container,
                                                     _Alloc>::value,
                                      void>::type>
  queue(_Myt&& _Right, const _Alloc& _Al)
    : c(std::move(_Right.c), _Al)
  {       // construct by moving _Right container, allocator
  }

  _Myt& operator=(_Myt&& _Right)
    _NOEXCEPT_OP(is_nothrow_move_assignable<_Container>::value)
  {       // assign by moving _Right
    c = std::move(_Right.c);
    return *this;
  }

  void push(value_type&& _Val)
  {       // insert element at beginning
    c.push_back(move(_Val));
  }

  template<class... _Valty>
  void emplace(_Valty&&... _Val)
  {       // insert element at beginning
    c.emplace_back(std::forward<_Valty>(_Val)...);
  }

  bool empty() const
  {       // test if queue is empty
    return c.empty();
  }

  size_type size() const
  {       // return length of queue
    return c.size();
  }

  reference front()
  {       // return first element of mutable queue
    return c.front();
  }

  const_reference front() const
  {       // return first element of nonmutable queue
    return c.front();
  }

  reference back()
  {       // return last element of mutable queue
    return c.back();
  }

  const_reference back() const
  {       // return last element of nonmutable queue
    return c.back();
  }

  void push(const value_type& _Val)
  {       // insert element at beginning
    c.push_back(_Val);
  }

  void pop()
  {       // erase element at end
    c.pop_front();
  }

  const _Container& _Get_container() const
  {       // get reference to container
    return c;
  }

  void swap(_Myt& _Right)
    _NOEXCEPT_OP(_NOEXCEPT_OP(_Swap_adl(this->c, _Right.c)))
  {       // exchange contents with _Right
    _Swap_adl(c, _Right.c);
  }

protected:
  _Container c;   // the underlying container
};

// queue TEMPLATE FUNCTIONS
template<class _Ty,
         class _Container> inline
void swap(queue<_Ty, _Container>& _Left,
          queue<_Ty, _Container>& _Right)
  _NOEXCEPT_OP(_NOEXCEPT_OP(_Left.swap(_Right)))
{       // swap _Left and _Right queues
  _Left.swap(_Right);
}

template<class _Ty,
         class _Container> inline
bool operator==(const queue<_Ty, _Container>& _Left,
                const queue<_Ty, _Container>& _Right)
{       // test for queue equality
  return _Left._Get_container() == _Right._Get_container();
}

template<class _Ty,
         class _Container> inline
bool operator!=(const queue<_Ty, _Container>& _Left,
                const queue<_Ty, _Container>& _Right)
{       // test for queue inequality
  return !(_Left == _Right);
}

template<class _Ty,
         class _Container> inline
bool operator<(const queue<_Ty, _Container>& _Left,
               const queue<_Ty, _Container>& _Right)
{       // test if _Left < _Right for queues
  return _Left._Get_container() < _Right._Get_container();
}

template<class _Ty,
         class _Container> inline
bool operator>(const queue<_Ty, _Container>& _Left,
               const queue<_Ty, _Container>& _Right)
{       // test if _Left > _Right for queues
  return _Right < _Left;
}

template<class _Ty,
         class _Container> inline
bool operator<=(const queue<_Ty, _Container>& _Left,
                const queue<_Ty, _Container>& _Right)
{       // test if _Left <= _Right for queues
  return !(_Right < _Left);
}

template<class _Ty,
         class _Container> inline
bool operator>=(const queue<_Ty, _Container>& _Left,
                const queue<_Ty, _Container>& _Right)
{       // test if _Left >= _Right for queues
  return !(_Left < _Right);
}

// TEMPLATE CLASS priority_queue
template<class _Ty,
         class _Container = vector<_Ty>,
         class _Pr = less<typename _Container::value_type> >
class priority_queue
{       // priority queue implemented with a _Container
public:
  typedef priority_queue<_Ty, _Container, _Pr> _Myt;
  typedef _Container container_type;
  typedef typename _Container::value_type value_type;
  typedef typename _Container::size_type size_type;
  typedef typename _Container::reference reference;
  typedef typename _Container::const_reference const_reference;
  typedef _Pr value_compare;

  static_assert((is_same<_Ty, value_type>::value),
                "mismatch between value_type of priority_queue and underlying container");

  priority_queue()
    : c(), comp()
  {       // construct with empty container, default comparator
  }

  priority_queue(const _Myt& _Right)
    : c(_Right.c), comp(_Right.comp)
  {       // construct by copying _Right
  }

  explicit priority_queue(const _Pr& _Pred)
    : c(), comp(_Pred)
  {       // construct with empty container, specified comparator
  }

  priority_queue(const _Pr& _Pred, const _Container& _Cont)
    : c(_Cont), comp(_Pred)
  {       // construct by copying specified container, comparator
    std::make_heap(c.begin(), c.end(), comp);
  }

  template<class _InIt>
  priority_queue(_InIt _First, _InIt _Last)
    : c(_First, _Last), comp()
  {       // construct by copying [_First, _Last), default comparator
    std::make_heap(c.begin(), c.end(), comp);
  }

  template<class _InIt>
  priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred)
    : c(_First, _Last), comp(_Pred)
  {       // construct by copying [_First, _Last), specified comparator
    std::make_heap(c.begin(), c.end(), comp);
  }

  template<class _InIt>
  priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred,
                 const _Container& _Cont)
    : c(_Cont), comp(_Pred)
  {       // construct by copying [_First, _Last), container, and comparator
    c.insert(c.end(), _First, _Last);
    std::make_heap(c.begin(), c.end(), comp);
  }

  _Myt& operator=(const _Myt& _Right)
  {       // assign by copying _Right
    c = _Right.c;
    comp = _Right.comp;
    return *this;
  }

  template<class _Alloc,
           class = typename enable_if<uses_allocator<_Container,
                                                     _Alloc>::value,
                                      void>::type>
  explicit priority_queue(const _Alloc& _Al)
    : c(_Al)
  {       // construct with empty container, allocator
  }

  template<class _Alloc,
           class = typename enable_if<uses_allocator<_Container,
                                                     _Alloc>::value,
                                      void>::type>
  priority_queue(const _Pr& _Pred, const _Alloc& _Al)
    : c(_Al), comp(_Pred)
  {       // construct with empty container, comparator, allocator
  }

  template<class _Alloc,
           class = typename enable_if<uses_allocator<_Container,
                                                     _Alloc>::value,
                                      void>::type>
  priority_queue(const _Pr& _Pred, const _Container& _Cont,
                 const _Alloc& _Al)
    : c(_Cont, _Al), comp(_Pred)
  {       // construct by copying specified container, comparator, allocator
    std::make_heap(c.begin(), c.end(), comp);
  }

  template<class _Alloc,
           class = typename enable_if<uses_allocator<_Container,
                                                     _Alloc>::value,
                                      void>::type>
  priority_queue(const _Myt& _Right, const _Alloc& _Al)
    : c(_Right.c, _Al), comp(_Right.comp)
  {       // construct by copying _Right, allocator
  }

  priority_queue(_Myt&& _Right)
    _NOEXCEPT_OP(   is_nothrow_move_constructible<_Container>::value
                 && is_nothrow_move_constructible<_Pr>::value)
  : c(std::move(_Right.c)), comp(std::move(_Right.comp))
  {       // construct by moving _Right
  }

  priority_queue(const _Pr& _Pred, _Container&& _Cont)
    : c(std::move(_Cont)), comp(_Pred)
  {       // construct by moving specified container, comparator
    std::make_heap(c.begin(), c.end(), comp);
  }

  template<class _InIt>
  priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred,
                 _Container&& _Cont)
    : c(std::move(_Cont)), comp(_Pred)
  {       // construct by copying [_First, _Last), moving container
    c.insert(c.end(), _First, _Last);
    std::make_heap(c.begin(), c.end(), comp);
  }

  template<class _Alloc,
           class = typename enable_if<uses_allocator<_Container,
                                                     _Alloc>::value,
                                      void>::type>
  priority_queue(const _Pr& _Pred, _Container&& _Cont,
                 const _Alloc& _Al)
    : c(std::move(_Cont), _Al), comp(_Pred)
  {       // construct by moving specified container, comparator, allocator
    std::make_heap(c.begin(), c.end(), comp);
  }

  template<class _Alloc,
           class = typename enable_if<uses_allocator<_Container,
                                                     _Alloc>::value,
                                      void>::type>
  priority_queue(_Myt&& _Right, const _Alloc& _Al)
    : c(std::move(_Right.c), _Al), comp(std::move(_Right.comp))
  {       // construct by moving _Right, allocator
  }

  _Myt& operator=(_Myt&& _Right)
    _NOEXCEPT_OP(   is_nothrow_move_assignable<_Container>::value
                 && is_nothrow_move_assignable<_Pr>::value)
  {       // assign by moving _Right
    c = std::move(_Right.c);
    comp = std::move(_Right.comp);
    return *this;
  }

  void push(value_type&& _Val)
  {       // insert element at beginning
    c.push_back(std::move(_Val));
    std::push_heap(c.begin(), c.end(), comp);
  }

  template<class... _Valty>
  void emplace(_Valty&&... _Val)
  {       // insert element at beginning
    c.emplace_back(std::forward<_Valty>(_Val)...);
    std::push_heap(c.begin(), c.end(), comp);
  }

  bool empty() const
  {       // test if queue is empty
    return c.empty();
  }

  size_type size() const
  {       // return length of queue
    return c.size();
  }

  const_reference top() const
  {       // return highest-priority element
    return c.front();
  }

  void push(const value_type& _Val)
  {       // insert value in priority order
    c.push_back(_Val);
    std::push_heap(c.begin(), c.end(), comp);
  }

  void pop()
  {       // erase highest-priority element
    std::pop_heap(c.begin(), c.end(), comp);
    c.pop_back();
  }

  void swap(_Myt& _Right)
    _NOEXCEPT_OP(   _NOEXCEPT_OP(_Swap_adl(this->c, _Right.c))
                 && _NOEXCEPT_OP(_Swap_adl(this->comp, _Right.comp)))
  {       // exchange contents with _Right
    _Swap_adl(c, _Right.c);
    _Swap_adl(comp, _Right.comp);
  }

protected:
  _Container c;   // the underlying container
  _Pr comp;       // the comparator functor
};

// priority_queue TEMPLATE FUNCTIONS
template<class _Ty,
         class _Container,
         class _Pr> inline
void swap(priority_queue<_Ty, _Container, _Pr>& _Left,
          priority_queue<_Ty, _Container, _Pr>& _Right)
  _NOEXCEPT_OP(_NOEXCEPT_OP(_Left.swap(_Right)))
{       // swap _Left and _Right queues
  _Left.swap(_Right);
}

template<class _Ty,
         class _Container,
         class _Alloc>
struct uses_allocator<queue<_Ty, _Container>, _Alloc>
  : uses_allocator<_Container, _Alloc>
{       // true_type if container allocator enabled
};

template<class _Ty,
         class _Container,
         class _Pr,
         class _Alloc>
struct uses_allocator<priority_queue<_Ty, _Container, _Pr>, _Alloc>
  : uses_allocator<_Container, _Alloc>
{       // true_type if container allocator enabled
};

}       // namespace std

#endif /* _QUEUE_ */

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0576 */
