1 // sol2 2 3 // The MIT License (MIT) 4 5 // Copyright (c) 2013-2018 Rapptz, ThePhD and contributors 6 7 // Permission is hereby granted, free of charge, to any person obtaining a copy of 8 // this software and associated documentation files (the "Software"), to deal in 9 // the Software without restriction, including without limitation the rights to 10 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 // the Software, and to permit persons to whom the Software is furnished to do so, 12 // subject to the following conditions: 13 14 // The above copyright notice and this permission notice shall be included in all 15 // copies or substantial portions of the Software. 16 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 #ifndef SOL_CONTAINER_USERTYPE_METATABLE_HPP 25 #define SOL_CONTAINER_USERTYPE_METATABLE_HPP 26 27 #include "stack.hpp" 28 #include "container_traits.hpp" 29 #include <unordered_map> 30 31 namespace sol { 32 33 template <typename X> 34 struct container_usertype_metatable { 35 typedef std::remove_pointer_t<meta::unqualified_t<X>> T; 36 typedef container_traits<T> traits; 37 typedef container_detail::container_traits_default<T> default_traits; 38 real_index_get_traitssol::container_usertype_metatable39 static int real_index_get_traits(std::true_type, lua_State* L) { 40 return traits::index_get(L); 41 } 42 real_index_get_traitssol::container_usertype_metatable43 static int real_index_get_traits(std::false_type, lua_State* L) { 44 return default_traits::index_get(L); 45 } 46 real_index_callsol::container_usertype_metatable47 static int real_index_call(lua_State* L) { 48 typedef usertype_detail::map_t<std::string, lua_CFunction> call_map; 49 static const call_map calls{ 50 { "at", &at_call }, 51 { "get", &real_get_call }, 52 { "set", &real_set_call }, 53 { "size", &real_length_call }, 54 { "add", &real_add_call }, 55 { "empty", &real_empty_call }, 56 { "insert", &real_insert_call }, 57 { "clear", &real_clear_call }, 58 { "find", &real_find_call }, 59 { "erase", &real_erase_call }, 60 { "pairs", &pairs_call }, 61 { "next", &next_call }, 62 }; 63 auto maybenameview = stack::unqualified_check_get<string_view>(L, 2); 64 if (maybenameview) { 65 const string_view& nameview = *maybenameview; 66 #if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH 67 auto it = calls.find(nameview, string_view_hash(), std::equal_to<string_view>()); 68 #else 69 std::string name(nameview.data(), nameview.size()); 70 auto it = calls.find(name); 71 #endif 72 if (it != calls.cend()) { 73 return stack::push(L, it->second); 74 } 75 } 76 return real_index_get_traits(container_detail::has_traits_index_get<traits>(), L); 77 } 78 real_at_traitssol::container_usertype_metatable79 static int real_at_traits(std::true_type, lua_State* L) { 80 return traits::at(L); 81 } 82 real_at_traitssol::container_usertype_metatable83 static int real_at_traits(std::false_type, lua_State* L) { 84 return default_traits::at(L); 85 } 86 real_at_callsol::container_usertype_metatable87 static int real_at_call(lua_State* L) { 88 return real_at_traits(container_detail::has_traits_at<traits>(), L); 89 } 90 real_get_traitssol::container_usertype_metatable91 static int real_get_traits(std::true_type, lua_State* L) { 92 return traits::get(L); 93 } 94 real_get_traitssol::container_usertype_metatable95 static int real_get_traits(std::false_type, lua_State* L) { 96 return default_traits::get(L); 97 } 98 real_get_callsol::container_usertype_metatable99 static int real_get_call(lua_State* L) { 100 return real_get_traits(container_detail::has_traits_get<traits>(), L); 101 } 102 real_set_traitssol::container_usertype_metatable103 static int real_set_traits(std::true_type, lua_State* L) { 104 return traits::set(L); 105 } 106 real_set_traitssol::container_usertype_metatable107 static int real_set_traits(std::false_type, lua_State* L) { 108 return default_traits::set(L); 109 } 110 real_set_callsol::container_usertype_metatable111 static int real_set_call(lua_State* L) { 112 return real_set_traits(container_detail::has_traits_set<traits>(), L); 113 } 114 real_index_set_traitssol::container_usertype_metatable115 static int real_index_set_traits(std::true_type, lua_State* L) { 116 return traits::index_set(L); 117 } 118 real_index_set_traitssol::container_usertype_metatable119 static int real_index_set_traits(std::false_type, lua_State* L) { 120 return default_traits::index_set(L); 121 } 122 real_new_index_callsol::container_usertype_metatable123 static int real_new_index_call(lua_State* L) { 124 return real_index_set_traits(container_detail::has_traits_index_set<traits>(), L); 125 } 126 real_pairs_traitssol::container_usertype_metatable127 static int real_pairs_traits(std::true_type, lua_State* L) { 128 return traits::pairs(L); 129 } 130 real_pairs_traitssol::container_usertype_metatable131 static int real_pairs_traits(std::false_type, lua_State* L) { 132 return default_traits::pairs(L); 133 } 134 real_pairs_callsol::container_usertype_metatable135 static int real_pairs_call(lua_State* L) { 136 return real_pairs_traits(container_detail::has_traits_pairs<traits>(), L); 137 } 138 real_ipairs_traitssol::container_usertype_metatable139 static int real_ipairs_traits(std::true_type, lua_State* L) { 140 return traits::ipairs(L); 141 } 142 real_ipairs_traitssol::container_usertype_metatable143 static int real_ipairs_traits(std::false_type, lua_State* L) { 144 return default_traits::ipairs(L); 145 } 146 real_ipairs_callsol::container_usertype_metatable147 static int real_ipairs_call(lua_State* L) { 148 return real_ipairs_traits(container_detail::has_traits_ipairs<traits>(), L); 149 } 150 real_next_traitssol::container_usertype_metatable151 static int real_next_traits(std::true_type, lua_State* L) { 152 return traits::next(L); 153 } 154 real_next_traitssol::container_usertype_metatable155 static int real_next_traits(std::false_type, lua_State* L) { 156 return default_traits::next(L); 157 } 158 real_next_callsol::container_usertype_metatable159 static int real_next_call(lua_State* L) { 160 return real_next_traits(container_detail::has_traits_next<traits>(), L); 161 } 162 real_size_traitssol::container_usertype_metatable163 static int real_size_traits(std::true_type, lua_State* L) { 164 return traits::size(L); 165 } 166 real_size_traitssol::container_usertype_metatable167 static int real_size_traits(std::false_type, lua_State* L) { 168 return default_traits::size(L); 169 } 170 real_length_callsol::container_usertype_metatable171 static int real_length_call(lua_State* L) { 172 return real_size_traits(container_detail::has_traits_size<traits>(), L); 173 } 174 real_add_traitssol::container_usertype_metatable175 static int real_add_traits(std::true_type, lua_State* L) { 176 return traits::add(L); 177 } 178 real_add_traitssol::container_usertype_metatable179 static int real_add_traits(std::false_type, lua_State* L) { 180 return default_traits::add(L); 181 } 182 real_add_callsol::container_usertype_metatable183 static int real_add_call(lua_State* L) { 184 return real_add_traits(container_detail::has_traits_add<traits>(), L); 185 } 186 real_insert_traitssol::container_usertype_metatable187 static int real_insert_traits(std::true_type, lua_State* L) { 188 return traits::insert(L); 189 } 190 real_insert_traitssol::container_usertype_metatable191 static int real_insert_traits(std::false_type, lua_State* L) { 192 return default_traits::insert(L); 193 } 194 real_insert_callsol::container_usertype_metatable195 static int real_insert_call(lua_State* L) { 196 return real_insert_traits(container_detail::has_traits_insert<traits>(), L); 197 } 198 real_clear_traitssol::container_usertype_metatable199 static int real_clear_traits(std::true_type, lua_State* L) { 200 return traits::clear(L); 201 } 202 real_clear_traitssol::container_usertype_metatable203 static int real_clear_traits(std::false_type, lua_State* L) { 204 return default_traits::clear(L); 205 } 206 real_clear_callsol::container_usertype_metatable207 static int real_clear_call(lua_State* L) { 208 return real_clear_traits(container_detail::has_traits_clear<traits>(), L); 209 } 210 real_empty_traitssol::container_usertype_metatable211 static int real_empty_traits(std::true_type, lua_State* L) { 212 return traits::empty(L); 213 } 214 real_empty_traitssol::container_usertype_metatable215 static int real_empty_traits(std::false_type, lua_State* L) { 216 return default_traits::empty(L); 217 } 218 real_empty_callsol::container_usertype_metatable219 static int real_empty_call(lua_State* L) { 220 return real_empty_traits(container_detail::has_traits_empty<traits>(), L); 221 } 222 real_erase_traitssol::container_usertype_metatable223 static int real_erase_traits(std::true_type, lua_State* L) { 224 return traits::erase(L); 225 } 226 real_erase_traitssol::container_usertype_metatable227 static int real_erase_traits(std::false_type, lua_State* L) { 228 return default_traits::erase(L); 229 } 230 real_erase_callsol::container_usertype_metatable231 static int real_erase_call(lua_State* L) { 232 return real_erase_traits(container_detail::has_traits_erase<traits>(), L); 233 } 234 real_find_traitssol::container_usertype_metatable235 static int real_find_traits(std::true_type, lua_State* L) { 236 return traits::find(L); 237 } 238 real_find_traitssol::container_usertype_metatable239 static int real_find_traits(std::false_type, lua_State* L) { 240 return default_traits::find(L); 241 } 242 real_find_callsol::container_usertype_metatable243 static int real_find_call(lua_State* L) { 244 return real_find_traits(container_detail::has_traits_find<traits>(), L); 245 } 246 add_callsol::container_usertype_metatable247 static int add_call(lua_State* L) { 248 return detail::typed_static_trampoline<decltype(&real_add_call), (&real_add_call)>(L); 249 } 250 erase_callsol::container_usertype_metatable251 static int erase_call(lua_State* L) { 252 return detail::typed_static_trampoline<decltype(&real_erase_call), (&real_erase_call)>(L); 253 } 254 insert_callsol::container_usertype_metatable255 static int insert_call(lua_State* L) { 256 return detail::typed_static_trampoline<decltype(&real_insert_call), (&real_insert_call)>(L); 257 } 258 clear_callsol::container_usertype_metatable259 static int clear_call(lua_State* L) { 260 return detail::typed_static_trampoline<decltype(&real_clear_call), (&real_clear_call)>(L); 261 } 262 empty_callsol::container_usertype_metatable263 static int empty_call(lua_State* L) { 264 return detail::typed_static_trampoline<decltype(&real_empty_call), (&real_empty_call)>(L); 265 } 266 find_callsol::container_usertype_metatable267 static int find_call(lua_State* L) { 268 return detail::typed_static_trampoline<decltype(&real_find_call), (&real_find_call)>(L); 269 } 270 length_callsol::container_usertype_metatable271 static int length_call(lua_State* L) { 272 return detail::typed_static_trampoline<decltype(&real_length_call), (&real_length_call)>(L); 273 } 274 pairs_callsol::container_usertype_metatable275 static int pairs_call(lua_State* L) { 276 return detail::typed_static_trampoline<decltype(&real_pairs_call), (&real_pairs_call)>(L); 277 } 278 ipairs_callsol::container_usertype_metatable279 static int ipairs_call(lua_State* L) { 280 return detail::typed_static_trampoline<decltype(&real_ipairs_call), (&real_ipairs_call)>(L); 281 } 282 next_callsol::container_usertype_metatable283 static int next_call(lua_State* L) { 284 return detail::typed_static_trampoline<decltype(&real_next_call), (&real_next_call)>(L); 285 } 286 at_callsol::container_usertype_metatable287 static int at_call(lua_State* L) { 288 return detail::typed_static_trampoline<decltype(&real_at_call), (&real_at_call)>(L); 289 } 290 get_callsol::container_usertype_metatable291 static int get_call(lua_State* L) { 292 return detail::typed_static_trampoline<decltype(&real_get_call), (&real_get_call)>(L); 293 } 294 set_callsol::container_usertype_metatable295 static int set_call(lua_State* L) { 296 return detail::typed_static_trampoline<decltype(&real_set_call), (&real_set_call)>(L); 297 } 298 index_callsol::container_usertype_metatable299 static int index_call(lua_State* L) { 300 return detail::typed_static_trampoline<decltype(&real_index_call), (&real_index_call)>(L); 301 } 302 new_index_callsol::container_usertype_metatable303 static int new_index_call(lua_State* L) { 304 return detail::typed_static_trampoline<decltype(&real_new_index_call), (&real_new_index_call)>(L); 305 } 306 }; 307 308 namespace stack { 309 namespace stack_detail { 310 template <typename T, bool is_shim = false> 311 struct metatable_setup { 312 lua_State* L; 313 metatable_setupsol::stack::stack_detail::metatable_setup314 metatable_setup(lua_State* L) 315 : L(L) { 316 } 317 operator ()sol::stack::stack_detail::metatable_setup318 void operator()() { 319 typedef container_usertype_metatable<std::conditional_t<is_shim, 320 as_container_t<std::remove_pointer_t<T>>, 321 std::remove_pointer_t<T>>> 322 meta_cumt; 323 static const char* metakey = is_shim ? &usertype_traits<as_container_t<std::remove_pointer_t<T>>>::metatable()[0] : &usertype_traits<T>::metatable()[0]; 324 static const std::array<luaL_Reg, 19> reg = { { 325 { "__pairs", &meta_cumt::pairs_call }, 326 { "__ipairs", &meta_cumt::ipairs_call }, 327 { "__len", &meta_cumt::length_call }, 328 { "__index", &meta_cumt::index_call }, 329 { "__newindex", &meta_cumt::new_index_call }, 330 { "pairs", &meta_cumt::pairs_call }, 331 { "next", &meta_cumt::next_call }, 332 { "at", &meta_cumt::at_call }, 333 { "get", &meta_cumt::get_call }, 334 { "set", &meta_cumt::set_call }, 335 { "size", &meta_cumt::length_call }, 336 { "empty", &meta_cumt::empty_call }, 337 { "clear", &meta_cumt::clear_call }, 338 { "insert", &meta_cumt::insert_call }, 339 { "add", &meta_cumt::add_call }, 340 { "find", &meta_cumt::find_call }, 341 { "erase", &meta_cumt::erase_call }, 342 std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destruct<T> }, 343 { nullptr, nullptr } 344 } }; 345 346 if (luaL_newmetatable(L, metakey) == 1) { 347 luaL_setfuncs(L, reg.data(), 0); 348 } 349 lua_setmetatable(L, -2); 350 } 351 }; 352 } // namespace stack_detail 353 354 template <typename T> 355 struct pusher<as_container_t<T>> { 356 typedef meta::unqualified_t<T> C; 357 push_lvaluesol::stack::pusher358 static int push_lvalue(std::true_type, lua_State* L, const C& cont) { 359 stack_detail::metatable_setup<C*, true> fx(L); 360 return pusher<detail::as_pointer_tag<const C>>{}.push_fx(L, fx, detail::ptr(cont)); 361 } 362 push_lvaluesol::stack::pusher363 static int push_lvalue(std::false_type, lua_State* L, const C& cont) { 364 stack_detail::metatable_setup<C, true> fx(L); 365 return pusher<detail::as_value_tag<C>>{}.push_fx(L, fx, cont); 366 } 367 push_rvaluesol::stack::pusher368 static int push_rvalue(std::true_type, lua_State* L, C&& cont) { 369 stack_detail::metatable_setup<C, true> fx(L); 370 return pusher<detail::as_value_tag<C>>{}.push_fx(L, fx, std::move(cont)); 371 } 372 push_rvaluesol::stack::pusher373 static int push_rvalue(std::false_type, lua_State* L, const C& cont) { 374 return push_lvalue(std::is_lvalue_reference<T>(), L, cont); 375 } 376 pushsol::stack::pusher377 static int push(lua_State* L, const as_container_t<T>& as_cont) { 378 return push_lvalue(std::is_lvalue_reference<T>(), L, as_cont.source); 379 } 380 pushsol::stack::pusher381 static int push(lua_State* L, as_container_t<T>&& as_cont) { 382 return push_rvalue(meta::all<std::is_rvalue_reference<T>, meta::neg<std::is_lvalue_reference<T>>>(), L, std::forward<T>(as_cont.source)); 383 } 384 }; 385 386 template <typename T> 387 struct pusher<as_container_t<T*>> { 388 typedef std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>> C; 389 pushsol::stack::pusher390 static int push(lua_State* L, T* cont) { 391 stack_detail::metatable_setup<C> fx(L); 392 return pusher<detail::as_pointer_tag<T>>{}.push_fx(L, fx, cont); 393 } 394 }; 395 396 template <typename T> 397 struct pusher<T, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<is_lua_reference<meta::unqualified_t<T>>>>::value>> { 398 typedef meta::unqualified_t<T> C; 399 pushsol::stack::pusher400 static int push(lua_State* L, const T& cont) { 401 stack_detail::metatable_setup<C> fx(L); 402 return pusher<detail::as_value_tag<T>>{}.push_fx(L, fx, cont); 403 } 404 pushsol::stack::pusher405 static int push(lua_State* L, T&& cont) { 406 stack_detail::metatable_setup<C> fx(L); 407 return pusher<detail::as_value_tag<T>>{}.push_fx(L, fx, std::move(cont)); 408 } 409 }; 410 411 template <typename T> 412 struct pusher<T*, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<is_lua_reference<meta::unqualified_t<T>>>>::value>> { 413 typedef std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>> C; 414 pushsol::stack::pusher415 static int push(lua_State* L, T* cont) { 416 stack_detail::metatable_setup<C> fx(L); 417 return pusher<detail::as_pointer_tag<T>>{}.push_fx(L, fx, cont); 418 } 419 }; 420 421 template <typename T, typename C> 422 struct checker<as_container_t<T>, type::userdata, C> { 423 template <typename Handler> checksol::stack::checker424 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 425 return stack::check<T>(L, index, std::forward<Handler>(handler), tracking); 426 } 427 }; 428 429 template <typename T> 430 struct getter<as_container_t<T>> { getsol::stack::getter431 static decltype(auto) get(lua_State* L, int index, record& tracking) { 432 return stack::unqualified_get<T>(L, index, tracking); 433 } 434 }; 435 436 template <typename T> 437 struct getter<as_container_t<T>*> { getsol::stack::getter438 static decltype(auto) get(lua_State* L, int index, record& tracking) { 439 return stack::unqualified_get<T*>(L, index, tracking); 440 } 441 }; 442 } // namespace stack 443 444 } // namespace sol 445 446 #endif // SOL_CONTAINER_USERTYPE_METATABLE_HPP 447