Răsfoiți Sursa

Removing exceptions

Panagiotis Christopoulos Charitos 11 ani în urmă
părinte
comite
6e3a7dd83b

+ 5 - 4
include/anki/util/Filesystem.h

@@ -19,22 +19,23 @@ Bool fileExists(const CString& filename);
 /// Get file extension
 /// @param[in] filename The file to open
 /// @return nullptr on failure and if the dot is the last character
-String getFileExtension(const CString& filename, HeapAllocator<U8>& alloc);
+ANKI_USE_RESULT Error getFileExtension(
+	const CString& filename, HeapAllocator<U8>& alloc, String& out);
 
 /// Return true if directory exists?
 Bool directoryExists(const CString& dir);
 
 /// Equivalent to: rm -rf dir
-void removeDirectory(const CString& dir);
+ANKI_USE_RESULT Error removeDirectory(const CString& dir);
 
 /// Equivalent to: mkdir dir
-void createDirectory(const CString& dir);
+ANKI_USE_RESULT Error createDirectory(const CString& dir);
 
 /// Get the home directory.
 /// Write the home directory to @a buff. The @a buffSize is the size of the 
 /// @a buff. If the @buffSize is not enough the function will throw 
 /// an exception.
-String getHomeDirectory(HeapAllocator<U8>& alloc);
+ANKI_USE_RESULT Error getHomeDirectory(HeapAllocator<U8>& alloc, String& out);
 
 /// @}
 

+ 92 - 263
include/anki/util/String.h

@@ -6,9 +6,9 @@
 #ifndef ANKI_STRING_H
 #define ANKI_STRING_H
 
-#include "anki/util/Vector.h"
-#include "anki/util/Exception.h"
+#include "anki/util/DArray.h"
 #include "anki/util/Array.h"
+#include "anki/util/NonCopyable.h"
 #include <cstring>
 #include <cmath> // For HUGE_VAL
 #include <climits> // For LLONG_MAX
@@ -72,16 +72,16 @@ public:
 
 	static const PtrSize NPOS = MAX_PTR_SIZE;
 
-	CString() noexcept = default;
+	CString()  = default;
 
-	CString(const Char* ptr) noexcept
+	CString(const Char* ptr) 
 	:	m_ptr(ptr)
 	{
 		checkInit();
 	}
 
 	/// Copy constructor.
-	CString(const CString& b) noexcept
+	CString(const CString& b) 
 	:	m_ptr(b.m_ptr),
 		m_length(b.m_length)
 	{
@@ -89,7 +89,7 @@ public:
 	}
 
 	/// Copy.
-	CString& operator=(const CString& b) noexcept
+	CString& operator=(const CString& b) 
 	{
 		m_ptr = b.m_ptr;
 		m_length = b.m_length;
@@ -97,73 +97,73 @@ public:
 	}
 
 	/// Return true if the string is initialized.
-	operator Bool() const noexcept
+	operator Bool() const 
 	{
 		return !isEmpty();
 	}
 
 	/// Return char at the specified position.
-	const Char& operator[](U pos) const noexcept
+	const Char& operator[](U pos) const 
 	{
 		checkInit();
 		ANKI_ASSERT(pos <= getLength());
 		return m_ptr[pos];
 	}
 
-	const Char* begin() const noexcept
+	const Char* begin() const 
 	{
 		checkInit();
 		return &m_ptr[0];
 	}
 
-	const Char* end() const noexcept
+	const Char* end() const 
 	{
 		checkInit();
 		return &m_ptr[getLength()];
 	}
 
 	/// Return true if the string is not initialized.
-	Bool isEmpty() const noexcept
+	Bool isEmpty() const 
 	{
 		return m_ptr == nullptr || getLength() == 0;
 	}
 
-	Bool operator==(const CString& b) const noexcept
+	Bool operator==(const CString& b) const 
 	{
 		checkInit();
 		b.checkInit();
 		return std::strcmp(m_ptr, b.m_ptr) == 0;
 	}
 
