Commits

Igor Baidiuk  committed 0941b1b

Moved some constructors to private domain; also moved Variant string to use refcounted array. Preparing to make Variant on-stack placeable and of significantly smaller size

  • Participants
  • Parent commits 3ac8574

Comments (0)

Files changed (2)

File src/common/Variant.cpp

 #include "Variant.h"
 #include <common/StringMap.h>
 #include <vector>
+#include <memory>
 
 namespace love
 {
+	template<class T>
+	class RefArray
+	{
+	public:
+		static RefArray* create(size_t size)
+		{
+			if (!size)
+				return NULL;
+			RefArray* newArray = allocate(size);
+			// Initialize all elements with default constructor
+			for (T *i = newArray->begin(), *end = newArray->end(); i != end; ++i)
+				new (i) T();
+
+			return newArray;
+		}
+
+		static RefArray* create(size_t size, T value)
+		{
+			if (!size)
+				return NULL;
+			RefArray* newArray = allocate(size);
+			// Initialize all elements with specified value constructor
+			for (T *i = newArray->begin(), *end = newArray->end(); i != end; ++i)
+				new (i) T(value);
+
+			return newArray;
+		}
+
+		static RefArray* create(size_t size, T* values)
+		{
+			if (!size)
+				return NULL;
+			RefArray* newArray = allocate(size);
+			// Initialize all elements with values from array
+			for (T *i = newArray->begin(), *end = newArray->end(); i != end; ++i, ++values)
+				new (i) T(*values);
+
+			return newArray;
+		}
+
+		static RefArray* create(size_t size, const T* values)
+		{
+			if (!size)
+				return NULL;
+			RefArray* newArray = allocate(size);
+			// Initialize all elements with values from array
+			for (T *i = newArray->begin(), *end = newArray->end(); i != end; ++i, ++values)
+				new (i) T(*values);
+
+			return newArray;
+		}
+		// Increment reference count for this array
+		void retain()
+		{
+			++refcount;
+		}
+		// Decrement reference count, and self-deallocate if it reached zero
+		void release()
+		{
+			if (!refcount || !(--refcount))
+			{
+				for (T *i = begin(), *e = end(); i != e; ++i)
+					i->~T();
+				this->~RefArray();
+				delete[] ((char*)this);
+			}
+		}
+
+		size_t size() const
+		{
+			return dataSize;
+		}
+
+		T* begin()
+		{
+			return (T*)(this + 1);
+		}
+
+		const T* begin() const
+		{
+			return (const T*)(this + 1);
+		}
+
+		T* end()
+		{
+			return (T*)(this + 1) + dataSize;
+		}
+
+		const T* end() const
+		{
+			return (const T*)(this + 1) + dataSize;
+		}
+
+	private:
+		RefArray();
+		RefArray(const RefArray&);
+		void operator = (const RefArray&);
+
+		// Construct contiguous chunk for array and its elements
+		static RefArray* allocate(size_t size)
+		{
+			char* memchunk = new char[sizeof(RefArray) + sizeof(T) * size];
+			return new(memchunk) RefArray(size);
+		}
+
+		RefArray(size_t newSize)
+			: refcount(1)
+			, dataSize(newSize)
+		{ }
+
+		~RefArray()
+		{ }
+
+		size_t refcount;
+		size_t dataSize;
+	};
+
+	typedef RefArray<char>    RefString;
+
 	extern StringMap<Type, TYPE_MAX_ENUM> types;
 
 	love::Type extractudatatype(lua_State * L, int idx)
 	Variant::Variant(const char *string, size_t len)
 	{
 		type = STRING;
-		char *buf = new char[len+1];
-		memset(buf, 0, len+1);
-		memcpy(buf, string, len);
-		data.string.str = buf;
-		data.string.len = len;
+		if (!string || !len)
+			data.string = NULL;
+		else
+		{
+			RefString* str = RefString::create(len + 1, string);
+			*(str->end() - 1) = 0;
+			data.string = str;
+		}
 	}
 
 	Variant::Variant(char c)
 		switch(type)
 		{
 			case STRING:
-				delete[] data.string.str;
+				if (data.string)
+					((RefString*)data.string)->release();
 				break;
 			case FUSERDATA:
 				((love::Object *) data.userdata)->release();
 		}
 	}
 
