New base object customization point management example, derived directly form @NullCascade. Thanks!

This commit is contained in:
ThePhD 2020-01-24 19:58:12 -05:00
parent c77b5b432e
commit 5301bc1d4c
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
7 changed files with 294 additions and 14 deletions

View File

@ -0,0 +1,176 @@
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
#include <iostream>
#include <exception>
// We capture the base objects
// lifetime style
// You can add more here,
// e.g. "Unique" for a unique pointer kind of lifestyle,
// but you would need to think about how to handle
// copying / moving in that case
enum class BaseObjectLifetime { Value, Pointer, Shared };
// The base object
// that we do inheritance and other work
// on
class BaseObject {
public:
BaseObject() {
objectType = 0;
}
unsigned int getObjectType() const {
return objectType;
}
bool doArmorThing() const {
return false;
}
bool doWeaponThing() const {
return false;
}
// helper function defined later after we define all the
// base classes we care about
sol::object getAsRetyped(lua_State* L, BaseObjectLifetime Lifetime) const;
// For convenience with the customization points below
int pushAsRetyped(lua_State* L, BaseObjectLifetime Lifetime) const {
return getAsRetyped(L, Lifetime).push(L);
}
protected:
unsigned int objectType;
};
class Armor : public BaseObject {
public:
Armor() {
objectType = 1;
}
bool doArmorThing() const {
return true;
}
};
class Weapon : public BaseObject {
public:
Weapon() {
objectType = 2;
}
bool doWeaponThing() const {
return true;
}
};
// Get the most-derived type
// that we care about from the base object,
// obeying the lifetime type
sol::object BaseObject::getAsRetyped(lua_State* L, BaseObjectLifetime Lifetime) const {
switch (objectType) {
case 1:
std::cout << "Retyping as armor." << std::endl;
switch (Lifetime) {
case BaseObjectLifetime::Value:
return sol::make_object(L, *static_cast<const Armor*>(this));
case BaseObjectLifetime::Pointer:
return sol::make_object(L, static_cast<const Armor*>(this));
case BaseObjectLifetime::Shared:
return sol::make_object(L, std::make_shared<Armor>(*static_cast<const Armor*>(this)));
}
case 2:
std::cout << "Retyping as weapon." << std::endl;
switch (Lifetime) {
case BaseObjectLifetime::Value:
return sol::make_object(L, *static_cast<const Weapon*>(this));
case BaseObjectLifetime::Pointer:
return sol::make_object(L, static_cast<const Weapon*>(this));
case BaseObjectLifetime::Shared:
return sol::make_object(L, std::make_shared<Weapon>(*static_cast<const Weapon*>(this)));
}
default:
// we have a normal type here, so that means we
// must bypass customization points
std::cout << "Unknown type: falling back to base object." << std::endl;
switch (Lifetime) {
case BaseObjectLifetime::Value:
return sol::make_object_userdata(L, *this);
case BaseObjectLifetime::Shared:
return sol::make_object_userdata(L, std::make_shared<BaseObject>(*this));
case BaseObjectLifetime::Pointer:
default:
return sol::make_object_userdata(L, this);
}
}
}
//
// sol customization points
//
// Defining a customization point that lets us put the correct object type on the stack.
int sol_lua_push(sol::types<BaseObject>, lua_State* L, const BaseObject& obj) {
return obj.pushAsRetyped(L, BaseObjectLifetime::Value);
}
int sol_lua_push(sol::types<BaseObject*>, lua_State* L, const BaseObject* obj) {
return obj->pushAsRetyped(L, BaseObjectLifetime::Pointer);
}
int sol_lua_push(sol::types<std::shared_ptr<BaseObject>>, lua_State* L, const std::shared_ptr<BaseObject>& obj) {
return obj->pushAsRetyped(L, BaseObjectLifetime::Shared);
}
int main() {
// test our customization points out
std::cout << "=== Base object customization points ===" << std::endl;
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::table);
lua["objectCache"] = lua.create_table();
// Do basic type binding.
auto luaBaseObject = lua.new_usertype<BaseObject>("tes3baseObject");
luaBaseObject["objectType"] = sol::readonly_property(&BaseObject::getObjectType);
luaBaseObject["doArmorThing"] = &BaseObject::doArmorThing;
luaBaseObject["doWeaponThing"] = &BaseObject::doWeaponThing;
auto luaArmorObject = lua.new_usertype<Armor>("tes3armor");
luaArmorObject[sol::base_classes] = sol::bases<BaseObject>();
luaArmorObject["doArmorThing"] = &Armor::doArmorThing;
auto luaWeaponObject = lua.new_usertype<Weapon>("tes3weapon");
luaWeaponObject[sol::base_classes] = sol::bases<BaseObject>();
luaWeaponObject["doWeaponThing"] = &Weapon::doWeaponThing;
// Objects we'll play with.
BaseObject base;
Armor armor;
Weapon weapon;
// Push some objects to lua.
std::cout << "Normal pointers..." << std::endl;
lua["ptrBase"] = &base;
lua["ptrArmor"] = &armor;
lua["ptrWeapon"] = &weapon;
std::cout << std::endl;
// Same objects but as base objects to test mapping.
std::cout << "Base-cast pointers..." << std::endl;
lua["ptrArmorAsBase"] = static_cast<BaseObject*>(&armor);
lua["ptrWeaponAsBase"] = static_cast<BaseObject*>(&weapon);
std::cout << std::endl;
std::cout << "Smart direct pointers..." << std::endl;
lua["sharedBase"] = std::make_shared<BaseObject>();
lua["sharedArmor"] = std::make_shared<Armor>();
lua["sharedArmor"] = std::make_shared<Weapon>();
std::cout << std::endl;
std::cout << "Smart pointers put as the base class..." << std::endl;
lua["sharedArmorAsBase"] = (std::shared_ptr<BaseObject>)std::make_shared<Armor>();
lua["sharedArmorAsBase"] = (std::shared_ptr<BaseObject>)std::make_shared<Weapon>();
std::cout << std::endl;
return 0;
}

