Variant.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /**
  2. * Copyright (c) 2006-2021 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. #include <memory>
  21. #include "Variant.h"
  22. #include "common/StringMap.h"
  23. namespace love
  24. {
  25. static Proxy *tryextractproxy(lua_State *L, int idx)
  26. {
  27. Proxy *u = (Proxy *)lua_touserdata(L, idx);
  28. if (u == nullptr || u->type == nullptr)
  29. return nullptr;
  30. // We could get rid of the dynamic_cast for more performance, but it would
  31. // be less safe...
  32. if (dynamic_cast<Object *>(u->object) != nullptr)
  33. return u;
  34. return nullptr;
  35. }
  36. Variant::Variant()
  37. : type(NIL)
  38. {
  39. }
  40. Variant::Variant(bool boolean)
  41. : type(BOOLEAN)
  42. {
  43. data.boolean = boolean;
  44. }
  45. Variant::Variant(double number)
  46. : type(NUMBER)
  47. {
  48. data.number = number;
  49. }
  50. Variant::Variant(const char *str, size_t len)
  51. {
  52. if (len <= MAX_SMALL_STRING_LENGTH)
  53. {
  54. type = SMALLSTRING;
  55. memcpy(data.smallstring.str, str, len);
  56. data.smallstring.len = (uint8) len;
  57. }
  58. else
  59. {
  60. type = STRING;
  61. data.string = new SharedString(str, len);
  62. }
  63. }
  64. Variant::Variant(const std::string &str)
  65. : Variant(str.c_str(), str.length())
  66. {
  67. }
  68. Variant::Variant(void *lightuserdata)
  69. : type(LUSERDATA)
  70. {
  71. data.userdata = lightuserdata;
  72. }
  73. Variant::Variant(love::Type *lovetype, love::Object *object)
  74. : type(LOVEOBJECT)
  75. {
  76. data.objectproxy.type = lovetype;
  77. data.objectproxy.object = object;
  78. if (data.objectproxy.object != nullptr)
  79. data.objectproxy.object->retain();
  80. }
  81. // Variant gets ownership of the vector.
  82. Variant::Variant(std::vector<std::pair<Variant, Variant>> *table)
  83. : type(TABLE)
  84. {
  85. data.table = new SharedTable(table);
  86. }
  87. Variant::Variant(const Variant &v)
  88. : type(v.type)
  89. , data(v.data)
  90. {
  91. if (type == STRING)
  92. data.string->retain();
  93. else if (type == LOVEOBJECT && data.objectproxy.object != nullptr)
  94. data.objectproxy.object->retain();
  95. else if (type == TABLE)
  96. data.table->retain();
  97. }
  98. Variant::Variant(Variant &&v)
  99. : type(std::move(v.type))
  100. , data(std::move(v.data))
  101. {
  102. v.type = NIL;
  103. }
  104. Variant::~Variant()
  105. {
  106. if (type == STRING)
  107. data.string->release();
  108. else if (type == LOVEOBJECT && data.objectproxy.object != nullptr)
  109. data.objectproxy.object->release();
  110. else if (type == TABLE)
  111. data.table->release();
  112. }
  113. Variant &Variant::operator = (const Variant &v)
  114. {
  115. if (v.type == STRING)
  116. v.data.string->retain();
  117. else if (v.type == LOVEOBJECT && v.data.objectproxy.object != nullptr)
  118. v.data.objectproxy.object->retain();
  119. else if (v.type == TABLE)
  120. v.data.table->retain();
  121. if (type == STRING)
  122. data.string->release();
  123. else if (type == LOVEOBJECT && data.objectproxy.object != nullptr)
  124. data.objectproxy.object->release();
  125. else if (type == TABLE)
  126. data.table->release();
  127. type = v.type;
  128. data = v.data;
  129. return *this;
  130. }
  131. Variant Variant::fromLua(lua_State *L, int n, std::set<const void*> *tableSet)
  132. {
  133. size_t len;
  134. const char *str;
  135. Proxy *p = nullptr;
  136. if (n < 0) // Fix the stack position, we might modify it later
  137. n += lua_gettop(L) + 1;
  138. switch (lua_type(L, n))
  139. {
  140. case LUA_TBOOLEAN:
  141. return Variant(luax_toboolean(L, n));
  142. case LUA_TNUMBER:
  143. return Variant(lua_tonumber(L, n));
  144. case LUA_TSTRING:
  145. str = lua_tolstring(L, n, &len);
  146. return Variant(str, len);
  147. case LUA_TLIGHTUSERDATA:
  148. return Variant(lua_touserdata(L, n));
  149. case LUA_TUSERDATA:
  150. p = tryextractproxy(L, n);
  151. if (p != nullptr)
  152. return Variant(p->type, p->object);
  153. else
  154. {
  155. luax_typerror(L, n, "love type");
  156. return Variant();
  157. }
  158. case LUA_TNIL:
  159. return Variant();
  160. case LUA_TTABLE:
  161. {
  162. bool success = true;
  163. std::set<const void *> topTableSet;
  164. std::vector<std::pair<Variant, Variant>> *table = new std::vector<std::pair<Variant, Variant>>();
  165. // We can use a pointer to a stack-allocated variable because it's
  166. // never used after the stack-allocated variable is destroyed.
  167. if (tableSet == nullptr)
  168. tableSet = &topTableSet;
  169. // Now make sure this table wasn't already serialised
  170. const void *tablePointer = lua_topointer(L, n);
  171. {
  172. auto result = tableSet->insert(tablePointer);
  173. if (!result.second) // insertion failed
  174. throw love::Exception("Cycle detected in table");
  175. }
  176. size_t len = luax_objlen(L, -1);
  177. if (len > 0)
  178. table->reserve(len);
  179. lua_pushnil(L);
  180. while (lua_next(L, n))
  181. {
  182. table->emplace_back(fromLua(L, -2, tableSet), fromLua(L, -1, tableSet));
  183. lua_pop(L, 1);
  184. const auto &p = table->back();
  185. if (p.first.getType() == UNKNOWN || p.second.getType() == UNKNOWN)
  186. {
  187. success = false;
  188. break;
  189. }
  190. }
  191. // And remove the table from the set again
  192. tableSet->erase(tablePointer);
  193. if (success)
  194. return Variant(table);
  195. else
  196. delete table;
  197. }
  198. break;
  199. }
  200. Variant v;
  201. v.type = UNKNOWN;
  202. return v;
  203. }
  204. void Variant::toLua(lua_State *L) const
  205. {
  206. switch (type)
  207. {
  208. case BOOLEAN:
  209. lua_pushboolean(L, data.boolean);
  210. break;
  211. case NUMBER:
  212. lua_pushnumber(L, data.number);
  213. break;
  214. case STRING:
  215. lua_pushlstring(L, data.string->str, data.string->len);
  216. break;
  217. case SMALLSTRING:
  218. lua_pushlstring(L, data.smallstring.str, data.smallstring.len);
  219. break;
  220. case LUSERDATA:
  221. lua_pushlightuserdata(L, data.userdata);
  222. break;
  223. case LOVEOBJECT:
  224. luax_pushtype(L, *data.objectproxy.type, data.objectproxy.object);
  225. break;
  226. case TABLE:
  227. {
  228. std::vector<std::pair<Variant, Variant>> *table = data.table->table;
  229. int tsize = (int) table->size();
  230. lua_createtable(L, 0, tsize);
  231. for (int i = 0; i < tsize; ++i)
  232. {
  233. std::pair<Variant, Variant> &kv = (*table)[i];
  234. kv.first.toLua(L);
  235. kv.second.toLua(L);
  236. lua_settable(L, -3);
  237. }
  238. break;
  239. }
  240. case NIL:
  241. default:
  242. lua_pushnil(L);
  243. break;
  244. }
  245. }
  246. } // love