///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////
// The intrusive list container is similar to a list, with the primary
// different being that intrusive lists allow you to control memory
// allocation.
//
// * Intrusive lists store the nodes directly in the data items. This
//   is done by deriving the object from intrusive_list_node.
//
// * The container does no memory allocation -- it works entirely with
//   the submitted nodes. This does mean that it is the client's job to 
//   free the nodes in an intrusive list, though.
//
// * Valid node pointers can be converted back to iterators in O(1).
//   This is because objects in the list are also nodes in the list.
//
// * intrusive_list does not support copy construction or assignment; 
//   the push, pop, and insert operations take ownership of the 
//   passed object.
//
// Usage notes:
//
// * You can use an intrusive_list directly with the standard nodes
//   if you have some other way of converting the node pointer back
//   to your data pointer.
//
// * Remember that the list destructor doesn't deallocate nodes -- it can't.
//
// * The size is not cached; this makes size() linear time but splice() is
//   constant time. This does mean that you can remove() an element without
//   having to figure out which list it is in, however.
//
// * You can insert a node into multiple intrusive_lists. One way to do so
//   is to (ab)use inheritance:
//
//      struct NodeA : public intrusive_list_node {};
//      struct NodeB : public intrusive_list_node {};
//      struct Object : public NodeA, nodeB {};
//
//      intrusive_list<NodeA> listA;
//      intrusive_list<NodeB> listB;
//
//      listA.push_back(obj);
//      listB.push_back(obj);
//
// * find() vs. locate()
//   The find(v) algorithm returns an iterator p such that *p == v; intrusive_list::locate(v) 
//   returns an iterator p such that &*p == &v. intrusive_list<> doesn't have find() mainly 
//   because list<> doesn't have it either, but there's no reason it couldn't. intrusive_list
//   uses the name 'find' because:
//      - So as not to confuse the member function with the well-defined free function from algorithm.h.
//      - Because it is not API-compatible with eastl::find().
//      - Because it simply locates an object within the list based on its node entry and doesn't perform before any value-based searches or comparisons.
//
// Differences between intrusive_list and std::list:
//
// Issue                            std::list       intrusive_list
// --------------------------------------------------------------
// Automatic node ctor/dtor         Yes             No
// Can memmove() container          Maybe*          No
// Same item in list twice          Yes(copy/byref) No
// Can store non-copyable items     No              Yes
// size()                           O(1) or O(n)    O(n)
// clear()                          O(n)            O(1)
// erase(range)                     O(n)            O(1)
// splice(range)                    O(1) or O(n)    O(1)
// Convert reference to iterator    No              O(1)
// Remove without container         No              O(1)
// Nodes in mixed allocators        No              Yes
//
// *) Not required by standard but can be done with some STL implementations.
//
///////////////////////////////////////////////////////////////////////////////


#ifndef EASTL_INTRUSIVE_LIST_H
#define EASTL_INTRUSIVE_LIST_H


//#include <EASTL/internal/config.h>
//#include <EASTL/iterator.h>
//#include <EASTL/algorithm.h>

#if 1 //defined(EA_PRAGMA_ONCE_SUPPORTED)
	#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif



namespace eastl
{

	/// intrusive_list_node
	///
	/// By design this must be a POD, as user structs will be inheriting from 
	/// it and they may wish to remain POD themselves. However, if the 
	/// EASTL_VALIDATE_INTRUSIVE_LIST option is enabled
	/// 
	struct intrusive_list_node
	{
		intrusive_list_node* mpNext;
		intrusive_list_node* mpPrev;
	};



	/// intrusive_list_iterator
	///
	template <typename T, typename Pointer, typename Reference>
	class intrusive_list_iterator
	{
	public:
		typedef intrusive_list_iterator<T, Pointer, Reference>   this_type;
		typedef intrusive_list_iterator<T, T*, T&>               iterator;
		typedef intrusive_list_iterator<T, const T*, const T&>   const_iterator;
		typedef T                                                value_type;
		typedef T                                                node_type;
		typedef ptrdiff_t                                        difference_type;
		typedef Pointer                                          pointer;
		typedef Reference                                        reference;
		typedef std::bidirectional_iterator_tag         iterator_category;

	public:
		pointer mpNode; // Needs to be public for operator==() to work

	public:
		intrusive_list_iterator();
		explicit intrusive_list_iterator(pointer pNode);  // Note that you can also construct an iterator from T via this, since value_type == node_type.
		intrusive_list_iterator(const iterator& x);
		intrusive_list_iterator& operator=(const iterator& x);

		reference operator*() const;
		pointer   operator->() const;

		intrusive_list_iterator& operator++();
		intrusive_list_iterator& operator--();

		intrusive_list_iterator operator++(int);
		intrusive_list_iterator operator--(int);

	}; // class intrusive_list_iterator



