Browse Source

Removing exceptions

Panagiotis Christopoulos Charitos 11 years ago
parent
commit
7b7d62676f

+ 1 - 13
include/anki/misc/Xml.h

@@ -51,19 +51,7 @@ public:
 	}
 
 	/// Return the text inside a tag
-	CString getText() const
-	{
-		check();
-
-		if(m_el->GetText())
-		{
-			return CString(m_el->GetText());
-		}
-		else
-		{
-			return CString();
-		}
-	}
+	ANKI_USE_RESULT Error getText(CString& out) const;
 
 	/// Return the text inside as an int
 	ANKI_USE_RESULT Error getI64(I64& out) const;

+ 5 - 4
include/anki/resource/MaterialProgramCreator.h

@@ -87,17 +87,18 @@ private:
 
 	/// Parse what is within the
 	/// @code <programs></programs> @endcode
-	void parseProgramsTag(const XmlElement& el);
+	ANKI_USE_RESULT Error parseProgramsTag(const XmlElement& el);
 
 	/// Parse what is within the
 	/// @code <program></program> @endcode
-	void parseProgramTag(const XmlElement& el);
+	ANKI_USE_RESULT Error parseProgramTag(const XmlElement& el);
 
 	/// Parse what is within the @code <inputs></inputs> @endcode
-	void parseInputsTag(const XmlElement& programEl);
+	ANKI_USE_RESULT Error parseInputsTag(const XmlElement& programEl);
 
 	/// Parse what is within the @code <operation></operation> @endcode
-	void parseOperationTag(const XmlElement& el, GLenum glshader, 
+	ANKI_USE_RESULT Error parseOperationTag(
+		const XmlElement& el, GLenum glshader, 
 		GLbitfield glshaderbit, MPString& out);
 };
 

+ 144 - 0
include/anki/util/List.h

@@ -0,0 +1,144 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#ifndef ANKI_UTIL_LIST_H
+#define ANKI_UTIL_LIST_H
+
+#include "anki/util/Allocator.h"
+#include "anki/util/NonCopyable.h"
+
+namespace anki {
+
+/// @addtogroup util_containers
+/// @{
+
+/// Double linked list.
+template<typename T, typename TAlloc = HeapAllocator<T>>
+class List: public NonCopyable
+{
+public:
+	using Value = T;
+	using Allocator = TAlloc;
+	using Reference = Value&;
+	using ConstReference = const Value&;
+
+	List() = default;
+
+	/// Move.
+	List(List&& b)
+	:	List()
+	{
+		move(b);
+	}
+
+	~List()
+	{
+		ANKI_ASSERT(m_head == nullptr && "Requires manual destruction");
+	}
+
+	/// Move.
+	List& operator=(List&& b)
+	{
+		move(b);
+		return *this;
+	}
+
+	/// Destroy the list.
+	void destroy(Allocator alloc);
+
+	/// Get first element.
+	ConstReference getFront() const
+	{
+		ANKI_ASSERT(!isEmpty());
+		return m_head->m_value;
+	}
+
+	/// Get first element.
+	Reference getFront()
+	{
+		ANKI_ASSERT(!isEmpty());
+		return m_head->m_value;
+	}
+
+	/// Get last element.
+	ConstReference getBack() const
+	{
+		ANKI_ASSERT(!isEmpty());
+		return m_tail->m_value;
+	}
+
+	/// Get last element.
+	Reference getBack()
+	{
+		ANKI_ASSERT(!isEmpty());
+		return m_tail->m_value;
+	}
+
+	template<typename... TArgs>
+	ANKI_USE_RESULT Error emplaceBack(Allocator alloc, TArgs&&... args);
+
+	template<typename... TArgs>
+	ANKI_USE_RESULT Error emplaceFront(Allocator alloc, TArgs&&... args);
+
+	/// 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);
+
+	Bool isEmpty() const
+	{
+		return m_head == nullptr;
+	}
+
+	/// Quicksort.
+	template<typename TCompFunc = std::less<Value>>
+	void sort(TCompFunc compFunc = TCompFunc());
+
+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_tail = nullptr;
+
+	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;
+	}
+
+	/// Sort.
+	template<typename TCompFunc>
+	void sortInternal(TCompFunc compFunc, Node* l, Node* r);
+
+	/// Used in sortInternal.
+	template<typename TCompFunc>
+	Node* partition(TCompFunc compFunc, Node* l, Node* r);
+};
+
+/// @}
+
+} // end namespace anki
+
+#include "anki/util/List.inl.h"
+
+#endif
+