-	Bool operator!=(const CString& b) const noexcept
+	Bool operator!=(const CString& b) const 
 	{
 		checkInit();
 		b.checkInit();
 		return std::strcmp(m_ptr, b.m_ptr) != 0;
 	}
 
-	Bool operator<(const CString& b) const noexcept
+	Bool operator<(const CString& b) const 
 	{
 		checkInit();
 		b.checkInit();
 		return std::strcmp(m_ptr, b.m_ptr) < 0;
 	}
 
-	Bool operator<=(const CString& b) const noexcept
+	Bool operator<=(const CString& b) const 
 	{
 		checkInit();
 		b.checkInit();
 		return std::strcmp(m_ptr, b.m_ptr) <= 0;
 	}
 
-	Bool operator>(const CString& b) const noexcept
+	Bool operator>(const CString& b) const 
 	{
 		checkInit();
 		b.checkInit();
 		return std::strcmp(m_ptr, b.m_ptr) > 0;
 	}
 
-	Bool operator>=(const CString& b) const noexcept
+	Bool operator>=(const CString& b) const 
 	{
 		checkInit();
 		b.checkInit();
@@ -171,14 +171,14 @@ public:
 	}
 
 	/// Get the underlying C string.
-	const char* get() const noexcept
+	const char* get() const 
 	{
 		checkInit();
 		return m_ptr;
 	}
 
 	/// Get the string length.
-	U getLength() const noexcept
+	U getLength() const 
 	{
 		checkInit();
 		if(m_length == 0)
@@ -189,7 +189,7 @@ public:
 		return m_length;
 	}
 
