initializer_list support and tests, waiting for the day when we can use some kind of lua_any to store any value into Lua and thus have initializer lists become the new hot stuff

This commit is contained in:
ThePhD 2017-09-22 18:54:33 -04:00
parent 96fc84b4ef
commit 8f3699bea5
6 changed files with 172 additions and 22 deletions

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-09-22 15:04:13.948949 UTC // Generated 2017-09-22 22:53:40.988986 UTC
// This header was generated with sol v2.18.3 (revision 0114882) // This header was generated with sol v2.18.3 (revision 290a671)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP #ifndef SOL_SINGLE_INCLUDE_HPP
@ -5095,9 +5095,18 @@ namespace sol {
} }
namespace detail { namespace detail {
template <typename T>
struct is_initializer_list : std::false_type {};
template <typename T>
struct is_initializer_list<std::initializer_list<T>> : std::true_type {};
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 <typename T>
struct is_container<std::initializer_list<T>> : std::false_type {};
template <> template <>
struct is_container<std::string> : std::false_type {}; struct is_container<std::string> : std::false_type {};
@ -5125,7 +5134,8 @@ namespace sol {
#endif // C++ 17 #endif // C++ 17
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 && !is_initializer_list<meta::unqualified_t<T>>::value>> : std::true_type {};
template <typename T> template <typename T>
struct is_container<T, std::enable_if_t<std::is_array<meta::unqualified_t<T>>::value && !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<std::is_array<meta::unqualified_t<T>>::value && !meta::any_same<std::remove_all_extents_t<meta::unqualified_t<T>>, char, wchar_t, char16_t, char32_t>::value>> : std::true_type {};
@ -5216,6 +5226,9 @@ namespace sol {
template <typename T> template <typename T>
struct lua_type_of<as_table_t<T>> : std::integral_constant<type, type::table> {}; struct lua_type_of<as_table_t<T>> : std::integral_constant<type, type::table> {};
template <typename T>
struct lua_type_of<std::initializer_list<T>> : std::integral_constant<type, type::table> {};
template <bool b> template <bool b>
struct lua_type_of<basic_reference<b>> : std::integral_constant<type, type::poly> {}; struct lua_type_of<basic_reference<b>> : std::integral_constant<type, type::poly> {};
@ -6476,6 +6489,8 @@ namespace sol {
struct as_pointer_tag {}; struct as_pointer_tag {};
template <typename T> template <typename T>
struct as_value_tag {}; struct as_value_tag {};
template <typename T>
struct as_table_tag {};
using unique_destructor = void (*)(void*); using unique_destructor = void (*)(void*);
@ -6676,7 +6691,7 @@ namespace sol {
template <typename T, typename... Args> template <typename T, typename... Args>
inline int multi_push(lua_State* L, T&& t, Args&&... args) { inline int multi_push(lua_State* L, T&& t, Args&&... args) {
int pushcount = push(L, std::forward<T>(t)); int pushcount = push(L, std::forward<T>(t));
void(detail::swallow{(pushcount += stack::push(L, std::forward<Args>(args)), 0)...}); void(detail::swallow{ (pushcount += stack::push(L, std::forward<Args>(args)), 0)... });
return pushcount; return pushcount;
} }
@ -6688,7 +6703,7 @@ namespace sol {
template <typename T, typename... Args> template <typename T, typename... Args>
inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) { inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) {
int pushcount = push_reference(L, std::forward<T>(t)); int pushcount = push_reference(L, std::forward<T>(t));
void(detail::swallow{(pushcount += stack::push_reference(L, std::forward<Args>(args)), 0)...}); void(detail::swallow{ (pushcount += stack::push_reference(L, std::forward<Args>(args)), 0)... });
return pushcount; return pushcount;
} }
@ -8705,9 +8720,10 @@ namespace stack {
}; };
template <typename T> template <typename T>
struct pusher<as_table_t<T>, std::enable_if_t<is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { struct pusher<detail::as_table_tag<T>> {
static int push(lua_State* L, const T& tablecont) { static int push(lua_State* L, const T& tablecont) {
return push(meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>>(), L, tablecont); typedef meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>> has_kvp;
return push(has_kvp(), L, tablecont);
} }
static int push(std::true_type, lua_State* L, const T& tablecont) { static int push(std::true_type, lua_State* L, const T& tablecont) {
@ -8757,6 +8773,13 @@ namespace stack {
} }
}; };
template <typename T>
struct pusher<as_table_t<T>, std::enable_if_t<is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> {
static int push(lua_State* L, const T& tablecont) {
return stack::push<detail::as_table_tag<T>>(L, tablecont);
}
};
template <typename T> template <typename T>
struct pusher<as_table_t<T>, std::enable_if_t<!is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { struct pusher<as_table_t<T>, std::enable_if_t<!is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> {
static int push(lua_State* L, const T& v) { static int push(lua_State* L, const T& v) {
@ -8774,6 +8797,16 @@ namespace stack {
} }
}; };
template <typename T>
struct pusher<std::initializer_list<T>> {
static int push(lua_State* L, const std::initializer_list<T>& il) {
pusher<detail::as_table_tag<std::initializer_list<T>>> p{};
// silence annoying VC++ warning
(void)p;
return p.push(L, il);
}
};
template <typename T> template <typename T>
struct pusher<T, std::enable_if_t<is_lua_reference<T>::value>> { struct pusher<T, std::enable_if_t<is_lua_reference<T>::value>> {
static int push(lua_State* L, const T& ref) { static int push(lua_State* L, const T& ref) {
@ -9002,7 +9035,7 @@ namespace stack {
template <> template <>
struct pusher<char> { struct pusher<char> {
static int push(lua_State* L, char c) { static int push(lua_State* L, char c) {
const char str[2] = {c, '\0'}; const char str[2] = { c, '\0' };
return stack::push(L, str, 1); return stack::push(L, str, 1);
} }
}; };
@ -9167,7 +9200,7 @@ namespace stack {
template <> template <>
struct pusher<wchar_t> { struct pusher<wchar_t> {
static int push(lua_State* L, wchar_t c) { static int push(lua_State* L, wchar_t c) {
const wchar_t str[2] = {c, '\0'}; const wchar_t str[2] = { c, '\0' };
return stack::push(L, str, 1); return stack::push(L, str, 1);
} }
}; };
@ -9175,7 +9208,7 @@ namespace stack {
template <> template <>
struct pusher<char16_t> { struct pusher<char16_t> {
static int push(lua_State* L, char16_t c) { static int push(lua_State* L, char16_t c) {
const char16_t str[2] = {c, '\0'}; const char16_t str[2] = { c, '\0' };
return stack::push(L, str, 1); return stack::push(L, str, 1);
} }
}; };
@ -9183,7 +9216,7 @@ namespace stack {
template <> template <>
struct pusher<char32_t> { struct pusher<char32_t> {
static int push(lua_State* L, char32_t c) { static int push(lua_State* L, char32_t c) {
const char32_t str[2] = {c, '\0'}; const char32_t str[2] = { c, '\0' };
return stack::push(L, str, 1); return stack::push(L, str, 1);
} }
}; };
@ -9260,7 +9293,7 @@ namespace stack {
template <std::size_t... I, typename T> template <std::size_t... I, typename T>
static int push(std::index_sequence<I...>, lua_State* L, T&& t) { static int push(std::index_sequence<I...>, lua_State* L, T&& t) {
int pushcount = 0; int pushcount = 0;
(void)detail::swallow{0, (pushcount += stack::push(L, detail::forward_get<I>(t)), 0)...}; (void)detail::swallow{ 0, (pushcount += stack::push(L, detail::forward_get<I>(t)), 0)... };
return pushcount; return pushcount;
} }
@ -12929,6 +12962,11 @@ namespace sol {
return set(std::forward<U>(other)); return set(std::forward<U>(other));
} }
template <typename T>
proxy& operator=(std::initializer_list<T> other) {
return set(std::move(other));
}
template <typename T> template <typename T>
decltype(auto) get() const { decltype(auto) get() const {
return tuple_get<T>(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>()); return tuple_get<T>(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>());

View File

@ -87,6 +87,11 @@ namespace sol {
return set(std::forward<U>(other)); return set(std::forward<U>(other));
} }
template <typename T>
proxy& operator=(std::initializer_list<T> other) {
return set(std::move(other));
}
template <typename T> template <typename T>
decltype(auto) get() const { decltype(auto) get() const {
return tuple_get<T>(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>()); return tuple_get<T>(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>());

View File

@ -45,6 +45,8 @@ namespace sol {
struct as_pointer_tag {}; struct as_pointer_tag {};
template <typename T> template <typename T>
struct as_value_tag {}; struct as_value_tag {};
template <typename T>
struct as_table_tag {};
using unique_destructor = void (*)(void*); using unique_destructor = void (*)(void*);
@ -245,7 +247,7 @@ namespace sol {
template <typename T, typename... Args> template <typename T, typename... Args>
inline int multi_push(lua_State* L, T&& t, Args&&... args) { inline int multi_push(lua_State* L, T&& t, Args&&... args) {
int pushcount = push(L, std::forward<T>(t)); int pushcount = push(L, std::forward<T>(t));
void(detail::swallow{(pushcount += stack::push(L, std::forward<Args>(args)), 0)...}); void(detail::swallow{ (pushcount += stack::push(L, std::forward<Args>(args)), 0)... });
return pushcount; return pushcount;
} }
@ -257,7 +259,7 @@ namespace sol {
template <typename T, typename... Args> template <typename T, typename... Args>
inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) { inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) {
int pushcount = push_reference(L, std::forward<T>(t)); int pushcount = push_reference(L, std::forward<T>(t));
void(detail::swallow{(pushcount += stack::push_reference(L, std::forward<Args>(args)), 0)...}); void(detail::swallow{ (pushcount += stack::push_reference(L, std::forward<Args>(args)), 0)... });
return pushcount; return pushcount;
} }

View File

@ -245,9 +245,10 @@ namespace stack {
}; };
template <typename T> template <typename T>
struct pusher<as_table_t<T>, std::enable_if_t<is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { struct pusher<detail::as_table_tag<T>> {
static int push(lua_State* L, const T& tablecont) { static int push(lua_State* L, const T& tablecont) {
return push(meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>>(), L, tablecont); typedef meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>> has_kvp;
return push(has_kvp(), L, tablecont);
} }
static int push(std::true_type, lua_State* L, const T& tablecont) { static int push(std::true_type, lua_State* L, const T& tablecont) {
@ -297,6 +298,13 @@ namespace stack {
} }
}; };
template <typename T>
struct pusher<as_table_t<T>, std::enable_if_t<is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> {
static int push(lua_State* L, const T& tablecont) {
return stack::push<detail::as_table_tag<T>>(L, tablecont);
}
};
template <typename T> template <typename T>
struct pusher<as_table_t<T>, std::enable_if_t<!is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { struct pusher<as_table_t<T>, std::enable_if_t<!is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> {
static int push(lua_State* L, const T& v) { static int push(lua_State* L, const T& v) {
@ -314,6 +322,16 @@ namespace stack {
} }
}; };
template <typename T>
struct pusher<std::initializer_list<T>> {
static int push(lua_State* L, const std::initializer_list<T>& il) {
pusher<detail::as_table_tag<std::initializer_list<T>>> p{};
// silence annoying VC++ warning
(void)p;
return p.push(L, il);
}
};
template <typename T> template <typename T>
struct pusher<T, std::enable_if_t<is_lua_reference<T>::value>> { struct pusher<T, std::enable_if_t<is_lua_reference<T>::value>> {
static int push(lua_State* L, const T& ref) { static int push(lua_State* L, const T& ref) {
@ -542,7 +560,7 @@ namespace stack {
template <> template <>
struct pusher<char> { struct pusher<char> {
static int push(lua_State* L, char c) { static int push(lua_State* L, char c) {
const char str[2] = {c, '\0'}; const char str[2] = { c, '\0' };
return stack::push(L, str, 1); return stack::push(L, str, 1);
} }
}; };
@ -707,7 +725,7 @@ namespace stack {
template <> template <>
struct pusher<wchar_t> { struct pusher<wchar_t> {
static int push(lua_State* L, wchar_t c) { static int push(lua_State* L, wchar_t c) {
const wchar_t str[2] = {c, '\0'}; const wchar_t str[2] = { c, '\0' };
return stack::push(L, str, 1); return stack::push(L, str, 1);
} }
}; };
@ -715,7 +733,7 @@ namespace stack {
template <> template <>
struct pusher<char16_t> { struct pusher<char16_t> {
static int push(lua_State* L, char16_t c) { static int push(lua_State* L, char16_t c) {
const char16_t str[2] = {c, '\0'}; const char16_t str[2] = { c, '\0' };
return stack::push(L, str, 1); return stack::push(L, str, 1);
} }
}; };
@ -723,7 +741,7 @@ namespace stack {
template <> template <>
struct pusher<char32_t> { struct pusher<char32_t> {
static int push(lua_State* L, char32_t c) { static int push(lua_State* L, char32_t c) {
const char32_t str[2] = {c, '\0'}; const char32_t str[2] = { c, '\0' };
return stack::push(L, str, 1); return stack::push(L, str, 1);
} }
}; };
@ -800,7 +818,7 @@ namespace stack {
template <std::size_t... I, typename T> template <std::size_t... I, typename T>
static int push(std::index_sequence<I...>, lua_State* L, T&& t) { static int push(std::index_sequence<I...>, lua_State* L, T&& t) {
int pushcount = 0; int pushcount = 0;
(void)detail::swallow{0, (pushcount += stack::push(L, detail::forward_get<I>(t)), 0)...}; (void)detail::swallow{ 0, (pushcount += stack::push(L, detail::forward_get<I>(t)), 0)... };
return pushcount; return pushcount;
} }

View File

@ -33,6 +33,7 @@
#include "filters.hpp" #include "filters.hpp"
#include <array> #include <array>
#include <initializer_list>
#include <string> #include <string>
#ifdef SOL_CXX17_FEATURES #ifdef SOL_CXX17_FEATURES
#include <string_view> #include <string_view>
@ -755,9 +756,18 @@ namespace sol {
} }
namespace detail { namespace detail {
template <typename T>
struct is_initializer_list : std::false_type {};
template <typename T>
struct is_initializer_list<std::initializer_list<T>> : std::true_type {};
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 <typename T>
struct is_container<std::initializer_list<T>> : std::false_type {};
template <> template <>
struct is_container<std::string> : std::false_type {}; struct is_container<std::string> : std::false_type {};
@ -785,7 +795,8 @@ namespace sol {
#endif // C++ 17 #endif // C++ 17
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 && !is_initializer_list<meta::unqualified_t<T>>::value>> : std::true_type {};
template <typename T> template <typename T>
struct is_container<T, std::enable_if_t<std::is_array<meta::unqualified_t<T>>::value && !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<std::is_array<meta::unqualified_t<T>>::value && !meta::any_same<std::remove_all_extents_t<meta::unqualified_t<T>>, char, wchar_t, char16_t, char32_t>::value>> : std::true_type {};
@ -876,6 +887,9 @@ namespace sol {
template <typename T> template <typename T>
struct lua_type_of<as_table_t<T>> : std::integral_constant<type, type::table> {}; struct lua_type_of<as_table_t<T>> : std::integral_constant<type, type::table> {};
template <typename T>
struct lua_type_of<std::initializer_list<T>> : std::integral_constant<type, type::table> {};
template <bool b> template <bool b>
struct lua_type_of<basic_reference<b>> : std::integral_constant<type, type::poly> {}; struct lua_type_of<basic_reference<b>> : std::integral_constant<type, type::poly> {};

View File

@ -30,6 +30,30 @@ auto test_table_return_four() {
return sol::as_table(std::array<std::pair<std::string, int>, 4>{ { { "one", 1 }, { "two", 2 }, { "three", 3 }, { "four", 4 } } }); return sol::as_table(std::array<std::pair<std::string, int>, 4>{ { { "one", 1 }, { "two", 2 }, { "three", 3 }, { "four", 4 } } });
} }
template <typename S, typename T>
void check_ordered_values(S& src, T& target) {
std::size_t idx = 0;
auto b = std::begin(target);
auto e = std::end(target);
for (; b != e; ++b, ++idx) {
const auto& v = src[idx];
REQUIRE(*b == v);
}
}
template <typename S, typename T>
void check_unordered_values(S& src, T& target) {
std::size_t idx = 0;
auto b = std::begin(target);
auto e = std::end(target);
for (; b != e; ++b, ++idx) {
auto sb = std::begin(src);
auto se = std::end(src);
auto it = std::find(sb, se, *b);
REQUIRE(it != se);
}
}
TEST_CASE("containers/returns", "make sure that even references to vectors are being serialized as tables") { TEST_CASE("containers/returns", "make sure that even references to vectors are being serialized as tables") {
sol::state lua; sol::state lua;
std::vector<int> v{ 1, 2, 3 }; std::vector<int> v{ 1, 2, 3 };
@ -948,3 +972,52 @@ TEST_CASE("containers/pointer types", "check that containers with unique usertyp
REQUIRE(val2 == 500); REQUIRE(val2 == 500);
}()); }());
} }
TEST_CASE("containers/initializer-list", "test initializer lists get pushed as tables directly rather than userdata") {
SECTION("array-like") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::table);
lua["c"] = { 1, 2, 3, 4, 5 };
lua.safe_script(R"lua(
for k, v in pairs(c) do
assert(k == v)
end
)lua");
sol::as_table_t<std::vector<int>> t1vector = lua["c"];
sol::as_table_t<std::deque<int>> t1deque = lua["c"];
sol::as_table_t<std::list<int>> t1list = lua["c"];
sol::as_table_t<std::forward_list<int>> t1flist = lua["c"];
sol::as_table_t<std::set<int>> t1set = lua["c"];
const int src[5] = { 1, 2, 3, 4, 5 };
check_ordered_values(src, t1vector.source);
check_ordered_values(src, t1deque.source);
check_ordered_values(src, t1list.source);
check_ordered_values(src, t1flist.source);
check_ordered_values(src, t1set.source);
}
SECTION("map-like") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::table);
std::pair<const std::string, int> src[5]{
{ "a", 21 },
{ "b", 22 },
{ "c", 23 },
{ "d", 24 },
{ "e", 25 }
};
lua["c"] = std::initializer_list<std::pair<std::string, int>>{
{ "a", 21 },
{ "b", 22 },
{ "c", 23 },
{ "d", 24 },
{ "e", 25 }
};
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"];
check_unordered_values(src, t1umap.source);
check_unordered_values(src, t1ummap.source);
}
}