	/// intrusive_list_base
	///
	class intrusive_list_base
	{
	public:
		typedef size_t size_type; 
		typedef ptrdiff_t    difference_type;

	protected:
		intrusive_list_node mAnchor;          ///< Sentinel node (end). All data nodes are linked in a ring from this node.

	public:
		intrusive_list_base();
	   ~intrusive_list_base();

		bool            empty() const noexcept;
		size_t    size() const noexcept;  ///< Returns the number of elements in the list; O(n).
		void            clear() noexcept;       ///< Clears the list; O(1). No deallocation occurs.
		void            pop_front();               ///< Removes an element from the front of the list; O(1). The element must exist, but is not deallocated.
		void            pop_back();                ///< Removes an element from the back of the list; O(1). The element must exist, but is not deallocated.
		void  reverse() noexcept;     ///< Reverses a list so that front and back are swapped; O(n).

		bool  validate() const;          ///< Scans a list for linkage inconsistencies; O(n) time, O(1) space. Returns false if errors are detected, such as loops or branching.

	}; // class intrusive_list_base



	/// intrusive_list
	///
	/// Example usage:
	///    struct IntNode : public eastl::intrusive_list_node {
	///        int mX;
	///        IntNode(int x) : mX(x) { }
	///    };
	///    
	///    IntNode nodeA(0);
	///    IntNode nodeB(1);
	///    
	///    intrusive_list<IntNode> intList;
	///    intList.push_back(nodeA);
	///    intList.push_back(nodeB);
	///    intList.remove(nodeA);
	///    
	template <typename T = intrusive_list_node>
	class intrusive_list : public intrusive_list_base
	{
	public:
		typedef intrusive_list<T>                               this_type;
		typedef intrusive_list_base                             base_type;
		typedef T                                               node_type;
		typedef T                                               value_type;
		typedef typename base_type::size_type                   size_type;
		typedef typename base_type::difference_type             difference_type;
		typedef T&                                              reference;
		typedef const T&                                        const_reference;
		typedef T*                                              pointer;
		typedef const T*                                        const_pointer;
		typedef intrusive_list_iterator<T, T*, T&>              iterator;
		typedef intrusive_list_iterator<T, const T*, const T&>  const_iterator;
		typedef std::reverse_iterator<iterator>               reverse_iterator;
		typedef std::reverse_iterator<const_iterator>         const_reverse_iterator;

	public:
		intrusive_list();                                ///< Creates an empty list.
		intrusive_list(const this_type& x);              ///< Creates an empty list; ignores the argument.
	  //intrusive_list(std::initializer_list<value_type> ilist); To consider: Is this feasible, given how initializer_list works by creating a temporary array? Even if it is feasible, is it a good idea?

		this_type&  operator=(const this_type& x);       ///< Clears the list; ignores the argument.
		void        swap(this_type&);                    ///< Swaps the contents of two intrusive lists; O(1).

		iterator                begin() noexcept;                 ///< Returns an iterator pointing to the first element in the list.
		const_iterator          begin() const noexcept;           ///< Returns a const_iterator pointing to the first element in the list.
		const_iterator          cbegin() const noexcept;          ///< Returns a const_iterator pointing to the first element in the list.

		iterator                end() noexcept;                   ///< Returns an iterator pointing one-after the last element in the list.
		const_iterator          end() const noexcept;             ///< Returns a const_iterator pointing one-after the last element in the list.
		const_iterator          cend() const noexcept;            ///< Returns a const_iterator pointing one-after the last element in the list.

		reverse_iterator        rbegin() noexcept;                ///< Returns a reverse_iterator pointing at the end of the list (start of the reverse sequence).
		const_reverse_iterator  rbegin() const noexcept;          ///< Returns a const_reverse_iterator pointing at the end of the list (start of the reverse sequence).
		const_reverse_iterator  crbegin() const noexcept;         ///< Returns a const_reverse_iterator pointing at the end of the list (start of the reverse sequence).

		reverse_iterator        rend() noexcept;                  ///< Returns a reverse_iterator pointing at the start of the list (end of the reverse sequence).
		const_reverse_iterator  rend() const noexcept;            ///< Returns a const_reverse_iterator pointing at the start of the list (end of the reverse sequence).
		const_reverse_iterator  crend() const noexcept;           ///< Returns a const_reverse_iterator pointing at the start of the list (end of the reverse sequence).
		
		reference               front();                 ///< Returns a reference to the first element. The list must be non-empty.
		const_reference         front() const;           ///< Returns a const reference to the first element. The list must be non-empty.
		reference               back();                  ///< Returns a reference to the last element. The list must be non-empty.
		const_reference         back() const;            ///< Returns a const reference to the last element. The list must be non-empty.

