From 98d92d3e1f5e9969d1c9f6781380d37c0a35ea19 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Mon, 15 Jul 2013 11:53:24 +0200 Subject: [PATCH] Add support for "flat" tables to Variant. This means you can now use Variants (used by Channels and love.event, for instance) to send tables as long as they only contain keys and values supported by Variant, AND they are not tables themselves. --- src/common/Variant.cpp | 72 +++++++++++++++++++++++++++++++++++++++++- src/common/Variant.h | 9 ++++-- 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/src/common/Variant.cpp b/src/common/Variant.cpp index f2b1b6144..38cfcd0fa 100644 --- a/src/common/Variant.cpp +++ b/src/common/Variant.cpp @@ -42,6 +42,18 @@ love::Type extractudatatype(lua_State *L, int idx) return t; } +static inline void delete_table(std::vector > *table) +{ + while (!table->empty()) + { + std::pair &kv = table->back(); + kv.first->release(); + kv.second->release(); + table->pop_back(); + } + delete table; +} + Variant::Variant() : type(NIL) , data() @@ -97,6 +109,13 @@ Variant::Variant(love::Type udatatype, void *userdata) data.userdata = userdata; } +// Variant gets ownership of the vector. +Variant::Variant(std::vector > *table) + : type(TABLE) +{ + data.table = table; +} + Variant::~Variant() { switch (type) @@ -107,16 +126,21 @@ Variant::~Variant() case FUSERDATA: ((love::Object *) data.userdata)->release(); break; + case TABLE: + delete_table(data.table); default: break; } } -Variant *Variant::fromLua(lua_State *L, int n) +Variant *Variant::fromLua(lua_State *L, int n, bool allowTables) { Variant *v = NULL; size_t len; const char *str; + if (n < 0) // Fix the stack position, we might modify it later + n += lua_gettop(L) + 1; + switch (lua_type(L, n)) { case LUA_TBOOLEAN: @@ -138,6 +162,42 @@ Variant *Variant::fromLua(lua_State *L, int n) case LUA_TNIL: v = new Variant(); break; + case LUA_TTABLE: + if (allowTables) + { + bool success = true; + std::vector > *table = new std::vector >(); + lua_pushnil(L); + while (lua_next(L, n)) + { + Variant *key = fromLua(L, -2, false); + if (!key) + { + success = false; + lua_pop(L, 2); + break; + } + + Variant *value = fromLua(L, -1, false); + if (!value) + { + delete key; + success = false; + lua_pop(L, 2); + break; + } + + table->push_back(std::make_pair(key, value)); + + lua_pop(L, 1); + } + + if (success) + v = new Variant(table); + else + delete_table(table); + } + break; } return v; } @@ -175,6 +235,16 @@ void Variant::toLua(lua_State *L) // sadly, however, it's the most // I can do (at the moment). break; + case TABLE: + lua_newtable(L); + for (int i = 0; i < data.table->size(); ++i) + { + std::pair &kv = data.table->at(i); + kv.first->toLua(L); + kv.second->toLua(L); + lua_settable(L, -3); + } + break; case NIL: default: lua_pushnil(L); diff --git a/src/common/Variant.h b/src/common/Variant.h index 8f5dfa4e7..e75c676de 100644 --- a/src/common/Variant.h +++ b/src/common/Variant.h @@ -25,6 +25,8 @@ #include "common/Object.h" #include +#include +#include namespace love { @@ -40,9 +42,10 @@ public: Variant(char c); Variant(void *userdata); Variant(love::Type udatatype, void *userdata); + Variant(std::vector > *table); virtual ~Variant(); - static Variant *fromLua(lua_State *L, int n); + static Variant *fromLua(lua_State *L, int n, bool allowTables = true); void toLua(lua_State *L); private: @@ -55,7 +58,8 @@ private: STRING, LUSERDATA, FUSERDATA, - NIL + NIL, + TABLE } type; union { @@ -68,6 +72,7 @@ private: size_t len; } string; void *userdata; + std::vector > *table; } data; love::Type udatatype; bits flags;