2019-05-22 07:17:31 +08:00
|
|
|
#define SOL_ALL_SAFETIES_ON 1
|
2018-09-28 13:27:38 +08:00
|
|
|
#include <sol/sol.hpp>
|
2017-08-25 02:39:02 +08:00
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
struct my_thing {
|
2021-03-06 14:03:23 +08:00
|
|
|
std::map<std::string, int> m {
|
2017-08-25 02:39:02 +08:00
|
|
|
{ "bark", 20 },
|
|
|
|
{ "woof", 60 },
|
|
|
|
{ "borf", 30 },
|
|
|
|
{ "awoo", 5 },
|
|
|
|
};
|
|
|
|
|
|
|
|
my_thing() {
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct lua_iterator_state {
|
|
|
|
typedef std::map<std::string, int>::iterator it_t;
|
|
|
|
it_t it;
|
|
|
|
it_t last;
|
|
|
|
|
2021-03-06 23:14:48 +08:00
|
|
|
lua_iterator_state(my_thing& mt)
|
|
|
|
: it(mt.m.begin()), last(mt.m.end()) {
|
2021-03-06 14:03:23 +08:00
|
|
|
}
|
2017-08-25 02:39:02 +08:00
|
|
|
};
|
|
|
|
|
2021-03-06 23:14:48 +08:00
|
|
|
std::tuple<sol::object, sol::object> my_next(
|
|
|
|
sol::user<lua_iterator_state&> user_it_state,
|
|
|
|
sol::this_state l) {
|
2021-03-06 14:03:23 +08:00
|
|
|
// this gets called
|
2017-08-25 02:39:02 +08:00
|
|
|
// to start the first iteration, and every
|
|
|
|
// iteration there after
|
|
|
|
|
|
|
|
// the state you passed in my_pairs is argument 1
|
2021-03-06 14:03:23 +08:00
|
|
|
// the key value is argument 2, but we do not
|
2017-08-25 02:39:02 +08:00
|
|
|
// care about the key value here
|
|
|
|
lua_iterator_state& it_state = user_it_state;
|
|
|
|
auto& it = it_state.it;
|
|
|
|
if (it == it_state.last) {
|
2021-03-06 14:03:23 +08:00
|
|
|
// return nil to signify that
|
2017-08-25 02:39:02 +08:00
|
|
|
// there's nothing more to work with.
|
2021-03-06 23:14:48 +08:00
|
|
|
return std::make_tuple(sol::object(sol::lua_nil),
|
|
|
|
sol::object(sol::lua_nil));
|
2017-08-25 02:39:02 +08:00
|
|
|
}
|
|
|
|
auto itderef = *it;
|
|
|
|
// 2 values are returned (pushed onto the stack):
|
|
|
|
// the key and the value
|
|
|
|
// the state is left alone
|
2021-03-06 23:14:48 +08:00
|
|
|
auto r = std::make_tuple(
|
|
|
|
sol::object(l, sol::in_place, it->first),
|
|
|
|
sol::object(l, sol::in_place, it->second));
|
2017-08-25 02:39:02 +08:00
|
|
|
// the iterator must be moved forward one before we return
|
|
|
|
std::advance(it, 1);
|
|
|
|
return r;
|
2017-08-25 02:57:28 +08:00
|
|
|
}
|
2017-08-25 02:39:02 +08:00
|
|
|
|
|
|
|
auto my_pairs(my_thing& mt) {
|
|
|
|
// pairs expects 3 returns:
|
|
|
|
// the "next" function on how to advance,
|
|
|
|
// the "table" itself or some state,
|
|
|
|
// and an initial key value (can be nil)
|
|
|
|
|
|
|
|
// prepare our state
|
|
|
|
lua_iterator_state it_state(mt);
|
2021-03-06 23:14:48 +08:00
|
|
|
// sol::user is a space/time optimization over regular
|
|
|
|
// usertypes, it's incompatible with regular usertypes and
|
|
|
|
// stores the type T directly in lua without any pretty
|
|
|
|
// setup saves space allocation and a single dereference
|
|
|
|
return std::make_tuple(&my_next,
|
|
|
|
sol::user<lua_iterator_state>(std::move(it_state)),
|
|
|
|
sol::lua_nil);
|
2017-08-25 02:57:28 +08:00
|
|
|
}
|
2017-08-25 02:39:02 +08:00
|
|
|
|
2017-08-25 02:57:28 +08:00
|
|
|
int main(int, char*[]) {
|
2017-08-25 02:39:02 +08:00
|
|
|
std::cout << "===== pairs (advanced) =====" << std::endl;
|
|
|
|
|
|
|
|
sol::state lua;
|
|
|
|
lua.open_libraries(sol::lib::base);
|
|
|
|
|
2021-03-06 23:14:48 +08:00
|
|
|
lua.new_usertype<my_thing>(
|
|
|
|
"my_thing", sol::meta_function::pairs, my_pairs);
|
2017-08-25 02:39:02 +08:00
|
|
|
|
2021-05-07 06:44:25 +08:00
|
|
|
#if SOL_LUA_VERSION_I_ > 501
|
2017-08-25 02:39:02 +08:00
|
|
|
lua.safe_script(R"(
|
|
|
|
local mt = my_thing.new()
|
|
|
|
for k, v in pairs(mt) do
|
|
|
|
print(k, v)
|
|
|
|
end
|
|
|
|
)");
|
2017-08-25 05:12:13 +08:00
|
|
|
#endif // Does not work on Lua 5.1
|
2017-08-25 02:39:02 +08:00
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|