		void        push_front(value_type& x);             ///< Adds an element to the front of the list; O(1). The element is not copied. The element must not be in any other list.
		void        push_back(value_type& x);              ///< Adds an element to the back of the list; O(1). The element is not copied. The element must not be in any other list.

		bool        contains(const value_type& x) const;   ///< Returns true if the given element is in the list; O(n). Equivalent to (locate(x) != end()).

		iterator        locate(value_type& x);             ///< Converts a reference to an object in the list back to an iterator, or returns end() if it is not part of the list. O(n)
		const_iterator  locate(const value_type& x) const; ///< Converts a const reference to an object in the list back to a const iterator, or returns end() if it is not part of the list. O(n)

		iterator    insert(const_iterator pos, value_type& x);   ///< Inserts an element before the element pointed to by the iterator. O(1)
		iterator    erase(const_iterator pos);                   ///< Erases the element pointed to by the iterator. O(1)
		iterator    erase(const_iterator pos, const_iterator last);    ///< Erases elements within the iterator range [pos, last). O(1)

		reverse_iterator erase(const_reverse_iterator pos);
		reverse_iterator erase(const_reverse_iterator pos, const_reverse_iterator last);

		static void remove(value_type& value);                    ///< Erases an element from a list; O(1). Note that this is static so you don't need to know which list the element, although it must be in some list.

		void               splice(const_iterator pos, value_type& x);
				///< Moves the given element into this list before the element pointed to by pos; O(1).
				///< Required: x must be in some list or have first/next pointers that point it itself.

		void               splice(const_iterator pos, intrusive_list& x);
				///< Moves the contents of a list into this list before the element pointed to by pos; O(1).
				///< Required: &x != this (same as std::list).

		void               splice(const_iterator pos, intrusive_list& x, const_iterator i);
				///< Moves the given element pointed to i within the list x into the current list before
				///< the element pointed to by pos; O(1).

		void               splice(const_iterator pos, intrusive_list& x, const_iterator first, const_iterator last);
				///< Moves the range of elements [first, last) from list x into the current list before
				///< the element pointed to by pos; O(1).
				///< Required: pos must not be in [first, last). (same as std::list).

	public:
		// Sorting functionality
		// This is independent of the global sort algorithms, as lists are 
		// linked nodes and can be sorted more efficiently by moving nodes
		// around in ways that global sort algorithms aren't privy to.

		void merge(this_type& x);

		template <typename Compare>
		void merge(this_type& x, Compare compare);

		void unique();

		template <typename BinaryPredicate>
		void unique(BinaryPredicate);

		void sort();

		template<typename Compare>
		void sort(Compare compare);

	public:

	}; // intrusive_list




	///////////////////////////////////////////////////////////////////////
	// intrusive_list_node
	///////////////////////////////////////////////////////////////////////

	// Moved to be inline within the class because the may-alias attribute is
	// triggering what appears to be a bug in GCC that effectively requires 
	// may-alias structs to implement inline member functions within the class
	// declaration. We don't have a .cpp file for 
	// #if EASTL_VALIDATE_INTRUSIVE_LIST
	//     inline intrusive_list_node::intrusive_list_node()
	//     {
	//         mpNext = mpPrev = NULL;
	//     }
	//
	//     inline intrusive_list_node::~intrusive_list_node()
	//     {
	//         #if EASTL_ASSERT_ENABLED
	//             if(mpNext || mpPrev)
	//                 EASTL_FAIL_MSG("~intrusive_list_node(): List is non-empty.");
	//         #endif
	//     }
	// #endif


	///////////////////////////////////////////////////////////////////////
	// intrusive_list_iterator
	///////////////////////////////////////////////////////////////////////

	template <typename T, typename Pointer, typename Reference>
	inline intrusive_list_iterator<T, Pointer, Reference>::intrusive_list_iterator()
	{
		#if EASTL_DEBUG
			mpNode = NULL;
		#endif
	}


	template <typename T, typename Pointer, typename Reference>
	inline intrusive_list_iterator<T, Pointer, Reference>::intrusive_list_iterator(pointer pNode)
		: mpNode(pNode)
	{
		// Empty
	}


	template <typename T, typename Pointer, typename Reference>
	inline intrusive_list_iterator<T, Pointer, Reference>::intrusive_list_iterator(const iterator& x)
		: mpNode(x.mpNode)
	{
		// Empty
	}

	template <typename T, typename Pointer, typename Reference>
	inline typename intrusive_list_iterator<T, Pointer, Reference>::this_type&
	intrusive_list_iterator<T, Pointer, Reference>::operator=(const iterator& x)
	{
	    mpNode = x.mpNode;
	    return *this;
	}

	template <typename T, typename Pointer, typename Reference>
	inline typename intrusive_list_iterator<T, Pointer, Reference>::reference
	intrusive_list_iterator<T, Pointer, Reference>::operator*() const
	{
		return *mpNode;
	}