-	PtrSize find(const CString& cstr, PtrSize position = 0) const noexcept
+	PtrSize find(const CString& cstr, PtrSize position = 0) const 
 	{
 		checkInit();
 		ANKI_ASSERT(position < getLength());
@@ -247,7 +247,7 @@ private:
 	mutable U32 m_length = 0;
 
 	/// Constructor for friends
-	CString(const Char* ptr, U32 length) noexcept
+	CString(const Char* ptr, U32 length) 
 	:	m_ptr(ptr),
 		m_length(length)
 	{
@@ -255,7 +255,7 @@ private:
 		ANKI_ASSERT(std::strlen(ptr) == length);
 	}
 
-	void checkInit() const noexcept
+	void checkInit() const 
 	{
 		ANKI_ASSERT(m_ptr != nullptr);
 	}
@@ -269,7 +269,7 @@ inline CString operator"" _cstr(const char* str, unsigned long length)
 
 /// The base class for strings.
 template<typename TAlloc>
-class StringBase
+class StringBase: public NonCopyable
 {
 public:
 	using Char = char; ///< Character type
@@ -281,66 +281,40 @@ public:
 
 	static const PtrSize NPOS = MAX_PTR_SIZE;
 
-	StringBase() noexcept
-	{}
-
-	StringBase(Allocator alloc) noexcept
-	:	m_data(alloc)
-	{}
-
-	/// Initialize using a const string.
-	StringBase(const CStringType& cstr, Allocator alloc)
-	:	m_data(alloc)
-	{
-		auto size = cstr.getLength() + 1;
-		m_data.resize(size);
-		std::memcpy(&m_data[0], cstr.get(), sizeof(Char) * size);
-	}
-
-	/// Initialize using a range. Copies the range of [first, last)
-	StringBase(ConstIterator first, ConstIterator last, Allocator alloc)
-	:	m_data(alloc)
-	{
-		ANKI_ASSERT(first != 0 && last != 0);
-		auto length = last - first;
-		m_data.resize(length + 1);
-		std::memcpy(&m_data[0], first, length);
-		m_data[length] = '\0';
-	}
-
-	/// Copy constructor.
-	StringBase(const Self& b)
-	:	m_data(b.m_data)
+	/// Default constructor.
+	StringBase() 
 	{}
 
 	/// Move constructor.
-	StringBase(StringBase&& b) noexcept
+	StringBase(StringBase&& b) 
 	:	m_data(std::move(b.m_data))
 	{}
 
-	/// Destroys the string.
-	~StringBase() noexcept
+	/// Requires manual destruction.
+	~StringBase() 
 	{}
 
-	/// Copy another string to this one.
-	Self& operator=(const Self& b)
+	/// Initialize using a const string.
+	ANKI_USE_RESULT Error create(Allocator alloc, const CStringType& cstr);
+
+	/// Initialize using a range. Copies the range of [first, last)
+	ANKI_USE_RESULT Error create(Allocator alloc,
+		ConstIterator first, ConstIterator last);
+
+	/// Copy one string to another.
+	ANKI_USE_RESULT Error create(Allocator alloc, const Self& b)
 	{
-		ANKI_ASSERT(this != &b);
-		m_data = b.m_data;
-		return *this;
+		return create(alloc, b.toCString());
 	}
 
-	/// Copy a const string to this one.
-	Self& operator=(const CStringType& cstr)
+	/// Destroy the string.
+	void destroy(Allocator alloc)
 	{
-		auto size = cstr.getLength() + 1;
-		m_data.resize(size);
-		std::memcpy(&m_data[0], cstr.get(), sizeof(Char) * size);
-		return *this;
+		m_data.destroy(alloc);
 	}
 
 	/// Move one string to this one.
-	Self& operator=(Self&& b) noexcept
+	Self& operator=(Self&& b) 
 	{
 		ANKI_ASSERT(this != &b);
 		m_data = std::move(b.m_data);
@@ -348,80 +322,45 @@ public:
 	}
 
 	/// Return char at the specified position.
-	const Char& operator[](U pos) const noexcept
+	const Char& operator[](U pos) const 
 	{
 		checkInit();
 		return m_data[pos];
 	}
 
 	/// Return char at the specified position as a modifiable reference.
-	Char& operator[](U pos) noexcept
+	Char& operator[](U pos) 
 	{
 		checkInit();
 		return m_data[pos];
 	}
 
-	Iterator begin() noexcept
+	Iterator begin() 
 	{
 		checkInit();
 		return &m_data[0];
 	}
 
-	ConstIterator begin() const noexcept
+	ConstIterator begin() const 
 	{
 		checkInit();
 		return &m_data[0];
 	}
 
-	Iterator end() noexcept
+	Iterator end() 
 	{
 		checkInit();
 		return &m_data[m_data.size() - 1];
 	}
 
-	ConstIterator end() const noexcept
+	ConstIterator end() const 
 	{
 		checkInit();
 		return &m_data[m_data.size() - 1];
 	}
 
-	/// Add strings.
-	Self operator+(const Self& b) const
-	{
-		b.checkInit();
-		return add(&b.m_data[0], b.m_data.size());
-	}
-
-	/// Add strings.
-	Self operator+(const CString& cstr) const
-	{
-		return add(&cstr[0], cstr.getLength() + 1);
-	}
-
-	/// Append another string to this one.
-	template<typename TTAlloc>
-	Self& operator+=(const StringBase<TTAlloc>& b)
-	{
-		if(!b.isEmpty())
-		{
-			append(&b.m_data[0], b.m_data.size());
-		}
-		return *this;
-	}
-
-	/// Append a const string to this one.
-	Self& operator+=(const CStringType& cstr)
-	{
-		if(!cstr.isEmpty())
-		{
-			U size = cstr.getLength() + 1;
-			append(cstr.get(), size);
-		}
-		return *this;
-	}
-
 	/// Return true if strings are equal
-	Bool operator==(const Self& b) const noexcept
+	Bool operator==(const Self& b) const 
 	{
 		checkInit();
 		b.checkInit();
@@ -429,13 +368,13 @@ public:
 	}
 
 	/// Return true if strings are not equal
-	Bool operator!=(const Self& b) const noexcept
+	Bool operator!=(const Self& b) const 
 	{
 		return !(*this == b);
 	}
 
 	/// Return true if this is less than b
-	Bool operator<(const Self& b) const noexcept
+	Bool operator<(const Self& b) const 
 	{
 		checkInit();
 		b.checkInit();
@@ -443,7 +382,7 @@ public:
 	}
 
 	/// Return true if this is less or equal to b
-	Bool operator<=(const Self& b) const noexcept
+	Bool operator<=(const Self& b) const 
 	{
 		checkInit();
 		b.checkInit();
@@ -451,7 +390,7 @@ public:
 	}
 
 	/// Return true if this is greater than b
-	Bool operator>(const Self& b) const noexcept
+	Bool operator>(const Self& b) const 
 	{
 		checkInit();
 		b.checkInit();
@@ -459,7 +398,7 @@ public:
 	}
 
 	/// Return true if this is greater or equal to b
-	Bool operator>=(const Self& b) const noexcept
+	Bool operator>=(const Self& b) const 
 	{
 		checkInit();
 		b.checkInit();
@@ -467,146 +406,92 @@ public:
 	}
 
 	/// Return true if strings are equal
-	Bool operator==(const CStringType& cstr) const noexcept
+	Bool operator==(const CStringType& cstr) const 
 	{
 		checkInit();
 		return std::strcmp(&m_data[0], cstr.get()) == 0;
 	}
 
 	/// Return true if strings are not equal
-	Bool operator!=(const CStringType& cstr) const noexcept
+	Bool operator!=(const CStringType& cstr) const 
 	{
 		return !(*this == cstr);
 	}
 
 	/// Return true if this is less than cstr.
-	Bool operator<(const CStringType& cstr) const noexcept
+	Bool operator<(const CStringType& cstr) const 
 	{
 		checkInit();
 		return std::strcmp(&m_data[0], cstr.get()) < 0;
 	}
 
 	/// Return true if this is less or equal to cstr.
-	Bool operator<=(const CStringType& cstr) const noexcept
+	Bool operator<=(const CStringType& cstr) const 
 	{
 		checkInit();
 		return std::strcmp(&m_data[0], cstr.get()) <= 0;
 	}
 
 	/// Return true if this is greater than cstr.
-	Bool operator>(const CStringType& cstr) const noexcept
+	Bool operator>(const CStringType& cstr) const 
 	{
 		checkInit();
 		return std::strcmp(&m_data[0], cstr.get()) > 0;
 	}
 
 	/// Return true if this is greater or equal to cstr.
-	Bool operator>=(const CStringType& cstr) const noexcept
+	Bool operator>=(const CStringType& cstr) const 
 	{
 		checkInit();
 		return std::strcmp(&m_data[0], cstr.get()) >= 0;
 	}
 
 	/// Return the string's length. It doesn't count the terminating character.
-	PtrSize getLength() const noexcept
+	PtrSize getLength() const 
 	{
-		auto size = m_data.size();
+		auto size = m_data.getSize();
 		auto out = (size != 0) ? (size - 1) : 0;
 		ANKI_ASSERT(std::strlen(&m_data[0]) == out);
 		return out;
 	}
 
-	/// Return the allocator
-	Allocator getAllocator() const noexcept
-	{
-		return m_data.get_allocator();
-	}
-
 	/// Return the CString.
-	CStringType toCString() const noexcept
+	CStringType toCString() const 
 	{
 		checkInit();
 		return CStringType(&m_data[0], getLength());
 	}
 
-	Self& sprintf(CString fmt, ...)
+	/// Append another string to this one.
+	template<typename TTAlloc>
+	ANKI_USE_RESULT Error append(Allocator alloc, const StringBase<TTAlloc>& b)
 	{
-		Array<Char, 512> buffer;
-		va_list args;
-
-		va_start(args, fmt);
-		I len = std::vsnprintf(&buffer[0], sizeof(buffer), &fmt[0], args);
-		va_end(args);
-
-		if(len < 0)
-		{
-			throw ANKI_EXCEPTION("vsnprintf() failed");
-		}
-		else if(static_cast<PtrSize>(len) >= sizeof(buffer))
-		{
-			I size = len + 1;
-			m_data.resize(size);
-
-			va_start(args, fmt);
-			len = std::vsnprintf(&m_data[0], size, &fmt[0], args);
-			(void)len;
-			va_end(args);
-
-			ANKI_ASSERT((len + 1) == size);
-		}
-		else
+		Error err = ErrorCode::NONE;
+		if(!b.isEmpty())
 		{
-			// buffer was enough
-			*this = &buffer[0];
+			err = appendInternal(alloc, &b.m_data[0], b.m_data.getSize());
 		}
 
-		return *this;
-	}
-
-	/// Clears the contents of the string and makes it empty.
-	void clear()
-	{
-		m_data.clear();
-	}
-
-	/// Request string capacity change.
-	void reserve(PtrSize size)
-	{
-		++size;
-		if(size > m_data.size())
-		{
-			m_data.reserve(size);
-		}
+		return err;
 	}
 
-	/// Resize the string.
-	void resize(PtrSize newLength, const Char c = '\0')
+	/// Append a const string to this one.
+	ANKI_USE_RESULT Error append(Allocator alloc, const CStringType& cstr)
 	{
-		ANKI_ASSERT(newLength > 0);
-		auto size = m_data.size();
-		m_data.resize(newLength + 1);
-
-		if(size < newLength + 1)
+		Error err = ErrorCode::NONE;
+		if(!cstr.isEmpty())
 		{
-			// The string has grown
-			
-			// Fill the extra space with c
-			std::memset(
-				&m_data[(size > 0) ? (size - 1) : 0], 
-				c, 
-				newLength - size + 1);
-			m_data[newLength] = '\0';
+			err = appendInternal(cstr.get(), cstr.getLength() + 1);
 		}
-		else if(size > newLength + 1)
-		{
-			// The string got shrinked
 
-			m_data[newLength] = '\0';
-		}
+		return err;
 	}
 
+	/// Create formated string.
+	ANKI_USE_RESULT Error sprintf(Allocator alloc, CString fmt, ...);
+
 	/// Return true if it's empty.
-	Bool isEmpty() const noexcept
+	Bool isEmpty() const 
 	{
 		return m_data.empty();
 	}
@@ -616,7 +501,7 @@ public:
 	/// @param position Position of the first character in the string to be 
 	///                 considered in the search.
 	/// @return A valid position if the string is found or NPOS if not found.
-	PtrSize find(const CStringType& cstr, PtrSize position = 0) const noexcept
+	PtrSize find(const CStringType& cstr, PtrSize position = 0) const 
 	{
 		checkInit();
 		return toCString().find(cstr, position);
@@ -629,31 +514,16 @@ public:
 	/// @return A valid position if the string is found or NPOS if not found.
 	template<typename TTAlloc>
 	PtrSize find(
-		const StringBase<TTAlloc>& str, PtrSize position) const noexcept
+		const StringBase<TTAlloc>& str, PtrSize position) const 
 	{
 		str.chechInit();
 		return find(str.toCString(), position);
 	}
 
 	/// Convert a number to a string.
-	/// @param number The number to convert.
-	/// @param[in,out] alloc The allocator to allocate the returned string.
-	/// @return The string that presents the number.
-	template<typename TNumber, typename TTAlloc>
-	static Self toString(TNumber number, TTAlloc alloc)
-	{
-		Array<Char, 512> buff;
-		I ret = std::snprintf(
-			&buff[0], buff.size(), detail::toStringFormat<TNumber>(), number);
-
-		if(ret < 0 || ret > static_cast<I>(buff.size()))
-		{
-			throw ANKI_EXCEPTION("To small intermediate buffer");
-		}
-
-		using YAlloc = typename TTAlloc::template rebind<Char>::other;
-		return StringBase<YAlloc>(&buff[0], alloc);
-	}
+	template<typename TNumber>
+	static ANKI_USE_RESULT Error toString(
+		Allocator alloc, TNumber number, Self& out);
 
 	/// Convert to F64.
 	ANKI_USE_RESULT Error toF64(F64& out) const
@@ -668,61 +538,18 @@ public:
 	}
 
 private:
-	Vector<Char, TAlloc> m_data;
+	DArray<Char, Allocator> m_data;
 
 	void checkInit() const
 	{
-		ANKI_ASSERT(m_data.size() > 1);
+		ANKI_ASSERT(m_data.getSize() > 1);
 	}
 
-	void append(const Char* str, PtrSize strSize)
-	{
-		ANKI_ASSERT(str != nullptr);
-		ANKI_ASSERT(strSize > 1);
-
-		auto size = m_data.size();
-
-		// Fix empty string
-		if(size == 0)
-		{
-			size = 1;
-		}
-
-		m_data.resize(size + strSize - 1);
-		std::memcpy(&m_data[size - 1], str, sizeof(Char) * strSize);
-	}
-
-	Self add(const Char* str, PtrSize strSize) const
-	{
-		checkInit();
-
-		Self out(m_data.get_allocator());
-		out.m_data.resize(m_data.size() + strSize - 1);
-
-		std::memcpy(&out.m_data[0], &m_data[0], 
-			(m_data.size() - 1) * sizeof(Char));
-		std::memcpy(&out.m_data[m_data.size() - 1], str, 
-			strSize * sizeof(Char));
-
-		return out;
-	}
+	/// Append to this string.
+	ANKI_USE_RESULT Error appendInternal(
+		Allocator alloc, const Char* str, PtrSize strSize);
 };
 