View File

@ -49,6 +49,26 @@ namespace sol {
return r;
}
template <typename R = reference, bool should_pop = !is_stack_based_v<R>, typename T>
R make_reference_userdata(lua_State* L, T&& value) {
int backpedal = stack::push_userdata(L, std::forward<T>(value));
R r = stack::get<R>(L, -backpedal);
if (should_pop) {
lua_pop(L, backpedal);
}
return r;
}
template <typename T, typename R = reference, bool should_pop = !is_stack_based_v<R>, typename... Args>
R make_reference_userdata(lua_State* L, Args&&... args) {
int backpedal = stack::push_userdata<T>(L, std::forward<Args>(args)...);
R r = stack::get<R>(L, -backpedal);
if (should_pop) {
lua_pop(L, backpedal);
}
return r;
}
} // namespace sol
#endif // SOL_MAKE_REFERENCE_HPP

View File

@ -146,6 +146,16 @@ namespace sol {
object make_object(lua_State* L, Args&&... args) {
return make_reference<T, object, true>(L, std::forward<Args>(args)...);
}
template <typename T>
object make_object_userdata(lua_State* L, T&& value) {
return make_reference_userdata<object, true>(L, std::forward<T>(value));
}
template <typename T, typename... Args>
object make_object_userdata(lua_State* L, Args&&... args) {
return make_reference_userdata<T, object, true>(L, std::forward<Args>(args)...);
}
} // namespace sol
#endif // SOL_OBJECT_HPP

View File