	template <typename T, typename Pointer, typename Reference>
	inline typename intrusive_list_iterator<T, Pointer, Reference>::pointer
	intrusive_list_iterator<T, Pointer, Reference>::operator->() const
	{
		return mpNode;
	}


	template <typename T, typename Pointer, typename Reference>
	inline typename intrusive_list_iterator<T, Pointer, Reference>::this_type&
	intrusive_list_iterator<T, Pointer, Reference>::operator++()
	{
		mpNode = static_cast<node_type*>(mpNode->mpNext);
		return *this;
	}


	template <typename T, typename Pointer, typename Reference>
	inline typename intrusive_list_iterator<T, Pointer, Reference>::this_type
	intrusive_list_iterator<T, Pointer, Reference>::operator++(int)
	{
		intrusive_list_iterator it(*this);
		mpNode = static_cast<node_type*>(mpNode->mpNext);
		return it;
	}


	template <typename T, typename Pointer, typename Reference>
	inline typename intrusive_list_iterator<T, Pointer, Reference>::this_type&
	intrusive_list_iterator<T, Pointer, Reference>::operator--()
	{
		mpNode = static_cast<node_type*>(mpNode->mpPrev);
		return *this;
	}


	template <typename T, typename Pointer, typename Reference>
	inline typename intrusive_list_iterator<T, Pointer, Reference>::this_type
	intrusive_list_iterator<T, Pointer, Reference>::operator--(int)
	{
		intrusive_list_iterator it(*this);
		mpNode = static_cast<node_type*>(mpNode->mpPrev);
		return it;
	}


	// The C++ defect report #179 requires that we support comparisons between const and non-const iterators.
	// Thus we provide additional template paremeters here to support this. The defect report does not
	// require us to support comparisons between reverse_iterators and const_reverse_iterators.
	template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB>
	inline bool operator==(const intrusive_list_iterator<T, PointerA, ReferenceA>& a, 
							const intrusive_list_iterator<T, PointerB, ReferenceB>& b)
	{
		return a.mpNode == b.mpNode;
	}


	template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB>
	inline bool operator!=(const intrusive_list_iterator<T, PointerA, ReferenceA>& a, 
							const intrusive_list_iterator<T, PointerB, ReferenceB>& b)
	{
		return a.mpNode != b.mpNode;
	}


	// We provide a version of operator!= for the case where the iterators are of the 
	// same type. This helps prevent ambiguity errors in the presence of rel_ops.
	template <typename T, typename Pointer, typename Reference>
	inline bool operator!=(const intrusive_list_iterator<T, Pointer, Reference>& a, 
						   const intrusive_list_iterator<T, Pointer, Reference>& b)
	{
		return a.mpNode != b.mpNode;
	}




	///////////////////////////////////////////////////////////////////////
	// intrusive_list_base
	///////////////////////////////////////////////////////////////////////

	inline intrusive_list_base::intrusive_list_base() 
	{
		mAnchor.mpNext = mAnchor.mpPrev = &mAnchor;
	}

	inline intrusive_list_base::~intrusive_list_base()
	{
		#if EASTL_VALIDATE_INTRUSIVE_LIST
			clear();
			mAnchor.mpNext = mAnchor.mpPrev = NULL;
		#endif
	}


	inline bool intrusive_list_base::empty() const noexcept
	{
		return mAnchor.mpPrev == &mAnchor;
	}


	inline intrusive_list_base::size_type intrusive_list_base::size() const noexcept
	{
		const intrusive_list_node* p = &mAnchor;
		size_type n = (size_type)-1;

		do {
			++n;
			p = p->mpNext;
		} while(p != &mAnchor);

		return n;
	}


	inline void intrusive_list_base::clear() noexcept
	{
		#if EASTL_VALIDATE_INTRUSIVE_LIST
			// Need to clear out all the next/prev pointers in the elements;
			// this makes this operation O(n) instead of O(1).
			intrusive_list_node* pNode = mAnchor.mpNext;

			while(pNode != &mAnchor)
			{
				intrusive_list_node* const pNextNode = pNode->mpNext;
				pNode->mpNext = pNode->mpPrev = NULL;
				pNode = pNextNode;
			}
		#endif

		mAnchor.mpNext = mAnchor.mpPrev = &mAnchor;
	}


	inline void intrusive_list_base::pop_front()
	{
		#if EASTL_VALIDATE_INTRUSIVE_LIST
			intrusive_list_node* const pNode = mAnchor.mpNext;
		#endif

		mAnchor.mpNext->mpNext->mpPrev = &mAnchor;
		mAnchor.mpNext = mAnchor.mpNext->mpNext;

		#if EASTL_VALIDATE_INTRUSIVE_LIST
			if(pNode != &mAnchor)
				pNode->mpNext = pNode->mpPrev = NULL;
			#if EASTL_ASSERT_ENABLED
			else
				EASTL_FAIL_MSG("intrusive_list::pop_front(): empty list.");
			#endif
		#endif
	}


