add new tas for override_value and update_if_empty, improve the enable_if for a bunch of field_setter stuff

perform the last breaking change with .source()
prepare for the coming release...
This commit is contained in:
ThePhD 2019-02-16 17:27:03 -05:00
parent 95ffd10283
commit b6f40935c8
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
19 changed files with 1064 additions and 683 deletions

View File

@ -56,14 +56,14 @@ members
environment(lua_State* L, sol::new_table nt); environment(lua_State* L, sol::new_table nt);
environment(lua_State* L, sol::new_table nt, const sol::reference& fallback); environment(lua_State* L, sol::new_table nt, const sol::reference& fallback);
environment(sol::env_t, const sol::reference& object_that_has_environment); environment(sol::env_key_t, const sol::reference& object_that_has_environment);
environment(sol::env_t, const sol::stack_reference& object_that_has_environment); environment(sol::env_key_t, const sol::stack_reference& object_that_has_environment);
The ones from table are used here (of particular note is the ability to use ``sol::environment(my_lua_state, sol::create);`` to make a fresh, unnamed environment), plus the three unique constructors shown above. The ones from table are used here (of particular note is the ability to use ``sol::environment(my_lua_state, sol::create);`` to make a fresh, unnamed environment), plus the three unique constructors shown above.
The first constructor is generally used as ``sol::environment my_env(my_lua_state, sol::create, my_fallback_table);``. The fallback table serves as the backup to lookup attempts on the environment table being created. It is achieved by simply creating a metatable for the ``sol::environment`` being created, and then doing ``env_metatable["__index"] = fallback;``. You can achieve fancier effects by changing the metatable of the environment to your liking, by creating it in some fashion and then setting the metatable explicitly and populating it with data, particularly with :doc:`sol::metatable_key<metatable_key>`. The first constructor is generally used as ``sol::environment my_env(my_lua_state, sol::create, my_fallback_table);``. The fallback table serves as the backup to lookup attempts on the environment table being created. It is achieved by simply creating a metatable for the ``sol::environment`` being created, and then doing ``env_metatable["__index"] = fallback;``. You can achieve fancier effects by changing the metatable of the environment to your liking, by creating it in some fashion and then setting the metatable explicitly and populating it with data, particularly with :doc:`sol::metatable_key<metatable_key>`.
The second and third unique constructors take a special empty type that serves as a key to trigger this constructor and serves no other purpose, ``sol::env_t``. The shortcut value so you don't have to create one is called ``sol::env_key``. It is used like ``sol::environment my_env(sol::env_key, some_object);``. It will extract the environment out of whatever the second argument is that may or may not have an environment. If it does not have an environment, the constructor will complete but the object will have ``env.valid() == false``, since it will reference Lua's ``nil``. The second and third unique constructors take a special empty type that serves as a key to trigger this constructor and serves no other purpose, ``sol::env_key_t``. The shortcut value so you don't have to create one is called ``sol::env_key``. It is used like ``sol::environment my_env(sol::env_key, some_object);``. It will extract the environment out of whatever the second argument is that may or may not have an environment. If it does not have an environment, the constructor will complete but the object will have ``env.valid() == false``, since it will reference Lua's ``nil``.
.. code-block:: cpp .. code-block:: cpp

View File

