Browse Source

Adding some list additions

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
9e23ae40a5
4 changed files with 390 additions and 198 deletions
  1. 1 1
      include/anki/util/Allocator.h
  2. 3 5
      include/anki/util/HashMap.h
  3. 291 94
      include/anki/util/List.h
  4. 95 98
      include/anki/util/List.inl.h

+ 1 - 1
include/anki/util/Allocator.h

@@ -34,7 +34,7 @@ namespace anki {
 template<typename T, typename TPool>
 template<typename T, typename TPool>
 class GenericPoolAllocator
 class GenericPoolAllocator
 {
 {
-	template<typename Y, typename TPool_>
+	template<typename, typename>
 	friend class GenericPoolAllocator;
 	friend class GenericPoolAllocator;
 
 
 public:
 public:

+ 3 - 5
include/anki/util/HashMap.h

@@ -55,12 +55,10 @@ template<typename TNodePointer, typename TValuePointer,
 	typename TValueReference>
 	typename TValueReference>
 class HashMapIterator
 class HashMapIterator
 {
 {
-	template<typename TKey, typename TValue, typename THasher,
-		typename TCompare>
+	template<typename, typename, typename, typename>
 	friend class HashMap;
 	friend class HashMap;
 
 
-	template<typename TKey, typename TValue, typename THasher,
-		typename TCompare>
+	template<typename, typename, typename, typename>
 	friend class HashMapAllocFree;
 	friend class HashMapAllocFree;
 
 
 public:
 public:
@@ -393,7 +391,7 @@ private:
 	}
 	}
 };
 };
 
 
-/// Hash map that doesn't do any allocations. To work the TValue nodes will
+/// Hash map that doesn't perform any allocations. To work the TValue nodes will
 /// have to inherit from HashMapAllocFree.
 /// have to inherit from HashMapAllocFree.
 template<typename TKey, typename TValue, typename THasher, typename TCompare>
 template<typename TKey, typename TValue, typename THasher, typename TCompare>
 class HashMapAllocFree: public detail::HashMapBase<TKey, TValue, THasher,
 class HashMapAllocFree: public detail::HashMapBase<TKey, TValue, THasher,

+ 291 - 94
include/anki/util/List.h

@@ -14,16 +14,17 @@ namespace anki {
 template<typename T>
 template<typename T>
 class List;
 class List;
 
 
-/// @addtogroup util_private
+/// @addtogroup util_containers
 /// @{
 /// @{
 
 
+namespace detail {
+
 /// List node.
 /// List node.
+/// @internal
 template<typename T>
 template<typename T>
 class ListNode
 class ListNode
 {
 {
 public:
 public:
-	using Value = T;
-
 	T m_value;
 	T m_value;
 	ListNode* m_prev = nullptr;
 	ListNode* m_prev = nullptr;
 	ListNode* m_next = nullptr;
 	ListNode* m_next = nullptr;
@@ -32,17 +33,34 @@ public:
 	ListNode(TArgs&&... args)
 	ListNode(TArgs&&... args)
 		: m_value(std::forward<TArgs>(args)...)
 		: m_value(std::forward<TArgs>(args)...)
 	{}
 	{}
+
+	T& getValue()
+	{
+		return m_value;
+	}
+
+	const T& getValue() const
+	{
+		return m_value;
+	}
 };
 };
 
 
 /// List bidirectional iterator.
 /// List bidirectional iterator.
+/// @internal
 template<typename TNodePointer, typename TValuePointer,
 template<typename TNodePointer, typename TValuePointer,
 	typename TValueReference, typename TListPointer>
 	typename TValueReference, typename TListPointer>
 class ListIterator
 class ListIterator
 {
 {
-public:
-	TNodePointer m_node = nullptr;
-	TListPointer m_list = nullptr; ///< Used to go back from the end
+	template<typename, typename>
+	friend class ListBase;
+
+	template<typename>
+	friend class List;
+
+	template<typename, typename, typename, typename>
+	friend class ListIterator;
 
 
+public:
 	ListIterator() = default;
 	ListIterator() = default;
 
 
 	ListIterator(const ListIterator& b)
 	ListIterator(const ListIterator& b)
@@ -69,13 +87,13 @@ public:
 	TValueReference operator*() const
 	TValueReference operator*() const
 	{
 	{
 		ANKI_ASSERT(m_node);
 		ANKI_ASSERT(m_node);
-		return m_node->m_value;
+		return m_node->getValue();
 	}
 	}
 
 
 	TValuePointer operator->() const
 	TValuePointer operator->() const
 	{
 	{
 		ANKI_ASSERT(m_node);
 		ANKI_ASSERT(m_node);
-		return &m_node->m_value;
+		return &m_node->getValue();
 	}
 	}
 
 
 	ListIterator& operator++()
 	ListIterator& operator++()
@@ -152,87 +170,61 @@ public:
 	{
 	{
 		return !(*this == b);
 		return !(*this == b);
 	}
 	}
-};
-/// @}
 
 
-/// @addtogroup util_containers
-/// @{
+private:
+	TNodePointer m_node = nullptr;
+	TListPointer m_list = nullptr; ///< Used to go back from the end
+};
 
 
-/// Double linked list.
-template<typename T>
-class List: public NonCopyable
+/// Double linked list base.
+/// @internal
+template<typename T, typename TNode>
+class ListBase: public NonCopyable
 {
 {
-	template<typename TNodePointer, typename TValuePointer,
-		typename TValueReference, typename TListPointer>
+	template<typename, typename, typename, typename>
 	friend class ListIterator;
 	friend class ListIterator;
 
 
 public:
 public:
 	using Value = T;
 	using Value = T;
-	using Node = ListNode<Value>;
 	using Reference = Value&;
 	using Reference = Value&;
 	using ConstReference = const Value&;
 	using ConstReference = const Value&;
 	using Pointer = Value*;
 	using Pointer = Value*;
 	using ConstPointer = const Value*;
 	using ConstPointer = const Value*;
-	using Iterator = ListIterator<Node*, Pointer, Reference, List*>;
-	using ConstIterator =
-		ListIterator<const Node*, ConstPointer, ConstReference, const List*>;
-
-	List() = default;
-
-	/// Move.
-	List(List&& b)
-		: List()
-	{
-		move(b);
-	}
+	using Iterator = ListIterator<TNode*, Pointer, Reference, ListBase*>;
+	using ConstIterator = ListIterator<const TNode*, ConstPointer,
+		ConstReference, const ListBase*>;
 
 
-	/// You need to manually destroy the list.
-	/// @see List::destroy
-	~List()
-	{
-		ANKI_ASSERT(m_head == nullptr && "Requires manual destruction");
-	}
-
-	/// Move.
-	List& operator=(List&& b)
-	{
-		move(b);
-		return *this;
-	}
+	ListBase() = default;
 
 
 	/// Compare with another list.
 	/// Compare with another list.
-	Bool operator==(const List& b) const;
-
-	/// Destroy the list.
-	template<typename TAllocator>
-	void destroy(TAllocator alloc);
+	Bool operator==(const ListBase& b) const;
 
 
 	/// Get first element.
 	/// Get first element.
 	ConstReference getFront() const
 	ConstReference getFront() const
 	{
 	{
 		ANKI_ASSERT(!isEmpty());
 		ANKI_ASSERT(!isEmpty());
-		return m_head->m_value;
+		return m_head->getValue();
 	}
 	}
 
 
 	/// Get first element.
 	/// Get first element.
 	Reference getFront()
 	Reference getFront()
 	{
 	{
 		ANKI_ASSERT(!isEmpty());
 		ANKI_ASSERT(!isEmpty());
-		return m_head->m_value;
+		return m_head->getValue();
 	}
 	}
 
 
 	/// Get last element.
 	/// Get last element.
 	ConstReference getBack() const
 	ConstReference getBack() const
 	{
 	{
 		ANKI_ASSERT(!isEmpty());
 		ANKI_ASSERT(!isEmpty());
-		return m_tail->m_value;
+		return m_tail->getValue();
 	}
 	}
 
 
 	/// Get last element.
 	/// Get last element.
 	Reference getBack()
 	Reference getBack()
 	{
 	{
 		ANKI_ASSERT(!isEmpty());
 		ANKI_ASSERT(!isEmpty());
-		return m_tail->m_value;
+		return m_tail->getValue();
 	}
 	}
 
 
 	/// Get begin.
 	/// Get begin.
@@ -289,12 +281,97 @@ public:
 		return m_head == nullptr;
 		return m_head == nullptr;
 	}
 	}
 
 
+	/// Iterate the list using lambda.
+	template<typename TFunc>
+	ANKI_USE_RESULT Error iterateForward(TFunc func);
+
+	/// Iterate the list backwards using lambda.
+	template<typename TFunc>
+	ANKI_USE_RESULT Error iterateBackward(TFunc func);
+
+	/// Find item.
+	Iterator find(const Value& a);
+
+	/// Sort the list.
+	/// @note It's almost 300 slower than std::list::sort, at some point replace
+	///       the algorithm.
+	template<typename TCompFunc = std::less<Value>>
+	void sort(TCompFunc compFunc = TCompFunc());
+
+	/// Compute the size of elements in the list.
+	PtrSize getSize() const;
+
+protected:
+	TNode* m_head = nullptr;
+	TNode* m_tail = nullptr;
+
+	void move(ListBase& b)
+	{
+		m_head = b.m_head;
+		b.m_head = nullptr;
+		m_tail = b.m_tail;
+		b.m_tail = nullptr;
+	}
+
+	void pushBackNode(TNode* node);
+	void pushFrontNode(TNode* node);
+	void insertNode(TNode* pos, TNode* node);
+	void removeNode(TNode* node);
+	void popBack();
+	void popFront();
+
+private:
+	/// Used in sort.
+	TNode* swap(TNode* one, TNode* two);
+};
+
+} // end namespace detail
+
+/// Double linked list.
+template<typename T>
+class List: public detail::ListBase<T, detail::ListNode<T>>
+{
+private:
+	using Base = detail::ListBase<T, detail::ListNode<T>>;
+	using Node = detail::ListNode<T>;
+
+public:
+	/// Default constructor.
+	List()
+		: Base()
+	{}
+
+	/// Move.
+	List(List&& b)
+		: List()
+	{
+		move(b);
+	}
+
+	/// You need to manually destroy the list.
+	/// @see List::destroy
+	~List()
+	{
+		ANKI_ASSERT(!Base::isCreated() && "Requires manual destruction");
+	}
+
+	/// Move.
+	List& operator=(List&& b)
+	{
+		move(b);
+		return *this;
+	}
+
+	/// Destroy the list.
+	template<typename TAllocator>
+	void destroy(TAllocator alloc);
+
 	/// Copy an element at the end of the list.
 	/// Copy an element at the end of the list.
 	template<typename TAllocator>
 	template<typename TAllocator>
-	void pushBack(TAllocator alloc, const Value& x)
+	void pushBack(TAllocator alloc, const T& x)
 	{
 	{
 		Node* node = alloc.template newInstance<Node>(x);
 		Node* node = alloc.template newInstance<Node>(x);
-		pushBackNode(node);
+		Base::pushBackNode(node);
 	}
 	}
 
 
 	/// Construct an element at the end of the list.
 	/// Construct an element at the end of the list.
@@ -303,66 +380,79 @@ public:
 	{
 	{
 		Node* node = alloc.template newInstance<Node>(
 		Node* node = alloc.template newInstance<Node>(
 			std::forward<TArgs>(args)...);
 			std::forward<TArgs>(args)...);
-		pushBackNode(node);
+		Base::pushBackNode(node);
+	}
+
+	/// Copy an element at the beginning of the list.
+	template<typename TAllocator>
+	void pushFront(TAllocator alloc, const T& x)
+	{
+		Node* node = alloc.template newInstance<Node>(x);
+		Base::pushFrontNode(node);
 	}
 	}
 
 
 	/// Construct element at the beginning of the list.
 	/// Construct element at the beginning of the list.
 	template<typename TAllocator, typename... TArgs>
 	template<typename TAllocator, typename... TArgs>
-	void emplaceFront(TAllocator alloc, TArgs&&... args);
+	void emplaceFront(TAllocator alloc, TArgs&&... args)
+	{
+		Node* node = alloc.template newInstance<Node>(
+			std::forward<TArgs>(args)...);
+		Base::pushFrontNode(node);
+	}
+
+	/// Copy an element at the given position of the list.
+	template<typename TAllocator>
+	void insert(TAllocator alloc, typename Base::Iterator pos, const T& x)
+	{
+		Node* node = alloc.template newInstance<Node>(x);
+		Base::insertNode(pos.m_node, node);
+	}
 
 
 	/// Construct element at the the given position.
 	/// Construct element at the the given position.
 	template<typename TAllocator, typename... TArgs>
 	template<typename TAllocator, typename... TArgs>
-	void emplace(TAllocator alloc, Iterator pos, TArgs&&... args);
+	void emplace(TAllocator alloc, typename Base::Iterator pos, TArgs&&... args)
+	{
+		Node* node = alloc.template newInstance<Node>(
+			std::forward<TArgs>(args)...);
+		Base::insertNode(pos.m_node, node);
+	}
 
 
 	/// Pop a value from the back of the list.
 	/// Pop a value from the back of the list.
 	template<typename TAllocator>
 	template<typename TAllocator>
-	void popBack(TAllocator alloc);
+	void popBack(TAllocator alloc)
+	{
+		ANKI_ASSERT(Base::m_tail);
+		Node* node = Base::m_tail;
+		Base::popBack();
+		alloc.deleteInstance(node);
+	}
 
 
 	/// Pop a value from the front of the list.
 	/// Pop a value from the front of the list.
 	template<typename TAllocator>
 	template<typename TAllocator>
-	void popFront(TAllocator alloc);
+	void popFront(TAllocator alloc)
+	{
+		ANKI_ASSERT(Base::m_head);
+		Node* node = Base::m_head;
+		Base::popFront();
+		alloc.deleteInstance(node);
+	}
 
 
 	/// Erase an element.
 	/// Erase an element.
 	template<typename TAllocator>
 	template<typename TAllocator>
-	void erase(TAllocator alloc, Iterator position);
-
-	/// Iterate the list using lambda.
-	template<typename TFunc>
-	ANKI_USE_RESULT Error iterateForward(TFunc func);
-
-	/// Iterate the list backwards using lambda.
-	template<typename TFunc>
-	ANKI_USE_RESULT Error iterateBackward(TFunc func);
-
-	/// Find item.
-	Iterator find(const Value& a);
-
-	/// Sort the list.
-	/// @note It's almost 300 slower than std::list::sort, at some point replace
-	///       the algorithm.
-	template<typename TCompFunc = std::less<Value>>
-	void sort(TCompFunc compFunc = TCompFunc());
-
-	/// Compute the size of elements in the list.
-	PtrSize getSize() const;
-
-protected:
-	Node* m_head = nullptr;
-	Node* m_tail = nullptr;
+	void erase(TAllocator alloc, typename Base::Iterator pos)
+	{
+		ANKI_ASSERT(pos.m_node);
+		ANKI_ASSERT(pos.m_list == this);
+		Base::removeNode(pos.m_node);
+		alloc.deleteInstance(pos.m_node);
+	}
 
 
+private:
 	void move(List& b)
 	void move(List& b)
 	{
 	{
-		ANKI_ASSERT(isEmpty() && "Cannot move before destroying");
-		m_head = b.m_head;
-		b.m_head = nullptr;
-		m_tail = b.m_tail;
-		b.m_tail = nullptr;
+		ANKI_ASSERT(!Base::isCreated() && "Requires manual destruction");
+		Base::move(b);
 	}
 	}
-
-	/// Used in sort.
-	Node* swap(Node* one, Node* two);
-
-	void pushBackNode(Node* node);
 };
 };
 
 
 /// List with automatic destruction.
 /// List with automatic destruction.