	inline void intrusive_list_base::pop_back()
	{
		#if EASTL_VALIDATE_INTRUSIVE_LIST
			intrusive_list_node* const pNode = mAnchor.mpPrev;
		#endif

		mAnchor.mpPrev->mpPrev->mpNext = &mAnchor;
		mAnchor.mpPrev = mAnchor.mpPrev->mpPrev;

		#if EASTL_VALIDATE_INTRUSIVE_LIST
			if(pNode != &mAnchor)
				pNode->mpNext = pNode->mpPrev = NULL;
			#if EASTL_ASSERT_ENABLED
			else
				EASTL_FAIL_MSG("intrusive_list::pop_back(): empty list.");
			#endif
		#endif
	}




	///////////////////////////////////////////////////////////////////////
	// intrusive_list
	///////////////////////////////////////////////////////////////////////

	template <typename T>
	inline intrusive_list<T>::intrusive_list()
	{
	}


	template <typename T>
	inline intrusive_list<T>::intrusive_list(const this_type& /*x*/)
	  : intrusive_list_base()
	{
		// We intentionally ignore argument x.
		// To consider: Shouldn't this function simply not exist? Is there a useful purpose for having this function?
		// There should be a comment here about it, though my first guess is that this exists to quell VC++ level 4/-Wall compiler warnings.
	}


	template <typename T>
	inline typename intrusive_list<T>::this_type& intrusive_list<T>::operator=(const this_type& /*x*/)
	{ 
		// We intentionally ignore argument x.
		// See notes above in the copy constructor about questioning the existence of this function.
		return *this;
	}


	template <typename T>
	inline typename intrusive_list<T>::iterator intrusive_list<T>::begin() noexcept
	{
		return iterator(static_cast<T*>(mAnchor.mpNext));
	}


	template <typename T>
	inline typename intrusive_list<T>::const_iterator intrusive_list<T>::begin() const noexcept
	{
		return const_iterator(static_cast<T*>(mAnchor.mpNext));
	}


	template <typename T>
	inline typename intrusive_list<T>::const_iterator intrusive_list<T>::cbegin() const noexcept
	{
		return const_iterator(static_cast<T*>(mAnchor.mpNext));
	}


	template <typename T>
	inline typename intrusive_list<T>::iterator intrusive_list<T>::end() noexcept
	{
		return iterator(static_cast<T*>(&mAnchor));
	}


	template <typename T>
	inline typename intrusive_list<T>::const_iterator intrusive_list<T>::end() const noexcept
	{
		return const_iterator(static_cast<const T*>(&mAnchor));
	}


	template <typename T>
	inline typename intrusive_list<T>::const_iterator intrusive_list<T>::cend() const noexcept
	{
		return const_iterator(static_cast<const T*>(&mAnchor));
	}


	template <typename T>
	inline typename intrusive_list<T>::reverse_iterator intrusive_list<T>::rbegin() noexcept
	{
		return reverse_iterator(iterator(static_cast<T*>(&mAnchor)));
	}


	template <typename T>
	inline typename intrusive_list<T>::const_reverse_iterator intrusive_list<T>::rbegin() const noexcept
	{
		return const_reverse_iterator(const_iterator(static_cast<const T*>(&mAnchor)));
	}


	template <typename T>
	inline typename intrusive_list<T>::const_reverse_iterator intrusive_list<T>::crbegin() const noexcept
	{
		return const_reverse_iterator(const_iterator(static_cast<const T*>(&mAnchor)));
	}


	template <typename T>
	inline typename intrusive_list<T>::reverse_iterator intrusive_list<T>::rend() noexcept
	{
		return reverse_iterator(iterator(static_cast<T*>(mAnchor.mpNext)));
	}


	template <typename T>
	inline typename intrusive_list<T>::const_reverse_iterator intrusive_list<T>::rend() const noexcept
	{
		return const_reverse_iterator(const_iterator(static_cast<const T*>(mAnchor.mpNext)));
	}


	template <typename T>
	inline typename intrusive_list<T>::const_reverse_iterator intrusive_list<T>::crend() const noexcept
	{
		return const_reverse_iterator(const_iterator(static_cast<const T*>(mAnchor.mpNext)));
	}


	template <typename T>
	inline typename intrusive_list<T>::reference intrusive_list<T>::front()
	{
		#if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED
			if(mAnchor.mpNext == &mAnchor)
				EASTL_FAIL_MSG("intrusive_list::front(): empty list.");
		#endif

		return *static_cast<T*>(mAnchor.mpNext);
	}


