Browse Source

Removing exceptions

Panagiotis Christopoulos Charitos 11 years ago
parent
commit
25816f4bcf
3 changed files with 388 additions and 22 deletions
  1. 198 18
      include/anki/util/List.h
  2. 116 4
      include/anki/util/List.inl.h
  3. 74 0
      tests/util/List.cpp

+ 198 - 18
include/anki/util/List.h

@@ -11,6 +11,150 @@
 
 
 namespace anki {
 namespace anki {
 
 
+// Forward
+template<typename T, typename TAlloc>
+class List;
+
+/// @addtogroup util_private
+/// @{
+
+/// List node.
+template<typename T>
+class ListNode
+{
+public:
+	using Value = T;
+
+	T m_value;
+	ListNode* m_prev = nullptr;
+	ListNode* m_next = nullptr;
+
+	template<typename... TArgs>
+	ListNode(TArgs&&... args)
+	:	m_value(std::forward<TArgs>(args)...)
+	{}
+};
+
+/// List bidirectional iterator.
+template<typename TNodePointer, typename TValuePointer, 
+	typename TValueReference, typename TList>
+class ListIterator
+{
+public:
+	TNodePointer m_node = nullptr;
+	TList* m_list = nullptr; ///< Used to go back from the end
+
+	ListIterator() = default;
+
+	ListIterator(const ListIterator& b)
+	:	m_node(b.m_node),
+		m_list(b.m_list)
+	{}
+
+	/// Allow conversion from iterator to const iterator.
+	template<typename YNodePointer, typename YValuePointer, 
+		typename YValueReference, typename YList>
+	ListIterator(const ListIterator<YNodePointer, 
+		YValuePointer, YValueReference, YList>& b)
+	:	m_node(b.m_node),
+		m_list(b.m_list)
+	{}
+
+	ListIterator(TNodePointer node, TList* list)
+	:	m_node(node),
+		m_list(list)
+	{
+		ANKI_ASSERT(list);
+	}
+
+	TValueReference operator*() const
+	{
+		ANKI_ASSERT(m_node);
+		return m_node->m_value;
+	}
+
+	TValuePointer operator->() const
+	{
+		ANKI_ASSERT(m_node);
+		return &m_node->m_value;
+	}
+
+	ListIterator& operator++()
+	{
+		ANKI_ASSERT(m_node);
+		m_node = m_node->m_next;
+		return *this;
+	}
+
+	ListIterator operator++(int)
+	{
+		ANKI_ASSERT(m_node);
+		ListIterator out = *this;
+		++(*this);
+		return out;
+	}
+
+	ListIterator& operator--();
+
+	ListIterator operator--(int)
+	{
+		ANKI_ASSERT(m_node);
+		ListIterator out = *this;
+		--(*this);
+		return out;
+	}
+
+	ListIterator operator+(U n) const
+	{
+		ListIterator it = *this;
+		while(n-- != 0)
+		{
+			++it;
+		}
+		return it;
+	}
+
+	ListIterator operator-(U n) const
+	{
+		ListIterator it = *this;
+		while(n-- != 0)
+		{
+			--it;
+		}
+		return it;
+	}
+
+	ListIterator& operator+=(U n)
+	{
+		while(n-- != 0)
+		{
+			++(*this);
+		}
+		return *this;
+	}
+
+	ListIterator& operator-=(U n)
+	{
+		while(n-- != 0)
+		{
+			--(*this);
+		}
+		return *this;
+	}
+
+	Bool operator==(const ListIterator& b) const
+	{
+		return m_node == b.m_node && m_list == b.m_list;
+	}
+
+	Bool operator!=(const ListIterator& b) const
+	{
+		return !(*this == b);
+	}
+};
+
+/// @}
+
 /// @addtogroup util_containers
 /// @addtogroup util_containers
 /// @{
 /// @{
 
 
@@ -18,11 +162,21 @@ namespace anki {
 template<typename T, typename TAlloc = HeapAllocator<T>>
 template<typename T, typename TAlloc = HeapAllocator<T>>
 class List: public NonCopyable
 class List: public NonCopyable
 {
 {
+	template<typename TNodePointer, typename TValuePointer, 
+		typename TValueReference, typename TList>
+	friend class ListIterator;
+
 public:
 public:
 	using Value = T;
 	using Value = T;
 	using Allocator = TAlloc;
 	using Allocator = TAlloc;
+	using Node = ListNode<Value>;
 	using Reference = Value&;
 	using Reference = Value&;
 	using ConstReference = const Value&;
 	using ConstReference = const Value&;
+	using Pointer = Value*;
+	using ConstPointer = const Value*;
+	using Iterator = ListIterator<Node*, Pointer, Reference, List>;
+	using ConstIterator = 
+		ListIterator<const Node*, ConstPointer, ConstReference, List>;
 
 
 	List() = default;
 	List() = default;
 
 
@@ -33,6 +187,8 @@ public:
 		move(b);
 		move(b);
 	}
 	}
 
 
+	/// You need to manually destroy the list.
+	/// @see List::destroy
 	~List()
 	~List()
 	{
 	{
 		ANKI_ASSERT(m_head == nullptr && "Requires manual destruction");
 		ANKI_ASSERT(m_head == nullptr && "Requires manual destruction");
@@ -76,12 +232,54 @@ public:
 		return m_tail->m_value;
 		return m_tail->m_value;
 	}
 	}
 
 
+	/// Get begin.
+	Iterator getBegin()
+	{
+		return Iterator(m_head, this);
+	}
+
+	/// Get begin.
+	ConstIterator getBegin() const
+	{
+		return ConstIterator(m_head, this);
+	}
+
+	/// Get end.
+	Iterator getEnd()
+	{
+		Iterator it(nullptr, this);
+		return it;
+	}
+
+	/// Get end.
+	ConstIterator getEnd() const
+	{
+		ConstIterator it(nullptr, this);
+		return it;
+	}
+
+	/// Return true if list is empty.
+	Bool isEmpty() const
+	{
+		return m_head == nullptr;
+	}
+
+	/// Construct element at the end of the list.
 	template<typename... TArgs>
 	template<typename... TArgs>
 	ANKI_USE_RESULT Error emplaceBack(Allocator alloc, TArgs&&... args);
 	ANKI_USE_RESULT Error emplaceBack(Allocator alloc, TArgs&&... args);
 
 
+	/// Construct element at the beginning of the list.
 	template<typename... TArgs>
 	template<typename... TArgs>
 	ANKI_USE_RESULT Error emplaceFront(Allocator alloc, TArgs&&... args);
 	ANKI_USE_RESULT Error emplaceFront(Allocator alloc, TArgs&&... args);
 
 
+	/// Construct element at the the given position.
+	template<typename... TArgs>
+	ANKI_USE_RESULT Error emplace(
+		Allocator alloc, Iterator pos, TArgs&&... args);
+
+	/// Erase an element.
+	void erase(Allocator alloc, Iterator position);
+
 	/// Iterate the list using lambda.
 	/// Iterate the list using lambda.
 	template<typename TFunc>
 	template<typename TFunc>
 	ANKI_USE_RESULT Error iterateForward(TFunc func);
 	ANKI_USE_RESULT Error iterateForward(TFunc func);
@@ -90,29 +288,11 @@ public:
 	template<typename TFunc>
 	template<typename TFunc>
 	ANKI_USE_RESULT Error iterateBackward(TFunc func);
 	ANKI_USE_RESULT Error iterateBackward(TFunc func);
 
 
-	Bool isEmpty() const
-	{
-		return m_head == nullptr;
-	}
-
 	/// Quicksort.
 	/// Quicksort.
 	template<typename TCompFunc = std::less<Value>>
 	template<typename TCompFunc = std::less<Value>>
 	void sort(TCompFunc compFunc = TCompFunc());
 	void sort(TCompFunc compFunc = TCompFunc());
 
 
 private:
 private:
-	class Node
-	{
-	public:
-		Value m_value;
-		Node* m_prev = nullptr;
-		Node* m_next = nullptr;
-
-		template<typename... TArgs>
-		Node(TArgs&&... args)
-		:	m_value(std::forward<TArgs>(args)...)
-		{}
-	};
-
 	Node* m_head = nullptr;
 	Node* m_head = nullptr;
 	Node* m_tail = nullptr;
 	Node* m_tail = nullptr;
 
 

+ 116 - 4
include/anki/util/List.inl.h

@@ -5,6 +5,35 @@
 
 
 namespace anki {
 namespace anki {
 
 
+//==============================================================================
+// ListIterator                                                                =
+//==============================================================================
+
+//==============================================================================
+template<typename TNodePointer, typename TValuePointer, 
+	typename TValueReference, typename TList>
+ListIterator<TNodePointer, TValuePointer, TValueReference, TList>& 
+	ListIterator<TNodePointer, TValuePointer, TValueReference, TList>::
+	operator--()
+{
+	ANKI_ASSERT(m_list);
+
+	if(m_node)
+	{
+		m_node = m_node->m_prev;
+	}
+	else
+	{
+		m_node = m_list->m_tail;
+	}
+
+	return *this;
+}
+
+//==============================================================================
+// List                                                                        =
+//==============================================================================
+
 //==============================================================================
 //==============================================================================
 template<typename T, typename TAlloc>
 template<typename T, typename TAlloc>
 template<typename... TArgs>
 template<typename... TArgs>
@@ -12,8 +41,7 @@ Error List<T, TAlloc>::emplaceBack(Allocator alloc, TArgs&&... args)
 {
 {
 	Error err = ErrorCode::NONE;
 	Error err = ErrorCode::NONE;
 	
 	
-	Node* el = alloc.template newInstance<Node>(
-		std::forward<TArgs>(args)...);
+	Node* el = alloc.template newInstance<Node>(std::forward<TArgs>(args)...);
 	if(el != nullptr)
 	if(el != nullptr)
 	{
 	{
 		if(m_tail != nullptr)
 		if(m_tail != nullptr)
@@ -44,8 +72,7 @@ Error List<T, TAlloc>::emplaceFront(Allocator alloc, TArgs&&... args)
 {
 {
 	Error err = ErrorCode::NONE;
 	Error err = ErrorCode::NONE;
 
 
-	Node* el = alloc.template newInstance<Node>(
-		std::forward<TArgs>(args)...);
+	Node* el = alloc.template newInstance<Node>(std::forward<TArgs>(args)...);
 	if(el != nullptr)
 	if(el != nullptr)
 	{
 	{
 		if(m_head != nullptr)
 		if(m_head != nullptr)
@@ -69,6 +96,57 @@ Error List<T, TAlloc>::emplaceFront(Allocator alloc, TArgs&&... args)
 	return err;
 	return err;
 }
 }
 
 
+//==============================================================================
+template<typename T, typename TAlloc>
+template<typename... TArgs>
+Error List<T, TAlloc>::emplace(Allocator alloc, Iterator pos, TArgs&&... args)
+{
+	ANKI_ASSERT(pos.m_list == this);
+	Error err = ErrorCode::NONE;
+
+	Node* el = alloc.template newInstance<Node>(std::forward<TArgs>(args)...);
+	if(el != nullptr)
+	{
+		Node* node = pos.m_node;
+
+		if(node == nullptr)
+		{
+			// Place after the last
+
+			if(m_tail != nullptr)
+			{
+				ANKI_ASSERT(m_head != nullptr);
+				m_tail->m_next = el;
+				el->m_prev = m_tail;
+				m_tail = el;
+			}
+			else
+			{
+				ANKI_ASSERT(m_head == nullptr);
+				m_tail = m_head = el;
+			}
+		}
+		else
+		{
+			el->m_prev = node->m_prev;
+			el->m_next = node;
+			node->m_prev = el;
+
+			if(node == m_head)
+			{
+				ANKI_ASSERT(m_tail != nullptr);
+				m_head = el;
+			}
+		}
+	}
+	else
+	{
+		err = ErrorCode::OUT_OF_MEMORY;
+	}
+
+	return err;
+}
+
 //==============================================================================
 //==============================================================================
 template<typename T, typename TAlloc>
 template<typename T, typename TAlloc>
 void List<T, TAlloc>::destroy(Allocator alloc)
 void List<T, TAlloc>::destroy(Allocator alloc)
@@ -169,5 +247,39 @@ typename List<T, TAlloc>::Node* List<T, TAlloc>::partition(
 	return i;
 	return i;
 }
 }
 
 
+//==============================================================================
+template<typename T, typename TAlloc>
+void List<T, TAlloc>::erase(Allocator alloc, Iterator pos)
+{
+	ANKI_ASSERT(pos.m_node);
+	ANKI_ASSERT(pos.m_list == this);
+
+	Node* node = pos.m_node;
+	
+	if(node == m_tail)
+	{
+		m_tail = node->m_prev;
+	}
+
+	if(node == m_head)
+	{
+		m_head = node->m_next;
+	}
+
+	if(node->m_prev)
+	{
+		ANKI_ASSERT(node->m_prev->m_next == node);
+		node->m_prev->m_next = node->m_next;
+	}
+
+	if(node->m_next)
+	{
+		ANKI_ASSERT(node->m_next->m_prev == node);
+		node->m_next->m_prev = node->m_prev;
+	}
+
+	alloc.deleteInstance(node);
+}
+
 } // end namespace anki
 } // end namespace anki
 
 

+ 74 - 0
tests/util/List.cpp

@@ -92,5 +92,79 @@ ANKI_TEST(Util, List)
 
 
 		a.destroy(alloc);
 		a.destroy(alloc);
 	}
 	}
+
+	// Iterate
+	{
+		List<I> a;
+		Error err = ErrorCode::NONE;
+
+		err = a.emplaceBack(alloc, 10);
+		ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE);
+		err = a.emplaceBack(alloc, 9);
+		ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE);
+		err = a.emplaceBack(alloc, 11);
+		ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE);
+		err = a.emplaceBack(alloc, 2);
+		ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE);
+
+		Array<I, 4> arr = {{10, 9, 11, 2}};
+		U count = 0;
+		
+		// Forward
+		List<I>::ConstIterator it = a.getBegin();
+		for(; it != a.getEnd() && !err; ++it)
+		{
+			if(*it != arr[count++])
+			{
+				err = ErrorCode::UNKNOWN;
+			}
+		}
+		
+		ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE);
+
+		// Backwards
+		--it;
+		for(; it != a.getBegin() && !err; --it)
+		{
+			if(*it != arr[--count])
+			{
+				err = ErrorCode::UNKNOWN;
+			}
+		}
+
+		ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE);
+
+		a.destroy(alloc);
+	}
+
+	// Erase
+	{
+		List<I> a;
+
+		ANKI_TEST_EXPECT_EQ(a.emplaceBack(alloc, 10), ErrorCode::NONE);
+
+		a.erase(alloc, a.getBegin());
+		ANKI_TEST_EXPECT_EQ(a.isEmpty(), true);
+
+		ANKI_TEST_EXPECT_EQ(a.emplaceBack(alloc, 10), ErrorCode::NONE);
+		ANKI_TEST_EXPECT_EQ(a.emplaceBack(alloc, 20), ErrorCode::NONE);
+
+		a.erase(alloc, a.getBegin() + 1);
+		ANKI_TEST_EXPECT_EQ(10, *a.getBegin());
+
+		ANKI_TEST_EXPECT_EQ(a.emplaceFront(alloc, 5), ErrorCode::NONE);
+		ANKI_TEST_EXPECT_EQ(a.emplaceBack(alloc, 30), ErrorCode::NONE);
+
+		ANKI_TEST_EXPECT_EQ(5, *(a.getBegin()));
+		ANKI_TEST_EXPECT_EQ(10, *(a.getEnd() - 2));
+		ANKI_TEST_EXPECT_EQ(30, *(a.getEnd() - 1));
+		
+		a.erase(alloc, a.getEnd() - 2);
+		ANKI_TEST_EXPECT_EQ(5, *(a.getBegin()));
+		ANKI_TEST_EXPECT_EQ(30, *(a.getEnd() - 1));
+
+		a.erase(alloc, a.getBegin());
+		a.erase(alloc, a.getBegin());
+	}
 }
 }