Browse Source

Fix an the wrong line reporting in shader compilation failures. Refactor StringList a bit

Panagiotis Christopoulos Charitos 9 năm trước cách đây
mục cha
commit
f4591934a5

+ 29 - 16
include/anki/util/StringList.h

@@ -21,6 +21,7 @@ class StringList : public List<String>
 public:
 	using Char = char; ///< Char type
 	using Base = List<String>; ///< Base
+	using Allocator = GenericMemoryPoolAllocator<Char>;
 
 	/// Sort method for sortAll().
 	enum class Sort
@@ -32,13 +33,11 @@ public:
 	// Use the base constructors
 	using Base::Base;
 
-	template<typename TAllocator>
-	void destroy(TAllocator alloc);
+	void destroy(Allocator alloc);
 
 	/// Join all the elements into a single big string using a the
 	/// seperator @a separator
-	template<typename TAllocator>
-	void join(TAllocator alloc, const CString& separator, String& out) const;
+	void join(Allocator alloc, const CString& separator, String& out) const;
 
 	/// Returns the index position of the last occurrence of @a value in
 	/// the list
@@ -48,14 +47,23 @@ public:
 	/// Sort the string list
 	void sortAll(const Sort method = Sort::ASCENDING);
 
-	/// Push at the end of the list a formated string
-	template<typename TAllocator, typename... TArgs>
-	void pushBackSprintf(TAllocator alloc, const TArgs&... args);
+	/// Push at the end of the list a formated string.
+	template<typename... TArgs>
+	void pushBackSprintf(Allocator alloc, const TArgs&... args)
+	{
+		String str;
+		str.sprintf(alloc, args...);
+
+		Base::emplaceBack(alloc);
+		Base::getBack() = std::move(str);
+	}
 
 	/// Split a string using a separator (@a separator) and return these
 	/// strings in a string list
-	template<typename TAllocator>
-	void splitString(TAllocator alloc, const CString& s, const Char separator);
+	void splitString(Allocator alloc,
+		const CString& s,
+		const Char separator,
+		Bool keepEmpty = false);
 };
 
 /// String list with automatic destruction.