	template <typename T>
	inline typename intrusive_list<T>::const_reference intrusive_list<T>::front() const
	{
		#if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED
			if(mAnchor.mpNext == &mAnchor)
				EASTL_FAIL_MSG("intrusive_list::front(): empty list.");
		#endif

		return *static_cast<const T*>(mAnchor.mpNext);
	}


	template <typename T>
	inline typename intrusive_list<T>::reference intrusive_list<T>::back()
	{
		#if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED
			if(mAnchor.mpNext == &mAnchor)
				EASTL_FAIL_MSG("intrusive_list::back(): empty list.");
		#endif

		return *static_cast<T*>(mAnchor.mpPrev);
	}


	template <typename T>
	inline typename intrusive_list<T>::const_reference intrusive_list<T>::back() const
	{
		#if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED
			if(mAnchor.mpNext == &mAnchor)
				EASTL_FAIL_MSG("intrusive_list::back(): empty list.");
		#endif

		return *static_cast<const T*>(mAnchor.mpPrev);
	}


	template <typename T>
	inline void intrusive_list<T>::push_front(value_type& x)
	{
		#if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED
			if(x.mpNext || x.mpPrev)
				EASTL_FAIL_MSG("intrusive_list::push_front(): element already on a list.");
		#endif

		x.mpNext = mAnchor.mpNext;
		x.mpPrev = &mAnchor;
		mAnchor.mpNext = &x;
		x.mpNext->mpPrev = &x;
	}


	template <typename T>
	inline void intrusive_list<T>::push_back(value_type& x)
	{
		#if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED
			if(x.mpNext || x.mpPrev)
				EASTL_FAIL_MSG("intrusive_list::push_back(): element already on a list.");
		#endif

		x.mpPrev = mAnchor.mpPrev;
		x.mpNext = &mAnchor;
		mAnchor.mpPrev = &x;
		x.mpPrev->mpNext = &x;
	}


	template <typename T>
	inline bool intrusive_list<T>::contains(const value_type& x) const
	{
		for(const intrusive_list_node* p = mAnchor.mpNext; p != &mAnchor; p = p->mpNext)
		{
			if(p == &x)
				return true;
		}

		return false;
	}


	template <typename T>
	inline typename intrusive_list<T>::iterator intrusive_list<T>::locate(value_type& x)
	{
		for(intrusive_list_node* p = (T*)mAnchor.mpNext; p != &mAnchor; p = p->mpNext)
		{
			if(p == &x)
				return iterator(static_cast<T*>(p));
		}

		return iterator((T*)&mAnchor);
	}


	template <typename T>
	inline typename intrusive_list<T>::const_iterator intrusive_list<T>::locate(const value_type& x) const
	{
		for(const intrusive_list_node* p = mAnchor.mpNext; p != &mAnchor; p = p->mpNext)
		{
			if(p == &x)
				return const_iterator(static_cast<const T*>(p));
		}

		return const_iterator((T*)&mAnchor);
	}


	template <typename T>
	inline typename intrusive_list<T>::iterator intrusive_list<T>::insert(const_iterator pos, value_type& x)
	{
		#if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED
			if(x.mpNext || x.mpPrev)
				EASTL_FAIL_MSG("intrusive_list::insert(): element already on a list.");
		#endif

		intrusive_list_node& next = *const_cast<node_type*>(pos.mpNode);
		intrusive_list_node& prev = *static_cast<node_type*>(next.mpPrev);
		prev.mpNext = next.mpPrev = &x;
		x.mpPrev    = &prev;
		x.mpNext    = &next;

		return iterator(&x);
	}


	template <typename T>
	inline typename intrusive_list<T>::iterator
	intrusive_list<T>::erase(const_iterator pos)
	{
		intrusive_list_node& prev = *static_cast<node_type*>(pos.mpNode->mpPrev);
		intrusive_list_node& next = *static_cast<node_type*>(pos.mpNode->mpNext);
		prev.mpNext = &next;
		next.mpPrev = &prev;

		#if EASTL_VALIDATE_INTRUSIVE_LIST
			iterator ii(const_cast<node_type*>(pos.mpNode));
			ii.mpNode->mpPrev = ii.mpNode->mpNext = NULL;
		#endif

		return iterator(static_cast<node_type*>(&next));
	}