@@ -454,6 +544,113 @@ private:
 		m_alloc = b.m_alloc;
 		m_alloc = b.m_alloc;
 	}
 	}
 };
 };
+
+/// The classes that will use the ListAllocFree need to inherit from this
+/// one.
+template<typename TClass>
+class ListAllocFreeEnabled
+{
+	template<typename, typename, typename, typename>
+	friend class ListIterator;
+
+	template<typename, typename>
+	friend class ListBase;
+
+	template<typename>
+	friend class List;
+
+	template<typename>
+	friend class ListAllocFree;
+
+private:
+	TClass* m_left;
+	TClass* m_right;
+
+	ListAllocFreeEnabled()
+		: m_left(nullptr)
+		, m_right(nullptr)
+	{}
+
+	TClass& getValue()
+	{
+		return *static_cast<TClass*>(this);
+	}
+
+	const TClass& getValue() const
+	{
+		return *static_cast<const TClass*>(this);
+	}
+};
+
+/// List that doesn't perform any allocations. To work the T nodes will
+/// have to inherit from ListAllocFree.
+template<typename T>
+class ListAllocFree: public detail::ListBase<T, T>
+{
+	template<typename, typename, typename, typename>
+	friend class detail::ListIterator;
+
+private:
+	using Base = detail::ListBase<T, T>;
+
+public:
+	/// Default constructor.
+	ListAllocFree()
+		: Base()
+	{}
+
+	/// Move.
+	ListAllocFree(ListAllocFree&& b)
+		: ListAllocFree()
+	{
+		Base::move(b);
+	}
+
+	~ListAllocFree() = default;
+
+	/// Move.
+	ListAllocFree& operator=(ListAllocFree&& b)
+	{
+		Base::move(b);
+		return *this;
+	}
+
+	/// Copy an element at the end of the list.
+	void pushBack(T* x)
+	{
+		Base::pushBackNode(x);
+	}
+
+	/// Copy an element at the beginning of the list.
+	void pushFront(T* x)
+	{
+		Base::pushFrontNode(x);
+	}
+
+	/// Copy an element at the given position of the list.
+	void insert(typename Base::Iterator pos, T* x)
+	{
+		Base::insertNode(pos.m_node, x);
+	}
+
+	/// Pop a value from the back of the list.
+	void popBack()
+	{
+		Base::popBack();
+	}
+
+	/// Pop a value from the front of the list.
+	void popFront()
+	{
+		Base::popFront();
+	}
+
+	/// Erase an element.
+	void erase(typename Base::Iterator pos)
+	{
+		Base::removeNode(pos.m_node);
+	}
+};
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 95 - 98
include/anki/util/List.inl.h

