diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp deleted file mode 100644 index cc511cee..00000000 --- a/sol/usertype_metatable.hpp +++ /dev/null @@ -1,842 +0,0 @@ -// sol2 - -// The MIT License (MIT) - -// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors - -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef SOL_USERTYPE_METATABLE_HPP -#define SOL_USERTYPE_METATABLE_HPP - -#include "wrapper.hpp" -#include "call.hpp" -#include "stack.hpp" -#include "types.hpp" -#include "stack_reference.hpp" -#include "usertype_traits.hpp" -#include "inheritance.hpp" -#include "raii.hpp" -#include "deprecate.hpp" -#include "object.hpp" -#include "container_usertype_metatable.hpp" -#include "usertype_core.hpp" -#include -#include -#include -#include -#include - -namespace sol { - - struct usertype_metatable_core; - - namespace usertype_detail { - const int metatable_index = 2; - const int metatable_core_index = 3; - const int filler_index = 4; - const int magic_index = 5; - - const int simple_metatable_index = 2; - const int index_function_index = 3; - const int newindex_function_index = 4; - - typedef void (*base_walk)(lua_State*, bool&, int&, string_view&); - typedef int (*member_search)(lua_State*, void*, usertype_metatable_core&, int); - - struct call_information { - member_search index; - member_search new_index; - int runtime_target; - - call_information(member_search index, member_search newindex) - : call_information(index, newindex, -1) { - } - call_information(member_search index, member_search newindex, int runtimetarget) - : index(index), new_index(newindex), runtime_target(runtimetarget) { - } - }; - - typedef map_t mapping_t; - - struct variable_wrapper { - virtual int index(lua_State* L) = 0; - virtual int new_index(lua_State* L) = 0; - virtual ~variable_wrapper(){}; - }; - - template - struct callable_binding : variable_wrapper { - F fx; - - template - callable_binding(Arg&& arg) - : fx(std::forward(arg)) { - } - - virtual int index(lua_State* L) override { - return call_detail::call_wrapped(L, fx); - } - - virtual int new_index(lua_State* L) override { - return call_detail::call_wrapped(L, fx); - } - }; - - typedef map_t> variable_map; - typedef map_t function_map; - - struct simple_map { - const char* metakey; - variable_map variables; - function_map functions; - object index; - object newindex; - base_walk indexbaseclasspropogation; - base_walk newindexbaseclasspropogation; - - simple_map(const char* mkey, base_walk index, base_walk newindex, object i, object ni, variable_map&& vars, function_map&& funcs) - : metakey(mkey), variables(std::move(vars)), functions(std::move(funcs)), index(std::move(i)), newindex(std::move(ni)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) { - } - }; - } // namespace usertype_detail - - struct usertype_metatable_core { - usertype_detail::mapping_t mapping; - lua_CFunction indexfunc; - lua_CFunction newindexfunc; - std::vector runtime; - bool mustindex; - - usertype_metatable_core(lua_CFunction ifx, lua_CFunction nifx) - : mapping(), indexfunc(ifx), newindexfunc(nifx), runtime(), mustindex(false) { - } - - usertype_metatable_core(const usertype_metatable_core&) = default; - usertype_metatable_core(usertype_metatable_core&&) = default; - usertype_metatable_core& operator=(const usertype_metatable_core&) = default; - usertype_metatable_core& operator=(usertype_metatable_core&&) = default; - }; - - namespace usertype_detail { - const lua_Integer toplevel_magic = static_cast(0xCCC2CCC1); - - inline int is_indexer(string_view s) { - if (s == to_string(meta_function::index)) { - return 1; - } - else if (s == to_string(meta_function::new_index)) { - return 2; - } - return 0; - } - - inline int is_indexer(meta_function mf) { - if (mf == meta_function::index) { - return 1; - } - else if (mf == meta_function::new_index) { - return 2; - } - return 0; - } - - inline int is_indexer(call_construction) { - return 0; - } - - inline int is_indexer(base_classes_tag) { - return 0; - } - - inline auto make_string_view(string_view s) { - return s; - } - - inline auto make_string_view(call_construction) { - return string_view(to_string(meta_function::call_function)); - } - - inline auto make_string_view(meta_function mf) { - return string_view(to_string(mf)); - } - - inline auto make_string_view(base_classes_tag) { - return string_view(detail::base_class_cast_key()); - } - - template - inline std::string make_string(Arg&& arg) { - string_view s = make_string_view(arg); - return std::string(s.data(), s.size()); - } - - template - inline luaL_Reg make_reg(N&& n, lua_CFunction f) { - luaL_Reg l{make_string_view(std::forward(n)).data(), f}; - return l; - } - - struct registrar { - registrar() = default; - registrar(const registrar&) = default; - registrar(registrar&&) = default; - registrar& operator=(const registrar&) = default; - registrar& operator=(registrar&&) = default; - virtual int push_um(lua_State* L) = 0; - virtual ~registrar() { - } - }; - - inline bool is_toplevel(lua_State* L, int index = magic_index) { - int isnum = 0; - lua_Integer magic = lua_tointegerx(L, upvalue_index(index), &isnum); - return isnum != 0 && magic == toplevel_magic; - } - - inline int runtime_object_call(lua_State* L, void*, usertype_metatable_core& umc, int runtimetarget) { - std::vector& runtime = umc.runtime; - object& runtimeobj = runtime[runtimetarget]; - return stack::push(L, runtimeobj); - } - - template - inline int indexing_fail(lua_State* L) { - if (is_index) { -#if 0 //defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE - auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); - string_view accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); - return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data()); -#else - if (is_toplevel(L)) { - if (lua_getmetatable(L, 1) == 1) { - int metatarget = lua_gettop(L); - stack::get_field(L, stack_reference(L, raw_index(2)), metatarget); - return 1; - } - } - // With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately... - return stack::push(L, lua_nil); -#endif - } - else { - auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); - string_view accessor = maybeaccessor.value_or(string_view("(unknown)")); - return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data()); - } - } - - int runtime_new_index(lua_State* L, void*, usertype_metatable_core&, int runtimetarget); - - template - inline int metatable_new_index(lua_State* L) { - if (is_toplevel(L)) { - auto non_indexable = [&L]() { - if (is_simple) { - simple_map& sm = stack::get>(L, upvalue_index(simple_metatable_index)); - function_map& functions = sm.functions; - optional maybeaccessor = stack::get>(L, 2); - if (!maybeaccessor) { - return; - } - string_view& accessor_view = maybeaccessor.value(); -#if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH - auto preexistingit = functions.find(accessor_view, string_view_hash(), std::equal_to()); -#else - std::string accessor(accessor_view.data(), accessor_view.size()); - auto preexistingit = functions.find(accessor); -#endif - if (preexistingit == functions.cend()) { -#if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH - std::string accessor(accessor_view.data(), accessor_view.size()); -#endif - functions.emplace_hint(preexistingit, std::move(accessor), object(L, 3)); - } - else { - preexistingit->second = object(L, 3); - } - return; - } - usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); - bool mustindex = umc.mustindex; - if (!mustindex) - return; - optional maybeaccessor = stack::get>(L, 2); - if (!maybeaccessor) { - return; - } - string_view& accessor_view = maybeaccessor.value(); - mapping_t& mapping = umc.mapping; - std::vector& runtime = umc.runtime; - int target = static_cast(runtime.size()); -#if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH - auto preexistingit = mapping.find(accessor_view, string_view_hash(), std::equal_to()); -#else - std::string accessor(accessor_view.data(), accessor_view.size()); - auto preexistingit = mapping.find(accessor); -#endif - if (preexistingit == mapping.cend()) { -#if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH - std::string accessor(accessor_view.data(), accessor_view.size()); -#endif - runtime.emplace_back(L, 3); - mapping.emplace_hint(mapping.cend(), std::move(accessor), call_information(&runtime_object_call, &runtime_new_index, target)); - } - else { - target = preexistingit->second.runtime_target; - runtime[target] = object(L, 3); - preexistingit->second = call_information(&runtime_object_call, &runtime_new_index, target); - } - }; - non_indexable(); - for (std::size_t i = 0; i < 4; lua_settop(L, 3), ++i) { - const char* metakey = nullptr; - switch (i) { - case 0: - metakey = &usertype_traits::metatable()[0]; - luaL_getmetatable(L, metakey); - break; - case 1: - metakey = &usertype_traits>::metatable()[0]; - luaL_getmetatable(L, metakey); - break; - case 2: - metakey = &usertype_traits::metatable()[0]; - luaL_getmetatable(L, metakey); - break; - case 3: - default: - metakey = &usertype_traits::user_metatable()[0]; - { - luaL_getmetatable(L, metakey); - lua_getmetatable(L, -1); - } - break; - } - int tableindex = lua_gettop(L); - if (type_of(L, tableindex) == type::lua_nil) { - continue; - } - stack::set_field(L, stack_reference(L, raw_index(2)), stack_reference(L, raw_index(3)), tableindex); - } - lua_settop(L, 0); - return 0; - } - return indexing_fail(L); - } - - inline int runtime_new_index(lua_State* L, void*, usertype_metatable_core& umc, int runtimetarget) { - std::vector& runtime = umc.runtime; - object& runtimeobj = runtime[runtimetarget]; - runtimeobj = object(L, 3); - return 0; - } - - template - static void walk_single_base(lua_State* L, bool& found, int& ret, string_view&) { - if (found) - return; - const char* metakey = &usertype_traits::metatable()[0]; - const char* gcmetakey = &usertype_traits::gc_table()[0]; - const char* basewalkkey = is_index ? detail::base_class_index_propogation_key() : detail::base_class_new_index_propogation_key(); - - luaL_getmetatable(L, metakey); - if (type_of(L, -1) == type::lua_nil) { - lua_pop(L, 1); - return; - } - - stack::get_field(L, basewalkkey); - if (type_of(L, -1) == type::lua_nil) { - lua_pop(L, 2); - return; - } - lua_CFunction basewalkfunc = stack::pop(L); - lua_pop(L, 1); - - stack::get_field(L, gcmetakey); - int value = basewalkfunc(L); - if (value > -1) { - found = true; - ret = value; - } - } - - template - static void walk_all_bases(lua_State* L, bool& found, int& ret, string_view& accessor) { - (void)L; - (void)found; - (void)ret; - (void)accessor; - (void)detail::swallow{0, (walk_single_base(L, found, ret, accessor), 0)...}; - } - } // namespace usertype_detail - - template - struct clean_type { - typedef std::conditional_t>::value, T&, std::decay_t> type; - }; - - template - using clean_type_t = typename clean_type::type; - - template - struct usertype_metatable : usertype_detail::registrar {}; - - template - struct usertype_metatable, Tn...> : usertype_metatable_core, usertype_detail::registrar { - typedef std::make_index_sequence indices; - typedef std::index_sequence half_indices; - typedef std::array regs_t; - typedef std::tuple RawTuple; - typedef std::tuple...> Tuple; - template - struct check_binding : is_variable_binding> {}; - Tuple functions; - lua_CFunction destructfunc; - lua_CFunction callconstructfunc; - lua_CFunction indexbase; - lua_CFunction newindexbase; - usertype_detail::base_walk indexbaseclasspropogation; - usertype_detail::base_walk newindexbaseclasspropogation; - void* baseclasscheck; - void* baseclasscast; - bool secondarymeta; - std::bitset<32> properties; - - template >> = meta::enabler> - lua_CFunction make_func() const { - return std::get(functions); - } - - template >> = meta::enabler> - lua_CFunction make_func() const { - const auto& name = std::get(functions); - return (usertype_detail::make_string_view(name) == "__newindex") ? &call : &call; - } - - static bool contains_variable() { - typedef meta::any...> has_variables; - return has_variables::value; - } - - bool contains_index() const { - bool idx = false; - (void)detail::swallow{0, ((idx |= (usertype_detail::is_indexer(std::get(functions)) != 0)), 0)...}; - return idx; - } - - int finish_regs(regs_t& l, int& index) { - auto prop_fx = [&](meta_function mf) { return !properties[static_cast(mf)]; }; - usertype_detail::insert_default_registrations(l, index, prop_fx); - if (destructfunc != nullptr) { - l[index] = luaL_Reg{to_string(meta_function::garbage_collect).c_str(), destructfunc}; - ++index; - } - return index; - } - - template - void make_regs(regs_t&, int&, call_construction, F&&) { - callconstructfunc = call; - secondarymeta = true; - } - - template - void make_regs(regs_t&, int&, base_classes_tag, bases) { - static_assert(!meta::any_same::value, "base classes cannot list the original class as part of the bases"); - if (sizeof...(Bases) < 1) { - return; - } - mustindex = true; - (void)detail::swallow{0, ((detail::has_derived::value = true), 0)...}; - - static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - baseclasscheck = (void*)&detail::inheritance::type_check; - baseclasscast = (void*)&detail::inheritance::type_cast; - indexbaseclasspropogation = usertype_detail::walk_all_bases; - newindexbaseclasspropogation = usertype_detail::walk_all_bases; - } - - template , base_classes_tag, call_construction>::value>> - void make_regs(regs_t& l, int& index, N&& n, F&&) { - if (is_variable_binding>::value) { - return; - } - luaL_Reg reg = usertype_detail::make_reg(std::forward(n), make_func()); - for (std::size_t i = 0; i < properties.size(); ++i) { - meta_function mf = static_cast(i); - const std::string& mfname = to_string(mf); - if (mfname == reg.name) { - switch (mf) { - case meta_function::construct: - if (properties[i]) { -#if !(defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS) - throw error("sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); -#else - assert(false && "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); -#endif - } - break; - case meta_function::garbage_collect: - if (destructfunc != nullptr) { -#if !(defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS) - throw error("sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); -#else - assert(false && "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); -#endif - } - destructfunc = reg.func; - return; - case meta_function::index: - indexfunc = reg.func; - mustindex = true; - properties.set(i); - return; - case meta_function::new_index: - newindexfunc = reg.func; - mustindex = true; - properties.set(i); - return; - default: - break; - } - properties.set(i); - break; - } - } - l[index] = reg; - ++index; - } - - template > - usertype_metatable(Args&&... args) - : usertype_metatable_core(&usertype_detail::indexing_fail, &usertype_detail::metatable_new_index), usertype_detail::registrar(), functions(std::forward(args)...), destructfunc(nullptr), callconstructfunc(nullptr), indexbase(&core_indexing_call), newindexbase(&core_indexing_call), indexbaseclasspropogation(usertype_detail::walk_all_bases), newindexbaseclasspropogation(usertype_detail::walk_all_bases), baseclasscheck(nullptr), baseclasscast(nullptr), secondarymeta(contains_variable()), properties() { - properties.reset(); - std::initializer_list ilist{{std::pair(usertype_detail::make_string(std::get(functions)), - usertype_detail::call_information(&usertype_metatable::real_find_call, - &usertype_metatable::real_find_call))}...}; - this->mapping.insert(ilist); - for (const auto& n : meta_function_names()) { - this->mapping.erase(n); - } - this->mustindex = contains_variable() || contains_index(); - } - - usertype_metatable(const usertype_metatable&) = default; - usertype_metatable(usertype_metatable&&) = default; - usertype_metatable& operator=(const usertype_metatable&) = default; - usertype_metatable& operator=(usertype_metatable&&) = default; - - template - static int real_find_call(lua_State* L, void* um, usertype_metatable_core&, int) { - auto& f = *static_cast(um); - if (is_variable_binding(f.functions))>::value) { - return real_call_with(L, f); - } - // set up upvalues - // for a chained call - int upvalues = 0; - upvalues += stack::push(L, nullptr); - upvalues += stack::push(L, light(f)); - auto cfunc = &call; - return stack::push(L, c_closure(cfunc, upvalues)); - } - - template - static int real_meta_call(lua_State* L, void* um, int) { - auto& f = *static_cast(um); - return is_index ? f.indexfunc(L) : f.newindexfunc(L); - } - - template - static int core_indexing_call(lua_State* L) { - usertype_metatable& f = toplevel - ? static_cast(stack::get>(L, upvalue_index(usertype_detail::metatable_index))) - : static_cast(stack::pop>(L)); - static const int keyidx = -2 + static_cast(is_index); - if (toplevel && stack::get(L, keyidx) != type::string) { - return is_index ? f.indexfunc(L) : f.newindexfunc(L); - } - int runtime_target = 0; - usertype_detail::member_search member = nullptr; - { -#if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH - string_view name = stack::get(L, keyidx); - auto memberit = f.mapping.find(name, string_view_hash(), std::equal_to()); -#else - std::string name = stack::get(L, keyidx); - auto memberit = f.mapping.find(name); -#endif - if (memberit != f.mapping.cend()) { - const usertype_detail::call_information& ci = memberit->second; - member = is_index ? ci.index : ci.new_index; - runtime_target = ci.runtime_target; - } - } - if (member != nullptr) { - return (member)(L, static_cast(&f), static_cast(f), runtime_target); - } - string_view accessor = stack::get(L, keyidx); - int ret = 0; - bool found = false; - // Otherwise, we need to do propagating calls through the bases - if (is_index) - f.indexbaseclasspropogation(L, found, ret, accessor); - else - f.newindexbaseclasspropogation(L, found, ret, accessor); - if (found) { - return ret; - } - if (is_meta_bound) { - return is_index ? usertype_detail::indexing_fail(L) : usertype_detail::metatable_new_index(L); - } - return toplevel ? (is_index ? f.indexfunc(L) : f.newindexfunc(L)) : -1; - } - - static int real_index_call(lua_State* L) { - return core_indexing_call(L); - } - - static int real_new_index_call(lua_State* L) { - return core_indexing_call(L); - } - - static int real_meta_index_call(lua_State* L) { - return core_indexing_call(L); - } - - static int real_meta_new_index_call(lua_State* L) { - return core_indexing_call(L); - } - - template - static int real_call(lua_State* L) { - usertype_metatable& f = stack::get>(L, upvalue_index(usertype_detail::metatable_index)); - return real_call_with(L, f); - } - - template - static int real_call_with(lua_State* L, usertype_metatable& um) { - typedef meta::unqualified_tuple_element_t K; - typedef meta::unqualified_tuple_element_t F; - static const int boost = !detail::is_non_factory_constructor::value - && std::is_same::value - ? 1 - : 0; - auto& f = std::get(um.functions); - return call_detail::call_wrapped(L, f); - } - - template - static int call(lua_State* L) { - return detail::typed_static_trampoline), (&real_call)>(L); - } - - template - static int call_with(lua_State* L) { - return detail::typed_static_trampoline), (&real_call_with)>(L); - } - - static int index_call(lua_State* L) { - return detail::typed_static_trampoline(L); - } - - static int new_index_call(lua_State* L) { - return detail::typed_static_trampoline(L); - } - - static int meta_index_call(lua_State* L) { - return detail::typed_static_trampoline(L); - } - - static int meta_new_index_call(lua_State* L) { - return detail::typed_static_trampoline(L); - } - - virtual int push_um(lua_State* L) override { - return stack::push(L, std::move(*this)); - } - - ~usertype_metatable() override { - } - }; - - namespace stack { - - template - struct pusher, Args...>> { - typedef usertype_metatable, Args...> umt_t; - typedef typename umt_t::regs_t regs_t; - - static umt_t& make_cleanup(lua_State* L, umt_t&& umx) { - // ensure some sort of uniqueness - static int uniqueness = 0; - std::string uniquegcmetakey = usertype_traits::user_gc_metatable(); - // std::to_string doesn't exist in android still, with NDK, so this bullshit - // is necessary - // thanks, Android :v - int appended = snprintf(nullptr, 0, "%d", uniqueness); - std::size_t insertionpoint = uniquegcmetakey.length() - 1; - uniquegcmetakey.append(appended, '\0'); - char* uniquetarget = &uniquegcmetakey[insertionpoint]; - snprintf(uniquetarget, uniquegcmetakey.length(), "%d", uniqueness); - ++uniqueness; - - const char* gcmetakey = &usertype_traits::gc_table()[0]; - // Make sure userdata's memory is properly in lua first, - // otherwise all the light userdata we make later will become invalid - stack::push>(L, metatable_key, uniquegcmetakey, std::move(umx)); - // Create the top level thing that will act as our deleter later on - stack_reference umt(L, -1); - stack::set_field(L, gcmetakey, umt); - umt.pop(); - - stack::get_field(L, gcmetakey); - umt_t& target_umt = stack::pop>(L); - return target_umt; - } - - static int push(lua_State* L, umt_t&& umx) { - - umt_t& um = make_cleanup(L, std::move(umx)); - usertype_metatable_core& umc = um; - regs_t value_table{{}}; - int lastreg = 0; - (void)detail::swallow{0, (um.template make_regs<(I * 2)>(value_table, lastreg, std::get<(I * 2)>(um.functions), std::get<(I * 2 + 1)>(um.functions)), 0)...}; - um.finish_regs(value_table, lastreg); - value_table[lastreg] = {nullptr, nullptr}; - regs_t ref_table = value_table; - regs_t unique_table = value_table; - bool hasdestructor = !value_table.empty() && to_string(meta_function::garbage_collect) == value_table[lastreg - 1].name; - if (hasdestructor) { - ref_table[lastreg - 1] = {nullptr, nullptr}; - } - unique_table[lastreg - 1] = {value_table[lastreg - 1].name, detail::unique_destruct}; - - lua_createtable(L, 0, 2); - stack_reference type_table(L, -1); - - stack::set_field(L, "name", detail::demangle(), type_table.stack_index()); - stack::set_field(L, "is", &usertype_detail::is_check, type_table.stack_index()); - - // Now use um - const bool& mustindex = umc.mustindex; - for (std::size_t i = 0; i < 3; ++i) { - // Pointer types, AKA "references" from C++ - const char* metakey = nullptr; - luaL_Reg* metaregs = nullptr; - switch (i) { - case 0: - metakey = &usertype_traits::metatable()[0]; - metaregs = ref_table.data(); - break; - case 1: - metakey = &usertype_traits>::metatable()[0]; - metaregs = unique_table.data(); - break; - case 2: - default: - metakey = &usertype_traits::metatable()[0]; - metaregs = value_table.data(); - break; - } - luaL_newmetatable(L, metakey); - stack_reference t(L, -1); - stack::set_field(L, meta_function::type, type_table, t.stack_index()); - int upvalues = 0; - upvalues += stack::push(L, nullptr); - upvalues += stack::push(L, make_light(um)); - luaL_setfuncs(L, metaregs, upvalues); - - if (um.baseclasscheck != nullptr) { - stack::set_field(L, detail::base_class_check_key(), um.baseclasscheck, t.stack_index()); - } - if (um.baseclasscast != nullptr) { - stack::set_field(L, detail::base_class_cast_key(), um.baseclasscast, t.stack_index()); - } - - stack::set_field(L, detail::base_class_index_propogation_key(), make_closure(um.indexbase, nullptr, make_light(um), make_light(umc)), t.stack_index()); - stack::set_field(L, detail::base_class_new_index_propogation_key(), make_closure(um.newindexbase, nullptr, make_light(um), make_light(umc)), t.stack_index()); - - if (mustindex) { - // Basic index pushing: specialize - // index and newindex to give variables and stuff - stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc)), t.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc)), t.stack_index()); - } - else { - // If there's only functions, we can use the fast index version - stack::set_field(L, meta_function::index, t, t.stack_index()); - } - // metatable on the metatable - // for call constructor purposes and such - lua_createtable(L, 0, 3); - stack_reference metabehind(L, -1); - stack::set_field(L, meta_function::type, type_table, metabehind.stack_index()); - if (um.callconstructfunc != nullptr) { - stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); - } - if (um.secondarymeta) { - stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); - } - // type information needs to be present on the behind-tables too - - stack::set_field(L, metatable_key, metabehind, t.stack_index()); - metabehind.pop(); - // We want to just leave the table - // in the registry only, otherwise we return it - t.pop(); - } - - // Now for the shim-table that actually gets assigned to the name - luaL_newmetatable(L, &usertype_traits::user_metatable()[0]); - stack_reference t(L, -1); - stack::set_field(L, meta_function::type, type_table, t.stack_index()); - int upvalues = 0; - upvalues += stack::push(L, nullptr); - upvalues += stack::push(L, make_light(um)); - luaL_setfuncs(L, value_table.data(), upvalues); - { - lua_createtable(L, 0, 3); - stack_reference metabehind(L, -1); - // type information needs to be present on the behind-tables too - stack::set_field(L, meta_function::type, type_table, metabehind.stack_index()); - if (um.callconstructfunc != nullptr) { - stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); - } - - stack::set_field(L, meta_function::index, make_closure(umt_t::meta_index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::meta_new_index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index()); - stack::set_field(L, metatable_key, metabehind, t.stack_index()); - metabehind.pop(); - } - - lua_remove(L, type_table.stack_index()); - - return 1; - } - }; - - } // namespace stack - -} // namespace sol - -#endif // SOL_USERTYPE_METATABLE_HPP