@@ -63,10 +71,10 @@ class StringListAuto : public StringList
 {
 public:
 	using Base = StringList;
+	using Allocator = typename Base::Allocator;
 
 	/// Create using an allocator.
-	template<typename TAllocator>
-	StringListAuto(TAllocator alloc)
+	StringListAuto(Allocator alloc)
 		: Base()
 		, m_alloc(alloc)
 	{
@@ -91,6 +99,12 @@ public:
 		return *this;
 	}
 
+	/// Destroy.
+	void destroy()
+	{
+		Base::destroy(m_alloc);
+	}
+
 	/// Push at the end of the list a formated string
 	template<typename... TArgs>
 	void pushBackSprintf(const TArgs&... args)
@@ -100,13 +114,14 @@ public:
 
 	/// Split a string using a separator (@a separator) and return these
 	/// strings in a string list
-	void splitString(const CString& s, const Base::Char separator)
+	void splitString(
+		const CString& s, const Base::Char separator, Bool keepEmpty = false)
 	{
-		Base::splitString(m_alloc, s, separator);
+		Base::splitString(m_alloc, s, separator, keepEmpty);
 	}
 
 private:
-	GenericMemoryPoolAllocator<Char> m_alloc;
+	Allocator m_alloc;
 
 	void move(StringListAuto& b)
 	{
@@ -117,5 +132,3 @@ private:
 /// @}
 
 } // end namespace anki
-
-#include <anki/util/StringList.inl.h>

+ 0 - 125
include/anki/util/StringList.inl.h

@@ -1,125 +0,0 @@
-// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <anki/util/StringList.h>
-#include <cstring>
-
-namespace anki
-{
-
-//==============================================================================
-template<typename TAllocator>
-inline void StringList::destroy(TAllocator alloc)
-{
-	auto it = Base::getBegin();
-	auto endit = Base::getEnd();
-	for(; it != endit; ++it)
-	{
-		(*it).destroy(alloc);
-	}
-
-	Base::destroy(alloc);
-}
-
-//==============================================================================
-template<typename TAllocator>
-inline void StringList::join(
-	TAllocator alloc, const CString& separator, String& out) const
-{
-	if(Base::isEmpty())
-	{
-		return;
-	}
-
-	// Count the characters
-	const I sepLen = separator.getLength();
-	I charCount = 0;
-	for(const String& str : *this)
-	{
-		charCount += str.getLength() + sepLen;
-	}
-
-	charCount -= sepLen; // Remove last separator
-	ANKI_ASSERT(charCount > 0);
-
-	// Allocate
-	out.create(alloc, '?', charCount);
-
-	// Append to output
-	Char* to = &out[0];
-	typename Base::ConstIterator it = Base::getBegin();
-	for(; it != Base::getEnd(); it++)
-	{
-		const String& from = *it;
-		std::memcpy(to, &from[0], from.getLength() * sizeof(Char));
-		to += from.getLength();
-
-		if(it != Base::end() - 1)
-		{
-			std::memcpy(to, &separator[0], sepLen * sizeof(Char));
-			to += sepLen;
-		}
-	}
-}
-
-//==============================================================================
-template<typename TAllocator>
-inline void StringList::splitString(
-	TAllocator alloc, const CString& s, const Char separator)
-{
-	ANKI_ASSERT(Base::isEmpty());
-
-	const Char* begin = &s[0];
-	const Char* end = begin;
-
-	while(1)
-	{
-		if(*end == '\0')
-		{
-			if(begin < end)
-			{
-				Base::emplaceBack(alloc);
-
-				String str;
-				str.create(alloc, begin, end);
-				Base::getBack() = std::move(str);
-			}
-
-			break;
-		}
-		else if(*end == separator)
-		{
-			if(begin < end)
-			{
-				Base::emplaceBack(alloc);
-
-				String str;
-				str.create(alloc, begin, end);
-
-				Base::getBack() = std::move(str);
-				begin = end + 1;
-			}
-			else
-			{
-				++begin;
-			}
-		}
-
-		++end;
-	}
-}
-
-//==============================================================================
-template<typename TAllocator, typename... TArgs>
-inline void StringList::pushBackSprintf(TAllocator alloc, const TArgs&... args)
-{
-	String str;
-	str.sprintf(alloc, args...);
-
-	Base::emplaceBack(alloc);
-	Base::getBack() = std::move(str);
-}
-
-} // end namespace anki

+ 11 - 2
src/gr/common/Misc.cpp

@@ -22,14 +22,23 @@ void logShaderErrorCode(const CString& error,
 	static const char* padding = "======================================="
 								 "=======================================";
 
-	lines.splitString(source, '\n');
+	lines.splitString(source, '\n', true);
 
 	I lineno = 0;
 	for(auto it = lines.getBegin(); it != lines.getEnd(); ++it)
 	{
+		++lineno;
 		StringAuto tmp(alloc);
 
-		tmp.sprintf("%4d: %s\n", ++lineno, &(*it)[0]);
+		if(!it->isEmpty())
+		{
+			tmp.sprintf("%4d: %s\n", lineno, &(*it)[0]);
+		}
+		else
+		{
+			tmp.sprintf("%4d:\n", lineno);
+		}
+
 		prettySrc.append(tmp);
 	}
 

+ 1 - 1
src/util/CMakeLists.txt

@@ -1,4 +1,4 @@
-set(ANKI_UTIL_SOURCES Assert.cpp Functions.cpp File.cpp Filesystem.cpp Memory.cpp System.cpp HighRezTimer.cpp ThreadPool.cpp ThreadHive.cpp Hash.cpp Logger.cpp String.cpp)
+set(ANKI_UTIL_SOURCES Assert.cpp Functions.cpp File.cpp Filesystem.cpp Memory.cpp System.cpp HighRezTimer.cpp ThreadPool.cpp ThreadHive.cpp Hash.cpp Logger.cpp String.cpp StringList.cpp)
 
 if(LINUX OR ANDROID OR MACOS)
 	set(ANKI_UTIL_SOURCES ${ANKI_UTIL_SOURCES} HighRezTimerPosix.cpp FilesystemPosix.cpp ThreadPosix.cpp)

+ 104 - 0
src/util/StringList.cpp

@@ -8,6 +8,110 @@
 namespace anki
 {
 
+//==============================================================================
+void StringList::destroy(Allocator alloc)
+{
+	auto it = Base::getBegin();
+	auto endit = Base::getEnd();
+	for(; it != endit; ++it)
+	{
+		(*it).destroy(alloc);
+	}
+
+	Base::destroy(alloc);
+}
+
+//==============================================================================
+void StringList::join(
+	Allocator alloc, const CString& separator, String& out) const
+{
+	if(Base::isEmpty())
+	{
+		return;
+	}
+
+	// Count the characters
+	const I sepLen = separator.getLength();
+	I charCount = 0;
+	for(const String& str : *this)
+	{
+		charCount += str.getLength() + sepLen;
+	}
+
+	charCount -= sepLen; // Remove last separator
+	ANKI_ASSERT(charCount > 0);
+
+	// Allocate
+	out.create(alloc, '?', charCount);
+
+	// Append to output
+	Char* to = &out[0];
+	typename Base::ConstIterator it = Base::getBegin();
+	for(; it != Base::getEnd(); it++)
+	{
+		const String& from = *it;
+		std::memcpy(to, &from[0], from.getLength() * sizeof(Char));
+		to += from.getLength();
+
+		if(it != Base::end() - 1)
+		{
+			std::memcpy(to, &separator[0], sepLen * sizeof(Char));
+			to += sepLen;
+		}
+	}
+}
+
+//==============================================================================
+void StringList::splitString(
+	Allocator alloc, const CString& s, const Char separator, Bool keepEmpty)
+{
+	ANKI_ASSERT(Base::isEmpty());
+
+	const Char* begin = &s[0];
+	const Char* end = begin;
+
+	while(1)
+	{
+		if(*end == '\0')
+		{
+			if(begin < end)
+			{
+				Base::emplaceBack(alloc);
+
+				String str;
+				str.create(alloc, begin, end);
+				Base::getBack() = std::move(str);
+			}
+
+			break;
+		}
+		else if(*end == separator)
+		{
+			if(begin < end)
+			{
+				Base::emplaceBack(alloc);
+
+				String str;
+				str.create(alloc, begin, end);
+
+				Base::getBack() = std::move(str);
+				begin = end + 1;
+			}
+			else
+			{
+				if(keepEmpty)
+				{
+					Base::emplaceBack(alloc);
+				}
+
+				++begin;
+			}
+		}
+
+		++end;
+	}
+}
+
 //==============================================================================
 void StringList::sortAll(const Sort method)
 {

+ 43 - 0
tests/util/StringList.cpp

@@ -0,0 +1,43 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "tests/framework/Framework.h"
+#include "anki/util/StringList.h"
+
+namespace anki
+{
+
+//==============================================================================
+ANKI_TEST(Util, StringList)
+{
+	HeapAllocator<U8> alloc(allocAligned, nullptr);
+
+	// Test splitString
+	{
+		CString toSplit = "foo\n\nboo\n";
+
+		StringListAuto list(alloc);
+		list.splitString(toSplit, '\n');
+
+		ANKI_TEST_EXPECT_EQ(list.getSize(), 2);
+		auto it = list.getBegin();
+		ANKI_TEST_EXPECT_EQ(*it, "foo");
+		++it;
+		ANKI_TEST_EXPECT_EQ(*it, "boo");
+
+		// Again
+		list.destroy();
+		list.splitString(toSplit, '\n', true);
+		ANKI_TEST_EXPECT_EQ(list.getSize(), 3);
+		it = list.getBegin();
+		ANKI_TEST_EXPECT_EQ(*it, "foo");
+		++it;
+		ANKI_TEST_EXPECT_EQ(it->isEmpty(), true);
+		++it;
+		ANKI_TEST_EXPECT_EQ(*it, "boo");
+	}
+}
+
+} // end namespace anki