1 // Copyright (c) 2004 Daniel Wallin and Arvid Norberg 2 3 // Permission is hereby granted, free of charge, to any person obtaining a 4 // copy of this software and associated documentation files (the "Software"), 5 // to deal in the Software without restriction, including without limitation 6 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 // and/or sell copies of the Software, and to permit persons to whom the 8 // Software is furnished to do so, subject to the following conditions: 9 10 // The above copyright notice and this permission notice shall be included 11 // in all copies or substantial portions of the Software. 12 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 14 // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 15 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 17 // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 18 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 21 // OR OTHER DEALINGS IN THE SOFTWARE. 22 23 #define LUABIND_BUILDING 24 25 #include <luabind/class.hpp> 26 #include <luabind/config.hpp> 27 #include <luabind/nil.hpp> 28 29 #include <boost/foreach.hpp> 30 #include <luabind/lua_include.hpp> 31 32 #include <cstring> 33 #include <iostream> 34 35 namespace luabind 36 { 37 LUABIND_API detail::nil_type nil; 38 } 39 40 namespace luabind { namespace detail { 41 42 43 namespace 44 { 45 struct cast_entry 46 { cast_entryluabind::detail::__anonb3de662a0111::cast_entry47 cast_entry(class_id src_, class_id target_, cast_function cast_) 48 : src(src_) 49 , target(target_) 50 , cast(cast_) 51 {} 52 53 class_id src; 54 class_id target; 55 cast_function cast; 56 }; 57 58 } // namespace unnamed 59 60 struct class_registration : registration 61 { 62 class_registration(char const* name); 63 64 void register_(lua_State* L) const; 65 66 const char* m_name; 67 68 mutable std::map<const char*, int, detail::ltstr> m_static_constants; 69 70 mutable std::vector<type_id> m_bases; 71 72 type_id m_type; 73 class_id m_id; 74 class_id m_wrapper_id; 75 type_id m_wrapper_type; 76 std::vector<cast_entry> m_casts; 77 78 scope m_scope; 79 scope m_members; 80 scope m_default_members; 81 }; 82 class_registration(char const * name)83 class_registration::class_registration(char const* name) 84 { 85 m_name = name; 86 } 87 register_(lua_State * L) const88 void class_registration::register_(lua_State* L) const 89 { 90 LUABIND_CHECK_STACK(L); 91 92 assert(lua_type(L, -1) == LUA_TTABLE); 93 94 if (m_name != 0) { 95 lua_pushstring(L, m_name); 96 } 97 98 detail::class_rep* crep; 99 100 detail::class_registry* r = detail::class_registry::get_registry(L); 101 // create a class_rep structure for this class. 102 // allocate it within lua to let lua collect it on 103 // lua_close(). This is better than allocating it 104 // as a static, since it will then be destructed 105 // when the program exits instead. 106 // warning: we assume that lua will not 107 // move the userdata memory. 108 lua_newuserdata(L, sizeof(detail::class_rep)); 109 crep = reinterpret_cast<detail::class_rep*>(lua_touserdata(L, -1)); 110 111 new(crep) detail::class_rep( 112 m_type 113 , m_name 114 , L 115 ); 116 117 // register this new type in the class registry 118 r->add_class(m_type, crep); 119 120 lua_rawgetp(L, LUA_REGISTRYINDEX, &class_map_tag); 121 class_map& classes = *static_cast<class_map*>( 122 lua_touserdata(L, -1)); 123 lua_pop(L, 1); 124 125 classes.put(m_id, crep); 126 127 bool const has_wrapper = m_wrapper_id != registered_class<null_type>::id; 128 129 if (has_wrapper) 130 classes.put(m_wrapper_id, crep); 131 132 crep->m_static_constants.swap(m_static_constants); 133 134 detail::class_registry* registry = detail::class_registry::get_registry(L); 135 136 crep->get_default_table(L); 137 m_scope.register_(L); 138 m_default_members.register_(L); 139 lua_pop(L, 1); 140 141 crep->get_table(L); 142 m_members.register_(L); 143 lua_pop(L, 1); 144 145 lua_rawgetp(L, LUA_REGISTRYINDEX, &cast_graph_tag); 146 cast_graph* const casts = static_cast<cast_graph*>( 147 lua_touserdata(L, -1)); 148 lua_pop(L, 1); 149 150 lua_rawgetp(L, LUA_REGISTRYINDEX, &classid_map_tag); 151 class_id_map* const class_ids = static_cast<class_id_map*>( 152 lua_touserdata(L, -1)); 153 lua_pop(L, 1); 154 155 class_ids->put(m_id, m_type); 156 157 if (has_wrapper) 158 class_ids->put(m_wrapper_id, m_wrapper_type); 159 160 BOOST_FOREACH(cast_entry const& e, m_casts) 161 { 162 casts->insert(e.src, e.target, e.cast); 163 } 164 165 for (std::vector<type_id>::iterator i = m_bases.begin(); 166 i != m_bases.end(); ++i) 167 { 168 LUABIND_CHECK_STACK(L); 169 170 // the baseclass' class_rep structure 171 detail::class_rep* bcrep = registry->find_class(*i); 172 173 crep->add_base_class(bcrep); 174 175 // copy base class table 176 crep->get_table(L); 177 bcrep->get_table(L); 178 lua_pushnil(L); 179 180 while (lua_next(L, -2)) 181 { 182 lua_pushvalue(L, -2); // copy key 183 lua_gettable(L, -5); 184 185 if (!lua_isnil(L, -1)) 186 { 187 lua_pop(L, 2); 188 continue; 189 } 190 191 lua_pop(L, 1); 192 lua_pushvalue(L, -2); // copy key 193 lua_insert(L, -2); 194 195 lua_settable(L, -5); 196 } 197 lua_pop(L, 2); 198 199 // copy base class detaults table 200 crep->get_default_table(L); 201 bcrep->get_default_table(L); 202 lua_pushnil(L); 203 204 while (lua_next(L, -2)) 205 { 206 lua_pushvalue(L, -2); // copy key 207 lua_gettable(L, -5); 208 209 if (!lua_isnil(L, -1)) 210 { 211 lua_pop(L, 2); 212 continue; 213 } 214 215 lua_pop(L, 1); 216 lua_pushvalue(L, -2); // copy key 217 lua_insert(L, -2); 218 219 lua_settable(L, -5); 220 } 221 lua_pop(L, 2); 222 223 } 224 225 if (m_name != 0) { 226 lua_settable(L, -3); 227 } 228 else { 229 lua_pop(L, 1); 230 } 231 } 232 233 // -- interface --------------------------------------------------------- 234 class_base(char const * name_)235 class_base::class_base(char const* name_) 236 #ifdef LUABIND_USE_CXX11 237 : scope(std::unique_ptr<registration>( 238 #else 239 : scope(std::auto_ptr<registration>( 240 #endif 241 m_registration = new class_registration(name_)) 242 ) 243 { 244 } 245 init(type_id const & type_id_,class_id id,type_id const & wrapper_type,class_id wrapper_id)246 void class_base::init( 247 type_id const& type_id_, class_id id 248 , type_id const& wrapper_type, class_id wrapper_id) 249 { 250 m_registration->m_type = type_id_; 251 m_registration->m_id = id; 252 m_registration->m_wrapper_type = wrapper_type; 253 m_registration->m_wrapper_id = wrapper_id; 254 } 255 add_base(type_id const & base)256 void class_base::add_base(type_id const& base) 257 { 258 m_registration->m_bases.push_back(base); 259 } 260 add_member(registration * member)261 void class_base::add_member(registration* member) 262 { 263 #ifdef LUABIND_USE_CXX11 264 std::unique_ptr<registration> ptr(member); 265 m_registration->m_members.operator,(scope(std::move(ptr))); 266 #else 267 std::auto_ptr<registration> ptr(member); 268 m_registration->m_members.operator,(scope(ptr)); 269 #endif 270 } 271 add_default_member(registration * member)272 void class_base::add_default_member(registration* member) 273 { 274 #ifdef LUABIND_USE_CXX11 275 std::unique_ptr<registration> ptr(member); 276 m_registration->m_default_members.operator,(scope(std::move(ptr))); 277 #else 278 std::auto_ptr<registration> ptr(member); 279 m_registration->m_default_members.operator,(scope(ptr)); 280 #endif 281 } 282 name() const283 const char* class_base::name() const 284 { 285 return m_registration->m_name; 286 } 287 add_static_constant(const char * name_,int val)288 void class_base::add_static_constant(const char* name_, int val) 289 { 290 m_registration->m_static_constants[name_] = val; 291 } 292 add_inner_scope(scope & s)293 void class_base::add_inner_scope(scope& s) 294 { 295 m_registration->m_scope.operator,(s); 296 } 297 add_cast(class_id src,class_id target,cast_function cast)298 void class_base::add_cast( 299 class_id src, class_id target, cast_function cast) 300 { 301 m_registration->m_casts.push_back(cast_entry(src, target, cast)); 302 } 303 304 get_class_name(lua_State * L,type_id const & i)305 std::string get_class_name(lua_State* L, type_id const& i) 306 { 307 std::string ret; 308 309 assert(L); 310 311 class_registry* r = class_registry::get_registry(L); 312 class_rep* crep = r->find_class(i); 313 314 if (!crep || !crep->name()) 315 { 316 ret = crep ? "unnamed [" : "custom ["; 317 ret += i.name(); 318 ret += ']'; 319 } 320 else 321 { 322 /* TODO reimplement this? 323 if (i == crep->holder_type()) 324 { 325 ret += "smart_ptr<"; 326 ret += crep->name(); 327 ret += ">"; 328 } 329 else if (i == crep->const_holder_type()) 330 { 331 ret += "smart_ptr<const "; 332 ret += crep->name(); 333 ret += ">"; 334 } 335 else*/ 336 { 337 ret += crep->name(); 338 } 339 } 340 return ret; 341 } 342 343 }} // namespace luabind::detail 344