-template<typename TAlloc>
-inline StringBase<TAlloc> operator+(
-	const CString& left, const StringBase<TAlloc>& right)
-{
-	StringBase<TAlloc> out(right.getAllocator());
-
-	auto leftLength = left.getLength();
-	out.resize(leftLength + right.getLength());
-
-	std::memcpy(&out[0], &left[0], leftLength);
-	std::memcpy(&out[leftLength], &right[0], right.getLength() + 1);
-
-	return out;
-}
-
 /// A common string type that uses heap allocator.
 using String = StringBase<HeapAllocator<char>>;
 
@@ -730,4 +557,6 @@ using String = StringBase<HeapAllocator<char>>;
 
 } // end namespace anki
 
+#include "anki/util/String.inl.h"
+
 #endif

+ 140 - 0
include/anki/util/String.inl.h

@@ -0,0 +1,140 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+namespace anki {
+
+//==============================================================================
+template<typename TAlloc>
+Error StringBase<TAlloc>::create(Allocator alloc, const CStringType& cstr)
+{
+	auto size = cstr.getLength() + 1;
+	Error err = m_data.create(alloc, size);
+
+	if(!err)
+	{
+		std::memcpy(&m_data[0], cstr.get(), sizeof(Char) * size);
+	}
+
+	return err;
+}
+
+//==============================================================================
+template<typename TAlloc>
+Error StringBase<TAlloc>::create(
+	Allocator alloc, ConstIterator first, ConstIterator last)
+{
+	ANKI_ASSERT(first != 0 && last != 0);
+	auto length = last - first;
+	Error err = m_data.create(alloc, length + 1);
+
+	if(!err)
+	{
+		std::memcpy(&m_data[0], first, length);
+		m_data[length] = '\0';
+	}
+
+	return err;
+}
+
+//==============================================================================
+template<typename TAlloc>
+Error StringBase<TAlloc>::appendInternal(
+	Allocator alloc, const Char* str, PtrSize strSize)
+{
+	ANKI_ASSERT(str != nullptr);
+	ANKI_ASSERT(strSize > 1);
+
+	auto size = m_data.getSize();
+
+	// Fix empty string
+	if(size == 0)
+	{
+		size = 1;
+	}
+
+	DArray<Char, Allocator> newData;	
+	Error err = newData.create(alloc, size + strSize - 1);
+
+	if(!err)
+	{
+		std::memcpy(&newData[0], &m_data[0], sizeof(Char) * size);
+		std::memcpy(&newData[size - 1], str, sizeof(Char) * strSize);
+
+		m_data.destroy(alloc);
+		m_data = std::move(newData);
+	}
+
+	return err;
+}
+
+//==============================================================================
+template<typename TAlloc>
+Error StringBase<TAlloc>::sprintf(Allocator alloc, CString fmt, ...)
+{
+	Error err = ErrorCode::NONE;
+	Array<Char, 512> buffer;
+	va_list args;
+
+	va_start(args, fmt);
+	I len = std::vsnprintf(&buffer[0], sizeof(buffer), &fmt[0], args);
+	va_end(args);
+
+	if(len < 0)
+	{
+		ANKI_LOGE("vsnprintf() failed");
+		err = ErrorCode::FUNCTION_FAILED;
+	}
+	else if(static_cast<PtrSize>(len) >= sizeof(buffer))
+	{
+		I size = len + 1;
+		err = m_data.create(alloc, size);
+
+		if(!err)
+		{
+			va_start(args, fmt);
+			len = std::vsnprintf(&m_data[0], size, &fmt[0], args);
+			va_end(args);
+
+			(void)len;
+			ANKI_ASSERT((len + 1) == size);
+		}
+	}
+	else
+	{
+		// buffer was enough
+		err = create(alloc, CString(&buffer[0]));
+	}
+
+	return err;
+}
+
+//==============================================================================
+template<typename TAlloc>
+template<typename TNumber>
+Error StringBase<TAlloc>::toString(Allocator alloc, TNumber number, Self& out)
+{
+	Error err = ErrorCode::NONE;
+
+	destroy(alloc);
+
+	Array<Char, 512> buff;
+	I ret = std::snprintf(
+		&buff[0], buff.size(), detail::toStringFormat<TNumber>(), number);
+
+	if(ret < 0 || ret > static_cast<I>(buff.size()))
+	{
+		ANKI_LOGE("To small intermediate buffer");
+		err = ErrorCode::FUNCTION_FAILED;
+	}
+	else
+	{
+		err = create(alloc, &buff[0]);
+	}
+
+	return err;
+}
+
+} // end namespace anki
+

