diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 602d4d9..962d7f3 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -310,7 +310,48 @@ namespace chaiscript private: Callable m_func; }; - +#ifndef CHAISCRIPT_MSVC_12 + //http://stackoverflow.com/questions/18895583/convert-a-vectort-to-initializer-listt + constexpr size_t DEFAULT_MAX_LENGTH = 128; + + template struct backingValue { static V value; }; + template V backingValue::value; + + template struct backingList { static std::initializer_list list; }; + template + std::initializer_list backingList::list = { (Vcount)backingValue::value... }; + + template + static typename std::enable_if< sizeof...(Vcount) >= maxLength, + std::initializer_list >::type generate_n(It begin, It end, It current) + { + throw std::length_error("More than maxLength elements in range."); + } + + template + static typename std::enable_if< sizeof...(Vcount) < maxLength, + std::initializer_list >::type generate_n(It begin, It end, It current) + { + if (current != end) + { + return generate_n(begin, end, ++current); + } + + current = begin; + for (auto it = backingList::list.begin(); + it != backingList::list.end(); + ++current, ++it) + *const_cast(&*it) = *current; + + return backingList::list; + } + + template + std::initializer_list range_to_initializer_list(It begin, It end) + { + return detail::generate_n(begin, end, begin); + } +#endif } class Type_Conversions @@ -582,7 +623,7 @@ namespace chaiscript const std::vector &from_vec = detail::Cast_Helper &>::cast(t_bv, nullptr); To vec; - + vec.reserve(from_vec.size()); for (const Boxed_Value &bv : from_vec) { vec.push_back(detail::Cast_Helper::cast(bv, nullptr)); } @@ -593,6 +634,26 @@ namespace chaiscript return chaiscript::make_shared>(user_type>(), user_type(), func); } +#ifndef CHAISCRIPT_MSVC_12 + template + Type_Conversion initializer_list_conversion() + { + auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { + const std::vector &from_vec = detail::Cast_Helper &>::cast(t_bv, nullptr); + + std::vector vec; + vec.reserve(from_vec.size()); + for (const auto &bv : from_vec) + { + vec.push_back(detail::Cast_Helper::cast(bv, nullptr)); + } + + return Boxed_Value(detail::range_to_initializer_list(vec.begin(), vec.end())); + }; + auto ret = chaiscript::make_shared>(user_type>(), user_type(), func); + return ret; + } +#endif } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index aa01de9..c3391b5 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -1005,6 +1005,7 @@ namespace chaiscript try { std::vector vec; if (!children.empty()) { + vec.reserve(children[0]->children.size()); for (const auto &child : children[0]->children) { auto obj = child->eval(t_ss); if (!obj.is_return_value()) { diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index d4d429e..4d65bee 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -913,3 +913,46 @@ TEST_CASE("Return of converted type from script") chai.add(chaiscript::user_type(), "Returned_Converted_Config"); } +#ifndef CHAISCRIPT_MSVC_12 +TEST_CASE("Return initializer_list") +{ + chaiscript::ChaiScript chai; + + chai.add(chaiscript::initializer_list_conversion>()); + + auto initlist = chai.eval>(R"( + return [11, 22, 33, 44]; + )"); + + CHECK(initlist.size() == 4); + CHECK(typeid(decltype(initlist)) == typeid(std::initializer_list)); +} + +bool initializer_list_of_enums_interface(std::initializer_list initlist) +{ + return initlist.size() == 3 && *initlist.begin() == THREE; +} + +TEST_CASE("Call from script with initializer_list argument") +{ + chaiscript::ChaiScript chai; + + chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module()); + chaiscript::utility::add_class(*m, + "Utility_Test_Numbers", + { { ONE, "ONE" }, + { TWO, "TWO" }, + { THREE, "THREE" } + } + ); + chai.add(m); + + chai.add(chaiscript::initializer_list_conversion>()); + chai.add(chaiscript::fun(&initializer_list_of_enums_interface), "initializer_list_of_enums_interface"); + + auto interface_result = chai.eval("return initializer_list_of_enums_interface([THREE, TWO, ONE]);"); + + CHECK(interface_result == true); +} +#endif +