The input is a formatted string in which the name of the function, its arguments and the types of the arguments are indicated. You need to be able to call the appropriate function handler, passing all arguments correctly.
<invoke name="test" returntype="xml"><arguments><string>str</string><false/><number>1.0</number></arguments></invoke>
void test_handler(const std::wstring& str, bool flag, double n);
InvokeParser
, which will store the name of the function and an array of pairs of argument type — its value : #include "boost/property_tree/ptree.hpp" #include "boost/property_tree/xml_parser.hpp" namespace as3 { class InvokeParser { public: using ArgsContainer = std::vector< std::pair< std::wstring, // Argument type std::wstring // Argument value >>; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); // Are 'invoke' tag attributes and 'arguments' tag exists? auto invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); auto arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; // Is 'name' exists ? auto name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(const auto& arg_value_pair : *arguments_xml) { std::wstring arg_type = arg_value_pair.first; std::wstring arg_value = arg_value_pair.second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.emplace_back(arg_type, arg_value); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; }; } // as3
Type
class that will have one parameter — some C ++ — the type into which you will need to turn the string, as well as learn the corresponding name from ActionScript. For example: Type<short>::convert(L"20"); // 20, short Type<short>::name(); // short ActionScript "number"
Type
Code: template<typename CppType> struct Type : std::enable_if< !std::is_array<CppType>::value, TypeHelper< typename std::decay<CppType>::type> >::type { }; template<typename CppType> struct Type<CppType*> { };
TypeHelper
class. TypeHelper
instantiated by the “naked” type. For example, for const std::wstring&
get std::wstring
, etc. This is done using decay . And this is done in order to remove the differences between functions that have signatures of type f(const std::wstring&)
and f(std::wstring)
. We also do some precaution for arrays, as in this case, an obedient decay
will cope well with the robot and we will get not exactly what we wanted.TypeHelper
. It will serve to convert numbers. In our case, it will work fine for Arithmetic types, although, in an amicable way, you would need to exclude all character types (it is not difficult to do this by slightly modifying is_valid_type
with std::is_same
). template<typename CppType> struct TypeHelper { private: enum { is_valid_type = std::is_arithmetic<CppType>::value }; public: typedef typename std::enable_if<is_valid_type, CppType>::type Type; static typename std::enable_if<is_valid_type, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType static Type convert(const std::wstring& str) { double value = std::stod(str); return static_cast<Type>(value); } };
double
, and then to the type we need.bool
, std::wstring
and void
types: template<> struct TypeHelper<bool> { typedef bool Type; static std::wstring name() { return L"bool"; } static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { return str; } }; template<> struct TypeHelper<void> { typedef void Type; static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { } };
IFunction
interface: struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } };
template<typename ReturnType, typename... Args> struct Function : public IFunction { Function(const std::wstring& function_name, ReturnType (*f)(Args...)) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { if(name_ != parser.function_name()) return false; const auto ArgsCount = sizeof...(Args); if(ArgsCount != parser.arguments_count()) return false; auto indexes = typename generate_sequence<ArgsCount>::type(); auto args = parser.arguments(); if(!validate_types(args, indexes)) return false; return call(args, indexes); } private: template<int... S> bool validate_types(const InvokeParser::ArgsContainer& args, sequence<S...>) { std::array<std::wstring, sizeof...(Args)> cpp_types = { Type<Args>::name()... }; std::array<std::wstring, sizeof...(S)> as3_types = { args[S].first... }; return (cpp_types == as3_types); } template<int... S> bool call(const InvokeParser::ArgsContainer& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } protected: std::function<ReturnType (Args...)> f_; std::wstring name_; }; template<typename ReturnType, typename... Args> std::shared_ptr<IFunction> make_function(const std::wstring& as3_function_name, ReturnType (*f)(Args...)) { return std::make_shared<Function<ReturnType, Args...>>(as3_function_name, f); }
void test_handler(const std::wstring& str, bool flag, double n) { std::wcout << L"test: " << str << L", " << std::boolalpha << flag << ", " << n << std::endl; } int main() { as3::InvokeParser parser; std::wstring str = L"<invoke name=\"test\" returntype=\"xml\">" L"<arguments><string>str</string><false/><number>1.0</number></arguments>" L"</invoke>"; if(parser.parse(str)) { auto function = as3::make_function(L"test", test_handler); function->call(parser); } }
as3::make_function()
, which helps not to think about the type of callback passed.sequence
and generate_sequence
: template<size_t N, size_t... Sequence> struct generate_sequence : generate_sequence<N - 1, N - 1, Sequence...> { }; template<size_t...> struct sequence { }; template<int... Sequence> struct generate_sequence<0, Sequence...> { typedef sequence<Sequence...> type; };
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
generate_sequence 0, 1, 2, ... N - 1
, (: " ") sequence
. Pack expansion ( " ").
:
typename... Args
f
. f
, , f
:
template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())
test
Args = <int, float>
:
f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))
!
- Function::validate_types
. C++ - ActionScript- , - , . - ! . !
- call(const InvokeParser::ArgsContainer& args, sequence<S...>)
, , .
- make_function()
, IFunction
, ( ) .
, , boost::function_traits
mpl
:)
InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };
TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };
, - FunctionCaller
- .... :
FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };
Function
:
Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }
!
UPD: - , , 14 () std::make_index_sequence , , generate_sequence
.
Source: https://habr.com/ru/post/223865/
All Articles