@ -55,6 +55,8 @@ namespace sol {
template <typename T>
struct as_value_tag {};
template <typename T>
struct as_unique_tag {};
template <typename T>
struct as_table_tag {};
using lua_reg_table = luaL_Reg[64];
@ -921,14 +923,26 @@ namespace sol {
template <typename T, typename... Args>
int push_userdata(lua_State* L, T&& t, Args&&... args) {
using U = meta::unqualified_t<T>;
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
using Tr = meta::conditional_t<std::is_pointer_v<U>,
detail::as_pointer_tag<std::remove_pointer_t<U>>,
meta::conditional_t<is_unique_usertype_v<U>,
detail::as_unique_tag<U>,
detail::as_value_tag<U>
>
>;
return stack::push<Tr>(L, std::forward<T>(t), std::forward<Args>(args)...);
}
template <typename T, typename Arg, typename... Args>
int push_userdata(lua_State* L, Arg&& arg, Args&&... args) {
using U = meta::unqualified_t<T>;
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
using Tr = meta::conditional_t<std::is_pointer_v<U>,
detail::as_pointer_tag<std::remove_pointer_t<U>>,
meta::conditional_t<is_unique_usertype_v<U>,
detail::as_unique_tag<U>,
detail::as_value_tag<U>
>
>;
return stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}

View File

@ -189,6 +189,16 @@ namespace sol { namespace stack {
}
};
template <typename T>
struct unqualified_pusher<detail::as_unique_tag<T>> {
template <typename... Args>
static int push (lua_State* L, Args&&... args) {
stack_detail::uu_pusher<T> p;
(void)p;
return p.push(L, std::forward<Args>(args)...);
}
};
namespace stack_detail {
template <typename T>
struct uu_pusher {
@ -293,9 +303,7 @@ namespace sol { namespace stack {
return stack::push<detail::as_pointer_tag<std::remove_pointer_t<T>>>(L, std::forward<Args>(args)...);
}
else if constexpr (is_unique_usertype_v<Tu>) {
stack_detail::uu_pusher<T> p;
(void)p;
return p.push(L, std::forward<Args>(args)...);
return stack::push<detail::as_unique_tag<T>>(L, std::forward<Args>(args)...);
}
else {
return stack::push<detail::as_value_tag<T>>(L, std::forward<Args>(args)...);

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2020-01-17 10:21:31.165776 UTC
// This header was generated with sol v3.2.0 (revision 1c89390)
// Generated 2020-01-25 00:57:45.038692 UTC
// This header was generated with sol v3.2.0 (revision c77b5b4)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2020-01-17 10:21:30.504542 UTC
// This header was generated with sol v3.2.0 (revision 1c89390)
// Generated 2020-01-25 00:57:44.490128 UTC
// This header was generated with sol v3.2.0 (revision c77b5b4)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP
@ -9499,6 +9499,8 @@ namespace sol {
template <typename T>
struct as_value_tag {};
template <typename T>
struct as_unique_tag {};
template <typename T>
struct as_table_tag {};
using lua_reg_table = luaL_Reg[64];
@ -10364,14 +10366,26 @@ namespace sol {
template <typename T, typename... Args>
int push_userdata(lua_State* L, T&& t, Args&&... args) {
using U = meta::unqualified_t<T>;
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
using Tr = meta::conditional_t<std::is_pointer_v<U>,
detail::as_pointer_tag<std::remove_pointer_t<U>>,
meta::conditional_t<is_unique_usertype_v<U>,
detail::as_unique_tag<U>,
detail::as_value_tag<U>
>
>;
return stack::push<Tr>(L, std::forward<T>(t), std::forward<Args>(args)...);
}
template <typename T, typename Arg, typename... Args>
int push_userdata(lua_State* L, Arg&& arg, Args&&... args) {
using U = meta::unqualified_t<T>;
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
using Tr = meta::conditional_t<std::is_pointer_v<U>,
detail::as_pointer_tag<std::remove_pointer_t<U>>,
meta::conditional_t<is_unique_usertype_v<U>,
detail::as_unique_tag<U>,
detail::as_value_tag<U>
>
>;
return stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
@ -13262,6 +13276,16 @@ namespace sol { namespace stack {
}
};
template <typename T>
struct unqualified_pusher<detail::as_unique_tag<T>> {
template <typename... Args>
static int push (lua_State* L, Args&&... args) {
stack_detail::uu_pusher<T> p;
(void)p;
return p.push(L, std::forward<Args>(args)...);
}
};
namespace stack_detail {
template <typename T>
struct uu_pusher {
@ -13366,9 +13390,7 @@ namespace sol { namespace stack {
return stack::push<detail::as_pointer_tag<std::remove_pointer_t<T>>>(L, std::forward<Args>(args)...);
}
else if constexpr (is_unique_usertype_v<Tu>) {
stack_detail::uu_pusher<T> p;
(void)p;
return p.push(L, std::forward<Args>(args)...);
return stack::push<detail::as_unique_tag<T>>(L, std::forward<Args>(args)...);
}
else {
return stack::push<detail::as_value_tag<T>>(L, std::forward<Args>(args)...);
@ -14870,6 +14892,26 @@ namespace sol {
return r;
}
template <typename R = reference, bool should_pop = !is_stack_based_v<R>, typename T>
R make_reference_userdata(lua_State* L, T&& value) {
int backpedal = stack::push_userdata(L, std::forward<T>(value));
R r = stack::get<R>(L, -backpedal);
if (should_pop) {
lua_pop(L, backpedal);
}
return r;
}
template <typename T, typename R = reference, bool should_pop = !is_stack_based_v<R>, typename... Args>
R make_reference_userdata(lua_State* L, Args&&... args) {
int backpedal = stack::push_userdata<T>(L, std::forward<Args>(args)...);
R r = stack::get<R>(L, -backpedal);
if (should_pop) {
lua_pop(L, backpedal);
}
return r;
}
} // namespace sol
// end of sol/make_reference.hpp
@ -15052,6 +15094,16 @@ namespace sol {
object make_object(lua_State* L, Args&&... args) {
return make_reference<T, object, true>(L, std::forward<Args>(args)...);
}
template <typename T>
object make_object_userdata(lua_State* L, T&& value) {
return make_reference_userdata<object, true>(L, std::forward<T>(value));
}
template <typename T, typename... Args>
object make_object_userdata(lua_State* L, Args&&... args) {
return make_reference_userdata<T, object, true>(L, std::forward<Args>(args)...);
}
} // namespace sol
// end of sol/object.hpp