+ 173 - 0
include/anki/util/List.inl.h

@@ -0,0 +1,173 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+namespace anki {
+
+//==============================================================================
+template<typename T, typename TAlloc>
+template<typename... TArgs>
+Error List<T, TAlloc>::emplaceBack(Allocator alloc, TArgs&&... args)
+{
+	Error err = ErrorCode::NONE;
+	
+	Node* el = alloc.template newInstance<Node>(
+		std::forward<TArgs>(args)...);
+	if(el != nullptr)
+	{
+		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
+	{
+		err = ErrorCode::OUT_OF_MEMORY;
+	}
+
+	return err;
+}
+
+//==============================================================================
+template<typename T, typename TAlloc>
+template<typename... TArgs>
+Error List<T, TAlloc>::emplaceFront(Allocator alloc, TArgs&&... args)
+{
+	Error err = ErrorCode::NONE;
+
+	Node* el = alloc.template newInstance<Node>(
+		std::forward<TArgs>(args)...);
+	if(el != nullptr)
+	{
+		if(m_head != nullptr)
+		{
+			ANKI_ASSERT(m_tail != nullptr);
+			m_head->m_prev = el;
+			el->m_next = m_head;
+			m_head = el;
+		}
+		else
+		{
+			ANKI_ASSERT(m_tail == nullptr);
+			m_tail = m_head = el;
+		}
+	}
+	else
+	{
+		err = ErrorCode::OUT_OF_MEMORY;
+	}
+
+	return err;
+}
+
+//==============================================================================
+template<typename T, typename TAlloc>
+void List<T, TAlloc>::destroy(Allocator 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, typename TAlloc>
+template<typename TFunc>
+Error List<T, TAlloc>::iterateForward(TFunc func)
+{
+	Error err = ErrorCode::NONE;
+	Node* el = m_head;
+	while(el && !err)
+	{
+		err = func(el->m_value);
+		el = el->m_next;
+	}
+
+	return err;
+}
+
+//==============================================================================
+template<typename T, typename TAlloc>
+template<typename TFunc>
+Error List<T, TAlloc>::iterateBackward(TFunc func)
+{
+	Error err = ErrorCode::NONE;
+	Node* el = m_tail;
+	while(el && !err)
+	{
+		err = func(el->m_value);
+		el = el->m_prev;
+	}
+
+	return err;
+}
+
+//==============================================================================
+template<typename T, typename TAlloc>
+template<typename TCompFunc>
+void List<T, TAlloc>::sort(TCompFunc compFunc)
+{
+	sortInternal(compFunc, m_head, m_tail);
+}
+
+//==============================================================================
+template<typename T, typename TAlloc>
+template<typename TCompFunc>
+void List<T, TAlloc>::sortInternal(TCompFunc compFunc, Node* l, Node* r)
+{
+	if (r != nullptr && l != r && l != r->m_next)
+	{
+		Node* p = partition(compFunc, l, r);
+		sortInternal(compFunc, l, p->m_prev);
+		sortInternal(compFunc, p->m_next, r);
+	}
+}
+
+//==============================================================================
+template<typename T, typename TAlloc>
+template<typename TCompFunc>
+typename List<T, TAlloc>::Node* List<T, TAlloc>::partition(
+	TCompFunc compFunc, Node* l, Node* r)
+{
+	// Set pivot as h element
+	Value& x = r->m_value;
+ 
+	// similar to i = l-1 for array implementation
+	Node* i = l->m_prev;
+ 
+	// Similar to "for (int j = l; j <= h- 1; j++)"
+	for(Node* j = l; j != r; j = j->m_next)
+	{
+		if(compFunc(j->m_value, x))
+		{
+			// Similar to i++ for array
+			i = (i == nullptr) ? l : i->m_next;
+
+			// Swap
+			std::swap(i->m_value, j->m_value);
+		}
+	}
+
+	i = (i == nullptr) ? l : i->m_next; // Similar to i++
+	
+	std::swap(i->m_value, r->m_value);
+
+	return i;
+}
+
+} // end namespace anki
+

+ 16 - 0
src/misc/Xml.cpp

@@ -26,6 +26,22 @@ ANKI_USE_RESULT Error XmlElement::check() const
 	return err;
 }
 
+//==============================================================================
+Error XmlElement::getText(CString& out) const
+{
+	Error err = check();
+	if(!err && m_el->GetText())
+	{
+		out = CString(m_el->GetText());
+	}
+	else
+	{
+		out = CString();
+	}
+
+	return err;
+}
+
 //==============================================================================
 Error XmlElement::getI64(I64& out) const
 {

+ 3 - 1
src/resource/Animation.cpp

@@ -78,7 +78,9 @@ void Animation::loadInternal(
 
 		// <name>
 		chEl.getChildElement("name", el);
-		ch.m_name = el.getText();
+		CString tmp;
+		el.getText(tmp);
+		ch.m_name = tmp;
 
 		XmlElement keysEl, keyEl;
 

+ 6 - 2
src/resource/Material.cpp

@@ -378,13 +378,17 @@ void Material::parseMaterialTag(const XmlElement& materialEl,
 
 	if(blendFunctionsEl)
 	{
+		CString cstr;
+
 		// sFactor
 		blendFunctionsEl.getChildElement("sFactor", el);
-		m_blendingSfactor = blendToEnum(el.getText());
+		el.getText(cstr);
+		m_blendingSfactor = blendToEnum(cstr);
 
 		// dFactor
 		blendFunctionsEl.getChildElement("dFactor", el);
-		m_blendingDfactor = blendToEnum(el.getText());
+		el.getText(cstr);
+		m_blendingDfactor = blendToEnum(cstr);
 	}
 	else
 	{

+ 111 - 70
src/resource/MaterialProgramCreator.cpp

@@ -18,6 +18,14 @@ namespace anki {
 // Misc                                                                        =
 //==============================================================================
 
+// Sortcut
+#define ANKI_CHECK(x_) \
+	err = x_; \
+	if(ANKI_UNLIKELY(err)) \
+	{ \
+		return err; \
+	}
+
 //==============================================================================
 /// Define string literal
 #define ANKI_STRL(cstr_) MPString(cstr_, m_alloc)
@@ -35,12 +43,14 @@ public:
 
 //==============================================================================
 /// Given a string return info about the shader
-static void getShaderInfo(
+static ANKI_USE_RESULT Error getShaderInfo(
 	const CString& str, 
 	GLenum& type, 
 	GLbitfield& bit,
 	U& idx)
 {
+	Error err = ErrorCode::NONE;
+
 	if(str == "vert")
 	{
 		type = GL_VERTEX_SHADER;
@@ -73,8 +83,11 @@ static void getShaderInfo(
 	}
 	else
 	{
-		throw ANKI_EXCEPTION("Incorrect type %s", &str[0]);
+		ANKI_LOGE("Incorrect type %s", &str[0]);
+		err = ErrorCode::USER_DATA;
 	}
+
+	return err;
 }
 
 //==============================================================================
@@ -85,7 +98,6 @@ static void getShaderInfo(
 MaterialProgramCreator::MaterialProgramCreator(
 	const XmlElement& el, TempResourceAllocator<U8>& alloc)
 :	m_alloc(alloc),
-	m_inputs(m_alloc),
 	m_uniformBlock(m_alloc)
 {
 	parseProgramsTag(el);
@@ -96,18 +108,20 @@ MaterialProgramCreator::~MaterialProgramCreator()
 {}
 
 //==============================================================================
-void MaterialProgramCreator::parseProgramsTag(const XmlElement& el)
+Error MaterialProgramCreator::parseProgramsTag(const XmlElement& el)
 {
+	Error err = ErrorCode::NONE;
+
 	//
 	// First gather all the inputs
 	//
 	XmlElement programEl;
-	el.getChildElement("program", programEl);
+	ANKI_CHECK(el.getChildElement("program", programEl));
 	do
 	{
-		parseInputsTag(programEl);
+		ANKI_CHECK(parseInputsTag(programEl));
 
-		programEl.getNextSiblingElement("program", programEl);
+		ANKI_CHECK(programEl.getNextSiblingElement("program", programEl));
 	} while(programEl);
 
 	// Sort them by name to decrease the change of creating unique shaders
@@ -116,12 +130,12 @@ void MaterialProgramCreator::parseProgramsTag(const XmlElement& el)
 	//
 	// Then parse the includes, operations and other parts of the program
 	//
-	el.getChildElement("program", programEl);
+	ANKI_CHECK(el.getChildElement("program", programEl));
 	do
 	{
-		parseProgramTag(programEl);
+		ANKI_CHECK(parseProgramTag(programEl));
 
-		programEl.getNextSiblingElement("program", programEl);
+		ANKI_CHECK(programEl.getNextSiblingElement("program", programEl));
 	} while(programEl);
 
 	//
@@ -133,25 +147,30 @@ void MaterialProgramCreator::parseProgramsTag(const XmlElement& el)
 	{
 		if(in.m_shaderDefinedMask != in.m_shaderReferencedMask)
 		{
-			throw ANKI_EXCEPTION("Variable not referenced or not defined %s", 
+			ANKI_LOGE("Variable not referenced or not defined %s", 
 				&in.m_name[0]);
+			return ErrorCode::USER_DATA;
 		}
 	}
+
+	return err;
 }
 
 //==============================================================================
-void MaterialProgramCreator::parseProgramTag(
+Error MaterialProgramCreator::parseProgramTag(
 	const XmlElement& programEl)
 {
+	Error err = ErrorCode::NONE;
 	XmlElement el;
 
 	// <type>
-	programEl.getChildElement("type", el);
-	CString type = el.getText();
+	ANKI_CHECK(programEl.getChildElement("type", el));
+	CString type;
+	ANKI_CHECK(el.getText(type));
 	GLbitfield glshaderbit;
 	GLenum glshader;
 	U shaderidx;
-	getShaderInfo(type, glshader, glshaderbit, shaderidx);
+	ANKI_CHECK(getShaderInfo(type, glshader, glshaderbit, shaderidx));
 
 	m_source[shaderidx] = MPStringList(m_alloc);
 	auto& lines = m_source[shaderidx];
@@ -165,17 +184,19 @@ void MaterialProgramCreator::parseProgramTag(
 
 	// <includes></includes>
 	XmlElement includesEl;
-	programEl.getChildElement("includes", includesEl);
+	ANKI_CHECK(programEl.getChildElement("includes", includesEl));
 	XmlElement includeEl;
-	includesEl.getChildElement("include", includeEl);
+	ANKI_CHECK(includesEl.getChildElement("include", includeEl));
 
 	do
 	{
-		MPString fname(includeEl.getText(), m_alloc);
+		CString tmp;
+		ANKI_CHECK(includeEl.getText(tmp));
+		MPString fname(tmp, m_alloc);
 		lines.push_back(
 			ANKI_STRL("#pragma anki include \"") + fname + "\"");
 
-		includeEl.getNextSiblingElement("include", includeEl);
+		ANKI_CHECK(includeEl.getNextSiblingElement("include", includeEl));
 	} while(includeEl);
 
 	// Inputs
@@ -207,70 +228,76 @@ void MaterialProgramCreator::parseProgramTag(
 	lines.push_back(ANKI_STRL("\nvoid main()\n{"));
 
 	XmlElement opsEl;
-	programEl.getChildElement("operations", opsEl);
+	ANKI_CHECK(programEl.getChildElement("operations", opsEl));
 	XmlElement opEl;
-	opsEl.getChildElement("operation", opEl);
+	ANKI_CHECK(opsEl.getChildElement("operation", opEl));
 	do
 	{
 		MPString out(m_alloc);
-		parseOperationTag(opEl, glshader, glshaderbit, out);
+		ANKI_CHECK(parseOperationTag(opEl, glshader, glshaderbit, out));
 		lines.push_back(out);
 
 		// Advance
-		opEl.getNextSiblingElement("operation", opEl);
+		ANKI_CHECK(opEl.getNextSiblingElement("operation", opEl));
 	} while(opEl);
 
 	lines.push_back(ANKI_STRL("}\n"));
+	return err;
 }
 
 //==============================================================================
-void MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
+Error MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
 {
+	Error err = ErrorCode::NONE;
 	XmlElement el;
+	CString cstr;
 	XmlElement inputsEl;
-	programEl.getChildElementOptional("inputs", inputsEl);
+	ANKI_CHECK(programEl.getChildElementOptional("inputs", inputsEl));
 	if(!inputsEl)
 	{
-		return;
+		return err;
 	}
 
 	// Get shader type
 	GLbitfield glshaderbit;
 	GLenum glshader;
 	U shaderidx;
-	programEl.getChildElement("type", el);
-	getShaderInfo(el.getText(), glshader, glshaderbit, shaderidx);
+	ANKI_CHECK(programEl.getChildElement("type", el));
+	ANKI_CHECK(el.getText(cstr));
+	ANKI_CHECK(getShaderInfo(cstr, glshader, glshaderbit, shaderidx));
 
 	XmlElement inputEl;
-	inputsEl.getChildElement("input", inputEl);
+	ANKI_CHECK(inputsEl.getChildElement("input", inputEl));
 	do
 	{
 		Input inpvar(m_alloc);
 
 		// <name>
-		inputEl.getChildElement("name", el);
-		inpvar.m_name = el.getText();
+		ANKI_CHECK(inputEl.getChildElement("name", el));
+		ANKI_CHECK(el.getText(cstr));
+		inpvar.m_name = cstr;
 
 		// <type>
-		inputEl.getChildElement("type", el);
-		inpvar.m_type = el.getText();
+		ANKI_CHECK(inputEl.getChildElement("type", el));
+		ANKI_CHECK(el.getText(cstr));
+		inpvar.m_type = cstr;
 
 		// <value>
 		XmlElement valueEl;
-		inputEl.getChildElement("value", valueEl);
-		if(valueEl.getText())
+		ANKI_CHECK(inputEl.getChildElement("value", valueEl));
+		ANKI_CHECK(valueEl.getText(cstr));
+		if(cstr)
 		{
-			inpvar.m_value = MPStringList::splitString(
-				valueEl.getText(), ' ', m_alloc);
+			inpvar.m_value = MPStringList::splitString(cstr, ' ', m_alloc);
 		}
 
 		// <const>
 		XmlElement constEl;
-		inputEl.getChildElementOptional("const", constEl);
+		ANKI_CHECK(inputEl.getChildElementOptional("const", constEl));
 		if(constEl)
 		{
 			I64 tmp;
-			constEl.getI64(tmp);
+			ANKI_CHECK(constEl.getI64(tmp));
 			inpvar.m_constant = tmp;
 		}
 		else
@@ -280,11 +307,11 @@ void MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
 
 		// <arraySize>
 		XmlElement arrSizeEl;
-		inputEl.getChildElementOptional("arraySize", arrSizeEl);
+		ANKI_CHECK(inputEl.getChildElementOptional("arraySize", arrSizeEl));
 		if(arrSizeEl)
 		{
 			I64 tmp;
-			arrSizeEl.getI64(tmp);
+			ANKI_CHECK(arrSizeEl.getI64(tmp));
 			inpvar.m_arraySize = tmp;
 		}
 		else
@@ -296,12 +323,13 @@ void MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
 		if(inpvar.m_arraySize == 0)
 		{
 			XmlElement instancedEl;
-			inputEl.getChildElementOptional("instanced", instancedEl);
+			ANKI_CHECK(
+				inputEl.getChildElementOptional("instanced", instancedEl));
 
 			if(instancedEl)
 			{
 				I64 tmp;
-				instancedEl.getI64(tmp);
+				ANKI_CHECK(instancedEl.getI64(tmp));
 				inpvar.m_instanced = tmp;
 			}
 			else
@@ -339,8 +367,9 @@ void MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
 
 			if(!same)
 			{
-				throw ANKI_EXCEPTION("Variable defined differently between "
+				ANKI_LOGE("Variable defined differently between "
 					"shaders: %s", &inpvar.m_name[0]);
+				return ErrorCode::USER_DATA;
 			}
 
 			duplicateInp->m_shaderDefinedMask |= glshaderbit;
@@ -399,13 +428,14 @@ void MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
 
 			if(inpvar.m_value.size() == 0)
 			{
-				throw ANKI_EXCEPTION("Empty value and const is illogical");
+				ANKI_LOGE("Empty value and const is illogical");
+				return ErrorCode::USER_DATA;
 			}
 
 			if(inpvar.m_arraySize > 0)
 			{
-				throw ANKI_EXCEPTION("Const arrays currently cannot "
-					"be handled");
+				ANKI_LOGE("Const arrays currently cannot be handled");
+				return ErrorCode::USER_DATA;
 			}
 
 			inpvar.m_inBlock = false;
@@ -421,28 +451,33 @@ void MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
 
 advance:
 		// Advance
-		inputEl.getNextSiblingElement("input", inputEl);
+		ANKI_CHECK(inputEl.getNextSiblingElement("input", inputEl));
 	} while(inputEl);
+
+	return err;
 }
 
 //==============================================================================
-void MaterialProgramCreator::parseOperationTag(
+Error MaterialProgramCreator::parseOperationTag(
 	const XmlElement& operationTag, GLenum glshader, GLbitfield glshaderbit,
 	MPString& out)
 {
+	Error err = ErrorCode::NONE;
+	CString cstr;
 	static const char OUT[] = {"out"};
 	XmlElement el;
 
 	// <id></id>
 	I64 tmp;
-	operationTag.getChildElement("id", el);
-	el.getI64(tmp);
+	ANKI_CHECK(operationTag.getChildElement("id", el));
+	ANKI_CHECK(el.getI64(tmp));
 	I id = tmp;
 	
 	// <returnType></returnType>
 	XmlElement retTypeEl;
-	operationTag.getChildElement("returnType", retTypeEl);
-	MPString retType(retTypeEl.getText(), m_alloc);
+	ANKI_CHECK(operationTag.getChildElement("returnType", retTypeEl));
+	ANKI_CHECK(retTypeEl.getText(cstr));
+	MPString retType(cstr, m_alloc);
 	MPString operationOut(m_alloc);
 	if(retType != "void")
 	{
@@ -451,22 +486,24 @@ void MaterialProgramCreator::parseOperationTag(
 	}
 	
 	// <function>functionName</function>
-	operationTag.getChildElement("function", el);
-	MPString funcName(el.getText(), m_alloc);
+	ANKI_CHECK(operationTag.getChildElement("function", el));
+	ANKI_CHECK(el.getText(cstr));
+	MPString funcName(cstr, m_alloc);
 	
 	// <arguments></arguments>
 	XmlElement argsEl;
-	operationTag.getChildElementOptional("arguments", argsEl);
+	ANKI_CHECK(operationTag.getChildElementOptional("arguments", argsEl));
 	MPStringList argsList(m_alloc);
 	
 	if(argsEl)
 	{
 		// Get all arguments
 		XmlElement argEl;
-		argsEl.getChildElement("argument", argEl);
+		ANKI_CHECK(argsEl.getChildElement("argument", argEl));
 		do
 		{
-			MPString arg(argEl.getText(), m_alloc);
+			ANKI_CHECK(argEl.getText(cstr));
+			MPString arg(cstr, m_alloc);
 
 			// Search for all the inputs and mark the appropriate
 			Input* input = nullptr;
@@ -486,53 +523,55 @@ void MaterialProgramCreator::parseOperationTag(
 			if(!(input != nullptr 
 				|| std::strncmp(&arg[0], OUT, sizeof(OUT) - 1) == 0))
 			{
-				throw ANKI_EXCEPTION("Incorrect argument: %s", &arg[0]);
+				ANKI_LOGE("Incorrect argument: %s", &arg[0]);
+				return ErrorCode::USER_DATA;
 			}
 
 			// Add to a list and do something special if instanced
 			if(input && input->m_instanced)
 			{
+				ANKI_CHECK(argEl.getText(cstr));
+
 				if(glshader == GL_VERTEX_SHADER)
 				{
-					argsList.push_back(ANKI_STRL(argEl.getText()) 
-						+ "[gl_InstanceID]");
+					argsList.push_back(ANKI_STRL(cstr) + "[gl_InstanceID]");
 
 					m_instanceIdMask |= glshaderbit;
 				}
 				else if(glshader == GL_TESS_CONTROL_SHADER)
 				{
-					argsList.push_back(ANKI_STRL(argEl.getText()) 
-						+ "[vInstanceId[0]]");
+					argsList.push_back(ANKI_STRL(cstr) + "[vInstanceId[0]]");
 
 					m_instanceIdMask |= glshaderbit;
 				}
 				else if(glshader == GL_TESS_EVALUATION_SHADER)
 				{
-					argsList.push_back(ANKI_STRL(argEl.getText()) 
+					argsList.push_back(ANKI_STRL(cstr) 
 						+ "[commonPatch.instanceId]");
 					
 					m_instanceIdMask |= glshaderbit;
 				}
 				else if(glshader == GL_FRAGMENT_SHADER)
 				{
-					argsList.push_back(ANKI_STRL(argEl.getText()) 
-						+ "[vInstanceId]");
+					argsList.push_back(ANKI_STRL(cstr) + "[vInstanceId]");
 					
 					m_instanceIdMask |= glshaderbit;
 				}
 				else
 				{
-					throw ANKI_EXCEPTION(
+					ANKI_LOGE(
 						"Cannot access the instance ID in all shaders");
+					return ErrorCode::USER_DATA;
 				}
 			}
 			else
 			{
-				argsList.push_back(MPString(argEl.getText(), m_alloc));
+				ANKI_CHECK(argEl.getText(cstr));
+				argsList.push_back(MPString(cstr, m_alloc));
 			}
 
 			// Advance
-			argEl.getNextSiblingElement("argument", argEl);
+			ANKI_CHECK(argEl.getNextSiblingElement("argument", argEl));
 		} while(argEl);
 	}
 
@@ -553,8 +592,9 @@ void MaterialProgramCreator::parseOperationTag(
 
 	if(retType != "void")
 	{
+		ANKI_CHECK(retTypeEl.getText(cstr));
 		lines += "#\tdefine " + operationOut + "_DEFINED\n\t"
-			+ retTypeEl.getText() + " " + operationOut + " = ";
+			+ cstr + " " + operationOut + " = ";
 	}
 	else
 	{
@@ -569,6 +609,7 @@ void MaterialProgramCreator::parseOperationTag(
 
 	// Done
 	out = std::move(lines);
+	return err;
 }
 
 } // end namespace anki

+ 2 - 1
src/resource/Mesh.cpp

@@ -265,7 +265,8 @@ void BucketMesh::load(const CString& filename, ResourceInitializer& init)
 		U i = 0;
 		do
 		{
-			CString subMeshFilename = meshEl.getText();
+			CString subMeshFilename;
+			meshEl.getText(subMeshFilename);
 
 			// Load the submesh and if not the first load the append the 
 			// vertices to the fullMesh

+ 14 - 9
src/resource/Model.cpp

@@ -305,7 +305,8 @@ void Model::load(const CString& filename, ResourceInitializer& init)
 		if(collEl)
 		{
 			collEl.getChildElement("type", el);
-			CString type = el.getText();
+			CString type;
+			el.getText(type);
 			XmlElement valEl;
 			collEl.getChildElement("value", valEl);
 			(void)valEl; // XXX
@@ -352,23 +353,25 @@ void Model::load(const CString& filename, ResourceInitializer& init)
 				XmlElement meshEl2;
 				modelPatchEl.getChildElementOptional("mesh2", meshEl2);
 
-				meshesFnames[0] = meshEl.getText();
+				meshEl.getText(meshesFnames[0]);
 
 				if(meshEl1)
 				{
 					++meshesCount;
-					meshesFnames[1] = meshEl1.getText();
+					meshEl1.getText(meshesFnames[1]);
 				}
 
 				if(meshEl2)
 				{
 					++meshesCount;
-					meshesFnames[2] = meshEl2.getText();
+					meshEl2.getText(meshesFnames[2]);
 				}
 
+				CString cstr;
+				materialEl.getText(cstr);
 				patch = init.m_alloc.newInstance<
 					ModelPatch<MeshResourcePointer>>(
-					&meshesFnames[0], meshesCount, materialEl.getText(),
+					&meshesFnames[0], meshesCount, cstr,
 					&init.m_resources);
 			}
 			else
@@ -380,23 +383,25 @@ void Model::load(const CString& filename, ResourceInitializer& init)
 				XmlElement bmeshEl2;
 				modelPatchEl.getChildElementOptional("bucketMesh2", bmeshEl2);
 
-				meshesFnames[0] = bmeshEl.getText();
+				bmeshEl.getText(meshesFnames[0]);
 
 				if(bmeshEl1)
 				{
 					++meshesCount;
-					meshesFnames[1] = bmeshEl1.getText();
+					bmeshEl1.getText(meshesFnames[1]);
 				}
 
 				if(bmeshEl2)
 				{
 					++meshesCount;
-					meshesFnames[2] = bmeshEl2.getText();
+					bmeshEl2.getText(meshesFnames[2]);
 				}
 
+				CString cstr;
+				materialEl.getText(cstr);
 				patch = init.m_alloc.newInstance<
 					ModelPatch<BucketMeshResourcePointer>>(
-					&meshesFnames[0], meshesCount, materialEl.getText(),
+					&meshesFnames[0], meshesCount, cstr,
 					&init.m_resources);
 			}
 

+ 3 - 1
src/resource/ParticleEmitterResource.cpp

@@ -163,7 +163,9 @@ void ParticleEmitterResource::loadInternal(const XmlElement& rootel,
 
 	XmlElement el;
 	rootel.getChildElement("material", el);
-	m_material.load(el.getText(), &init.m_resources);
+	CString cstr;
+	el.getText(cstr);
+	m_material.load(cstr, &init.m_resources);
 
 	// sanity checks
 	//

+ 3 - 1
src/resource/Skeleton.cpp

@@ -54,7 +54,9 @@ void Skeleton::load(const CString& filename, ResourceInitializer& init)
 		// <name>
 		XmlElement nameEl;
 		boneEl.getChildElement("name", nameEl);
-		bone.m_name = nameEl.getText();
+		CString tmp;
+		nameEl.getText(tmp);
+		bone.m_name = tmp;
 
 		// <transform>
 		XmlElement trfEl;

+ 1 - 4
tests/Main.cpp

@@ -4,7 +4,6 @@
 // http://www.anki3d.org/LICENSE
 
 #include "tests/framework/Framework.h"
-#include "anki/core/Logger.h"
 #include "anki/util/Filesystem.h"
 
 using namespace anki;
@@ -14,9 +13,7 @@ int main(int argc, char** argv)
 	HeapAllocator<U8> alloc(allocAligned, nullptr);
 
 	// Call a few singletons to avoid memory leak confusion
-	LoggerSingleton::init(
-		Logger::InitFlags::WITH_SYSTEM_MESSAGE_HANDLER,
-		alloc, &(getHomeDirectory(alloc) + ".anki/tests.log")[0]);
+	LoggerSingleton::get();
 
 	int exitcode = getTesterSingleton().run(argc, argv);
 

+ 96 - 0
tests/util/List.cpp

@@ -0,0 +1,96 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "tests/framework/Framework.h"
+#include "tests/util/Foo.h"
+#include "anki/util/List.h"
+
+ANKI_TEST(Util, List)
+{
+	HeapAllocator<U8> alloc(allocAligned, nullptr);
+
+	// Simple
+	{
+		List<Foo> a;
+		Error err = ErrorCode::NONE;
+
+		err = a.emplaceBack(alloc, 10);
+		ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE);
+		err = a.emplaceBack(alloc, 11);
+		ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE);
+
+		U sum = 0;
+
+		err = a.iterateForward([&](const Foo& f) -> Error
+		{
+			sum += f.x;
+			return ErrorCode::NONE;
+		});
+
+		ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE);
+		ANKI_TEST_EXPECT_EQ(sum, 21);
+
+		a.destroy(alloc);
+	}
+
+	// Sort
+	{
+		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);
+
+		a.sort();
+
+		Array<I, 4> arr = {{2, 9, 10, 11}};
+		U u = 0;
+
+		err = a.iterateForward([&](const I& i) -> Error
+		{
+			if(arr[u++] == i)
+			{
+				return ErrorCode::NONE;
+			}
+			else
+			{
+				return ErrorCode::UNKNOWN;
+			}
+		});
+
+		ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE);
+
+		a.sort([](I& a, I& b) -> Bool
+		{
+			return a > b;
+		});
+
+		Array<I, 4> arr2 = {{11, 10, 9, 2}};
+		u = 0;
+
+		err = a.iterateForward([&](const I& i) -> Error
+		{
+			if(arr2[u++] == i)
+			{
+				return ErrorCode::NONE;
+			}
+			else
+			{
+				return ErrorCode::UNKNOWN;
+			}
+		});
+
+		ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE);
+
+		a.destroy(alloc);
+	}
+}
+