// Profiling list implementation -*- C++ -*-
// Copyright (C) 2009-2018 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// .
/** @file profile/list
 *  This file is a GNU profile extension to the Standard C++ Library.
 */
#ifndef _GLIBCXX_PROFILE_LIST
#define _GLIBCXX_PROFILE_LIST 1
#include 
#include 
#include 
namespace std _GLIBCXX_VISIBILITY(default)
{
namespace __profile
{
  template
    class _List_profile
    {
      _List&
      _M_conjure()
      { return *static_cast<_List*>(this); }
    public:
      __gnu_profile::__list2slist_info* _M_list2slist_info;
      __gnu_profile::__list2vector_info* _M_list2vector_info;
      _List_profile() _GLIBCXX_NOEXCEPT
      { _M_profile_construct(); }
      void
      _M_profile_construct() _GLIBCXX_NOEXCEPT
      {
	_M_list2slist_info = __profcxx_list2slist_construct();
	_M_list2vector_info = __profcxx_list2vector_construct();
      }
      void
      _M_profile_destruct() _GLIBCXX_NOEXCEPT
      {
	__profcxx_list2vector_destruct(_M_list2vector_info);
	_M_list2vector_info = 0;
	__profcxx_list2slist_destruct(_M_list2slist_info);
	_M_list2slist_info = 0;
      }
      void
      _M_swap(_List_profile& __other)
      {
	std::swap(_M_list2slist_info, __other._M_list2slist_info);
	std::swap(_M_list2vector_info, __other._M_list2vector_info);
      }
#if __cplusplus >= 201103L
      _List_profile(const _List_profile&) noexcept
      : _List_profile() { }
      _List_profile(_List_profile&& __other) noexcept
      : _List_profile()
      { _M_swap(__other); }
      _List_profile&
      operator=(const _List_profile&) noexcept
      {
	_M_profile_destruct();
	_M_profile_construct();
      }
      _List_profile&
      operator=(_List_profile&& __other) noexcept
      {
	_M_swap(__other);
	__other._M_profile_destruct();
	__other._M_profile_construct();
      }
#endif
      ~_List_profile()
      { _M_profile_destruct(); }
    };
  /** @brief List wrapper with performance instrumentation.  */
  template >
    class list
    : public _GLIBCXX_STD_C::list<_Tp, _Allocator>,
      public _List_profile >
    {
      typedef _GLIBCXX_STD_C::list<_Tp, _Allocator>	_Base;
    public:
      typedef typename _Base::reference			reference;
      typedef typename _Base::const_reference		const_reference;
      typedef __iterator_tracker
							iterator;
      typedef __iterator_tracker
							const_iterator;
      typedef typename _Base::size_type			size_type;
      typedef typename _Base::difference_type		difference_type;
      typedef _Tp					value_type;
      typedef _Allocator				allocator_type;
      typedef typename _Base::pointer			pointer;
      typedef typename _Base::const_pointer		const_pointer;
      typedef std::reverse_iterator		reverse_iterator;
      typedef std::reverse_iterator	const_reverse_iterator;
      // 23.2.2.1 construct/copy/destroy:
#if __cplusplus < 201103L
      list() { }
      list(const list& __x)
      : _Base(__x) { }
      ~list() { }
#else
      list() = default;
      list(const list&) = default;
      list(list&&) = default;
      ~list() = default;
      list(initializer_list __l,
	   const allocator_type& __a = allocator_type())
      : _Base(__l, __a) { }
      list(const list& __x, const allocator_type& __a)
      : _Base(__x, __a) { }
      list(list&& __x, const allocator_type& __a)
      : _Base(std::move(__x), __a) { }
#endif
      explicit
      list(const _Allocator& __a) _GLIBCXX_NOEXCEPT
      : _Base(__a) { }
#if __cplusplus >= 201103L
      explicit
      list(size_type __n, const allocator_type& __a = allocator_type())
      : _Base(__n, __a) { }
      list(size_type __n, const _Tp& __value,
	   const _Allocator& __a = _Allocator())
      : _Base(__n, __value, __a) { }
#else
      explicit
      list(size_type __n, const _Tp& __value = _Tp(),
	   const _Allocator& __a = _Allocator())
      : _Base(__n, __value, __a) { }
#endif
#if __cplusplus >= 201103L
      template>
#else
      template
#endif
      list(_InputIterator __first, _InputIterator __last,
	   const _Allocator& __a = _Allocator())
      : _Base(__first, __last, __a) { }
      list(const _Base& __x)
      : _Base(__x) { }
#if __cplusplus < 201103L
      list&
      operator=(const list& __x)
      {
	this->_M_profile_destruct();
	_M_base() = __x;
	this->_M_profile_construct();
	return *this;
      }
#else
      list&
      operator=(const list&) = default;
      list&
      operator=(list&&) = default;
      list&
      operator=(initializer_list __l)
      {
	this->_M_profile_destruct();
	_M_base() = __l;
	this->_M_profile_construct();
	return *this;
      }
#endif
      // iterators:
      iterator
      begin() _GLIBCXX_NOEXCEPT
      { return iterator(_Base::begin(), this); }
      const_iterator
      begin() const _GLIBCXX_NOEXCEPT
      { return const_iterator(_Base::begin(), this); }
      iterator
      end() _GLIBCXX_NOEXCEPT
      {
	__profcxx_list2slist_rewind(this->_M_list2slist_info);
	return iterator(_Base::end(), this);
      }
      const_iterator
      end() const _GLIBCXX_NOEXCEPT
      {
	__profcxx_list2slist_rewind(this->_M_list2slist_info);
	return const_iterator(_Base::end(), this);
      }
      reverse_iterator
      rbegin() _GLIBCXX_NOEXCEPT
      {
	__profcxx_list2slist_rewind(this->_M_list2slist_info);
	return reverse_iterator(end());
      }
      const_reverse_iterator
      rbegin() const _GLIBCXX_NOEXCEPT
      {
	__profcxx_list2slist_rewind(this->_M_list2slist_info);
	return const_reverse_iterator(end());
      }
      reverse_iterator
      rend() _GLIBCXX_NOEXCEPT
      { return reverse_iterator(begin()); }
      const_reverse_iterator
      rend() const _GLIBCXX_NOEXCEPT
      { return const_reverse_iterator(begin()); }
#if __cplusplus >= 201103L
      const_iterator
      cbegin() const noexcept
      { return const_iterator(_Base::cbegin(), this); }
      const_iterator
      cend() const noexcept
      { return const_iterator(_Base::cend(), this); }
      const_reverse_iterator
      crbegin() const noexcept
      { return const_reverse_iterator(end()); }
      const_reverse_iterator
      crend() const noexcept
      { return const_reverse_iterator(begin()); }
#endif
      // 23.2.2.2 capacity:
      reference
      back() _GLIBCXX_NOEXCEPT
      {
	__profcxx_list2slist_rewind(this->_M_list2slist_info);
	return _Base::back();
      }
      const_reference
      back() const _GLIBCXX_NOEXCEPT
      {
	__profcxx_list2slist_rewind(this->_M_list2slist_info);
	return _Base::back();
      }
      // 23.2.2.3 modifiers:
      void
      push_front(const value_type& __x)
      {
	__profcxx_list2vector_invalid_operator(this->_M_list2vector_info);
	__profcxx_list2slist_operation(this->_M_list2slist_info);
	_Base::push_front(__x);
      }
      void
      pop_front() _GLIBCXX_NOEXCEPT
      {
	__profcxx_list2slist_operation(this->_M_list2slist_info);
	_Base::pop_front();
      }
      void
      pop_back() _GLIBCXX_NOEXCEPT
      {
	_Base::pop_back();
	__profcxx_list2slist_rewind(this->_M_list2slist_info);
      }
#if __cplusplus >= 201103L
      template
	iterator
	emplace(const_iterator __position, _Args&&... __args)
	{
	  return iterator(_Base::emplace(__position.base(),
					 std::forward<_Args>(__args)...),
			  this);
	}
#endif
      iterator
#if __cplusplus >= 201103L
      insert(const_iterator __pos, const _Tp& __x)
#else
      insert(iterator __pos, const _Tp& __x)
#endif
      {
	_M_profile_insert(__pos, this->size());
	return iterator(_Base::insert(__pos.base(), __x), this);
      }
#if __cplusplus >= 201103L
      iterator
      insert(const_iterator __pos, _Tp&& __x)
      {
	_M_profile_insert(__pos, this->size());
	return iterator(_Base::emplace(__pos.base(), std::move(__x)),
			this);
      }
      iterator
      insert(const_iterator __pos, initializer_list __l)
      {
	_M_profile_insert(__pos, this->size());
	return iterator(_Base::insert(__pos.base(), __l), this);
      }
#endif
#if __cplusplus >= 201103L
      iterator
      insert(const_iterator __pos, size_type __n, const _Tp& __x)
      {
	_M_profile_insert(__pos, this->size());
	return iterator(_Base::insert(__pos.base(), __n, __x), this);
      }
#else
      void
      insert(iterator __pos, size_type __n, const _Tp& __x)
      {
	_M_profile_insert(__pos, this->size());
	_Base::insert(__pos.base(), __n, __x);
      }
#endif
#if __cplusplus >= 201103L
      template>
	iterator
	insert(const_iterator __pos, _InputIterator __first,
	       _InputIterator __last)
	{
	  _M_profile_insert(__pos, this->size());
	  return iterator(_Base::insert(__pos.base(), __first, __last),
			  this);
	}
#else
      template
	void
	insert(iterator __pos, _InputIterator __first,
	       _InputIterator __last)
	{
	  _M_profile_insert(__pos, this->size());
	  _Base::insert(__pos.base(), __first, __last);
	}
#endif
      iterator
#if __cplusplus >= 201103L
      erase(const_iterator __pos) noexcept
#else
      erase(iterator __pos)
#endif
      {	return iterator(_Base::erase(__pos.base()), this); }
      iterator
#if __cplusplus >= 201103L
      erase(const_iterator __pos, const_iterator __last) noexcept
#else
      erase(iterator __pos, iterator __last)
#endif
      {
	// _GLIBCXX_RESOLVE_LIB_DEFECTS
	// 151. can't currently clear() empty container
	return iterator(_Base::erase(__pos.base(), __last.base()), this);
      }
      void
      swap(list& __x)
      _GLIBCXX_NOEXCEPT_IF( noexcept(declval<_Base&>().swap(__x)) )
      {
	_Base::swap(__x);
	this->_M_swap(__x);
      }
      void
      clear() _GLIBCXX_NOEXCEPT
      {
	this->_M_profile_destruct();
	_Base::clear();
	this->_M_profile_construct();
      }
      // 23.2.2.4 list operations:
      void
#if __cplusplus >= 201103L
      splice(const_iterator __pos, list&& __x) noexcept
#else
      splice(iterator __pos, list& __x)
#endif
      { this->splice(__pos, _GLIBCXX_MOVE(__x), __x.begin(), __x.end()); }
#if __cplusplus >= 201103L
      void
      splice(const_iterator __pos, list& __x) noexcept
      { this->splice(__pos, std::move(__x)); }
      void
      splice(const_iterator __pos, list& __x, const_iterator __i)
      { this->splice(__pos, std::move(__x), __i); }
#endif
      void
#if __cplusplus >= 201103L
      splice(const_iterator __pos, list&& __x, const_iterator __i) noexcept
#else
      splice(iterator __pos, list& __x, iterator __i)
#endif
      {
	// We used to perform the splice_alloc check:  not anymore, redundant
	// after implementing the relevant bits of N1599.
	// _GLIBCXX_RESOLVE_LIB_DEFECTS
	_Base::splice(__pos.base(), _GLIBCXX_MOVE(__x._M_base()),
		      __i.base());
      }
      void
#if __cplusplus >= 201103L
      splice(const_iterator __pos, list&& __x, const_iterator __first,
	     const_iterator __last) noexcept
#else
      splice(iterator __pos, list& __x, iterator __first,
	     iterator __last)
#endif
      {
	_Base::splice(__pos.base(), _GLIBCXX_MOVE(__x._M_base()),
		      __first.base(), __last.base());
      }
#if __cplusplus >= 201103L
      void
      splice(const_iterator __pos, list& __x,
	     const_iterator __first, const_iterator __last) noexcept
      { this->splice(__pos, std::move(__x), __first, __last); }
#endif
      void
      remove(const _Tp& __value)
      {
	for (iterator __x = begin(); __x != end(); )
	  {
	    if (*__x == __value)
	      __x = erase(__x);
	    else
	      ++__x;
	  }
      }
      template
	void
	remove_if(_Predicate __pred)
	{
	  for (iterator __x = begin(); __x != end(); )
	    {
	      __profcxx_list2slist_operation(this->_M_list2slist_info);
	      if (__pred(*__x))
		__x = erase(__x);
	      else
		++__x;
	    }
	}
      void
      unique()
      {
	iterator __first = begin();
	iterator __last = end();
	if (__first == __last)
	  return;
	iterator __next = __first;
	while (++__next != __last)
	  {
	    __profcxx_list2slist_operation(this->_M_list2slist_info);
	    if (*__first == *__next)
	      erase(__next);
	    else
	      __first = __next;
	    __next = __first;
	  }
      }
      template
	void
	unique(_BinaryPredicate __binary_pred)
	{
	  iterator __first = begin();
	  iterator __last = end();
	  if (__first == __last)
	    return;
	  iterator __next = __first;
	  while (++__next != __last)
	    {
	      __profcxx_list2slist_operation(this->_M_list2slist_info);
	      if (__binary_pred(*__first, *__next))
		erase(__next);
	      else
		__first = __next;
	      __next = __first;
	    }
	}
      void
#if __cplusplus >= 201103L
      merge(list&& __x)
#else
      merge(list& __x)
#endif
      { _Base::merge(_GLIBCXX_MOVE(__x._M_base())); }
#if __cplusplus >= 201103L
      void
      merge(list& __x)
      { this->merge(std::move(__x)); }
#endif
      template
	void
#if __cplusplus >= 201103L
	merge(list&& __x, _Compare __comp)
#else
	merge(list& __x, _Compare __comp)
#endif
	{ _Base::merge(_GLIBCXX_MOVE(__x._M_base()), __comp); }
#if __cplusplus >= 201103L
      template
	void
	merge(list& __x, _Compare __comp)
	{ this->merge(std::move(__x), __comp); }
#endif
      _Base&
      _M_base() _GLIBCXX_NOEXCEPT	{ return *this; }
      const _Base&
      _M_base() const _GLIBCXX_NOEXCEPT	{ return *this; }
      void _M_profile_iterate(int __rewind = 0) const
      {
	__profcxx_list2slist_operation(this->_M_list2slist_info);
	__profcxx_list2vector_iterate(this->_M_list2vector_info, __rewind);
	if (__rewind)
	  __profcxx_list2slist_rewind(this->_M_list2slist_info);
      }
    private:
      size_type
      _M_profile_insert(const_iterator __pos, size_type __size)
      {
	size_type __shift = 0;
	typename _Base::const_iterator __it = __pos.base();
	for (; __it != _Base::end(); ++__it)
	  __shift++;
	__profcxx_list2slist_rewind(this->_M_list2slist_info);
	__profcxx_list2slist_operation(this->_M_list2slist_info);
	__profcxx_list2vector_insert(this->_M_list2vector_info, __shift, __size);
      }
    };
  template
    inline bool
    operator==(const list<_Tp, _Alloc>& __lhs,
	       const list<_Tp, _Alloc>& __rhs)
    { return __lhs._M_base() == __rhs._M_base(); }
  template
    inline bool
    operator!=(const list<_Tp, _Alloc>& __lhs,
	       const list<_Tp, _Alloc>& __rhs)
    { return __lhs._M_base() != __rhs._M_base(); }
  template
    inline bool
    operator<(const list<_Tp, _Alloc>& __lhs,
	      const list<_Tp, _Alloc>& __rhs)
    { return __lhs._M_base() < __rhs._M_base(); }
  template
    inline bool
    operator<=(const list<_Tp, _Alloc>& __lhs,
	       const list<_Tp, _Alloc>& __rhs)
    { return __lhs._M_base() <= __rhs._M_base(); }
  template
    inline bool
    operator>=(const list<_Tp, _Alloc>& __lhs,
	       const list<_Tp, _Alloc>& __rhs)
    { return __lhs._M_base() >= __rhs._M_base(); }
  template
    inline bool
    operator>(const list<_Tp, _Alloc>& __lhs,
	      const list<_Tp, _Alloc>& __rhs)
    { return __lhs._M_base() > __rhs._M_base(); }
  template
    inline void
    swap(list<_Tp, _Alloc>& __lhs, list<_Tp, _Alloc>& __rhs)
    _GLIBCXX_NOEXCEPT_IF(noexcept(__lhs.swap(__rhs)))
    { __lhs.swap(__rhs); }
} // namespace __profile
} // namespace std
#endif