New feature: nested getter for complex nested tables, plus docs and example

This commit is contained in:
ThePhD 2017-03-30 14:11:43 -04:00
parent 92d31b39b7
commit 4094ba3e7a
6 changed files with 255 additions and 24 deletions

View File

@ -0,0 +1,16 @@
nested
======
.. code-block:: cpp
template <typename T>
struct nested {
T source;
};
``sol::nested<...>`` is a template class similar to :doc:`sol::as_table<as_table>`, but with the caveat that every :doc:`container type<containers>` within the ``sol::nested`` type will be retrieved as a table from lua. This is helpful when you need to receive C++-style vectors, lists, and maps nested within each other: all of them will be deserialized from lua using table properties rather than anything else.
The `example`_ provides a very in-depth look at both ``sol::as_table<T>`` and ``sol::nested<T>``, and how the two are equivalent.
.. _example: https://github.com/ThePhD/sol2/blob/develop/examples/containers_as_table.cpp

View File

@ -6,21 +6,51 @@
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
// Nota bene the signature here
// Every container-type that's a table must be wrapped in `sol::as_table_t` // nested allows serialization of maps with vectors inside, and vice-versa
// it's verbose, so feel free to use typedefs ot make it easy on you // all from a nested structure of Lua tables
void demo (sol::as_table_t<std::map<std::string, sol::as_table_t<std::vector<std::string>>>> src) { // it has less control over which pieces are considered tables in Lua,
// and which ones are considered userdata, but it covers a good 90% of cases
// where someone wants to handle a nested table
void demo(sol::nested<std::map<std::string, std::vector<std::string>>> src) {
std::cout << "demo, sol::nested<...>" << std::endl;
const auto& listmap = src.source; const auto& listmap = src.source;
assert(listmap.size() == 2); assert(listmap.size() == 2);
for (const auto& kvp : listmap) { for (const auto& kvp : listmap) {
const std::vector<std::string>& strings = kvp.second.source; const std::vector<std::string>& strings = kvp.second;
assert(strings.size() == 3); assert(strings.size() == 3);
std::cout << kvp.first << " = "; std::cout << "\t" << kvp.first << " = ";
for (const auto& s : strings) { for (const auto& s : strings) {
std::cout << "'" << s << "'" << " "; std::cout << "'" << s << "'" << " ";
} }
std::cout << std::endl; std::cout << std::endl;
} }
std::cout << std::endl;
}
// This second demo is equivalent to the first
// Nota bene the signature here
// Every container-type that's meant to be
// a table must be wrapped in `sol::as_table_t`
// it's verbose, so feel free to use typedefs to make it easy on you
// you can mix which parts are considered tables from Lua, and which parts
// are considered other kinds of types, such as userdata and the like
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;
// Have to access the "source" member variable for as_table_t
const auto& listmap = src.source;
assert(listmap.size() == 2);
for (const auto& kvp : listmap) {
// Have to access the internal "source" for the inner as_table_t, as well
const std::vector<std::string>& strings = kvp.second.source;
assert(strings.size() == 3);
std::cout << "\t" << kvp.first << " = ";
for (const auto& s : strings) {
std::cout << "'" << s << "'" << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
} }
int main(int, char**) { int main(int, char**) {
@ -29,12 +59,15 @@ int main(int, char**) {
sol::state lua; sol::state lua;
// bind the function // bind the function
lua.set_function("f", &demo); lua.set_function("f", &demo);
lua.set_function("g", &demo_explicit);
// Call it with a table that has string sequences set to distinct keys // Call it with a table that has string sequences set to distinct keys
lua.script(R"( lua.script(R"(
f({ t = {
key1 = {'hello', 'there', 'world'}, key1 = {'hello', 'there', 'world'},
key2 = {'bark', 'borf', 'woof'} key2 = {'bark', 'borf', 'woof'}
}) }
f(t)
g(t)
)"); )");
std::cout << std::endl; std::cout << std::endl;

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 2017-03-30 08:20:24.093445 UTC // Generated 2017-03-30 18:11:26.562402 UTC
// This header was generated with sol v2.16.0 (revision 4f72880) // This header was generated with sol v2.16.0 (revision 92d31b3)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP #ifndef SOL_SINGLE_INCLUDE_HPP
@ -3286,6 +3286,18 @@ namespace sol {
} }
}; };
template <typename T>
struct nested {
T source;
template <typename... Args>
nested(Args&&... args) : source(std::forward<Args>(args)...) {}
operator std::add_lvalue_reference_t<T>() {
return source;
}
};
template <typename T> template <typename T>
as_table_t<T> as_table(T&& container) { as_table_t<T> as_table(T&& container) {
return as_table_t<T>(std::forward<T>(container)); return as_table_t<T>(std::forward<T>(container));
@ -3674,6 +3686,18 @@ namespace sol {
template <typename T, typename C = void> template <typename T, typename C = void>
struct is_container : std::false_type {}; struct is_container : std::false_type {};
template <>
struct is_container<std::string> : std::false_type {};
template <>
struct is_container<std::wstring> : std::false_type {};
template <>
struct is_container<std::u16string> : std::false_type {};
template <>
struct is_container<std::u32string> : std::false_type {};
template <typename T> template <typename T>
struct is_container<T, std::enable_if_t<meta::has_begin_end<meta::unqualified_t<T>>::value>> : std::true_type {}; struct is_container<T, std::enable_if_t<meta::has_begin_end<meta::unqualified_t<T>>::value>> : std::true_type {};
@ -3810,6 +3834,14 @@ namespace sol {
inline type type_of() { inline type type_of() {
return lua_type_of<meta::unqualified_t<T>>::value; return lua_type_of<meta::unqualified_t<T>>::value;
} }
namespace detail {
template <typename T>
struct lua_type_of<nested<T>, std::enable_if_t<::sol::is_container<T>::value>> : std::integral_constant<type, type::table> {};
template <typename T>
struct lua_type_of<nested<T>, std::enable_if_t<!::sol::is_container<T>::value>> : lua_type_of<T> {};
} // detail
} // sol } // sol
// end of sol/types.hpp // end of sol/types.hpp
@ -5131,7 +5163,7 @@ namespace sol {
return true; return true;
} }
if (t != type::userdata) { if (t != type::userdata) {
handler(L, index, type::function, t); handler(L, index, type::table, t);
return false; return false;
} }
return true; return true;
@ -5330,6 +5362,11 @@ namespace sol {
struct getter<as_table_t<T>, std::enable_if_t<!meta::has_key_value_pair<meta::unqualified_t<T>>::value>> { struct getter<as_table_t<T>, std::enable_if_t<!meta::has_key_value_pair<meta::unqualified_t<T>>::value>> {
static T get(lua_State* L, int relindex, record& tracking) { static T get(lua_State* L, int relindex, record& tracking) {
typedef typename T::value_type V; typedef typename T::value_type V;
return get(types<V>(), L, relindex, tracking);
}
template <typename V>
static T get(types<V>, lua_State* L, int relindex, record& tracking) {
tracking.use(1); tracking.use(1);
int index = lua_absindex(L, relindex); int index = lua_absindex(L, relindex);
@ -5385,10 +5422,15 @@ namespace sol {
typedef typename T::value_type P; typedef typename T::value_type P;
typedef typename P::first_type K; typedef typename P::first_type K;
typedef typename P::second_type V; typedef typename P::second_type V;
return get(types<K, V>(), L, index, tracking);
}
template <typename K, typename V>
static T get(types<K, V>, lua_State* L, int relindex, record& tracking) {
tracking.use(1); tracking.use(1);
T associative; T associative;
index = lua_absindex(L, index); int index = lua_absindex(L, relindex);
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, index) != 0) { while (lua_next(L, index) != 0) {
decltype(auto) key = stack::check_get<K>(L, -2); decltype(auto) key = stack::check_get<K>(L, -2);
@ -5403,6 +5445,40 @@ namespace sol {
} }
}; };
template<typename T>
struct getter<nested<T>, std::enable_if_t<!is_container<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
getter<T> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(L, index, tracking);
}
};
template<typename T>
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::neg<meta::has_key_value_pair<meta::unqualified_t<T>>>>::value>> {
static T get(lua_State* L, int index, record& tracking) {
typedef typename T::value_type V;
getter<as_table_t<T>> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(types<nested<V>>(), L, index, tracking);
}
};
template<typename T>
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::has_key_value_pair<meta::unqualified_t<T>>>::value>> {
static T get(lua_State* L, int index, record& tracking) {
typedef typename T::value_type P;
typedef typename P::first_type K;
typedef typename P::second_type V;
getter<as_table_t<T>> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(types<K, nested<V>>(), L, index, tracking);
}
};
template<typename T> template<typename T>
struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> { struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> {
static T get(lua_State* L, int index, record& tracking) { static T get(lua_State* L, int index, record& tracking) {
@ -5716,35 +5792,50 @@ namespace sol {
tracking.use(1); tracking.use(1);
return nullptr; return nullptr;
} }
return getter<detail::as_value_tag<T>>::get_no_lua_nil(L, index, tracking); getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get_no_lua_nil(L, index, tracking);
} }
}; };
template<typename T> template<typename T>
struct getter<non_null<T*>> { struct getter<non_null<T*>> {
static T* get(lua_State* L, int index, record& tracking) { static T* get(lua_State* L, int index, record& tracking) {
return getter<detail::as_value_tag<T>>::get_no_lua_nil(L, index, tracking); getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get_no_lua_nil(L, index, tracking);
} }
}; };
template<typename T> template<typename T>
struct getter<T&> { struct getter<T&> {
static T& get(lua_State* L, int index, record& tracking) { static T& get(lua_State* L, int index, record& tracking) {
return getter<detail::as_value_tag<T>>::get(L, index, tracking); getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
} }
}; };
template<typename T> template<typename T>
struct getter<std::reference_wrapper<T>> { struct getter<std::reference_wrapper<T>> {
static T& get(lua_State* L, int index, record& tracking) { static T& get(lua_State* L, int index, record& tracking) {
return getter<T&>{}.get(L, index, tracking); getter<T&> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
} }
}; };
template<typename T> template<typename T>
struct getter<T*> { struct getter<T*> {
static T* get(lua_State* L, int index, record& tracking) { static T* get(lua_State* L, int index, record& tracking) {
return getter<detail::as_pointer_tag<T>>::get(L, index, tracking); getter<detail::as_pointer_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
} }
}; };

View File

@ -259,7 +259,7 @@ namespace sol {
return true; return true;
} }
if (t != type::userdata) { if (t != type::userdata) {
handler(L, index, type::function, t); handler(L, index, type::table, t);
return false; return false;
} }
return true; return true;

View File

@ -81,6 +81,11 @@ namespace sol {
struct getter<as_table_t<T>, std::enable_if_t<!meta::has_key_value_pair<meta::unqualified_t<T>>::value>> { struct getter<as_table_t<T>, std::enable_if_t<!meta::has_key_value_pair<meta::unqualified_t<T>>::value>> {
static T get(lua_State* L, int relindex, record& tracking) { static T get(lua_State* L, int relindex, record& tracking) {
typedef typename T::value_type V; typedef typename T::value_type V;
return get(types<V>(), L, relindex, tracking);
}
template <typename V>
static T get(types<V>, lua_State* L, int relindex, record& tracking) {
tracking.use(1); tracking.use(1);
int index = lua_absindex(L, relindex); int index = lua_absindex(L, relindex);
@ -136,10 +141,15 @@ namespace sol {
typedef typename T::value_type P; typedef typename T::value_type P;
typedef typename P::first_type K; typedef typename P::first_type K;
typedef typename P::second_type V; typedef typename P::second_type V;
return get(types<K, V>(), L, index, tracking);
}
template <typename K, typename V>
static T get(types<K, V>, lua_State* L, int relindex, record& tracking) {
tracking.use(1); tracking.use(1);
T associative; T associative;
index = lua_absindex(L, index); int index = lua_absindex(L, relindex);
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, index) != 0) { while (lua_next(L, index) != 0) {
decltype(auto) key = stack::check_get<K>(L, -2); decltype(auto) key = stack::check_get<K>(L, -2);
@ -154,6 +164,40 @@ namespace sol {
} }
}; };
template<typename T>
struct getter<nested<T>, std::enable_if_t<!is_container<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {
getter<T> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(L, index, tracking);
}
};
template<typename T>
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::neg<meta::has_key_value_pair<meta::unqualified_t<T>>>>::value>> {
static T get(lua_State* L, int index, record& tracking) {
typedef typename T::value_type V;
getter<as_table_t<T>> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(types<nested<V>>(), L, index, tracking);
}
};
template<typename T>
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::has_key_value_pair<meta::unqualified_t<T>>>::value>> {
static T get(lua_State* L, int index, record& tracking) {
typedef typename T::value_type P;
typedef typename P::first_type K;
typedef typename P::second_type V;
getter<as_table_t<T>> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(types<K, nested<V>>(), L, index, tracking);
}
};
template<typename T> template<typename T>
struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> { struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> {
static T get(lua_State* L, int index, record& tracking) { static T get(lua_State* L, int index, record& tracking) {
@ -467,35 +511,50 @@ namespace sol {
tracking.use(1); tracking.use(1);
return nullptr; return nullptr;
} }
return getter<detail::as_value_tag<T>>::get_no_lua_nil(L, index, tracking); getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get_no_lua_nil(L, index, tracking);
} }
}; };
template<typename T> template<typename T>
struct getter<non_null<T*>> { struct getter<non_null<T*>> {
static T* get(lua_State* L, int index, record& tracking) { static T* get(lua_State* L, int index, record& tracking) {
return getter<detail::as_value_tag<T>>::get_no_lua_nil(L, index, tracking); getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get_no_lua_nil(L, index, tracking);
} }
}; };
template<typename T> template<typename T>
struct getter<T&> { struct getter<T&> {
static T& get(lua_State* L, int index, record& tracking) { static T& get(lua_State* L, int index, record& tracking) {
return getter<detail::as_value_tag<T>>::get(L, index, tracking); getter<detail::as_value_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
} }
}; };
template<typename T> template<typename T>
struct getter<std::reference_wrapper<T>> { struct getter<std::reference_wrapper<T>> {
static T& get(lua_State* L, int index, record& tracking) { static T& get(lua_State* L, int index, record& tracking) {
return getter<T&>{}.get(L, index, tracking); getter<T&> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
} }
}; };
template<typename T> template<typename T>
struct getter<T*> { struct getter<T*> {
static T* get(lua_State* L, int index, record& tracking) { static T* get(lua_State* L, int index, record& tracking) {
return getter<detail::as_pointer_tag<T>>::get(L, index, tracking); getter<detail::as_pointer_tag<T>> g;
// Avoid VC++ warning
(void)g;
return g.get(L, index, tracking);
} }
}; };

View File

@ -307,6 +307,18 @@ namespace sol {
} }
}; };
template <typename T>
struct nested {
T source;
template <typename... Args>
nested(Args&&... args) : source(std::forward<Args>(args)...) {}
operator std::add_lvalue_reference_t<T>() {
return source;
}
};
template <typename T> template <typename T>
as_table_t<T> as_table(T&& container) { as_table_t<T> as_table(T&& container) {
return as_table_t<T>(std::forward<T>(container)); return as_table_t<T>(std::forward<T>(container));
@ -695,6 +707,18 @@ namespace sol {
template <typename T, typename C = void> template <typename T, typename C = void>
struct is_container : std::false_type {}; struct is_container : std::false_type {};
template <>
struct is_container<std::string> : std::false_type {};
template <>
struct is_container<std::wstring> : std::false_type {};
template <>
struct is_container<std::u16string> : std::false_type {};
template <>
struct is_container<std::u32string> : std::false_type {};
template <typename T> template <typename T>
struct is_container<T, std::enable_if_t<meta::has_begin_end<meta::unqualified_t<T>>::value>> : std::true_type {}; struct is_container<T, std::enable_if_t<meta::has_begin_end<meta::unqualified_t<T>>::value>> : std::true_type {};
@ -831,6 +855,14 @@ namespace sol {
inline type type_of() { inline type type_of() {
return lua_type_of<meta::unqualified_t<T>>::value; return lua_type_of<meta::unqualified_t<T>>::value;
} }
namespace detail {
template <typename T>
struct lua_type_of<nested<T>, std::enable_if_t<::sol::is_container<T>::value>> : std::integral_constant<type, type::table> {};
template <typename T>
struct lua_type_of<nested<T>, std::enable_if_t<!::sol::is_container<T>::value>> : lua_type_of<T> {};
} // detail
} // sol } // sol
#endif // SOL_TYPES_HPP #endif // SOL_TYPES_HPP