-	static VariantPtr getVariant(lua_State *L, int n)
+	VariantPtr Variant::getVariant(lua_State *L, int n)
 	{
 		size_t len = 0;
 		const char *str = 0;
 				str = lua_tolstring(L, n, &len);
 				return VariantPtr::make(str, len);
 			case LUA_TLIGHTUSERDATA:
-				return VariantPtr::make(lua_touserdata(L, n));
+				return new Variant(lua_touserdata(L, n));
 			case LUA_TUSERDATA:
-				return VariantPtr::make(extractudatatype(L, n), lua_touserdata(L, n));
+				return new Variant(extractudatatype(L, n), lua_touserdata(L, n));
 			case LUA_TTABLE:
 				{
 					lua_checkstack(L, 4);
 							pairs.push_back(pair);
 						lua_pop(L, 1);
 					}
-					return VariantPtr::make(&pairs.front(), pairs.size());
+					return new Variant(&pairs.front(), pairs.size());
 				}
 		}
 		return VariantPtr();
 					items.push_back(v);
 			}
 
-			return VariantPtr::make(&items.front(), items.size()).detach();
+			return new Variant(&items.front(), items.size());
 		}
 		else
 			return getVariant(L, n_from).detach();
 				lua_pushnumber(L, data.number);
 				break;
 			case STRING:
-				lua_pushlstring(L, data.string.str, data.string.len);
+				if (data.string)
+				{
+					RefString* str = (RefString*)data.string;
+					lua_pushlstring(L, str->begin(), str->size() - 1);
+				}
+				else
+					lua_pushlstring(L, "", 0);
 				break;
 			case LUSERDATA:
 				lua_pushlightuserdata(L, data.userdata);
 			printf("Character '%c'\n", data.character);
 			break;
 		case STRING:
-			printf("String '%.*s'\n", data.string.len, data.string.str);
+			if (data.string)
+			{
+				RefString* str = (RefString*)data.string;
+				printf("String '%.*s'\n", str->size() - 1, str->begin());
+			}
+			else
+				printf("String ''\n");
 			break;
 		case LUSERDATA:
 			printf("Light userdata at %p\n", data.userdata);

File src/common/Variant.h

 {
 	class Variant : public love::Object
 	{
-	public:
+	private:
 		struct Pair
 		{
 			Ptr<Variant> key;
 			Ptr<Variant> value;
 		};
-	private:
+
 		enum Type
 		{
 			UNKNOWN = 0,
 			bool boolean;
 			char character;
 			double number;
-			struct {
-				const char *str;
-				size_t len;
-			} string;
+			void *string;
 			void *userdata;
 			struct {
 				Ptr<Variant>* array;
 		love::Type udatatype;
 		bits flags;
 
-	public:
-		
+		Variant(void *userdata);
+		Variant(love::Type udatatype, void *userdata);
+		Variant(Ptr<Variant>* tuple, size_t size);
+		Variant(Pair* table, size_t size);
+
+		static Ptr<Variant> getVariant(lua_State* L, int n);
+
+	public:		
 		Variant(bool boolean);
 		Variant(double number);
 		Variant(const char *string, size_t len);
 		Variant(char c);
-		Variant(void *userdata);
-		Variant(love::Type udatatype, void *userdata);
-		Variant(Ptr<Variant>* tuple, size_t size);
-		Variant(Pair* table, size_t size);
+
+		Variant(const Variant& other);
+		Variant& operator = (const Variant& other);
 
 		virtual ~Variant();