@@ -4,15 +4,16 @@
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
 namespace anki {
 namespace anki {
+namespace detail {
 
 
 //==============================================================================
 //==============================================================================
 // ListIterator                                                                =
 // ListIterator                                                                =
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-template<typename TNodePointer, typename TValuePointer, 
+template<typename TNodePointer, typename TValuePointer,
 	typename TValueReference, typename TList>
 	typename TValueReference, typename TList>
-ListIterator<TNodePointer, TValuePointer, TValueReference, TList>& 
+ListIterator<TNodePointer, TValuePointer, TValueReference, TList>&
 	ListIterator<TNodePointer, TValuePointer, TValueReference, TList>::
 	ListIterator<TNodePointer, TValuePointer, TValueReference, TList>::
 	operator--()
 	operator--()
 {
 {
@@ -31,12 +32,12 @@ ListIterator<TNodePointer, TValuePointer, TValueReference, TList>&
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-// List                                                                        =
+// ListBase                                                                    =
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-template<typename T>
-Bool List<T>::operator==(const List& b) const
+template<typename T, typename TNode>
+Bool ListBase<T, TNode>::operator==(const ListBase& b) const
 {
 {
 	Bool same = true;
 	Bool same = true;
 	ConstIterator ita = getBegin();
 	ConstIterator ita = getBegin();
@@ -58,8 +59,8 @@ Bool List<T>::operator==(const List& b) const
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-template<typename T>
-void List<T>::pushBackNode(Node* node)
+template<typename T, typename TNode>
+void ListBase<T, TNode>::pushBackNode(TNode* node)
 {
 {
 	ANKI_ASSERT(node);
 	ANKI_ASSERT(node);
 
 
@@ -78,121 +79,101 @@ void List<T>::pushBackNode(Node* node)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-template<typename T>
-template<typename TAllocator, typename... TArgs>
-void List<T>::emplaceFront(TAllocator alloc, TArgs&&... args)
+template<typename T, typename TNode>
+void ListBase<T, TNode>::pushFrontNode(TNode* node)
 {
 {
-	Node* el = alloc.template newInstance<Node>(std::forward<TArgs>(args)...);
+	ANKI_ASSERT(node);
+
 	if(m_head != nullptr)
 	if(m_head != nullptr)
 	{
 	{
 		ANKI_ASSERT(m_tail != nullptr);
 		ANKI_ASSERT(m_tail != nullptr);
-		m_head->m_prev = el;
-		el->m_next = m_head;
-		m_head = el;
+		m_head->m_prev = node;
+		node->m_next = m_head;
+		m_head = node;
 	}
 	}
 	else
 	else
 	{
 	{
 		ANKI_ASSERT(m_tail == nullptr);
 		ANKI_ASSERT(m_tail == nullptr);
-		m_tail = m_head = el;
+		m_tail = m_head = node;
 	}
 	}
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-template<typename T>
-template<typename TAllocator, typename... TArgs>
-void List<T>::emplace(TAllocator alloc, Iterator pos, TArgs&&... args)
+template<typename T, typename TNode>
+void ListBase<T, TNode>::insertNode(TNode* pos, TNode* node)
 {
 {
-	ANKI_ASSERT(pos.m_list == this);
-
-	Node* el = alloc.template newInstance<Node>(std::forward<TArgs>(args)...);
-	Node* node = pos.m_node;
+	ANKI_ASSERT(node);
 
 
-	if(node == nullptr)
+	if(pos == nullptr)
 	{
 	{
 		// Place after the last
 		// Place after the last
 
 
 		if(m_tail != nullptr)
 		if(m_tail != nullptr)
 		{
 		{
 			ANKI_ASSERT(m_head != nullptr);
 			ANKI_ASSERT(m_head != nullptr);
-			m_tail->m_next = el;
-			el->m_prev = m_tail;
-			m_tail = el;
+			m_tail->m_next = node;
+			node->m_prev = m_tail;
+			m_tail = node;
 		}
 		}
 		else
 		else
 		{
 		{
 			ANKI_ASSERT(m_head == nullptr);
 			ANKI_ASSERT(m_head == nullptr);
-			m_tail = m_head = el;
+			m_tail = m_head = node;
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
-		el->m_prev = node->m_prev;
-		el->m_next = node;
-		node->m_prev = el;
+		node->m_prev = pos->m_prev;
+		node->m_next = pos;
+		pos->m_prev = node;
 
 
-		if(node == m_head)
+		if(pos == m_head)
 		{
 		{
 			ANKI_ASSERT(m_tail != nullptr);
 			ANKI_ASSERT(m_tail != nullptr);
-			m_head = el;
+			m_head = node;
 		}
 		}
 	}
 	}
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-template<typename T>
-template<typename TAllocator>
-void List<T>::destroy(TAllocator alloc)
-{
-	Node* el = m_head;
-	while(el)
-	{
-		Node* next = el->m_next;
-		alloc.deleteInstance(el);
-		el = next;
-	}
-
-	m_head = m_tail = nullptr;
-}
-
-//==============================================================================
-template<typename T>
+template<typename T, typename TNode>
 template<typename TFunc>
 template<typename TFunc>
-Error List<T>::iterateForward(TFunc func)
+Error ListBase<T, TNode>::iterateForward(TFunc func)
 {
 {
 	Error err = ErrorCode::NONE;
 	Error err = ErrorCode::NONE;
-	Node* el = m_head;
-	while(el && !err)
+	TNode* node = m_head;
+	while(node && !err)
 	{
 	{
-		err = func(el->m_value);
-		el = el->m_next;
+		err = func(node->getValue());
+		node = node->m_next;
 	}
 	}
 
 
 	return err;
 	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-template<typename T>
+template<typename T, typename TNode>
 template<typename TFunc>
 template<typename TFunc>
-Error List<T>::iterateBackward(TFunc func)
+Error ListBase<T, TNode>::iterateBackward(TFunc func)
 {
 {
 	Error err = ErrorCode::NONE;
 	Error err = ErrorCode::NONE;
-	Node* el = m_tail;
-	while(el && !err)
+	TNode* node = m_tail;
+	while(node && !err)
 	{
 	{
-		err = func(el->m_value);
-		el = el->m_prev;
+		err = func(node->getValue());
+		node = node->m_prev;
 	}
 	}
 
 
 	return err;
 	return err;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-template<typename T>
+template<typename T, typename TNode>
 template<typename TCompFunc>
 template<typename TCompFunc>
-void List<T>::sort(TCompFunc compFunc)
+void ListBase<T, TNode>::sort(TCompFunc compFunc)
 {
 {
-	Node* sortPtr;
-	Node* newTail = m_tail;
+	TNode* sortPtr;
+	TNode* newTail = m_tail;
 
 
 	while(newTail != m_head)
 	while(newTail != m_head)
 	{
 	{
@@ -203,10 +184,10 @@ void List<T>::sort(TCompFunc compFunc)
 		do
 		do
 		{
 		{
 			ANKI_ASSERT(sortPtr != nullptr);
 			ANKI_ASSERT(sortPtr != nullptr);
-			Node* sortPtrNext = sortPtr->m_next;
+			TNode* sortPtrNext = sortPtr->m_next;
 			ANKI_ASSERT(sortPtrNext != nullptr);
 			ANKI_ASSERT(sortPtrNext != nullptr);
 
 
-			if(compFunc(sortPtrNext->m_value, sortPtr->m_value))
+			if(compFunc(sortPtrNext->getValue(), sortPtr->getValue()))
 			{
 			{
 				sortPtr = swap(sortPtr, sortPtrNext);
 				sortPtr = swap(sortPtr, sortPtrNext);
 				swapped = true;
 				swapped = true;
@@ -234,8 +215,8 @@ void List<T>::sort(TCompFunc compFunc)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-template<typename T>
-typename List<T>::Node* List<T>::swap(Node* one, Node* two)
+template<typename T, typename TNode>
+TNode* ListBase<T, TNode>::swap(TNode* one, TNode* two)
 {
 {
 	if(one->m_prev == nullptr)
 	if(one->m_prev == nullptr)
 	{
 	{
@@ -266,15 +247,11 @@ typename List<T>::Node* List<T>::swap(Node* one, Node* two)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-template<typename T>
-template<typename TAllocator>
-void List<T>::erase(TAllocator alloc, Iterator pos)
+template<typename T, typename TNode>
+void ListBase<T, TNode>::removeNode(TNode* node)
 {
 {
-	ANKI_ASSERT(pos.m_node);
-	ANKI_ASSERT(pos.m_list == this);
+	ANKI_ASSERT(node);
 
 
-	Node* node = pos.m_node;
-	
 	if(node == m_tail)
 	if(node == m_tail)
 	{
 	{
 		m_tail = node->m_prev;
 		m_tail = node->m_prev;
@@ -297,30 +274,12 @@ void List<T>::erase(TAllocator alloc, Iterator pos)
 		node->m_next->m_prev = node->m_prev;
 		node->m_next->m_prev = node->m_prev;
 	}
 	}
 
 
-	alloc.deleteInstance(node);
+	node->m_next = node->m_prev = nullptr;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-template<typename T>
-template<typename TAllocator>
-void List<T>::popBack(TAllocator alloc)
-{
-	ANKI_ASSERT(m_tail);
-	erase(alloc, Iterator(m_tail, this));
-}
-
-//==============================================================================
-template<typename T>
-template<typename TAllocator>
-void List<T>::popFront(TAllocator alloc)
-{
-	ANKI_ASSERT(m_tail);
-	erase(alloc, Iterator(m_head, this));
-}
-
-//==============================================================================
-template<typename T>
-typename List<T>::Iterator List<T>::find(const Value& a)
+template<typename T, typename TNode>
+typename ListBase<T, TNode>::Iterator ListBase<T, TNode>::find(const Value& a)
 {
 {
 	Iterator it = getBegin();
 	Iterator it = getBegin();
 	Iterator endit = getEnd();
 	Iterator endit = getEnd();
@@ -338,8 +297,8 @@ typename List<T>::Iterator List<T>::find(const Value& a)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-template<typename T>
-PtrSize List<T>::getSize() const
+template<typename T, typename TNode>
+PtrSize ListBase<T, TNode>::getSize() const
 {
 {
 	PtrSize size = 0;
 	PtrSize size = 0;
 	ConstIterator it = getBegin();
 	ConstIterator it = getBegin();
@@ -352,5 +311,43 @@ PtrSize List<T>::getSize() const
 	return size;
 	return size;
 }
 }
 
 
+//==============================================================================
+template<typename T, typename TNode>
+void ListBase<T, TNode>::popBack()
+{
+	ANKI_ASSERT(m_tail);
+	removeNode(m_tail);
+}
+
+//==============================================================================
+template<typename T, typename TNode>
+void ListBase<T, TNode>::popFront()
+{
+	ANKI_ASSERT(m_head);
+	removeNode(m_head);
+}
+
+} // end namespace detail
+
+//==============================================================================
+// List                                                                        =
+//==============================================================================
+
+//==============================================================================
+template<typename T>
+template<typename TAllocator>
+void List<T>::destroy(TAllocator alloc)
+{
+	Node* el = Base::m_head;
+	while(el)
+	{
+		Node* next = el->m_next;
+		alloc.deleteInstance(el);
+		el = next;
+	}
+
+	Base::m_head = Base::m_tail = nullptr;
+}
+
 } // end namespace anki
 } // end namespace anki