You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/extern/sol3/sol/usertype_container_launch.hpp

433 lines
14 KiB
C++

// sol2
// The MIT License (MIT)
// Copyright (c) 2013-2021 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_CONTAINER_LAUNCH_HPP
#define SOL_USERTYPE_CONTAINER_LAUNCH_HPP
#include <sol/stack.hpp>
#include <sol/usertype_container.hpp>
#include <unordered_map>
namespace sol {
namespace container_detail {
template <typename X>
struct u_c_launch {
using T = std::remove_pointer_t<meta::unqualified_t<X>>;
using uc = usertype_container<T>;
using default_uc = usertype_container_default<T>;
static inline int real_index_get_traits(std::true_type, lua_State* L) {
return uc::index_get(L);
}
static inline int real_index_get_traits(std::false_type, lua_State* L) {
return default_uc::index_get(L);
}
static inline int real_index_call(lua_State* L) {
static const std::unordered_map<string_view, lua_CFunction> calls {
{ "at", &real_at_call },
{ "get", &real_get_call },
{ "set", &real_set_call },
{ "size", &real_length_call },
{ "add", &real_add_call },
{ "empty", &real_empty_call },
{ "insert", &real_insert_call },
{ "clear", &real_clear_call },
{ "find", &real_find_call },
{ "index_of", &real_index_of_call },
{ "erase", &real_erase_call },
{ "pairs", &pairs_call },
{ "next", &next_call },
};
auto maybenameview = stack::unqualified_check_get<string_view>(L, 2);
if (maybenameview) {
const string_view& name = *maybenameview;
auto it = calls.find(name);
if (it != calls.cend()) {
return stack::push(L, it->second);
}
}
return real_index_get_traits(container_detail::has_traits_index_get<uc>(), L);
}
static inline int real_at_traits(std::true_type, lua_State* L) {
return uc::at(L);
}
static inline int real_at_traits(std::false_type, lua_State* L) {
return default_uc::at(L);
}
static inline int real_at_call(lua_State* L) {
return real_at_traits(container_detail::has_traits_at<uc>(), L);
}
static inline int real_get_traits(std::true_type, lua_State* L) {
return uc::get(L);
}
static inline int real_get_traits(std::false_type, lua_State* L) {
return default_uc::get(L);
}
static inline int real_get_call(lua_State* L) {
return real_get_traits(container_detail::has_traits_get<uc>(), L);
}
static inline int real_set_traits(std::true_type, lua_State* L) {
return uc::set(L);
}
static inline int real_set_traits(std::false_type, lua_State* L) {
return default_uc::set(L);
}
static inline int real_set_call(lua_State* L) {
return real_set_traits(container_detail::has_traits_set<uc>(), L);
}
static inline int real_index_set_traits(std::true_type, lua_State* L) {
return uc::index_set(L);
}
static inline int real_index_set_traits(std::false_type, lua_State* L) {
return default_uc::index_set(L);
}
static inline int real_new_index_call(lua_State* L) {
return real_index_set_traits(container_detail::has_traits_index_set<uc>(), L);
}
static inline int real_pairs_traits(std::true_type, lua_State* L) {
return uc::pairs(L);
}
static inline int real_pairs_traits(std::false_type, lua_State* L) {
return default_uc::pairs(L);
}
static inline int real_pairs_call(lua_State* L) {
return real_pairs_traits(container_detail::has_traits_pairs<uc>(), L);
}
static inline int real_ipairs_traits(std::true_type, lua_State* L) {
return uc::ipairs(L);
}
static inline int real_ipairs_traits(std::false_type, lua_State* L) {
return default_uc::ipairs(L);
}
static inline int real_ipairs_call(lua_State* L) {
return real_ipairs_traits(container_detail::has_traits_ipairs<uc>(), L);
}
static inline int real_next_traits(std::true_type, lua_State* L) {
return uc::next(L);
}
static inline int real_next_traits(std::false_type, lua_State* L) {
return default_uc::next(L);
}
static inline int real_next_call(lua_State* L) {
return real_next_traits(container_detail::has_traits_next<uc>(), L);
}
static inline int real_size_traits(std::true_type, lua_State* L) {
return uc::size(L);
}
static inline int real_size_traits(std::false_type, lua_State* L) {
return default_uc::size(L);
}
static inline int real_length_call(lua_State* L) {
return real_size_traits(container_detail::has_traits_size<uc>(), L);
}
static inline int real_add_traits(std::true_type, lua_State* L) {
return uc::add(L);
}
static inline int real_add_traits(std::false_type, lua_State* L) {
return default_uc::add(L);
}
static inline int real_add_call(lua_State* L) {
return real_add_traits(container_detail::has_traits_add<uc>(), L);
}
static inline int real_insert_traits(std::true_type, lua_State* L) {
return uc::insert(L);
}
static inline int real_insert_traits(std::false_type, lua_State* L) {
return default_uc::insert(L);
}
static inline int real_insert_call(lua_State* L) {
return real_insert_traits(container_detail::has_traits_insert<uc>(), L);
}
static inline int real_clear_traits(std::true_type, lua_State* L) {
return uc::clear(L);
}
static inline int real_clear_traits(std::false_type, lua_State* L) {
return default_uc::clear(L);
}
static inline int real_clear_call(lua_State* L) {
return real_clear_traits(container_detail::has_traits_clear<uc>(), L);
}
static inline int real_empty_traits(std::true_type, lua_State* L) {
return uc::empty(L);
}
static inline int real_empty_traits(std::false_type, lua_State* L) {
return default_uc::empty(L);
}
static inline int real_empty_call(lua_State* L) {
return real_empty_traits(container_detail::has_traits_empty<uc>(), L);
}
static inline int real_erase_traits(std::true_type, lua_State* L) {
return uc::erase(L);
}
static inline int real_erase_traits(std::false_type, lua_State* L) {
return default_uc::erase(L);
}
static inline int real_erase_call(lua_State* L) {
return real_erase_traits(container_detail::has_traits_erase<uc>(), L);
}
static inline int real_find_traits(std::true_type, lua_State* L) {
return uc::find(L);
}
static inline int real_find_traits(std::false_type, lua_State* L) {
return default_uc::find(L);
}
static inline int real_find_call(lua_State* L) {
return real_find_traits(container_detail::has_traits_find<uc>(), L);
}
static inline int real_index_of_call(lua_State* L) {
if constexpr (container_detail::has_traits_index_of<uc>()) {
return uc::index_of(L);
}
else {
return default_uc::index_of(L);
}
}
static inline int add_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_add_call), (&real_add_call)>(L);
}
static inline int erase_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_erase_call), (&real_erase_call)>(L);
}
static inline int insert_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_insert_call), (&real_insert_call)>(L);
}
static inline int clear_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_clear_call), (&real_clear_call)>(L);
}
static inline int empty_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_empty_call), (&real_empty_call)>(L);
}
static inline int find_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_find_call), (&real_find_call)>(L);
}
static inline int index_of_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_index_of_call), (&real_index_of_call)>(L);
}
static inline int length_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_length_call), (&real_length_call)>(L);
}
static inline int pairs_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_pairs_call), (&real_pairs_call)>(L);
}
static inline int ipairs_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_ipairs_call), (&real_ipairs_call)>(L);
}
static inline int next_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_next_call), (&real_next_call)>(L);
}
static inline int at_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_at_call), (&real_at_call)>(L);
}
static inline int get_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_get_call), (&real_get_call)>(L);
}
static inline int set_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_set_call), (&real_set_call)>(L);
}
static inline int index_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_index_call), (&real_index_call)>(L);
}
static inline int new_index_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_new_index_call), (&real_new_index_call)>(L);
}
};
} // namespace container_detail
namespace stack {
namespace stack_detail {
template <typename T, bool is_shim = false>
struct metatable_setup {
lua_State* L;
metatable_setup(lua_State* L) : L(L) {
}
void operator()() {
using meta_usertype_container
= container_detail::u_c_launch<meta::conditional_t<is_shim, as_container_t<std::remove_pointer_t<T>>, std::remove_pointer_t<T>>>;
static const char* metakey
= is_shim ? &usertype_traits<as_container_t<std::remove_pointer_t<T>>>::metatable()[0] : &usertype_traits<T>::metatable()[0];
static const std::array<luaL_Reg, 20> reg = { {
// clang-format off
{ "__pairs", &meta_usertype_container::pairs_call },
{ "__ipairs", &meta_usertype_container::ipairs_call },
{ "__len", &meta_usertype_container::length_call },
{ "__index", &meta_usertype_container::index_call },
{ "__newindex", &meta_usertype_container::new_index_call },
{ "pairs", &meta_usertype_container::pairs_call },
{ "next", &meta_usertype_container::next_call },
{ "at", &meta_usertype_container::at_call },
{ "get", &meta_usertype_container::get_call },
{ "set", &meta_usertype_container::set_call },
{ "size", &meta_usertype_container::length_call },
{ "empty", &meta_usertype_container::empty_call },
{ "clear", &meta_usertype_container::clear_call },
{ "insert", &meta_usertype_container::insert_call },
{ "add", &meta_usertype_container::add_call },
{ "find", &meta_usertype_container::find_call },
{ "index_of", &meta_usertype_container::index_of_call },
{ "erase", &meta_usertype_container::erase_call },
std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy<T> },
{ nullptr, nullptr }
// clang-format on
} };
if (luaL_newmetatable(L, metakey) == 1) {
luaL_setfuncs(L, reg.data(), 0);
}
lua_setmetatable(L, -2);
}
};
} // namespace stack_detail
template <typename T>
struct unqualified_pusher<as_container_t<T>> {
using C = meta::unqualified_t<T>;
static int push_lvalue(std::true_type, lua_State* L, const C& cont) {
stack_detail::metatable_setup<C*, true> fx(L);
return stack::push<detail::as_pointer_tag<const C>>(L, detail::with_function_tag(), fx, detail::ptr(cont));
}
static int push_lvalue(std::false_type, lua_State* L, const C& cont) {
stack_detail::metatable_setup<C, true> fx(L);
return stack::push<detail::as_value_tag<C>>(L, detail::with_function_tag(), fx, cont);
}
static int push_rvalue(std::true_type, lua_State* L, C&& cont) {
stack_detail::metatable_setup<C, true> fx(L);
return stack::push<detail::as_value_tag<C>>(L, detail::with_function_tag(), fx, std::move(cont));
}
static int push_rvalue(std::false_type, lua_State* L, const C& cont) {
return push_lvalue(std::is_lvalue_reference<T>(), L, cont);
}
static int push(lua_State* L, const as_container_t<T>& as_cont) {
return push_lvalue(std::is_lvalue_reference<T>(), L, as_cont.value());
}
static int push(lua_State* L, as_container_t<T>&& as_cont) {
return push_rvalue(meta::all<std::is_rvalue_reference<T>, meta::neg<std::is_lvalue_reference<T>>>(), L, std::forward<T>(as_cont.value()));
}
};
template <typename T>
struct unqualified_pusher<as_container_t<T*>> {
using C = std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>>;
static int push(lua_State* L, T* cont) {
stack_detail::metatable_setup<C> fx(L);
return stack::push<detail::as_pointer_tag<T>>(L, detail::with_function_tag(), fx, cont);
}
};
template <typename T>
struct unqualified_pusher<T, std::enable_if_t<is_container_v<T>>> {
using C = T;
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
stack_detail::metatable_setup<C> fx(L);
return stack::push<detail::as_value_tag<T>>(L, detail::with_function_tag(), fx, std::forward<Args>(args)...);
}
};
template <typename T>
struct unqualified_pusher<T*, std::enable_if_t<is_container_v<T>>> {
using C = std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>>;
static int push(lua_State* L, T* cont) {
stack_detail::metatable_setup<C> fx(L);
return stack::push<detail::as_pointer_tag<T>>(L, detail::with_function_tag(), fx, cont);
}
};
} // namespace stack
} // namespace sol
#endif // SOL_USERTYPE_CONTAINER_LAUNCH_HPP