object_rep.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. // Copyright (c) 2003 Daniel Wallin and Arvid Norberg
  2. // Permission is hereby granted, free of charge, to any person obtaining a
  3. // copy of this software and associated documentation files (the "Software"),
  4. // to deal in the Software without restriction, including without limitation
  5. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  6. // and/or sell copies of the Software, and to permit persons to whom the
  7. // Software is furnished to do so, subject to the following conditions:
  8. // The above copyright notice and this permission notice shall be included
  9. // in all copies or substantial portions of the Software.
  10. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
  11. // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  12. // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  13. // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
  14. // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  15. // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  16. // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
  18. // OR OTHER DEALINGS IN THE SOFTWARE.
  19. #define LUABIND_BUILDING
  20. #include <luabind/detail/object_rep.hpp>
  21. #include <luabind/detail/class_rep.hpp>
  22. namespace luabind { namespace detail
  23. {
  24. // dest is a function that is called to delete the c++ object this struct holds
  25. object_rep::object_rep(instance_holder* instance, class_rep* crep)
  26. : m_instance(instance)
  27. , m_classrep(crep)
  28. , m_dependency_cnt(0)
  29. {}
  30. object_rep::~object_rep()
  31. {
  32. if (!m_instance)
  33. return;
  34. m_instance->~instance_holder();
  35. deallocate(m_instance);
  36. }
  37. void object_rep::add_dependency(lua_State* L, int index)
  38. {
  39. assert(m_dependency_cnt < sizeof(object_rep));
  40. void* key = (char*)this + m_dependency_cnt;
  41. lua_pushlightuserdata(L, key);
  42. lua_pushvalue(L, index);
  43. lua_rawset(L, LUA_REGISTRYINDEX);
  44. ++m_dependency_cnt;
  45. }
  46. void object_rep::release_dependency_refs(lua_State* L)
  47. {
  48. for (std::size_t i = 0; i < m_dependency_cnt; ++i)
  49. {
  50. void* key = (char*)this + i;
  51. lua_pushlightuserdata(L, key);
  52. lua_pushnil(L);
  53. lua_rawset(L, LUA_REGISTRYINDEX);
  54. }
  55. }
  56. int destroy_instance(lua_State* L)
  57. {
  58. object_rep* instance = static_cast<object_rep*>(lua_touserdata(L, 1));
  59. lua_pushstring(L, "__finalize");
  60. lua_gettable(L, 1);
  61. if (lua_isnil(L, -1))
  62. {
  63. lua_pop(L, 1);
  64. }
  65. else
  66. {
  67. lua_pushvalue(L, 1);
  68. lua_call(L, 1, 0);
  69. }
  70. instance->release_dependency_refs(L);
  71. instance->~object_rep();
  72. return 0;
  73. }
  74. namespace
  75. {
  76. int set_instance_value(lua_State* L)
  77. {
  78. lua_getfenv(L, 1);
  79. lua_pushvalue(L, 2);
  80. lua_rawget(L, -2);
  81. if (lua_isnil(L, -1) && lua_getmetatable(L, -2))
  82. {
  83. lua_pushvalue(L, 2);
  84. lua_rawget(L, -2);
  85. lua_replace(L, -3);
  86. lua_pop(L, 1);
  87. }
  88. if (lua_tocfunction(L, -1) == &property_tag)
  89. {
  90. // this member is a property, extract the "set" function and call it.
  91. lua_getupvalue(L, -1, 2);
  92. if (lua_isnil(L, -1))
  93. {
  94. lua_pushfstring(L, "property '%s' is read only", lua_tostring(L, 2));
  95. lua_error(L);
  96. }
  97. lua_pushvalue(L, 1);
  98. lua_pushvalue(L, 3);
  99. lua_call(L, 2, 0);
  100. return 0;
  101. }
  102. lua_pop(L, 1);
  103. if (!lua_getmetatable(L, 4))
  104. {
  105. lua_newtable(L);
  106. lua_pushvalue(L, -1);
  107. lua_setfenv(L, 1);
  108. lua_pushvalue(L, 4);
  109. lua_setmetatable(L, -2);
  110. }
  111. else
  112. {
  113. lua_pop(L, 1);
  114. }
  115. lua_pushvalue(L, 2);
  116. lua_pushvalue(L, 3);
  117. lua_rawset(L, -3);
  118. return 0;
  119. }
  120. int get_instance_value(lua_State* L)
  121. {
  122. lua_getfenv(L, 1);
  123. lua_pushvalue(L, 2);
  124. lua_rawget(L, -2);
  125. if (lua_isnil(L, -1) && lua_getmetatable(L, -2))
  126. {
  127. lua_pushvalue(L, 2);
  128. lua_rawget(L, -2);
  129. }
  130. if (lua_tocfunction(L, -1) == &property_tag)
  131. {
  132. // this member is a property, extract the "get" function and call it.
  133. lua_getupvalue(L, -1, 1);
  134. lua_pushvalue(L, 1);
  135. lua_call(L, 1, 1);
  136. }
  137. return 1;
  138. }
  139. int dispatch_operator(lua_State* L)
  140. {
  141. for (int i = 0; i < 2; ++i)
  142. {
  143. if (get_instance(L, 1 + i))
  144. {
  145. int nargs = lua_gettop(L);
  146. lua_pushvalue(L, lua_upvalueindex(1));
  147. lua_gettable(L, 1 + i);
  148. if (lua_isnil(L, -1))
  149. {
  150. lua_pop(L, 1);
  151. continue;
  152. }
  153. lua_insert(L, 1); // move the function to the bottom
  154. nargs = lua_toboolean(L, lua_upvalueindex(2)) ? 1 : nargs;
  155. if (lua_toboolean(L, lua_upvalueindex(2))) // remove trailing nil
  156. lua_remove(L, 3);
  157. lua_call(L, nargs, 1);
  158. return 1;
  159. }
  160. }
  161. lua_pop(L, lua_gettop(L));
  162. lua_pushstring(L, "No such operator defined");
  163. lua_error(L);
  164. return 0;
  165. }
  166. } // namespace unnamed
  167. LUABIND_API void push_instance_metatable(lua_State* L)
  168. {
  169. lua_newtable(L);
  170. // This is used as a tag to determine if a userdata is a luabind
  171. // instance. We use a numeric key and a cclosure for fast comparision.
  172. lua_pushnumber(L, 1);
  173. lua_pushcclosure(L, get_instance_value, 0);
  174. lua_rawset(L, -3);
  175. lua_pushcclosure(L, destroy_instance, 0);
  176. lua_setfield(L, -2, "__gc");
  177. lua_pushcclosure(L, get_instance_value, 0);
  178. lua_setfield(L, -2, "__index");
  179. lua_pushcclosure(L, set_instance_value, 0);
  180. lua_setfield(L, -2, "__newindex");
  181. for (int op = 0; op < number_of_operators; ++op)
  182. {
  183. lua_pushstring(L, get_operator_name(op));
  184. lua_pushvalue(L, -1);
  185. lua_pushboolean(L, op == op_unm || op == op_len);
  186. lua_pushcclosure(L, &dispatch_operator, 2);
  187. lua_settable(L, -3);
  188. }
  189. }
  190. LUABIND_API object_rep* get_instance(lua_State* L, int index)
  191. {
  192. object_rep* result = static_cast<object_rep*>(lua_touserdata(L, index));
  193. if (!result || !lua_getmetatable(L, index))
  194. return 0;
  195. lua_rawgeti(L, -1, 1);
  196. if (lua_tocfunction(L, -1) != &get_instance_value)
  197. result = 0;
  198. lua_pop(L, 2);
  199. return result;
  200. }
  201. LUABIND_API object_rep* push_new_instance(lua_State* L, class_rep* cls)
  202. {
  203. void* storage = lua_newuserdata(L, sizeof(object_rep));
  204. object_rep* result = new (storage) object_rep(0, cls);
  205. cls->get_table(L);
  206. lua_setfenv(L, -2);
  207. lua_rawgeti(L, LUA_REGISTRYINDEX, cls->metatable_ref());
  208. lua_setmetatable(L, -2);
  209. return result;
  210. }
  211. }}