	template <typename T>
	inline typename intrusive_list<T>::iterator
	intrusive_list<T>::erase(const_iterator first, const_iterator last)
	{
		intrusive_list_node& prev = *static_cast<node_type*>(first.mpNode->mpPrev);
		intrusive_list_node& next = *const_cast<node_type*>(last.mpNode);

		#if EASTL_VALIDATE_INTRUSIVE_LIST
			// need to clear out all the next/prev pointers in the elements;
			// this makes this operation O(n) instead of O(1), sadly, although
			// it's technically amortized O(1) since you could count yourself
			// as paying this cost with each insert.
			intrusive_list_node* pCur = const_cast<node_type*>(first.mpNode);

			while(pCur != &next)
			{
				intrusive_list_node* const pCurNext = pCur->mpNext;
				pCur->mpPrev = pCur->mpNext = NULL;
				pCur = pCurNext;
			}
		#endif

		prev.mpNext = &next;
		next.mpPrev = &prev;

		return iterator(const_cast<node_type*>(last.mpNode));
	}


	template <typename T>
	inline typename intrusive_list<T>::reverse_iterator
	intrusive_list<T>::erase(const_reverse_iterator position)
	{
		return reverse_iterator(erase((++position).base()));
	}


	template <typename T>
	inline typename intrusive_list<T>::reverse_iterator
	intrusive_list<T>::erase(const_reverse_iterator first, const_reverse_iterator last)
	{
		// Version which erases in order from first to last.
		// difference_type i(first.base() - last.base());
		// while(i--)
		//     first = erase(first);
		// return first;

		// Version which erases in order from last to first, but is slightly more efficient:
		return reverse_iterator(erase((++last).base(), (++first).base()));
	}


	template <typename T>
	void intrusive_list<T>::swap(intrusive_list& x)
	{
		// swap anchors
		intrusive_list_node temp(mAnchor);
		mAnchor   = x.mAnchor;
		x.mAnchor = temp;

		// Fixup node pointers into the anchor, since the addresses of 
		// the anchors must stay the same with each list.
		if(mAnchor.mpNext == &x.mAnchor)
			mAnchor.mpNext = mAnchor.mpPrev = &mAnchor;
		else
			mAnchor.mpNext->mpPrev = mAnchor.mpPrev->mpNext = &mAnchor;

		if(x.mAnchor.mpNext == &mAnchor)
			x.mAnchor.mpNext = x.mAnchor.mpPrev = &x.mAnchor;
		else
			x.mAnchor.mpNext->mpPrev = x.mAnchor.mpPrev->mpNext = &x.mAnchor;

		#if EASTL_VALIDATE_INTRUSIVE_LIST
			temp.mpPrev = temp.mpNext = NULL;
		#endif
	}


	template <typename T>
	void intrusive_list<T>::splice(const_iterator pos, value_type& value)
	{
		// Note that splice(pos, x, pos) and splice(pos+1, x, pos)
		// are valid and need to be handled correctly.

		if(pos.mpNode != &value)
		{
			// Unlink item from old list.
			intrusive_list_node& oldNext = *value.mpNext;
			intrusive_list_node& oldPrev = *value.mpPrev;
			oldNext.mpPrev = &oldPrev;
			oldPrev.mpNext = &oldNext;

			// Relink item into new list.
			intrusive_list_node& newNext = *const_cast<node_type*>(pos.mpNode);
			intrusive_list_node& newPrev = *newNext.mpPrev;

			newPrev.mpNext = &value;
			newNext.mpPrev = &value;
			value.mpPrev = &newPrev;
			value.mpNext = &newNext;
		}
	}


	template <typename T>
	void intrusive_list<T>::splice(const_iterator pos, intrusive_list& x)
	{
		// Note: &x == this is prohibited, so self-insertion is not a problem.
		if(x.mAnchor.mpNext != &x.mAnchor) // If the list 'x' isn't empty...
		{
			intrusive_list_node& next       = *const_cast<node_type*>(pos.mpNode);
			intrusive_list_node& prev       = *static_cast<node_type*>(next.mpPrev);
			intrusive_list_node& insertPrev = *static_cast<node_type*>(x.mAnchor.mpNext);
			intrusive_list_node& insertNext = *static_cast<node_type*>(x.mAnchor.mpPrev);

			prev.mpNext       = &insertPrev;
			insertPrev.mpPrev = &prev;
			insertNext.mpNext = &next;
			next.mpPrev       = &insertNext;
			x.mAnchor.mpPrev  = x.mAnchor.mpNext = &x.mAnchor;
		}
	}


	template <typename T>
	void intrusive_list<T>::splice(const_iterator pos, intrusive_list& /*x*/, const_iterator i)
	{
		// Note: &x == this is prohibited, so self-insertion is not a problem.

		// Note that splice(pos, x, pos) and splice(pos + 1, x, pos)
		// are valid and need to be handled correctly.

		// We don't need to check if the source list is empty, because 
		// this function expects a valid iterator from the source list,
		// and thus the list cannot be empty in such a situation.

		iterator ii(const_cast<node_type*>(i.mpNode)); // Make a temporary non-const version.

		if(pos != ii)
		{
			// Unlink item from old list.
			intrusive_list_node& oldNext = *ii.mpNode->mpNext;
			intrusive_list_node& oldPrev = *ii.mpNode->mpPrev;
			oldNext.mpPrev = &oldPrev;
			oldPrev.mpNext = &oldNext;

			// Relink item into new list.
			intrusive_list_node& newNext = *const_cast<node_type*>(pos.mpNode);
			intrusive_list_node& newPrev = *newNext.mpPrev;

			newPrev.mpNext = ii.mpNode;
			newNext.mpPrev = ii.mpNode;
			ii.mpNode->mpPrev = &newPrev;
			ii.mpNode->mpNext = &newNext;
		}
	}


