stack_reference

zero-overhead object on the stack

When you work with a sol::reference, the object gotten from the stack has a reference to it made in the registry, keeping it alive. If you want to work with the Lua stack directly without having any additional references made, sol::stack_reference is for you. Its API is identical to sol::reference in every way, except it contains a int stack_index() member function that allows you to retrieve the stack index.

Note that this will not pin the object since a copy is not made in the registry, meaning things can be pulled out from under it, the stack can shrink under it, things can be added onto the stack before this object’s position, and what sol::stack_reference will point to will change. Please know what the Lua stack is and have discipline while managing your Lua stack when working at this level.

All of the base types have stack versions of themselves, and the APIs are identical to their non-stack forms. This includes sol::stack_table, sol::stack_function, sol::stack_protected_function, sol::stack_(light_)userdata and sol::stack_object. There is a special case for sol::stack_function, which has an extra type called sol::stack_aligned_function (and similar sol::stack_aligned_protected_function).

stack_aligned_function

This type is particular to working with the stack. It does not push the function object on the stack before pushing the arguments, assuming that the function present is already on the stack before going ahead and invoking the function it is targeted at. It is identical to sol::function and has a protected counterpart as well. If you are working with the stack and know there is a callable object in the right place (i.e., at the top of the Lua stack), use this abstraction to have it call your stack-based function while still having the easy-to-use Lua abstractions.

Furthermore, if you know you have a function in the right place alongside proper arguments on top of it, you can use the sol::stack_count structure and give its constructor the number of arguments off the top that you want to call your pre-prepared function with:

stack_aligned_function.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include "assert.hpp"

int main(int, char* []) {
	sol::state lua;
	lua.script("function func (a, b) return (a + b) * 2 end");

	sol::reference func_ref = lua["func"];

	// for some reason, you need to use the low-level API
	func_ref.push(); // function on stack now

	// maybe this is in a lua_CFunction you bind,
	// or maybe you're trying to work with a pre-existing system
	// maybe you've used a custom lua_load call, or you're working
	// with state_view's load(lua_Reader, ...) call...
	// here's a little bit of how you can work with the stack
	lua_State* L = lua.lua_state();
	sol::stack_aligned_unsafe_function func(L, -1);
	lua_pushinteger(L, 5); // argument 1, using plain API
	lua_pushinteger(L, 6); // argument 2

	// take 2 arguments from the top,
	// and use "stack_aligned_function" to call
	int result = func(sol::stack_count(2));

	// make sure everything is clean
	c_assert(result == 22);
	c_assert(lua.stack_top() == 0); // stack is empty/balanced

	return 0;
}

Finally, there is a special abstraction that provides further stack optimizations for sol::protected_function variants that are aligned, and it is called sol::stack_aligned_stack_handler_protected_function. This typedef expects you to pass a stack_reference handler to its constructor, meaning that you have already placed an appropriate error-handling function somewhere on the stack before the aligned function. You can use sol::stack_count with this type as well.

Warning

Do not use sol::stack_count with a sol::stack_aligned_protected_function. The default behavior checks if the error_handler member variable is valid, and attempts to push the handler onto the stack in preparation for calling the function. This inevitably changes the stack. Only use sol::stack_aligned_protected_function with sol::stack_count if you know that the handler is not valid (it is nil or its error_handler.valid() function returns false), or if you use sol::stack_aligned_stack_handler_protected_function, which references an existing stack index that can be before the precise placement of the function and its arguments.