summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2018-01-17 21:39:42 -0200
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2018-01-17 21:39:42 -0200
commit1440ff4c9be3a01f889b78cb0713e65252153f59 (patch)
treed09083d5602303b41f49fe9728d52df64e97fa5f
parent166c371e93505adfcc6217c706ec704c30b99450 (diff)
downloadefl-1440ff4c9be3a01f889b78cb0713e65252153f59.tar.gz
eolian-js: Add parameter passing code
-rw-r--r--src/bin/eolian_js/eolian/grammar/class_registration.hpp15
-rw-r--r--src/bin/eolian_js/eolian/grammar/out_parameter_definition.hpp112
-rw-r--r--src/bin/eolian_js/eolian/grammar/parameter.hpp102
-rw-r--r--src/bin/eolian_js/eolian/grammar/stub_function_definition.hpp32
-rw-r--r--src/bin/eolian_js/main.cc38
-rw-r--r--src/bindings/js/eina_js/eina_js_get_value.hh42
-rw-r--r--src/lib/eolian_cxx/grammar/empty_generator.hpp34
-rw-r--r--src/lib/eolian_cxx/grammar/if.hpp131
8 files changed, 488 insertions, 18 deletions
diff --git a/src/bin/eolian_js/eolian/grammar/class_registration.hpp b/src/bin/eolian_js/eolian/grammar/class_registration.hpp
index d6e5cac4b4..f9b072f077 100644
--- a/src/bin/eolian_js/eolian/grammar/class_registration.hpp
+++ b/src/bin/eolian_js/eolian/grammar/class_registration.hpp
@@ -7,6 +7,8 @@
#include <grammar/attribute_reorder.hpp>
#include <grammar/attributed.hpp>
#include <grammar/attribute_replace.hpp>
+#include <grammar/if.hpp>
+#include <grammar/empty_generator.hpp>
#include <eolian/grammar/stub_function_definition.hpp>
namespace eolian { namespace js { namespace grammar {
@@ -49,12 +51,15 @@ struct class_registration_generator
(
attribute_reorder<0, 1, 2, 3, 0, 1, 0, 1>
(
- "static void register_prototype_"
+ "static void register_prototype_"
<< lower_case[*(string << "_")]
<< lower_case[string]
<< "(v8::Handle<v8::Object> global, v8::Local<v8::ObjectTemplate> prototype, v8::Isolate* isolate)\n"
<< "{\n"
- << *attribute_reorder<1, 1, 1, 1>
+ << *
+ if_([] (attributes::function_def const& f) { return !f.is_beta && !f.is_protected; })
+ [
+ attribute_reorder<1, 1, 1, 1>
(
scope_tab << "prototype->Set( ::efl::eina::js::compatibility_new<v8::String>(isolate, \""
<< attribute_replace(&eolian::js::format::format_method)[string] << "\")\n"
@@ -66,8 +71,9 @@ struct class_registration_generator
<< lower_case[string] << "_"
]
<< lower_case[string]
- << "));\n"
+ << "));\n"
)
+ ][empty_generator]
<<
*(
scope_tab << "register_prototype_"
@@ -88,7 +94,8 @@ struct class_registration_generator
<< lower_case[string]
<< "(global, prototype, isolate);\n"
<< "}\n"
- )).generate(sink, std::make_tuple(cls.namespaces, cls.cxx_name, cls.functions, cls.immediate_inherits), context);
+ )).generate(sink, std::make_tuple(cls.namespaces, cls.cxx_name, cls.functions, cls.immediate_inherits
+ , cls.eolian_name), context);
as_generator
(
diff --git a/src/bin/eolian_js/eolian/grammar/out_parameter_definition.hpp b/src/bin/eolian_js/eolian/grammar/out_parameter_definition.hpp
new file mode 100644
index 0000000000..a90b1a5408
--- /dev/null
+++ b/src/bin/eolian_js/eolian/grammar/out_parameter_definition.hpp
@@ -0,0 +1,112 @@
+#ifndef EOLIAN_JS_OUT_PARAMETER_DEFINITION_HPP
+#define EOLIAN_JS_OUT_PARAMETER_DEFINITION_HPP
+
+#include <grammar/klass_def.hpp>
+#include <grammar/indentation.hpp>
+#include <grammar/string.hpp>
+#include <grammar/attribute_reorder.hpp>
+#include <grammar/attributed.hpp>
+#include <grammar/attribute_replace.hpp>
+#include <eolian/grammar/stub_function_definition.hpp>
+
+namespace eolian { namespace js { namespace grammar {
+
+namespace attributes = efl::eolian::grammar::attributes;
+
+template <typename ParameterContainer, typename Generator>
+struct out_parameter_definition_generator
+{
+ out_parameter_definition_generator(attributes::klass_def const& cls, ParameterContainer const& container
+ , Generator prefix_generator)
+ : klass(cls), container(container), prefix_generator(prefix_generator) {}
+
+ template <typename OutputIterator, typename Context>
+ bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
+ {
+ using namespace efl::eolian::grammar;
+ using efl::eolian::grammar::attributes::unused;
+ namespace attributes = efl::eolian::grammar::attributes;
+
+ std::size_t index;
+ {
+ auto iterator = std::find(container.begin(), container.end(), param);
+ assert(iterator != container.end());
+ index = std::distance(container.begin(), iterator);
+ }
+
+ switch(param.direction)
+ {
+ case attributes::parameter_direction::in:
+ break;
+ case attributes::parameter_direction::inout:
+ case attributes::parameter_direction::out:
+ attributes::generate(prefix_generator, sink, param, context);
+
+ as_generator(string
+ << " __out_"
+ << string
+ ).generate(sink, std::make_tuple(param.type.c_type, param.param_name), context);
+
+ if(param.direction == attributes::parameter_direction::inout)
+ as_generator(" = ::efl::eina::js::get_value_from_javascript(args["
+ << string
+ << "], isolate, \"\", ::efl::eina::js::value_tag< "
+ << string
+ << " >{})"
+ ).generate(sink, std::make_tuple(std::to_string(index), param.type.c_type), context);
+
+ *sink++ = ';';
+ *sink++ = '\n';
+ break;
+ };
+
+
+ return true;
+ }
+
+ attributes::klass_def klass;
+ ParameterContainer const& container;
+ Generator prefix_generator;
+};
+
+template <typename ParameterContainer>
+struct out_parameter_definition_directive
+{
+ template <typename Generator>
+ out_parameter_definition_generator<ParameterContainer, Generator>
+ operator[](Generator const& gen) const
+ {
+ return {klass, container, gen};
+ }
+
+ attributes::klass_def klass;
+ ParameterContainer const& container;
+};
+
+template <typename ParameterContainer>
+out_parameter_definition_directive<ParameterContainer>
+out_parameter_definition(attributes::klass_def const& cls, ParameterContainer const& container)
+{
+ return {cls, container};
+}
+
+} } }
+
+namespace efl { namespace eolian { namespace grammar {
+
+template <typename ParameterContainer, typename Generator>
+struct is_generator< ::eolian::js::grammar::out_parameter_definition_generator<ParameterContainer, Generator> > : std::true_type {};
+template <typename ParameterContainer, typename Generator>
+struct is_eager_generator< ::eolian::js::grammar::out_parameter_definition_generator<ParameterContainer, Generator>> : std::true_type {};
+
+namespace type_traits {
+
+template <typename ParameterContainer, typename Generator>
+struct attributes_needed< ::eolian::js::grammar::out_parameter_definition_generator<ParameterContainer, Generator>> : std::integral_constant<int, 1> {};
+template <typename ParameterContainer, typename Generator>
+struct accepts_specific_tuple< ::eolian::js::grammar::out_parameter_definition_generator<ParameterContainer, Generator>
+ , ::efl::eolian::grammar::attributes::parameter_def > : std::true_type {};
+
+} } } }
+
+#endif
diff --git a/src/bin/eolian_js/eolian/grammar/parameter.hpp b/src/bin/eolian_js/eolian/grammar/parameter.hpp
new file mode 100644
index 0000000000..5c22715874
--- /dev/null
+++ b/src/bin/eolian_js/eolian/grammar/parameter.hpp
@@ -0,0 +1,102 @@
+#ifndef EOLIAN_JS_PARAMETER_HPP
+#define EOLIAN_JS_PARAMETER_HPP
+
+#include <grammar/klass_def.hpp>
+#include <grammar/indentation.hpp>
+#include <grammar/string.hpp>
+#include <grammar/attribute_reorder.hpp>
+#include <grammar/attributed.hpp>
+#include <grammar/attribute_replace.hpp>
+#include <eolian/grammar/stub_function_definition.hpp>
+
+namespace eolian { namespace js { namespace grammar {
+
+namespace attributes = efl::eolian::grammar::attributes;
+
+template <typename ParameterContainer>
+struct parameter_generator
+{
+ parameter_generator(attributes::klass_def const& cls, ParameterContainer const& container)
+ : klass(cls), container(container) {}
+
+ template <typename OutputIterator, typename Context>
+ bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
+ {
+ using namespace efl::eolian::grammar;
+ using efl::eolian::grammar::attributes::unused;
+ namespace attributes = efl::eolian::grammar::attributes;
+
+ std::size_t index;
+ {
+ auto iterator = std::find(container.begin(), container.end(), param);
+ assert(iterator != container.end());
+ index = std::distance(container.begin(), iterator);
+ }
+
+ bool is_function_ptr = false;
+ if(attributes::regular_type_def const* def
+ = ::efl::eina::get<attributes::regular_type_def>(&param.type.original_type))
+ {
+ is_function_ptr = def->is_function_ptr();
+ }
+
+ if(is_function_ptr)
+ {
+ as_generator(" NULL, NULL, NULL").generate(sink, unused, context);
+ }
+ else
+ {
+ switch(param.direction)
+ {
+ case attributes::parameter_direction::in:
+ as_generator(" ::efl::eina::js::get_value_from_javascript(args["
+ << string
+ << "], isolate, \"\", ::efl::eina::js::value_tag< "
+ << string
+ << " >{})"
+ ).generate(sink, std::make_tuple(std::to_string(index), param.type.c_type), context);
+ break;
+ case attributes::parameter_direction::inout:
+ case attributes::parameter_direction::out:
+ as_generator("&__out_"
+ << string
+ ).generate(sink, param.param_name, context);
+ break;
+ };
+ }
+
+ return true;
+ }
+
+ attributes::klass_def klass;
+ ParameterContainer const& container;
+};
+
+
+template <typename ParameterContainer>
+parameter_generator<ParameterContainer>
+parameter(attributes::klass_def const& cls, ParameterContainer const& container)
+{
+ return {cls, container};
+}
+
+} } }
+
+namespace efl { namespace eolian { namespace grammar {
+
+template <typename ParameterContainer>
+struct is_generator< ::eolian::js::grammar::parameter_generator<ParameterContainer> > : std::true_type {};
+template <typename ParameterContainer>
+struct is_eager_generator< ::eolian::js::grammar::parameter_generator<ParameterContainer>> : std::true_type {};
+
+namespace type_traits {
+
+template <typename ParameterContainer>
+struct attributes_needed< ::eolian::js::grammar::parameter_generator<ParameterContainer>> : std::integral_constant<int, 1> {};
+template <typename ParameterContainer>
+struct accepts_specific_tuple< ::eolian::js::grammar::parameter_generator<ParameterContainer>
+ , ::efl::eolian::grammar::attributes::parameter_def > : std::true_type {};
+
+} } } }
+
+#endif
diff --git a/src/bin/eolian_js/eolian/grammar/stub_function_definition.hpp b/src/bin/eolian_js/eolian/grammar/stub_function_definition.hpp
index d5d7169431..f3ba9f084b 100644
--- a/src/bin/eolian_js/eolian/grammar/stub_function_definition.hpp
+++ b/src/bin/eolian_js/eolian/grammar/stub_function_definition.hpp
@@ -5,6 +5,8 @@
#include <grammar/indentation.hpp>
#include <grammar/string.hpp>
#include <grammar/attribute_reorder.hpp>
+#include <eolian/grammar/parameter.hpp>
+#include <eolian/grammar/out_parameter_definition.hpp>
namespace eolian { namespace js { namespace grammar {
@@ -21,6 +23,9 @@ struct stub_function_definition_generator
using namespace efl::eolian::grammar;
using efl::eolian::grammar::attributes::unused;
+ if(f.is_beta || f.is_protected)
+ return true;
+
// std::string suffix;
// switch(cls.type)
// {
@@ -45,7 +50,7 @@ struct stub_function_definition_generator
as_generator
(
- //attribute_reorder<0, 1, 0, 1, 0, 1>
+ attribute_reorder<0, 1, 2, 3, 4, 3>
(
"eina::js::compatibility_return_type stub_function_"
<< lower_case[*(string << "_")]
@@ -54,14 +59,21 @@ struct stub_function_definition_generator
<< lower_case[string]
<< "(eina::js::compatibility_callback_info_type args)\n"
<< "{\n"
- << scope_tab << "if(/*input_parameters*/" << std::to_string(ins) << " != args.Length())\n"
+ << scope_tab << "if(/*input_parameters*/" << std::to_string(ins) << " == args.Length())\n"
<< scope_tab << "{\n"
+ << scope_tab(2) << "v8::Isolate* isolate = args.GetIsolate(); static_cast<void>(isolate);\n"
<< scope_tab(2) << "v8::Local<v8::Object> self = args.This();\n"
<< scope_tab(2) << "v8::Local<v8::Value> external = self->GetInternalField(0);\n"
<< scope_tab(2) << "Eo* eo = static_cast<Eo*>(v8::External::Cast(*external)->Value());\n"
<< scope_tab(2) << "try\n"
<< scope_tab(2) << "{\n"
- << scope_tab(3) << ";"
+ << *(out_parameter_definition(klass, f.parameters)[scope_tab(3)])
+ << scope_tab(3) << "::" << lower_case[string]
+ << "("
+ << "eo"
+ << *(", " << parameter(klass, f.parameters))
+ << ")"
+ << ";\n"
<< scope_tab(2) << "}\n"
<< scope_tab(2) << "catch(std::logic_error const&)\n"
<< scope_tab(2) << "{\n"
@@ -75,7 +87,8 @@ struct stub_function_definition_generator
<< scope_tab(4) << "(eina::js::compatibility_new<v8::String>(nullptr, \"Expected more arguments for this call\")));\n"
<< scope_tab << "}\n"
<< "}\n"
- )).generate(sink, std::make_tuple(klass.namespaces, klass.cxx_name, f.name), context);
+ )).generate(sink, std::make_tuple(klass.namespaces, klass.cxx_name, f.name, f.parameters
+ , f.c_name), context);
// methods
@@ -104,7 +117,16 @@ template <>
struct is_generator< ::eolian::js::grammar::stub_function_definition_generator> : std::true_type {};
template <>
struct is_eager_generator< ::eolian::js::grammar::stub_function_definition_generator> : std::true_type {};
+
+namespace type_traits {
+
+template <>
+struct attributes_needed< ::eolian::js::grammar::stub_function_definition_generator> : std::integral_constant<int, 1> {};
+template <>
+struct accepts_specific_tuple< ::eolian::js::grammar::stub_function_definition_generator
+ , ::efl::eolian::grammar::attributes::function_def> : std::true_type {};
+
-} } }
+} } } }
#endif
diff --git a/src/bin/eolian_js/main.cc b/src/bin/eolian_js/main.cc
index 6d755da249..7dced737d2 100644
--- a/src/bin/eolian_js/main.cc
+++ b/src/bin/eolian_js/main.cc
@@ -702,17 +702,21 @@ int main(int argc, char** argv)
}
};
- os << "extern \"C\" {\n\n";
-
- auto includes_fun = [&os] (Eolian_Class const* klass)
+ auto generate_includes =
+ [&]
{
+ os << "extern \"C\" {\n\n";
+
+ auto includes_fun = [&os] (Eolian_Class const* klass)
+ {
+ os << "#include <" << eolian_class_file_get(klass) << ".h>\n\n";
+ };
+ // generate include for all inheritance
+ recurse_inherits(klass, includes_fun);
os << "#include <" << eolian_class_file_get(klass) << ".h>\n\n";
- };
- // generate include for all inheritance
- recurse_inherits(klass, includes_fun);
- os << "#include <" << eolian_class_file_get(klass) << ".h>\n\n";
- os << "}\n\n";
+ os << "}\n\n";
+ };
using efl::eolian::grammar::attributes::unused;
using efl::eolian::grammar::context_null;
@@ -720,9 +724,26 @@ int main(int argc, char** argv)
using efl::eolian::grammar::lower_case;
using efl::eolian::grammar::string;
using efl::eolian::grammar::as_generator;
+ using efl::eolian::grammar::attribute_reorder;
+ using efl::eolian::grammar::upper_case;
if(!dummy_generation)
{
context_null context;
+
+ // as_generator
+ // (attribute_reorder<0, 1, 0, 1>
+ // (
+ // "#define "
+ // << *(upper_case[string] << "_")
+ // << upper_case[string]
+ // << "_BETA\n"
+ // "#define "
+ // << *(upper_case[string] << "_")
+ // << upper_case[string]
+ // << "_PROTECTED\n"
+ // )).generate(iterator, std::make_tuple(klass_def.namespaces, klass_def.eolian_name), context);
+
+ generate_includes();
as_generator("namespace efl { namespace js { namespace binding { namespace {\n")
.generate(iterator, unused, context);
@@ -753,6 +774,7 @@ int main(int argc, char** argv)
}
else
{
+ generate_includes();
as_generator
(
"namespace efl { namespace js { namespace binding { namespace {\n"
diff --git a/src/bindings/js/eina_js/eina_js_get_value.hh b/src/bindings/js/eina_js/eina_js_get_value.hh
index 450ba067fc..c7aa483bea 100644
--- a/src/bindings/js/eina_js/eina_js_get_value.hh
+++ b/src/bindings/js/eina_js/eina_js_get_value.hh
@@ -35,6 +35,18 @@ inline int get_value_from_javascript
return 0;
}
+template <typename T>
+inline T get_value_from_javascript
+ (v8::Local<v8::Value> v
+ , v8::Isolate* isolate
+ , const char*
+ , value_tag<T>
+ , bool throw_js_exception = true
+ , typename std::enable_if<(std::is_pointer<T>::value && std::is_function<typename std::remove_pointer<T>::type>::value)>::type* = 0)
+{
+ return 0;
+}
+
inline char* get_value_from_javascript
(v8::Local<v8::Value> v
, v8::Isolate* isolate
@@ -262,7 +274,35 @@ inline T get_value_from_javascript
!std::is_same<T, const Eina_Array*>::value &&
!std::is_same<T, const Eina_Iterator*>::value &&
!std::is_same<T, const Eina_Hash*>::value &&
- !std::is_same<T, const Eina_List*>::value
+ !std::is_same<T, const Eina_List*>::value &&
+ !std::is_function<typename std::remove_pointer<T>::type>::value
+ >::type* = 0)
+{
+ if (throw_js_exception)
+ eina::js::compatibility_throw
+ (isolate, v8::Exception::TypeError
+ (eina::js::compatibility_new<v8::String>(isolate, "Not implemented yet")));
+ throw std::logic_error("");
+}
+
+// TODO:
+template <typename T>
+inline T get_value_from_javascript
+ (v8::Local<v8::Value>, v8::Isolate* isolate, const char*, value_tag<T>
+ , bool throw_js_exception = true
+ , typename std::enable_if<
+ std::is_same<T, Eina_Accessor*>::value ||
+ std::is_same<T, Eina_Array*>::value ||
+ std::is_same<T, Eina_Iterator*>::value ||
+ std::is_same<T, Eina_Hash*>::value ||
+ std::is_same<T, Eina_List*>::value ||
+ std::is_same<T, const Eina_Accessor*>::value ||
+ std::is_same<T, const Eina_Array*>::value ||
+ std::is_same<T, const Eina_Iterator*>::value ||
+ std::is_same<T, const Eina_Hash*>::value ||
+ std::is_same<T, const Eina_List*>::value ||
+ std::is_same<T, Eina_Iterator*>::value ||
+ std::is_same<T, const Eina_Iterator*>::value
>::type* = 0)
{
if (throw_js_exception)
diff --git a/src/lib/eolian_cxx/grammar/empty_generator.hpp b/src/lib/eolian_cxx/grammar/empty_generator.hpp
new file mode 100644
index 0000000000..30077f54b9
--- /dev/null
+++ b/src/lib/eolian_cxx/grammar/empty_generator.hpp
@@ -0,0 +1,34 @@
+#ifndef EOLIAN_CXX_EMPTY_GENERATOR_HH
+#define EOLIAN_CXX_EMPTY_GENERATOR_HH
+
+#include "grammar/generator.hpp"
+
+namespace efl { namespace eolian { namespace grammar {
+
+struct empty_generator
+{
+ template <typename OutputIterator, typename Attribute, typename Context>
+ bool generate(OutputIterator const&, Attribute const&, Context const&) const
+ {
+ return true;
+ }
+};
+
+struct empty_generator const empty_generator = {};
+
+template <>
+struct is_eager_generator<struct ::efl::eolian::grammar::empty_generator> : std::true_type {};
+template <>
+struct is_generator<struct ::efl::eolian::grammar::empty_generator> : std::true_type {};
+
+namespace type_traits {
+
+template <>
+struct attributes_needed<struct ::efl::eolian::grammar::empty_generator>
+ : std::integral_constant<int, 0> {};
+
+}
+
+} } }
+
+#endif
diff --git a/src/lib/eolian_cxx/grammar/if.hpp b/src/lib/eolian_cxx/grammar/if.hpp
new file mode 100644
index 0000000000..401a81a0d7
--- /dev/null
+++ b/src/lib/eolian_cxx/grammar/if.hpp
@@ -0,0 +1,131 @@
+#ifndef EOLIAN_CXX_IF_HH
+#define EOLIAN_CXX_IF_HH
+
+#include "grammar/generator.hpp"
+
+namespace efl { namespace eolian { namespace grammar {
+
+template <typename F, typename TrueGenerator, typename FalseGenerator>
+struct if_true_false_generator
+{
+ template <typename OutputIterator, typename Attribute, typename Context>
+ bool generate(OutputIterator sink, Attribute const& attribute, Context const& ctx) const
+ {
+ if(f(attribute))
+ {
+ return true_generator.generate(sink, attribute, ctx);
+ }
+ else
+ {
+ return false_generator.generate(sink, attribute, ctx);
+ }
+ }
+
+ F f;
+ TrueGenerator true_generator;
+ FalseGenerator false_generator;
+};
+
+template <typename F, typename TrueGenerator>
+struct if_true_generator
+{
+ template <typename FalseGenerator>
+ if_true_false_generator<F, TrueGenerator, FalseGenerator> operator[](FalseGenerator false_g) const
+ {
+ return {f, true_generator, false_g};
+ }
+
+ template <typename OutputIterator, typename Attribute, typename Context>
+ bool generate(OutputIterator sink, Attribute const& attribute, Context const& context) const
+ {
+ if(f(attribute))
+ {
+ return true_generator.generate(sink, attribute, context);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ F f;
+ TrueGenerator true_generator;
+};
+
+template <typename F>
+struct if_generator
+{
+ template <typename TrueGenerator>
+ if_true_generator<F, TrueGenerator> operator[](TrueGenerator true_g) const
+ {
+ return {f, true_g};
+ }
+
+ template <typename OutputIterator, typename Attribute, typename Context>
+ bool generate(OutputIterator, Attribute const& attribute, Context const&) const
+ {
+ return f(attribute);
+ }
+
+ F f;
+};
+
+struct if_terminal
+{
+ template <typename F>
+ if_generator<F> operator()(F f) const
+ {
+ return {f};
+ }
+} const if_ = {};
+
+template <typename F>
+struct is_eager_generator<if_generator<F>> : std::true_type {};
+template <typename F, typename TrueGenerator>
+struct is_eager_generator<if_true_generator<F, TrueGenerator>> : std::true_type {};
+template <typename F, typename TrueGenerator, typename FalseGenerator>
+struct is_eager_generator<if_true_false_generator<F, TrueGenerator, FalseGenerator>> : std::true_type {};
+
+template <typename F>
+struct is_generator<if_generator<F>> : std::true_type {};
+template <typename F, typename TrueGenerator>
+struct is_generator<if_true_generator<F, TrueGenerator>> : std::true_type {};
+template <typename F, typename TrueGenerator, typename FalseGenerator>
+struct is_generator<if_true_false_generator<F, TrueGenerator, FalseGenerator>> : std::true_type {};
+
+namespace type_traits {
+
+template <typename F>
+struct attributes_needed<if_generator<F>>
+ : std::integral_constant<int, 1> {};
+
+template <typename F, typename TrueGenerator>
+struct attributes_needed<if_true_generator<F, TrueGenerator>> : attributes_needed<TrueGenerator> {};
+template <typename F, typename TrueGenerator, typename FalseGenerator>
+struct attributes_needed<if_true_false_generator<F, TrueGenerator, FalseGenerator>>
+ : std::conditional<(attributes_needed<TrueGenerator>::value >= attributes_needed<FalseGenerator>::value)
+ , attributes_needed<TrueGenerator>, attributes_needed<FalseGenerator>>::type
+{};
+
+template <typename F, typename TrueGenerator, typename T>
+struct accepts_specific_tuple<if_true_generator<F, TrueGenerator>, T>
+ : accepts_specific_tuple<TrueGenerator, T> {};
+template <typename F, typename TrueGenerator, typename FalseGenerator, typename T>
+struct accepts_specific_tuple<if_true_false_generator<F, TrueGenerator, FalseGenerator>, T>
+ : std::integral_constant<bool, accepts_specific_tuple<TrueGenerator, T>::value
+ ||accepts_specific_tuple<FalseGenerator, T>::value>
+{};
+
+template <typename F, typename TrueGenerator>
+struct accepts_tuple<if_true_generator<F, TrueGenerator>>
+ : accepts_tuple<TrueGenerator> {};
+template <typename F, typename TrueGenerator, typename FalseGenerator>
+struct accepts_tuple<if_true_false_generator<F, TrueGenerator, FalseGenerator>>
+ : std::integral_constant<bool, accepts_tuple<TrueGenerator>::value || accepts_tuple<FalseGenerator>::value>
+{};
+
+}
+
+} } }
+
+#endif