	template <typename T>
	void intrusive_list<T>::splice(const_iterator pos, intrusive_list& /*x*/, const_iterator first, const_iterator last)
	{
		// Note: &x == this is prohibited, so self-insertion is not a problem.
		if(first != last)
		{
			intrusive_list_node& insertPrev = *const_cast<node_type*>(first.mpNode);
			intrusive_list_node& insertNext = *static_cast<node_type*>(last.mpNode->mpPrev);

			// remove from old list
			insertNext.mpNext->mpPrev = insertPrev.mpPrev;
			insertPrev.mpPrev->mpNext = insertNext.mpNext;

			// insert into this list
			intrusive_list_node& next = *const_cast<node_type*>(pos.mpNode);
			intrusive_list_node& prev = *static_cast<node_type*>(next.mpPrev);

			prev.mpNext       = &insertPrev;
			insertPrev.mpPrev = &prev;
			insertNext.mpNext = &next;
			next.mpPrev       = &insertNext;
		}
	}


	template <typename T>
	inline void intrusive_list<T>::remove(value_type& value)
	{
		intrusive_list_node& prev = *value.mpPrev;
		intrusive_list_node& next = *value.mpNext;
		prev.mpNext = &next;
		next.mpPrev = &prev;

		#if EASTL_VALIDATE_INTRUSIVE_LIST
			value.mpPrev = value.mpNext = NULL;
		#endif
	}


	template <typename T>
	void intrusive_list<T>::merge(this_type& x)
	{
		if(this != &x)
		{
			iterator       first(begin());
			iterator       firstX(x.begin());
			const iterator last(end());
			const iterator lastX(x.end());

			while((first != last) && (firstX != lastX))
			{
				if(*firstX < *first)
				{
					iterator next(firstX);

					splice(first, x, firstX, ++next);
					firstX = next;
				}
				else
					++first;
			}

			if(firstX != lastX)
				splice(last, x, firstX, lastX);
		}
	}


	template <typename T>
	template <typename Compare>
	void intrusive_list<T>::merge(this_type& x, Compare compare)
	{
		if(this != &x)
		{
			iterator       first(begin());
			iterator       firstX(x.begin());
			const iterator last(end());
			const iterator lastX(x.end());

			while((first != last) && (firstX != lastX))
			{
				if(compare(*firstX, *first))
				{
					iterator next(firstX);

					splice(first, x, firstX, ++next);
					firstX = next;
				}
				else
					++first;
			}

			if(firstX != lastX)
				splice(last, x, firstX, lastX);
		}
	}


	template <typename T>
	void intrusive_list<T>::unique()
	{
		iterator       first(begin());
		const iterator last(end());

		if(first != last)
		{
			iterator next(first);

			while(++next != last)
			{
				if(*first == *next)
					erase(next);
				else
					first = next;
				next = first;
			}
		}
	}


	template <typename T>
	template <typename BinaryPredicate>
	void intrusive_list<T>::unique(BinaryPredicate predicate)
	{
		iterator       first(begin());
		const iterator last(end());

		if(first != last)
		{
			iterator next(first);

			while(++next != last)
			{
				if(predicate(*first, *next))
					erase(next);
				else
					first = next;
				next = first;
			}
		}
	}


	///////////////////////////////////////////////////////////////////////
	// global operators
	///////////////////////////////////////////////////////////////////////

	template <typename T>
	bool operator==(const intrusive_list<T>& a, const intrusive_list<T>& b)
	{
		// If we store an mSize member for intrusive_list, we want to take advantage of it here.
		typename intrusive_list<T>::const_iterator ia   = a.begin();
		typename intrusive_list<T>::const_iterator ib   = b.begin();
		typename intrusive_list<T>::const_iterator enda = a.end();
		typename intrusive_list<T>::const_iterator endb = b.end();

		while((ia != enda) && (ib != endb) && (*ia == *ib))
		{
			++ia;
			++ib;
		}
		return (ia == enda) && (ib == endb);
	}
	
	template <typename T>
	void swap(intrusive_list<T>& a, intrusive_list<T>& b)
	{
		a.swap(b);
	}


} // namespace eastl


#endif // Header include guard