@ -14,7 +14,7 @@
// where someone wants to handle a nested table // where someone wants to handle a nested table
void demo(sol::nested<std::map<std::string, std::vector<std::string>>> src) { void demo(sol::nested<std::map<std::string, std::vector<std::string>>> src) {
std::cout << "demo, sol::nested<...>" << std::endl; std::cout << "demo, sol::nested<...>" << std::endl;
const auto& listmap = src.source; const auto& listmap = src.value();
c_assert(listmap.size() == 2); c_assert(listmap.size() == 2);
for (const auto& kvp : listmap) { for (const auto& kvp : listmap) {
const std::vector<std::string>& strings = kvp.second; const std::vector<std::string>& strings = kvp.second;
@ -38,11 +38,11 @@ void demo(sol::nested<std::map<std::string, std::vector<std::string>>> src) {
void demo_explicit (sol::as_table_t<std::map<std::string, sol::as_table_t<std::vector<std::string>>>> src) { void demo_explicit (sol::as_table_t<std::map<std::string, sol::as_table_t<std::vector<std::string>>>> src) {
std::cout << "demo, explicit sol::as_table_t<...>" << std::endl; std::cout << "demo, explicit sol::as_table_t<...>" << std::endl;
// Have to access the "source" member variable for as_table_t // Have to access the "source" member variable for as_table_t
const auto& listmap = src.source; const auto& listmap = src.value();
c_assert(listmap.size() == 2); c_assert(listmap.size() == 2);
for (const auto& kvp : listmap) { for (const auto& kvp : listmap) {
// Have to access the internal "source" for the inner as_table_t, as well // Have to access the internal "source" for the inner as_table_t, as well
const std::vector<std::string>& strings = kvp.second.source; const std::vector<std::string>& strings = kvp.second.value();
c_assert(strings.size() == 3); c_assert(strings.size() == 3);
std::cout << "\t" << kvp.first << " = "; std::cout << "\t" << kvp.first << " = ";
for (const auto& s : strings) { for (const auto& s : strings) {

View File

@ -42,9 +42,11 @@ namespace sol { namespace detail {
ebco(T&& v) : value_(std::move(v)){}; ebco(T&& v) : value_(std::move(v)){};
ebco& operator=(const T& v) { ebco& operator=(const T& v) {
value = v; value = v;
return *this;
} }
ebco& operator=(T&& v) { ebco& operator=(T&& v) {
value_ = std::move(v); value_ = std::move(v);
return *this;
}; };
template <typename Arg, typename... Args, template <typename Arg, typename... Args,
typename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, typename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>,
@ -68,17 +70,20 @@ namespace sol { namespace detail {
ebco(const T& v) : T(v){}; ebco(const T& v) : T(v){};
ebco(T&& v) : T(std::move(v)){}; ebco(T&& v) : T(std::move(v)){};
template <typename Arg, typename... Args, template <typename Arg, typename... Args,
typename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, typename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>,
ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T>>> ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T>>>
ebco(Arg&& arg, Args&&... args) : T(std::forward<Arg>(arg), std::forward<Args>(args)...){} ebco(Arg&& arg, Args&&... args) : T(std::forward<Arg>(arg), std::forward<Args>(args)...) {
}
ebco& operator=(const ebco&) = default; ebco& operator=(const ebco&) = default;
ebco& operator=(ebco&&) = default; ebco& operator=(ebco&&) = default;
ebco& operator=(const T& v) { ebco& operator=(const T& v) {
static_cast<T&>(*this) = v; static_cast<T&>(*this) = v;
return *this;
} }
ebco& operator=(T&& v) { ebco& operator=(T&& v) {
static_cast<T&>(*this) = std::move(v); static_cast<T&>(*this) = std::move(v);
return *this;
}; };
T& value() { T& value() {
@ -90,6 +95,48 @@ namespace sol { namespace detail {
} }
}; };
template <typename T, std::size_t tag>
struct ebco<T&, tag> {
T& ref;
ebco() = default;
ebco(const ebco&) = default;
ebco(ebco&&) = default;
ebco(T& v) : ref(v){};
ebco& operator=(const ebco&) = default;
ebco& operator=(ebco&&) = default;
ebco& operator=(T& v) {
ref = v;
return *this;
}
T& value() const {
return const_cast<ebco<T&, tag>&>(*this).ref;
}
};
template <typename T, std::size_t tag>
struct ebco<T&&, tag> {
T&& ref;
ebco() = default;
ebco(const ebco&) = default;
ebco(ebco&&) = default;
ebco(T&& v) : ref(v){};
ebco& operator=(const ebco&) = default;
ebco& operator=(ebco&&) = default;
ebco& operator=(T&& v) {
ref = v;
return *this;
}
T&& value() && {
return std::move(ref);
}
};
}} // namespace sol::detail }} // namespace sol::detail
#endif // SOL_EBCO_HPP #endif // SOL_EBCO_HPP

View File

@ -60,20 +60,20 @@ namespace sol {
mt.pop(); mt.pop();
} }
basic_environment(env_t, const stack_reference& extraction_target) basic_environment(env_key_t, const stack_reference& extraction_target)
: base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
constructor_handler handler{}; constructor_handler handler{};
stack::check<env_t>(this->lua_state(), -1, handler); stack::check<env_key_t>(this->lua_state(), -1, handler);
#endif // Safety #endif // Safety
lua_pop(this->lua_state(), 2); lua_pop(this->lua_state(), 2);
} }
template <bool b> template <bool b>
basic_environment(env_t, const basic_reference<b>& extraction_target) basic_environment(env_key_t, const basic_reference<b>& extraction_target)
: base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
constructor_handler handler{}; constructor_handler handler{};
stack::check<env_t>(this->lua_state(), -1, handler); stack::check<env_key_t>(this->lua_state(), -1, handler);
#endif // Safety #endif // Safety
lua_pop(this->lua_state(), 2); lua_pop(this->lua_state(), 2);
} }
@ -187,7 +187,7 @@ namespace sol {
namespace stack { namespace stack {
template <> template <>
struct unqualified_getter<env_t> { struct unqualified_getter<env_key_t> {
static environment get(lua_State* L, int index, record& tracking) { static environment get(lua_State* L, int index, record& tracking) {
tracking.use(1); tracking.use(1);
return get_environment(stack_reference(L, raw_index(index))); return get_environment(stack_reference(L, raw_index(index)));

View File

@ -534,7 +534,7 @@ namespace sol {
template <typename F, typename... Filters> template <typename F, typename... Filters>
struct unqualified_pusher<filter_wrapper<F, Filters...>> { struct unqualified_pusher<filter_wrapper<F, Filters...>> {
typedef filter_wrapper<F, Filters...> P; using P = filter_wrapper<F, Filters...>;
static int push(lua_State* L, const P& p) { static int push(lua_State* L, const P& p) {
lua_CFunction cf = call_detail::call_user<void, false, false, P, 2>; lua_CFunction cf = call_detail::call_user<void, false, false, P, 2>;
@ -552,6 +552,27 @@ namespace sol {
return stack::push(L, c_closure(cf, upvalues)); return stack::push(L, c_closure(cf, upvalues));
} }
}; };
template <typename T>
struct unqualified_pusher<push_invoke_t<T>> {
static int push(lua_State* L, push_invoke_t<T>&& pi) {
if constexpr (std::is_invocable_v<std::add_rvalue_reference_t<T>, lua_State*>) {
return stack::push(L, std::move(pi.value())(L));
}
else {
return stack::push(L, std::move(pi.value())());
}
}
static int push(lua_State* L, const push_invoke_t<T>& pi) {
if constexpr (std::is_invocable_v<const T, lua_State*>) {
return stack::push(L, pi.value()(L));
}
else {
return stack::push(L, pi.value()());
}
}
};
} // namespace stack } // namespace stack
} // namespace sol } // namespace sol

View File

@ -392,7 +392,7 @@ namespace sol { namespace stack {
}; };
template <type expected, typename C> template <type expected, typename C>
struct unqualified_checker<metatable_t, expected, C> { struct unqualified_checker<metatable_key_t, expected, C> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
@ -414,7 +414,7 @@ namespace sol { namespace stack {
}; };
template <typename C> template <typename C>
struct unqualified_checker<env_t, type::poly, C> { struct unqualified_checker<env_key_t, type::poly, C> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);

View File

@ -31,87 +31,68 @@
namespace sol { namespace sol {
namespace stack { namespace stack {
template <typename T, bool, bool, typename> template <typename T, bool global, bool raw, typename>
struct field_getter { struct field_getter {
static constexpr int default_table_index = std::conditional_t<meta::is_c_str_v<T> || (std::is_integral_v<T> && !std::is_same_v<T, bool>)
|| (std::is_integral_v<T> && !std::is_same_v<T, bool>) || (raw && std::is_void_v<std::remove_pointer_t<T>>),
std::integral_constant<int, -1>, std::integral_constant<int, -2>> ::value;
template <typename Key> template <typename Key>
void get(lua_State* L, Key&& key, int tableindex = -2) { void get(lua_State* L, Key&& key, int tableindex = default_table_index) {
push(L, std::forward<Key>(key)); if constexpr (std::is_same_v<T, update_if_empty_t> || std::is_same_v<T, override_value_t>) {
lua_gettable(L, tableindex); (void)L;
} (void)key;
}; (void)tableindex;
template <typename T, bool global, typename C>
struct field_getter<T, global, true, C> {
template <typename Key>
void get(lua_State* L, Key&& key, int tableindex = -2) {
push(L, std::forward<Key>(key));
lua_rawget(L, tableindex);
}
};
template <bool b, bool raw, typename C>
struct field_getter<metatable_t, b, raw, C> {
void get(lua_State* L, metatable_t, int tableindex = -1) {
if (lua_getmetatable(L, tableindex) == 0)
push(L, lua_nil);
}
};
template <bool b, bool raw, typename C>
struct field_getter<env_t, b, raw, C> {
void get(lua_State* L, env_t, int tableindex = -1) {
#if SOL_LUA_VERSION < 502
// Use lua_setfenv
lua_getfenv(L, tableindex);
#else
// Use upvalues as explained in Lua 5.2 and beyond's manual
if (lua_getupvalue(L, tableindex, 1) == nullptr) {
push(L, lua_nil);
} }
else if constexpr (std::is_same_v<T, env_key_t>) {
#if SOL_LUA_VERSION < 502
// Use lua_setfenv
lua_getfenv(L, tableindex);
#else
// Use upvalues as explained in Lua 5.2 and beyond's manual
if (lua_getupvalue(L, tableindex, 1) == nullptr) {
push(L, lua_nil);
}
#endif #endif
} }
}; else if constexpr (std::is_same_v<T, metatable_key_t>) {
if (lua_getmetatable(L, tableindex) == 0)
template <typename T, bool raw> push(L, lua_nil);
struct field_getter<T, true, raw, std::enable_if_t<meta::is_c_str<T>::value>> { }
template <typename Key> else if constexpr(raw) {
void get(lua_State* L, Key&& key, int = -1) { if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) {
lua_getglobal(L, &key[0]); lua_rawgeti(L, tableindex, static_cast<lua_Integer>(key));
} }
};
template <typename T>
struct field_getter<T, false, false, std::enable_if_t<meta::is_c_str<T>::value>> {
template <typename Key>
void get(lua_State* L, Key&& key, int tableindex = -1) {
lua_getfield(L, tableindex, &key[0]);
}
};
#if SOL_LUA_VERSION >= 503
template <typename T>
struct field_getter<T, false, false, std::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>> {
template <typename Key>
void get(lua_State* L, Key&& key, int tableindex = -1) {
lua_geti(L, tableindex, static_cast<lua_Integer>(key));
}
};
#endif // Lua 5.3.x
#if SOL_LUA_VERSION >= 502 #if SOL_LUA_VERSION >= 502
template <typename C> else if constexpr (std::is_void_v<std::remove_pointer_t<T>>) {
struct field_getter<void*, false, true, C> { lua_rawgetp(L, tableindex, key);
void get(lua_State* L, void* key, int tableindex = -1) { }
lua_rawgetp(L, tableindex, key);
}
};
#endif // Lua 5.3.x #endif // Lua 5.3.x
else {
template <typename T> push(L, std::forward<Key>(key));
struct field_getter<T, false, true, std::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>> { lua_rawget(L, tableindex);
template <typename Key> }
void get(lua_State* L, Key&& key, int tableindex = -1) { }
lua_rawgeti(L, tableindex, static_cast<lua_Integer>(key)); else {
if constexpr (meta::is_c_str_v<T>) {
if constexpr (global) {
(void)tableindex;
lua_getglobal(L, &key[0]);
}
else {
lua_getfield(L, tableindex, &key[0]);
}
}
#if SOL_LUA_VERSION >= 503
else if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) {
lua_geti(L, tableindex, static_cast<lua_Integer>(key));
}
#endif // Lua 5.3.x
else {
push(L, std::forward<Key>(key));
lua_gettable(L, tableindex);
}
}
} }
}; };
@ -158,83 +139,67 @@ namespace stack {
} }
}; };
template <typename T, bool, bool, typename> template <typename T, bool global, bool raw, typename>
struct field_setter { struct field_setter {
static constexpr int default_table_index = std::conditional_t < meta::is_c_str_v<T> || (std::is_integral_v<T> && !std::is_same_v<T, bool>)
|| (std::is_integral_v<T> && !std::is_same_v<T, bool>) || (raw && std::is_void_v<std::remove_pointer_t<T>>),
std::integral_constant<int, -2>, std::integral_constant<int, -3>> ::value;
template <typename Key, typename Value> template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int tableindex = -3) { void set(lua_State* L, Key&& key, Value&& value, int tableindex = default_table_index) {
push(L, std::forward<Key>(key)); if constexpr (std::is_same_v<T, update_if_empty_t> || std::is_same_v<T, override_value_t>) {
push(L, std::forward<Value>(value)); (void)L;
lua_settable(L, tableindex); (void)key;
} (void)value;
}; (void)tableindex;
}
template <typename T, bool b> else if constexpr (std::is_same_v<T, metatable_key_t>) {
struct field_setter<T, b, true, std::enable_if_t<!std::is_same<metatable_t, meta::unqualified_t<T>>::value>> { push(L, std::forward<Value>(value));
template <typename Key, typename Value> lua_setmetatable(L, tableindex);
void set(lua_State* L, Key&& key, Value&& value, int tableindex = -3) { }
push(L, std::forward<Key>(key)); else if constexpr (raw) {
push(L, std::forward<Value>(value)); if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) {
lua_rawset(L, tableindex); push(L, std::forward<Value>(value));
} lua_rawseti(L, tableindex, static_cast<lua_Integer>(key));
}; }
template <bool b, bool raw, typename C>
struct field_setter<metatable_t, b, raw, C> {
template <typename Value>
void set(lua_State* L, metatable_t, Value&& value, int tableindex = -2) {
push(L, std::forward<Value>(value));
lua_setmetatable(L, tableindex);
}
};
template <typename T, bool raw>
struct field_setter<T, true, raw, std::enable_if_t<meta::is_c_str<T>::value>> {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int = -2) {
push(L, std::forward<Value>(value));
lua_setglobal(L, &key[0]);
}
};
template <typename T>
struct field_setter<T, false, false, std::enable_if_t<meta::is_c_str<T>::value>> {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) {
push(L, std::forward<Value>(value));
lua_setfield(L, tableindex, &key[0]);
}
};
#if SOL_LUA_VERSION >= 503
template <typename T>
struct field_setter<T, false, false, std::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>> {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) {
push(L, std::forward<Value>(value));
lua_seti(L, tableindex, static_cast<lua_Integer>(key));
}
};
#endif // Lua 5.3.x
template <typename T>
struct field_setter<T, false, true, std::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>> {
template <typename Key, typename Value>
void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) {
push(L, std::forward<Value>(value));
lua_rawseti(L, tableindex, static_cast<lua_Integer>(key));
}
};
#if SOL_LUA_VERSION >= 502 #if SOL_LUA_VERSION >= 502
template <typename C> else if constexpr (std::is_void_v<std::remove_pointer_t<T>>) {
struct field_setter<void*, false, true, C> { push(L, std::forward<Value>(value));
template <typename Key, typename Value> lua_rawsetp(L, tableindex, key);
void set(lua_State* L, void* key, Value&& value, int tableindex = -2) { }
push(L, std::forward<Value>(value)); #endif // Lua 5.2.x
lua_rawsetp(L, tableindex, key); else {
push(L, std::forward<Key>(key));
push(L, std::forward<Value>(value));
lua_rawset(L, tableindex);
}
}
else {
if constexpr (meta::is_c_str_v<T>) {
if constexpr (global) {
push(L, std::forward<Value>(value));
lua_setglobal(L, &key[0]);
(void)tableindex;
}
else {
push(L, std::forward<Value>(value));
lua_setfield(L, tableindex, &key[0]);
}
}
#if SOL_LUA_VERSION >= 503
else if constexpr(std::is_integral_v<T> && !std::is_same_v<bool, T>) {
push(L, std::forward<Value>(value));
lua_seti(L, tableindex, static_cast<lua_Integer>(key));
}
#endif // Lua 5.3.x
else {
push(L, std::forward<Key>(key));
push(L, std::forward<Value>(value));
lua_settable(L, tableindex);
}
}
} }
}; };
#endif // Lua 5.2.x
template <typename... Args, bool b, bool raw, typename C> template <typename... Args, bool b, bool raw, typename C>
struct field_setter<std::tuple<Args...>, b, raw, C> { struct field_setter<std::tuple<Args...>, b, raw, C> {
@ -268,7 +233,7 @@ namespace stack {
template <typename Keys, typename Value> template <typename Keys, typename Value>
void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -1) { void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -1) {
get_field<b, raw>(L, std::get<0>(std::forward<Keys>(keys)), tableindex); get_field<b, raw>(L, std::get<0>(std::forward<Keys>(keys)), tableindex);
set_field<false, raw>(L, std::get<1>(std::forward<Keys>(keys)), std::forward<Value>(value)); set_field<false, raw>(L, std::get<1>(std::forward<Keys>(keys)), std::forward<Value>(value), lua_gettop(L));
lua_pop(L, 1); lua_pop(L, 1);
} }
}; };

View File

@ -452,8 +452,8 @@ namespace sol {
}; };
template <> template <>
struct unqualified_pusher<metatable_t> { struct unqualified_pusher<metatable_key_t> {
static int push(lua_State* L, metatable_t) { static int push(lua_State* L, metatable_key_t) {
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); luaL_checkstack(L, 1, detail::not_enough_stack_space_generic);
#endif // make sure stack doesn't overflow #endif // make sure stack doesn't overflow
@ -604,7 +604,7 @@ namespace sol {
return 1; return 1;
} }
template <typename Arg, typename... Args, meta::disable<meta::any_same<meta::unqualified_t<Arg>, no_metatable_t, metatable_t>> = meta::enabler> template <typename Arg, typename... Args, meta::disable<meta::any_same<meta::unqualified_t<Arg>, no_metatable_t, metatable_key_t>> = meta::enabler>
static int push(lua_State* L, Arg&& arg, Args&&... args) { static int push(lua_State* L, Arg&& arg, Args&&... args) {
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
return push_with(L, name, std::forward<Arg>(arg), std::forward<Args>(args)...); return push_with(L, name, std::forward<Arg>(arg), std::forward<Args>(args)...);
@ -617,7 +617,7 @@ namespace sol {
} }
template <typename Key, typename... Args> template <typename Key, typename... Args>
static int push(lua_State* L, metatable_t, Key&& key, Args&&... args) { static int push(lua_State* L, metatable_key_t, Key&& key, Args&&... args) {
const auto name = &key[0]; const auto name = &key[0];
return push_with<true>(L, name, std::forward<Args>(args)...); return push_with<true>(L, name, std::forward<Args>(args)...);
} }

View File

@ -81,7 +81,7 @@ namespace sol {
namespace stack { namespace stack {
template <> template <>
struct unqualified_getter<metatable_t> { struct unqualified_getter<metatable_key_t> {
static table get(lua_State* L, int index = -1) { static table get(lua_State* L, int index = -1) {
if (lua_getmetatable(L, index) == 0) { if (lua_getmetatable(L, index) == 0) {
return table(L, ref_index(LUA_REFNIL)); return table(L, ref_index(LUA_REFNIL));

View File

@ -44,6 +44,7 @@ namespace sol {
lua_pop(L, static_cast<int>(n)); lua_pop(L, static_cast<int>(n));
} }
}; };
struct ref_clean { struct ref_clean {
lua_State* L; lua_State* L;
int& n; int& n;
@ -53,6 +54,7 @@ namespace sol {
lua_pop(L, static_cast<int>(n)); lua_pop(L, static_cast<int>(n));
} }
}; };
inline int fail_on_newindex(lua_State* L) { inline int fail_on_newindex(lua_State* L) {
return luaL_error(L, "sol: cannot modify the elements of an enumeration table"); return luaL_error(L, "sol: cannot modify the elements of an enumeration table");
} }
@ -62,6 +64,7 @@ namespace sol {
template <bool top_level, typename... Args> template <bool top_level, typename... Args>
constexpr inline bool is_global_v = is_global<top_level, Args...>::value; constexpr inline bool is_global_v = is_global<top_level, Args...>::value;
} // namespace detail } // namespace detail
template <bool top_level, typename ref_t> template <bool top_level, typename ref_t>
@ -154,20 +157,33 @@ namespace sol {
} }
} }
template <bool global, bool raw, bool forced, typename Key, typename... Keys> template <bool global, bool raw, detail::insert_mode mode, typename Key, typename... Keys>
void traverse_set_deep(int table_index, Key&& key, Keys&&... keys) const { void traverse_set_deep(int table_index, Key&& key, Keys&&... keys) const {
using KeyU = meta::unqualified_t<Key>; using KeyU = meta::unqualified_t<Key>;
lua_State* L = base_t::lua_state(); if constexpr (std::is_same_v<KeyU, update_if_empty_t>) {
if constexpr(std::is_same_v<KeyU, force_t>) {
(void)key; (void)key;
traverse_set_deep<false, raw, true>(table_index, std::forward<Keys>(keys)...); traverse_set_deep<false, raw, detail::insert_mode::update_if_empty>(table_index, std::forward<Keys>(keys)...);
}
else if constexpr (std::is_same_v<KeyU, override_value_t>) {
(void)key;
traverse_set_deep<false, raw, detail::insert_mode::override_value>(table_index, std::forward<Keys>(keys)...);
} }
else { else {
lua_State* L = base_t::lua_state();
if constexpr (sizeof...(Keys) == 1) { if constexpr (sizeof...(Keys) == 1) {
stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index); if constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty) {
stack::get_field<global, raw>(L, key, table_index);
type vt = type_of(L, -1);
if (vt == type::lua_nil || vt == type::none) {
stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index);
}
}
else {
stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index);
}
} }
else { else {
if constexpr (forced) { if constexpr ((mode & detail::insert_mode::override_value) == detail::insert_mode::override_value) {
stack::probe p = stack::probe_get_field<global, raw>(L, key, table_index); stack::probe p = stack::probe_get_field<global, raw>(L, key, table_index);
if (!p.success) { if (!p.success) {
constexpr bool is_seq = std::is_integral_v<KeyU>; constexpr bool is_seq = std::is_integral_v<KeyU>;
@ -175,10 +191,20 @@ namespace sol {
stack::get_field<global, raw>(L, std::forward<Key>(key), table_index); stack::get_field<global, raw>(L, std::forward<Key>(key), table_index);
} }
} }
else if constexpr((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty) {
stack::get_field<global, raw>(L, key, table_index);
type vt = type_of(L, -1);
if (vt == type::lua_nil || vt == type::none) {
constexpr bool is_seq = std::is_integral_v<KeyU>;
lua_pop(L, 1);
stack::set_field<global, raw>(L, key, new_table(static_cast<int>(is_seq), !static_cast<int>(is_seq)), table_index);
stack::get_field<global, raw>(L, std::forward<Key>(key), table_index);
}
}
else { else {
stack::get_field<global, raw>(L, std::forward<Key>(key), table_index); stack::get_field<global, raw>(L, std::forward<Key>(key), table_index);
} }
traverse_set_deep<false, raw, forced>(lua_gettop(L), std::forward<Keys>(keys)...); traverse_set_deep<false, raw, mode>(lua_gettop(L), std::forward<Keys>(keys)...);
} }
} }
} }
@ -251,7 +277,7 @@ namespace sol {
if (!is_table<meta::unqualified_t<T>>::value) { if (!is_table<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
constructor_handler handler{}; constructor_handler handler{};
stack::check<basic_table_core>(L, -1, handler); stack::check<basic_table_core>(lua_state(), -1, handler);
} }
#endif // Safety #endif // Safety
} }
@ -317,7 +343,7 @@ namespace sol {
int table_index = pp.index_of(*this); int table_index = pp.index_of(*this);
lua_State* L = base_t::lua_state(); lua_State* L = base_t::lua_state();
auto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2)); auto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2));
traverse_set_deep<top_level, false, false>(table_index, std::forward<Keys>(keys)...); traverse_set_deep<top_level, false, detail::insert_mode::none>(table_index, std::forward<Keys>(keys)...);
return *this; return *this;
} }

View File

@ -625,6 +625,9 @@ namespace sol {
using is_c_str = any<std::is_same<std::decay_t<unqualified_t<T>>, const char*>, std::is_same<std::decay_t<unqualified_t<T>>, char*>, using is_c_str = any<std::is_same<std::decay_t<unqualified_t<T>>, const char*>, std::is_same<std::decay_t<unqualified_t<T>>, char*>,
std::is_same<unqualified_t<T>, std::string>>; std::is_same<unqualified_t<T>, std::string>>;
template <typename T>
constexpr inline bool is_c_str_v = is_c_str<T>::value;
template <typename T> template <typename T>
struct is_move_only struct is_move_only
: all<neg<std::is_reference<T>>, neg<std::is_copy_constructible<unqualified_t<T>>>, std::is_move_constructible<unqualified_t<T>>> {}; : all<neg<std::is_reference<T>>, neg<std::is_copy_constructible<unqualified_t<T>>>, std::is_move_constructible<unqualified_t<T>>> {};

View File

@ -80,11 +80,9 @@ namespace sol {
template <typename T> template <typename T>
struct implicit_wrapper { struct implicit_wrapper {
T& item; T& item;
implicit_wrapper(T* item) implicit_wrapper(T* item) : item(*item) {
: item(*item) {
} }
implicit_wrapper(T& item) implicit_wrapper(T& item) : item(item) {
: item(item) {
} }
operator T&() { operator T&() {
return item; return item;
@ -115,11 +113,11 @@ namespace sol {
struct non_lua_nil_t {}; struct non_lua_nil_t {};
} // namespace detail } // namespace detail
struct metatable_t {}; struct metatable_key_t {};
const metatable_t metatable_key = {}; const metatable_key_t metatable_key = {};
struct env_t {}; struct env_key_t {};
const env_t env_key = {}; const env_key_t env_key = {};
struct no_metatable_t {}; struct no_metatable_t {};
const no_metatable_t no_metatable = {}; const no_metatable_t no_metatable = {};
@ -133,13 +131,13 @@ namespace sol {
yielding_t(yielding_t&&) = default; yielding_t(yielding_t&&) = default;
yielding_t& operator=(const yielding_t&) = default; yielding_t& operator=(const yielding_t&) = default;
yielding_t& operator=(yielding_t&&) = default; yielding_t& operator=(yielding_t&&) = default;
template <typename Arg, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, yielding_t>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler> template <typename Arg,
yielding_t(Arg&& arg) meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, yielding_t>>,
: func(std::forward<Arg>(arg)) { meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>
yielding_t(Arg&& arg) : func(std::forward<Arg>(arg)) {
} }
template <typename Arg0, typename Arg1, typename... Args> template <typename Arg0, typename Arg1, typename... Args>
yielding_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) yielding_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : func(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {
: func(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {
} }
}; };
@ -217,8 +215,7 @@ namespace sol {
struct upvalue_index { struct upvalue_index {
int index; int index;
upvalue_index(int idx) upvalue_index(int idx) : index(lua_upvalueindex(idx)) {
: index(lua_upvalueindex(idx)) {
} }
operator int() const { operator int() const {
@ -228,8 +225,7 @@ namespace sol {
struct raw_index { struct raw_index {
int index; int index;
raw_index(int i) raw_index(int i) : index(i) {
: index(i) {
} }
operator int() const { operator int() const {
@ -239,8 +235,7 @@ namespace sol {
struct absolute_index { struct absolute_index {
int index; int index;
absolute_index(lua_State* L, int idx) absolute_index(lua_State* L, int idx) : index(lua_absindex(L, idx)) {
: index(lua_absindex(L, idx)) {
} }
operator int() const { operator int() const {
@ -250,8 +245,7 @@ namespace sol {
struct ref_index { struct ref_index {
int index; int index;
ref_index(int idx) ref_index(int idx) : index(idx) {
: index(idx) {
} }
operator int() const { operator int() const {
@ -262,15 +256,13 @@ namespace sol {
struct stack_count { struct stack_count {
int count; int count;
stack_count(int cnt) stack_count(int cnt) : count(cnt) {
: count(cnt) {
} }
}; };
struct lightuserdata_value { struct lightuserdata_value {
void* value; void* value;
lightuserdata_value(void* data) lightuserdata_value(void* data) : value(data) {
: value(data) {
} }
operator void*() const { operator void*() const {
return value; return value;
@ -279,8 +271,7 @@ namespace sol {
struct userdata_value { struct userdata_value {
void* value; void* value;
userdata_value(void* data) userdata_value(void* data) : value(data) {
: value(data) {
} }
operator void*() const { operator void*() const {
return value; return value;
@ -291,14 +282,11 @@ namespace sol {
struct light { struct light {
L* value; L* value;
light(L& x) light(L& x) : value(std::addressof(x)) {
: value(std::addressof(x)) {
} }
light(L* x) light(L* x) : value(x) {
: value(x) {
} }
light(void* x) light(void* x) : value(static_cast<L*>(x)) {
: value(static_cast<L*>(x)) {
} }
operator L*() const { operator L*() const {
return value; return value;
@ -318,8 +306,7 @@ namespace sol {
struct user { struct user {
U value; U value;
user(U&& x) user(U&& x) : value(std::forward<U>(x)) {
: value(std::forward<U>(x)) {
} }
operator std::add_pointer_t<std::remove_reference_t<U>>() { operator std::add_pointer_t<std::remove_reference_t<U>>() {
return std::addressof(value); return std::addressof(value);
@ -342,8 +329,7 @@ namespace sol {
struct metatable_registry_key { struct metatable_registry_key {
T key; T key;
metatable_registry_key(T key) metatable_registry_key(T key) : key(std::forward<T>(key)) {
: key(std::forward<T>(key)) {
} }
}; };
@ -357,8 +343,7 @@ namespace sol {
struct closure { struct closure {
lua_CFunction c_function; lua_CFunction c_function;
std::tuple<Upvalues...> upvalues; std::tuple<Upvalues...> upvalues;
closure(lua_CFunction f, Upvalues... targetupvalues) closure(lua_CFunction f, Upvalues... targetupvalues) : c_function(f), upvalues(std::forward<Upvalues>(targetupvalues)...) {
: c_function(f), upvalues(std::forward<Upvalues>(targetupvalues)...) {
} }
}; };
@ -366,8 +351,7 @@ namespace sol {
struct closure<> { struct closure<> {
lua_CFunction c_function; lua_CFunction c_function;
int upvalues; int upvalues;
closure(lua_CFunction f, int upvalue_count = 0) closure(lua_CFunction f, int upvalue_count = 0) : c_function(f), upvalues(upvalue_count) {
: c_function(f), upvalues(upvalue_count) {
} }
}; };
@ -382,8 +366,7 @@ namespace sol {
struct function_arguments { struct function_arguments {
std::tuple<Ps...> arguments; std::tuple<Ps...> arguments;
template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, function_arguments>> = meta::enabler> template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, function_arguments>> = meta::enabler>
function_arguments(Arg&& arg, Args&&... args) function_arguments(Arg&& arg, Args&&... args) : arguments(std::forward<Arg>(arg), std::forward<Args>(args)...) {
: arguments(std::forward<Arg>(arg), std::forward<Args>(args)...) {
} }
}; };
@ -399,47 +382,75 @@ namespace sol {
template <typename T> template <typename T>
struct as_table_t { struct as_table_t {
T source; private:
T value_;
public:
as_table_t() = default; as_table_t() = default;
as_table_t(const as_table_t&) = default; as_table_t(const as_table_t&) = default;
as_table_t(as_table_t&&) = default; as_table_t(as_table_t&&) = default;
as_table_t& operator=(const as_table_t&) = default; as_table_t& operator=(const as_table_t&) = default;
as_table_t& operator=(as_table_t&&) = default; as_table_t& operator=(as_table_t&&) = default;
template <typename Arg, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, as_table_t>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler> template <typename Arg,
as_table_t(Arg&& arg) meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, as_table_t>>,
: source(std::forward<Arg>(arg)) { meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>
as_table_t(Arg&& arg) : value_(std::forward<Arg>(arg)) {
} }
template <typename Arg0, typename Arg1, typename... Args> template <typename Arg0, typename Arg1, typename... Args>
as_table_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) as_table_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {
: source(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) { }
T& value() & {
return value_;
}
T&& value() && {
return std::move(value_);
}
const T& value() const& {
return value_;
} }
operator std::add_lvalue_reference_t<T>() { operator std::add_lvalue_reference_t<T>() {
return source; return value_;
} }
}; };
template <typename T> template <typename T>
struct nested { struct nested {
T source; private:
T value_;
public:
nested() = default; nested() = default;
nested(const nested&) = default; nested(const nested&) = default;
nested(nested&&) = default; nested(nested&&) = default;
nested& operator=(const nested&) = default; nested& operator=(const nested&) = default;
nested& operator=(nested&&) = default; nested& operator=(nested&&) = default;
template <typename Arg, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, nested>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler> template <typename Arg,
nested(Arg&& arg) meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, nested>>,
: source(std::forward<Arg>(arg)) { meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>
nested(Arg&& arg) : value_(std::forward<Arg>(arg)) {
} }
template <typename Arg0, typename Arg1, typename... Args> template <typename Arg0, typename Arg1, typename... Args>
nested(Arg0&& arg0, Arg1&& arg1, Args&&... args) nested(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {
: source(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) { }
T& value() & {
return value_;
}
T&& value() && {
return std::move(value_);
}
const T& value() const& {
return value_;
} }
operator std::add_lvalue_reference_t<T>() { operator std::add_lvalue_reference_t<T>() {
return source; return value_;
} }
}; };
@ -465,29 +476,52 @@ namespace sol {
template <typename T> template <typename T>
struct as_container_t { struct as_container_t {
T source; private:
T value_;
as_container_t(T value) : source(std::move(value)) {
public:
as_container_t() = default;
as_container_t(const as_container_t&) = default;
as_container_t(as_container_t&&) = default;
as_container_t& operator=(const as_container_t&) = default;
as_container_t& operator=(as_container_t&&) = default;
template <typename Arg,
meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, as_container_t>>,
meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>
as_container_t(Arg&& arg) : value_(std::forward<Arg>(arg)) {
}
template <typename Arg0, typename Arg1, typename... Args>
as_container_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {
} }
operator std::add_rvalue_reference_t<T>() { T& value() & {
return std::move(source); return value_;
} }
operator std::add_lvalue_reference_t<std::add_const_t<T>>() const { T&& value() && {
return source; return std::move(value_);
}
const T& value() const& {
return value_;
} }
}; };
template <typename T> template <typename T>
struct as_container_t<T&> { struct as_container_t<T&> {
std::reference_wrapper<T> source; private:
std::reference_wrapper<T> value_;
as_container_t(T& value) : source(value) { public:
as_container_t(T& value) : value_(value) {
}
T& value() {
return value_;
} }
operator T&() { operator T&() {
return source; return value();
} }
}; };
@ -496,14 +530,69 @@ namespace sol {
return as_container_t<T>(std::forward<T>(value)); return as_container_t<T>(std::forward<T>(value));
} }
struct force_t {}; template <typename T>
constexpr inline force_t force = force_t(); struct push_invoke_t {
private:
T value_;
public:
push_invoke_t() = default;
push_invoke_t(const push_invoke_t&) = default;
push_invoke_t(push_invoke_t&&) = default;
push_invoke_t& operator=(const push_invoke_t&) = default;
push_invoke_t& operator=(push_invoke_t&&) = default;
template <typename Arg,
meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, push_invoke_t>>,
meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>
push_invoke_t(Arg&& arg) : value_(std::forward<Arg>(arg)) {
}
template <typename Arg0, typename Arg1, typename... Args>
push_invoke_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {
}
T& value() & {
return value_;
}
T&& value() && {
return std::move(value_);
}
const T& value() const & {
return value_;
}
};
template <typename T>
struct push_invoke_t<T&> {
std::reference_wrapper<T> value_;
push_invoke_t(T& value) : value_(value) {
}
T& value() {
return value_;
}
};
template <typename Fx>
auto push_invoke(Fx&& fx) {
return push_invoke_t<Fx>(std::forward<Fx>(fx));
}
struct override_value_t {};
constexpr inline override_value_t override_value = override_value_t();
struct update_if_empty_t {};
constexpr inline update_if_empty_t update_if_empty = update_if_empty_t();
namespace detail {
enum insert_mode { none = 0x0, update_if_empty = 0x01, override_value = 0x02 };
}
struct this_state { struct this_state {
lua_State* L; lua_State* L;
this_state(lua_State* Ls) this_state(lua_State* Ls) : L(Ls) {
: L(Ls) {
} }
operator lua_State*() const noexcept { operator lua_State*() const noexcept {
@ -522,8 +611,7 @@ namespace sol {
struct this_main_state { struct this_main_state {
lua_State* L; lua_State* L;
this_main_state(lua_State* Ls) this_main_state(lua_State* Ls) : L(Ls) {
: L(Ls) {
} }
operator lua_State*() const noexcept { operator lua_State*() const noexcept {
@ -549,8 +637,7 @@ namespace sol {
new_table& operator=(const new_table&) = default; new_table& operator=(const new_table&) = default;
new_table& operator=(new_table&&) = default; new_table& operator=(new_table&&) = default;
new_table(int sequence_hint, int map_hint = 0) new_table(int sequence_hint, int map_hint = 0) : sequence_hint(sequence_hint), map_hint(map_hint) {
: sequence_hint(sequence_hint), map_hint(map_hint) {
} }
}; };
@ -587,10 +674,7 @@ namespace sol {
count count
}; };
enum class call_syntax { enum class call_syntax { dot = 0, colon = 1 };
dot = 0,
colon = 1
};
enum class load_mode { enum class load_mode {
any = 0, any = 0,
@ -696,13 +780,9 @@ namespace sol {
} }
inline const std::string& to_string(load_status c) { inline const std::string& to_string(load_status c) {
static const std::array<std::string, 7> names{ { "ok", static const std::array<std::string, 7> names{
"memory", { "ok", "memory", "gc", "syntax", "file", "CRITICAL_EXCEPTION_FAILURE", "CRITICAL_INDETERMINATE_STATE_FAILURE" }
"gc", };
"syntax",
"file",
"CRITICAL_EXCEPTION_FAILURE",
"CRITICAL_INDETERMINATE_STATE_FAILURE" } };
switch (c) { switch (c) {
case load_status::ok: case load_status::ok:
return names[0]; return names[0];
@ -829,16 +909,15 @@ namespace sol {
template <typename T> template <typename T>
struct is_lua_reference : std::integral_constant<bool, struct is_lua_reference : std::integral_constant<bool,
std::is_base_of<reference, meta::unqualified_t<T>>::value std::is_base_of<reference, meta::unqualified_t<T>>::value || std::is_base_of<main_reference, meta::unqualified_t<T>>::value
|| std::is_base_of<main_reference, meta::unqualified_t<T>>::value || std::is_base_of<stack_reference, meta::unqualified_t<T>>::value> {};
|| std::is_base_of<stack_reference, meta::unqualified_t<T>>::value> {};
template <typename T> template <typename T>
inline constexpr bool is_lua_reference_v = is_lua_reference<T>::value; inline constexpr bool is_lua_reference_v = is_lua_reference<T>::value;
template <typename T> template <typename T>
struct is_lua_reference_or_proxy struct is_lua_reference_or_proxy
: std::integral_constant<bool, is_lua_reference<meta::unqualified_t<T>>::value || meta::is_specialization_of<meta::unqualified_t<T>, proxy>::value> {}; : std::integral_constant<bool, is_lua_reference<meta::unqualified_t<T>>::value || meta::is_specialization_of<meta::unqualified_t<T>, proxy>::value> {};
template <typename T> template <typename T>
inline constexpr bool is_lua_reference_or_proxy_v = is_lua_reference_or_proxy<T>::value; inline constexpr bool is_lua_reference_or_proxy_v = is_lua_reference_or_proxy<T>::value;
@ -873,17 +952,23 @@ namespace sol {
struct is_container<T, std::enable_if_t<meta::is_string_like<meta::unqualified_t<T>>::value>> : std::false_type {}; struct is_container<T, std::enable_if_t<meta::is_string_like<meta::unqualified_t<T>>::value>> : std::false_type {};
template <typename T> template <typename T>
struct is_container<T, std::enable_if_t<meta::all<std::is_array<meta::unqualified_t<T>>, meta::neg<meta::any_same<std::remove_all_extents_t<meta::unqualified_t<T>>, char, wchar_t, char16_t, char32_t>>>::value>> : std::true_type {}; struct is_container<T,
std::enable_if_t<meta::all<std::is_array<meta::unqualified_t<T>>,
meta::neg<meta::any_same<std::remove_all_extents_t<meta::unqualified_t<T>>, char, wchar_t, char16_t, char32_t>>>::value>> : std::true_type {
};
template <typename T> template <typename T>
struct is_container<T, std::enable_if_t<meta::all<meta::has_begin_end<meta::unqualified_t<T>>, meta::neg<is_initializer_list<meta::unqualified_t<T>>>, meta::neg<meta::is_string_like<meta::unqualified_t<T>>>>::value>> : std::true_type {}; struct is_container<T,
std::enable_if_t<meta::all<meta::has_begin_end<meta::unqualified_t<T>>, meta::neg<is_initializer_list<meta::unqualified_t<T>>>,
meta::neg<meta::is_string_like<meta::unqualified_t<T>>>>::value>> : std::true_type {};
} // namespace detail } // namespace detail
template <typename T> template <typename T>
struct is_container : detail::is_container<T> {}; struct is_container : detail::is_container<T> {};
template <typename T> template <typename T>
struct is_to_stringable : meta::any<meta::supports_to_string_member<meta::unqualified_t<T>>, meta::supports_adl_to_string<meta::unqualified_t<T>>, meta::supports_ostream_op<meta::unqualified_t<T>>> {}; struct is_to_stringable : meta::any<meta::supports_to_string_member<meta::unqualified_t<T>>, meta::supports_adl_to_string<meta::unqualified_t<T>>,
meta::supports_ostream_op<meta::unqualified_t<T>>> {};
namespace detail { namespace detail {
template <typename T, typename = void> template <typename T, typename = void>
@ -956,13 +1041,13 @@ namespace sol {
struct lua_type_of<basic_usertype<T, Base>> : std::integral_constant<type, type::table> {}; struct lua_type_of<basic_usertype<T, Base>> : std::integral_constant<type, type::table> {};
template <> template <>
struct lua_type_of<metatable_t> : std::integral_constant<type, type::table> {}; struct lua_type_of<metatable_key_t> : std::integral_constant<type, type::table> {};
template <typename B> template <typename B>
struct lua_type_of<basic_environment<B>> : std::integral_constant<type, type::poly> {}; struct lua_type_of<basic_environment<B>> : std::integral_constant<type, type::poly> {};
template <> template <>
struct lua_type_of<env_t> : std::integral_constant<type, type::poly> {}; struct lua_type_of<env_key_t> : std::integral_constant<type, type::poly> {};
template <> template <>
struct lua_type_of<new_table> : std::integral_constant<type, type::table> {}; struct lua_type_of<new_table> : std::integral_constant<type, type::table> {};
@ -1130,7 +1215,9 @@ namespace sol {
namespace detail { namespace detail {
template <typename...> template <typename...>
struct void_ { typedef void type; }; struct void_ {
typedef void type;
};
template <typename T, typename = void> template <typename T, typename = void>
struct has_internal_marker_impl : std::false_type {}; struct has_internal_marker_impl : std::false_type {};
template <typename T> template <typename T>
@ -1141,14 +1228,13 @@ namespace sol {
} // namespace detail } // namespace detail
template <typename T> template <typename T>
struct is_lua_primitive : std::integral_constant<bool, struct is_lua_primitive
type::userdata != lua_type_of<meta::unqualified_t<T>>::value : std::integral_constant<bool,
|| ((type::userdata == lua_type_of<meta::unqualified_t<T>>::value) type::userdata != lua_type_of<meta::unqualified_t<T>>::value
&& detail::has_internal_marker<lua_type_of<meta::unqualified_t<T>>>::value || ((type::userdata == lua_type_of<meta::unqualified_t<T>>::value) && detail::has_internal_marker<lua_type_of<meta::unqualified_t<T>>>::value
&& !detail::has_internal_marker<lua_size<meta::unqualified_t<T>>>::value) && !detail::has_internal_marker<lua_size<meta::unqualified_t<T>>>::value)
|| is_lua_reference<meta::unqualified_t<T>>::value || is_lua_reference<meta::unqualified_t<T>>::value || meta::is_specialization_of<meta::unqualified_t<T>, std::tuple>::value
|| meta::is_specialization_of<meta::unqualified_t<T>, std::tuple>::value || meta::is_specialization_of<meta::unqualified_t<T>, std::pair>::value> {};
|| meta::is_specialization_of<meta::unqualified_t<T>, std::pair>::value> {};
template <typename T> template <typename T>
struct is_main_threaded : std::is_base_of<main_reference, T> {}; struct is_main_threaded : std::is_base_of<main_reference, T> {};
@ -1217,9 +1303,11 @@ namespace sol {
public: public:
typedef std::integral_constant<bool, meta::count_for<is_variadic_arguments, typename base_t::args_list>::value != 0> runtime_variadics_t; typedef std::integral_constant<bool, meta::count_for<is_variadic_arguments, typename base_t::args_list>::value != 0> runtime_variadics_t;
static const std::size_t true_arity = base_t::arity; static const std::size_t true_arity = base_t::arity;
static const std::size_t arity = detail::accumulate_list<std::size_t, 0, lua_size, typename base_t::args_list>::value - meta::count_for<is_transparent_argument, typename base_t::args_list>::value; static const std::size_t arity = detail::accumulate_list<std::size_t, 0, lua_size, typename base_t::args_list>::value
- meta::count_for<is_transparent_argument, typename base_t::args_list>::value;
static const std::size_t true_free_arity = base_t::free_arity; static const std::size_t true_free_arity = base_t::free_arity;
static const std::size_t free_arity = detail::accumulate_list<std::size_t, 0, lua_size, typename base_t::free_args_list>::value - meta::count_for<is_transparent_argument, typename base_t::args_list>::value; static const std::size_t free_arity = detail::accumulate_list<std::size_t, 0, lua_size, typename base_t::free_args_list>::value
- meta::count_for<is_transparent_argument, typename base_t::args_list>::value;
}; };
template <typename T> template <typename T>

View File

@ -387,11 +387,11 @@ namespace sol {
} }
static int push(lua_State* L, const as_container_t<T>& as_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.source); return push_lvalue(std::is_lvalue_reference<T>(), L, as_cont.value());
} }
static int push(lua_State* L, as_container_t<T>&& as_cont) { 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.source)); return push_rvalue(meta::all<std::is_rvalue_reference<T>, meta::neg<std::is_lvalue_reference<T>>>(), L, std::forward<T>(as_cont.value()));
} }
}; };

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2019-02-14 09:52:13.841439 UTC // Generated 2019-02-16 22:26:16.417718 UTC
// This header was generated with sol v2.20.6 (revision b938e42) // This header was generated with sol v3.0.0 (revision 95ffd10)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
@ -376,8 +376,6 @@ namespace sol {
template <typename T> template <typename T>
struct as_container_t; struct as_container_t;
template <typename T> template <typename T>
struct force_t;
template <typename T>
struct nested; struct nested;
template <typename T> template <typename T>
struct light; struct light;

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,7 @@ TEST_CASE("containers/vector table roundtrip", "make sure vectors can be round-t
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
sol::as_table_t<std::vector<int>> x = lua["x"]; sol::as_table_t<std::vector<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.value() == v;
REQUIRE(areequal); REQUIRE(areequal);
} }
@ -60,7 +60,7 @@ TEST_CASE("containers/deque table roundtrip", "make sure deques can be round-tri
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
sol::as_table_t<std::deque<int>> x = lua["x"]; sol::as_table_t<std::deque<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.value() == v;
REQUIRE(areequal); REQUIRE(areequal);
} }
@ -73,7 +73,7 @@ TEST_CASE("containers/array table roundtrip", "make sure arrays can be round-tri
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
sol::as_table_t<std::array<int, 3>> x = lua["x"]; sol::as_table_t<std::array<int, 3>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.value() == v;
REQUIRE(areequal); REQUIRE(areequal);
} }
@ -86,7 +86,7 @@ TEST_CASE("containers/list table roundtrip", "make sure lists can be round-tripp
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
sol::as_table_t<std::list<int>> x = lua["x"]; sol::as_table_t<std::list<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.value() == v;
REQUIRE(areequal); REQUIRE(areequal);
} }
@ -99,7 +99,7 @@ TEST_CASE("containers/forward_list table roundtrip", "make sure forward_lists ca
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
sol::as_table_t<std::forward_list<int>> x = lua["x"]; sol::as_table_t<std::forward_list<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.value() == v;
REQUIRE(areequal); REQUIRE(areequal);
} }
@ -112,7 +112,7 @@ TEST_CASE("containers/map table roundtrip", "make sure maps can be round-tripped
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
sol::as_table_t<std::map<std::string, int>> x = lua["x"]; sol::as_table_t<std::map<std::string, int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.value() == v;
REQUIRE(areequal); REQUIRE(areequal);
} }
@ -125,7 +125,7 @@ TEST_CASE("containers/unordered_map table roundtrip", "make sure unordered_maps
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
sol::as_table_t<std::unordered_map<std::string, int>> x = lua["x"]; sol::as_table_t<std::unordered_map<std::string, int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.value() == v;
REQUIRE(areequal); REQUIRE(areequal);
} }
@ -138,7 +138,7 @@ TEST_CASE("containers/unordered_set table roundtrip", "make sure unordered_sets
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
sol::as_table_t<std::unordered_set<int>> x = lua["x"]; sol::as_table_t<std::unordered_set<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.value() == v;
REQUIRE(areequal); REQUIRE(areequal);
} }
@ -151,7 +151,7 @@ TEST_CASE("containers/set table roundtrip", "make sure sets can be round-tripped
auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error); auto result1 = lua.safe_script("x = f()", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
sol::as_table_t<std::set<int>> x = lua["x"]; sol::as_table_t<std::set<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.value() == v;
REQUIRE(areequal); REQUIRE(areequal);
} }
@ -248,8 +248,8 @@ TEST_CASE("containers/table conversion", "test table conversions with as_table a
sol::nested<std::vector<std::string>> nested_strings = lua["v2"]; sol::nested<std::vector<std::string>> nested_strings = lua["v2"];
std::vector<std::string> expected_values{ "bark", "woof" }; std::vector<std::string> expected_values{ "bark", "woof" };
REQUIRE(as_table_strings.source == expected_values); REQUIRE(as_table_strings.value() == expected_values);
REQUIRE(nested_strings.source == expected_values); REQUIRE(nested_strings.value() == expected_values);
} }
TEST_CASE("containers/from table argument conversions", "test table conversions without as_table and nested for function args") { TEST_CASE("containers/from table argument conversions", "test table conversions without as_table and nested for function args") {

View File

@ -201,11 +201,11 @@ end
sol::as_table_t<std::forward_list<int>> t1flist = lua["c"]; sol::as_table_t<std::forward_list<int>> t1flist = lua["c"];
sol::as_table_t<std::set<int>> t1set = lua["c"]; sol::as_table_t<std::set<int>> t1set = lua["c"];
const int src[5] = { 1, 2, 3, 4, 5 }; const int src[5] = { 1, 2, 3, 4, 5 };
check_ordered_values(src, t1vector.source); check_ordered_values(src, t1vector.value());
check_ordered_values(src, t1deque.source); check_ordered_values(src, t1deque.value());
check_ordered_values(src, t1list.source); check_ordered_values(src, t1list.value());
check_ordered_values(src, t1flist.source); check_ordered_values(src, t1flist.value());
check_ordered_values(src, t1set.source); check_ordered_values(src, t1set.value());
} }
SECTION("map-like") { SECTION("map-like") {
sol::state lua; sol::state lua;
@ -216,7 +216,7 @@ end
sol::as_table_t<std::unordered_map<std::string, int>> t1umap = lua["c"]; sol::as_table_t<std::unordered_map<std::string, int>> t1umap = lua["c"];
sol::as_table_t<std::unordered_multimap<std::string, int>> t1ummap = lua["c"]; sol::as_table_t<std::unordered_multimap<std::string, int>> t1ummap = lua["c"];
table_check_unordered_values(src, t1umap.source); table_check_unordered_values(src, t1umap.value());
table_check_unordered_values(src, t1ummap.source); table_check_unordered_values(src, t1ummap.value());
} }
} }

View File

@ -1,63 +0,0 @@
// sol3
// The MIT License (MIT)
// Copyright (c) 2013-2018 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.
#include "sol_test.hpp"
#include <catch.hpp>
#include <iostream>
TEST_CASE("tables/force", "allow force by way of key") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::io);
sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
lua["a"].force()["b"].force()["c"] = 357;
sol::optional<int> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there));
REQUIRE(*totally_there == 357);
}
TEST_CASE("tables/proxy force", "allow proxies to force creation of tables with explicit function") {
SECTION("explicit") {
sol::state lua;
sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
lua["a"].force()["b"].force()["c"] = 357;
sol::optional<int> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there));
REQUIRE(*totally_there == 357);
}
SECTION("key type") {
sol::state lua;
sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
lua[sol::force]["a"]["b"]["c"] = 357;
sol::optional<int> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there));
REQUIRE(*totally_there == 357);
}
}

View File

@ -0,0 +1,132 @@
// sol3
// The MIT License (MIT)
// Copyright (c) 2013-2018 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.
#include "sol_test.hpp"
#include <catch.hpp>
#include <iostream>
TEST_CASE("tables/proxy override_value", "allow override_value by way of key") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::io);
sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
lua["a"].force()["b"].force()["c"] = 357;
sol::optional<int> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there));
REQUIRE(*totally_there == 357);
}
TEST_CASE("tables/insertion override", "allow override all non-table values plus final value") {
SECTION("traverse") {
sol::state lua;
sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
lua.traverse_set(sol::override_value, "a", "b", "c", 357);
sol::optional<int> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there));
REQUIRE(*totally_there == 357);
lua.traverse_set(sol::override_value, "a", "b", 500);
sol::optional<int> b_totally_there = lua["a"]["b"];
sol::optional<int> totally_not_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(b_totally_there));
REQUIRE(*b_totally_there == 500);
REQUIRE_FALSE(static_cast<bool>(totally_not_there));
}
SECTION("proxy") {
sol::state lua;
sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
lua[sol::override_value]["a"]["b"]["c"] = 357;
sol::optional<int> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there));
REQUIRE(*totally_there == 357);
lua[sol::override_value]["a"]["b"] = 500;
sol::optional<int> b_totally_there = lua["a"]["b"];
sol::optional<int> totally_not_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(b_totally_there));
REQUIRE(*b_totally_there == 500);
REQUIRE_FALSE(static_cast<bool>(totally_not_there));
}
SECTION("complex proxy") {
sol::state lua;
sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
int definitely_there = (lua[sol::override_value]["a"]["b"]["c"] = 357);
sol::optional<int> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there));
REQUIRE(*totally_there == definitely_there);
REQUIRE(*totally_there == 357);
REQUIRE(definitely_there == 357);
}
}
TEST_CASE("tables/insertion update_if_empty", "allow updating a value only if it's missing") {
SECTION("traverse") {
sol::state lua;
sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
lua.traverse_set(sol::update_if_empty, "a", "b", "c", 357);
sol::optional<int> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there));
REQUIRE(*totally_there == 357);
}
SECTION("proxy") {
sol::state lua;
sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
lua[sol::update_if_empty]["a"]["b"]["c"] = 357;
sol::optional<int> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there));
REQUIRE(*totally_there == 357);
lua[sol::update_if_empty]["a"]["b"]["c"] = 500;
sol::optional<int> totally_there_still = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there_still));
REQUIRE(*totally_there_still == 357);
}
SECTION("proxy invoker") {
sol::state lua;
sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
lua[sol::update_if_empty]["a"]["b"]["c"] = sol::push_invoke([]() { return 357; });
sol::optional<int> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there));
REQUIRE(*totally_there == 357);
lua[sol::update_if_empty]["a"]["b"]["c"] = sol::push_invoke([]() { return 1000; });
sol::optional<int> totally_there_still = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_there_still));
REQUIRE(*totally_there_still == 357);
}
}