+ 15 - 5
src/util/Filesystem.cpp

@@ -8,19 +8,29 @@
 namespace anki {
 
 //==============================================================================
-String getFileExtension(const CString& filename, HeapAllocator<U8>& alloc)
+Error getFileExtension(
+	const CString& filename, HeapAllocator<U8>& alloc, String& out)
 {
+	Error err = ErrorCode::NONE;
 	const char* pc = std::strrchr(&filename[0], '.');
 
+	out.destroy(alloc);
+
 	if(pc == nullptr)
 	{
-		return String();
+		// Do nothing
+	}
+	else
+	{
+		++pc;
+		if(*pc != '\0')
+		{
+			err = out.create(alloc, CString(pc));
+		}
 	}
 
-	++pc;
-	return (*pc == '\0') ? String() : String(CString(pc), alloc);
+	return err;
 }
 
 } // end namespace anki
 
-

+ 23 - 11
src/util/FilesystemPosix.cpp

@@ -4,7 +4,6 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/util/File.h"
-#include "anki/util/Exception.h"
 #include "anki/util/Assert.h"
 #include <cstring>
 #include <sys/stat.h>
@@ -48,7 +47,7 @@ Bool directoryExists(const CString& filename)
 }
 
 //==============================================================================
-void removeDirectory(const CString& dirname)
+Error removeDirectory(const CString& dirname)
 {
 	DIR* dir;
 	struct dirent* entry;
@@ -56,13 +55,15 @@ void removeDirectory(const CString& dirname)
 
 	if(path == nullptr) 
 	{
-		throw ANKI_EXCEPTION("Out of memory error");
+		ANKI_LOGE("Out of memory error");
+		return ErrorCode::FUNCTION_FAILED;
 	}
 
 	dir = opendir(dirname.get());
 	if(dir == nullptr) 
 	{
-		throw ANKI_EXCEPTION("opendir() failed");
+		ANKI_LOGE("opendir() failed");
+		return ErrorCode::FUNCTION_FAILED;
 	}
 
 	while((entry = readdir(dir)) != nullptr) 
@@ -74,7 +75,11 @@ void removeDirectory(const CString& dirname)
 
 			if(entry->d_type == DT_DIR) 
 			{
-				removeDirectory(CString(path));
+				Error err = removeDirectory(CString(path));
+				if(err)
+				{
+					return err;
+				}
 			}
 			else
 			{
@@ -86,32 +91,39 @@ void removeDirectory(const CString& dirname)
 
 	closedir(dir);
 	remove(dirname.get());
+
+	return ErrorCode::NONE;
 }
 
 //==============================================================================
-void createDirectory(const CString& dir)
+Error createDirectory(const CString& dir)
 {
 	if(directoryExists(dir))
 	{
-		return;
+		return ErrorCode::NONE;
 	}
 
+	Error err = ErrorCode::NONE;
 	if(mkdir(dir.get(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH))
 	{
-		throw ANKI_EXCEPTION("%s : %s", strerror(errno), dir.get());
+		ANKI_LOGE("%s : %s", strerror(errno), dir.get());
+		err = ErrorCode::FUNCTION_FAILED;
 	}
+
+	return err;
 }
 
 //==============================================================================
-String getHomeDirectory(HeapAllocator<U8>& alloc)
+Error getHomeDirectory(HeapAllocator<U8>& alloc, String& out)
 {
 	const char* home = getenv("HOME");
 	if(home == nullptr)
 	{
-		throw ANKI_EXCEPTION("HOME environment variable not set");
+		ANKI_LOGE("HOME environment variable not set");
+		return ErrorCode::FUNCTION_FAILED;
 	}
 
-	return String(CString(home), alloc);
+	return out.create(alloc, home);
 }
 
 } // end namespace anki

+ 6 - 0
src/util/Logger.cpp

@@ -94,6 +94,8 @@ void Logger::defaultSystemMessageHandler(void*, const Info& info)
 		out = stderr;
 		terminalColor = "\033[0;31m";
 		break;
+	default:
+		ANKI_ASSERT(0);
 	}
 
 	fprintf(out, "%s(%s:%d %s) %s: %s\033[0m\n", terminalColor, info.m_file,
@@ -116,6 +118,8 @@ void Logger::defaultSystemMessageHandler(void*, const Info& info)
 	case Logger::MessageType::FATAL:
 		andMsgType = ANDROID_LOG_ERROR;
 		break;
+	default:
+		ANKI_ASSERT(0);
 	}
 
 	std::stringstream ss;
@@ -139,6 +143,8 @@ void Logger::defaultSystemMessageHandler(void*, const Info& info)
 	case Logger::MessageType::FATAL:
 		out = stderr;
 		break;
+	default:
+		ANKI_ASSERT(0);
 	}
 
 	fprintf(out, "(%s:%d %s) %s: %s\n", info.m_file,