-
-
Notifications
You must be signed in to change notification settings - Fork 493
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is it possible to have safe pointer walking/chaining ? #1491
Comments
I have not seen a feature like that.
Closest that comes to mind are policies https://sol2.readthedocs.io/en/latest/api/policies.html that do things during a function call from what I gather.
Maybe you could sketch this out a bit. I dont quite understand how you would intend to use the wrapper classes. Or what is the issue with the wrappers. Also, how do you use the chaining in C++ currently? You cant do this in C++ Here are some ideas, I think each one is a bit different and has pros and cons. In the end they are very similar though: (1) You can have a builder pattern system, where you have a lua implemented builder that holds "next" variable and advances it by calling GetNext if "next" is not null. Then it finally returns the "next" value at the end. function Chain(o)
return {
next = o,
GetNext = function(self)
if next then next = next:GetNext() end
return self
end,
Get = function(self)
return next
end,
}
end
local maybeExists = Chain(GetObj()):GetNext():GetNext():GetNext():Get()
if not maybeExists then return end (2) You could use inheritance to make a dummy return object instead of nullptr. struct LuaChainable { };
class Object : LuaChainable
{
private:
Object* Next = nullptr;
public:
Object* GetNext() { return Next ? Next : new LuaChainable(); } // probably memory leak. You want to return a pointer to a static instance instead
};
// bindings
lua.new_usertype<LuaChainable>("LuaChainable",
"GetNext", [](LuaChainable& self){ return self; },
"IsValid", [](){ return false; }
);
lua.new_usertype<Object>("Object",
sol::base_classes, sol::bases<LuaChainable>(),
"GetNext", &Object::GetNext,
"IsValid", [](){ return true; }
); local obj = GetObj():GetNext():GetNext():GetNext()
if not obj:IsValid() then return end (3) I think you had some kind of wrapper method in mind |
It seems that struct InvalidObject
{
static auto Index(sol::stack_object, sol::this_state) -> std::function<InvalidObject()>
{
return [] { return InvalidObject{}; };
}
};
static auto pointer_policy(lua_State* lua_state, int current_stack_return_count) -> int
{
// Multiple return values are not handled!
if (current_stack_return_count == 1 && lua_isnil(lua_state, -1))
{
sol::stack::push(lua_state, InvalidObject{});
}
return current_stack_return_count;
}
auto SolMod::start_mod() -> void
{
// ...
auto sol_invalid_object_class = sol().new_usertype<InvalidObject>(
sol::meta_function::index, &InvalidObject::Index,
"IsValid", [] { return false; }
);
// We have other criteria than 'nullptr' that determines if an object is valid.
// Therefore, the 'IsValid' function is a non-lambda function that's not included in this example.
// But this would otherwise just be '[] { return true; }'.
auto sol_object_class = sol().new_usertype<Object>(
"IsValid", &Object_IsValid,
"GetNext", sol_policies(&Object::GetNext, &pointer_policy)
);
} I'm unwilling to modify the classes that I'm creating bindings for, therefore any changes to the class itself would require a wrapper struct and this is how we currently do it, more or less: // Original class
class Object
{
auto my_func() -> SomeType*;
};
// Wrapper class that Lua constructs with all sorts of userdata, values and metamethods.
// An instance of this is always constructed and then we can check if the 'internal' pointer is nullptr on usage.
// This allows for pointer chaining as long as the user remembers to call 'IsValid' before any other function.
class LuaObject
{
Object* internal{};
}; So my unwillingness to change the original class and my desire to not have to create wrappers rules out your second example. Thanks for your help. |
I have an existing system that I'd like to convert into sol.
Let's say I have a class, and this class has a linked list:
I'm using a linked list here just as an example but we use this same idea for accessing all types of pointers.
In our code, we do a lot of pointer walking/chaining so we created a useful shortcut to avoid large amounts of validity checking.
It means that this code:
becomes:
We could go through and manually create wrapper classes for all our classes but the only way I can think of to do that would be to also create wrappers for every member variable and member function that return
Wrapper<OriginalType>
instead of the original type directly and I think the complexity and amount of work might get out of hand fairly quickly.So my question is: Does sol have any functionality built-in for this type of pointer walking/chaining or something to make it easier ?
The text was updated successfully, but these errors were encountered: