Generative Programming In The Large - Applied C++ meta-programming
Upcoming SlideShare
Loading in...5
×
 

Generative Programming In The Large - Applied C++ meta-programming

on

  • 2,460 views

Digs into the details of effective generative programming in C++. Major focus on using meta-programming techniques to create efficient, low cyclomatic complexity in artefacts.

Digs into the details of effective generative programming in C++. Major focus on using meta-programming techniques to create efficient, low cyclomatic complexity in artefacts.

Statistics

Views

Total Views
2,460
Views on SlideShare
2,456
Embed Views
4

Actions

Likes
2
Downloads
29
Comments
0

1 Embed 4

http://www.linkedin.com 4

Accessibility

Categories

Upload Details

Uploaded via as OpenOffice

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • This is a very high level conceptual definition. Most engineers will be more concerned with the techniques for applying configuration knowledge to get to the solution
  • The zero cyclomatic-complexity aim is the ideal. The real purpose is to eliminate any need to have to debug inside the generated code. This also makes a strong argument for the use of generic programming as an implementation strategy, as all the debugging can be done on the generic components even before anything has been generated.
  • The zero cyclomatic-complexity aim is the ideal. The real purpose is to eliminate any need to have to debug inside the generated code. This also makes a strong argument for the use of generic programming as an implementation strategy, as all the debugging can be done on the generic components even before anything has been generated.
  • It is totally possible to have different types depending on the platform. For instance it might be deemed to have WORD instead of uint16_t on a Win32 platform. Types, however, do not have to be OS-specific, types can be varied in order to obtain optimisations in specific products.
  • It is totally possible to have different types depending on the platform. For instance it might be deemed to have WORD instead of uint16_t on a Win32 platform. Types, however, do not have to be OS-specific, types can be varied in order to obtain optimisations in specific products.

Generative Programming In The Large - Applied C++ meta-programming Generative Programming In The Large - Applied C++ meta-programming Presentation Transcript

  • ACCU 2007Generative Programming in the LargeApplied meta-programmingSchalk W. Cronjéysb33r@gmail.com
  • ACCU 2007Even in this new millennium, many engineers will stillbuild components that have very little reuse potentialdue to the inflexible way that they were constructed.This leads to excessive time required to adapt acomponent for usage in another system.
  • ACCU 2007The world of modernC++ Generative Programmingis a vastly untapped field(we are just scraping the surface)
  • ACCU 2007DefinitionIt is a software engineering paradigm where the aim isto automatically manufacture highly customised andoptimised intermediate or end-products fromelementary, reusable components by means ofconfiguration knowledge.Implies Code GenerationDomain-specific languageGeneric Techniques
  • ACCU 2007Elements of GenerativeProgrammingProblem space Solution spaceConfigurationKnowledgeIllegal featurecombinationsDefault settings &dependenciesConstruction rulesOptimisationsConfigured ComponentsDomain-specificconceptsFeaturesGeneric Components
  • ACCU 2007Key Code-level Strategy
  • ACCU 2007For effective implementation there is one basic principlethat encompasses most GP strategies:Dijkstras Separation of ConcernsThis principle accepts the fact that we cannot deal withmany issues at once and that important issues shouldbe addressed with purpose.
  • ACCU 2007Key Code-level StrategiesDevelop elementary components as genericcomponentsFully testable outside of the intended productconfigurationConfigure these components using generated artefactsappropriate to the programming languageAim for zero cyclomatic-complexity in the generatedartefactsEliminate defects as early as possible
  • ACCU 2007In the large ...Generative C++ can lead to large number ofconfiguration classes or meta-classes beinggenerated.It is not uncommon to work with 50+ tag classes withina single type-listEffective integration of meta-programming, compile-time paradigms and run-time paradigms are required.Code-bloat must be avoided!
  • ACCU 2007ConventionsFor the examples assume that the followingnamespace aliases existusing namespace AccuConf;namespace mpl = AccuConf::mpl;namespace bmpl = boost::mpl;All code are implemented in namespaceAccuConf.
  • ACCU 2007Building a rule evaluator(as an example of a generative library)
  • ACCU 2007Requirement #1:Solve complex boolean statementsif (cond_A && cond_B || !cond_C)return outcome_A;else if (cond_D)return outcome_B;elsereturn outcome_C;
  • ACCU 2007Requirement #2:Rule-types are defined in a DSLcondition_expr:input: IP-addressoperation: ==condition_expr:input: IP-addressoperation: in_netmaskcondition_expr:input: Email-addressoperation: regex_match
  • ACCU 2007Requirement #3:Short-circuit// Jump to evaluate !cond_Cif (cond_A && !cond_A || !cond_C)// Never evaluate cond_Dif( cond_B || !cond_B || cond_D)// Dont evalute cond_A twiceif( cond_A || cond_A )if( cond_A && cond_A )
  • ACCU 2007Requirement #4:Compile-time & run-time rules// Hard-code compile-timerule1 = cond_A && cond_B// Loaded at run-timerule2 = load_rule( "ip in FEFE::/64" );
  • ACCU 2007Requirement #5:Early enforcmentOnly allow attribute-operator combinations that havebeen defined in DSLOnly allow attributes to be passed that were defined inDSL
  • ACCU 2007The conceptual evaluatorEvaluating rulesclass Evaluator{public:/**Evaluates the rules against a supplied set* of attributes* @param A A collected set of attributes thatwill* be used as input to the rules.* @return The outcome associated with the rule* that triggered*/Outcome const&resolve( Properties const& A) const;};
  • ACCU 2007The conceptual evaluatorAdding rulesclass Evaluator{public:Outcome const&resolve( Properties const& A) const;/**Adds a rule to the rule set* @param O The outcome to return if this rule* triggers* @param N The order of this rule in the ruleset* @param R the rule to add*/void add_rule(Outcome const& O,Order const& N,Rule const& R);};
  • ACCU 2007Idiom #1: Generative Property BagWhat does the Properties class look like?
  • ACCU 2007Properties classThis can be implemented as a heap-based or a stack-based approach.Heap-based:More memory-efficient, only allocate storedattributes. Suffers heap-access penalty. Potentialfor heap fragmentation.Stack-based:Pre-allocate space for all attributes, even if not used.
  • ACCU 2007Heap-based Properties classUse boost::any to provide generic storageUse boost::map to provide conditional storageIndex using meta-indexestemplate <typename GeneratedPropSet>class Properties{public:// To be implemented ...private:typedef std::map< int,boost::any > container_type;container_type m_attrs;};
  • ACCU 2007Generated Property Setstruct prop{struct ip_addr{typedef IPAddress value_type;typedef to-be-decided valid_matches;};struct email_addr{typedef std::string value_type;typedef to-be-decided valid_matches;};typedef boost::mpl::vector< ip_addr, email_addr >valid_attrs;};
  • ACCU 2007Setting a Propertytemplate <typename GeneratedPropSet>class Properties{public:template <typename P>void set(typename mpl::property_value<P>::type const&);private:typedef std::map< int,boost::any > container_type;};Properties<prop> A;A.set< prop::ip_addr >( "192.168.1.1" );
  • ACCU 2007Implementing Property::settemplate <typename GeneratedPropSet>template <typename P>void Properties<GeneratedPropSet>::set(typename mpl::property_value<P>::type const& v_){// Ensure that P is valid !BOOST_MPL_ASSERT_MSG((bmpl::contains<typename mpl::valid_properties<GeneratedPropSet >::type,P>::value),THIS_IS_NOT_A_VALID_PROPERTY,(P));// Rest to follow ...}Static Assertion providesrelatively useful compile-timeerror if a invalid type is supplied
  • ACCU 2007Implementing Property::settemplate <typename GeneratedPropSet>template <typename P>void Properties<GeneratedPropSet>::set(typename mpl::property_value<P>::type const& v_){// Ensure that P is valid !BOOST_MPL_ASSERT_MSG(bmpl::contains<typename mpl::valid_properties<GeneratedPropSet >::type,P>::value,THIS_IS_NOT_A_VALID_PROPERTY,(P));// Rest to follow ...}boost::mpl::contains is ametapredicate that returns TRUEif P is in the list of validproperties
  • ACCU 2007Implementing Property::settemplate <typename GeneratedPropSet>template <typename P>void Properties<GeneratedPropSet>::set(typename mpl::property_value<P>::type const& v_){// Ensure that P is valid !BOOST_MPL_ASSERT_MSG((bmpl::contains<typename mpl::valid_properties<GeneratedPropSet >::type,P>::value),THIS_IS_NOT_A_VALID_PROPERTY,(P));// Rest to follow ...}mpl::valid_properties is our ownmetaclass to extract the MPLsequence of valid property namesfrom GeneratedPropSet
  • ACCU 2007Implementing Property::settemplate <typename GeneratedPropSet>template <typename P>void Properties<GeneratedPropSet>::set(typename mpl::property_value<P>::type const& v_){BOOST_MPL_ASSERT_MSG( ... );// Find key for mapconst int pos =mpl::property_pos< GeneratedPropSet, P >::value;// Rest to follow ...}mpl::property_pos is our own metaclassreturning the relative position of a typein a typelist. We use this value as a keyinto the map. Due to the MPL_ASSERTwe can be ensured that this is avalid value.
  • ACCU 2007Implementing Property::settemplate <typename GeneratedPropSet>template <typename P>void Properties<GeneratedPropSet>::set(typename mpl::property_value<P>::type const& v_){BOOST_MPL_ASSERT_MSG( ... );// Find key for mapconst int pos =mpl::property_pos< GeneratedPropSet, P >::value;// Rest to follow ...}Use of const int allows for optimisationat compile-time
  • ACCU 2007Implementing Property::settemplate <typename GeneratedPropSet>template <typename P>void Properties<GeneratedPropSet>::set(typename mpl::property_value<P>::type const& v_){BOOST_MPL_ASSERT_MSG( ... );const int pos = ... ;// Assign the valuetypedef typename mpl::property_value<P>::typevalue_type;m_attrs[pos] = v_;}
  • ACCU 2007Implementing Property::set(alternative)template <typename GeneratedPropSet>template <typename P,typename V>void Properties<GeneratedPropSet>::set(V const& v_){BOOST_MPL_ASSERT_MSG( ... );const int pos = ... ;// Assign the valuetypedef typename mpl::property_value<P>::typevalue_type;m_attrs[pos] = value_type(v_);}
  • ACCU 2007Getting a Propertytemplate <typename GeneratedPropSet>class Properties{public:template <typename P>typename mpl::property_value<P>::type const&get() const;private:typedef std::map< int,boost::any > container_type;};Properties<prop> A;A.set< prop::ip_addr >( "192.168.1.1" );std::cout << A.get< prop::ip_addr >( );
  • ACCU 2007Implementing Property::gettemplate <typename GeneratedPropSet>template <typename P>typename mpl::property_value<P>::type const&Properties<GeneratedPropSet>::get() const{BOOST_MPL_ASSERT_MSG( ... );// Find key for maptypename container_type::const_iterator itr =m_attrs.find(mpl::property_pos< GeneratedPropSet, P>::value);// Rest to follow ...}Reusing mpl::property_pos we obtainan iterator to the appropiate property.Note the use of MPL_ASSERT to ensurea valid index value
  • ACCU 2007Implementing Property::gettemplate <typename GeneratedPropSet>template <typename P>typename mpl::property_value<P>::type const&Properties<GeneratedPropSet>::get() const{BOOST_MPL_ASSERT_MSG( ... );... itr = m_attrs.find( ... );if( m_attrs.end() == itr )throw range_error("Property not set");// Rest to follow ...}Throw an exception if the property is notset. Use Property::is_set predicate if ano_throw check is needed.(is_set implementation left as an exercise)
  • ACCU 2007Implementing Property::gettemplate <typename GeneratedPropSet>template <typename P>typename mpl::property_value<P>::type const&Properties<GeneratedPropSet>::get() const{BOOST_MPL_ASSERT_MSG( ... );... itr = m_attrs.find( ... );if( m_attrs.end() == itr ) ... ;typedef typename mpl::property_value<P>::typevalue_type;return *boost::any_cast<value_type>(&(itr->second));}We can assume thatthe type stored iscorrect. Need to usethe & to invoke anon-copy versionof any_cast.
  • ACCU 2007Idiom #2: GGSGeneric-Generated Separation: Access togenerated typelists from generic code shouldgo through metaclasses.
  • ACCU 2007MPL metaclassesAbstract access to type information throughmetaclassesThis allows for specialisation when neededImproves long-term maintenance
  • ACCU 2007Obtaining the value_typetemplate <typename Property>struct property_value{typedef typename Property::value_type type;};
  • ACCU 2007Sequence of Valid Propertiestemplate <typename Properties>struct valid_properties{typedef typename Properties::valid_propertiestype;};
  • ACCU 2007Property Positiontemplate <typename Properties,typename Property>struct valid_properties :bmpl::find<typename valid_properties< Properties>::type,Property>::type::pos{// Prevent invalid PropertyBOOST_MPL_ASSERT_MSG(bmpl::contains<typename valid_properties<Properties>::type,Property>::value,PROPERTY_NOT_FOUND_IN_SEQUENCE,(Property,Properties));};
  • ACCU 2007Idiom #3: Visit EachApply an operation to each generatedmember
  • ACCU 2007Using Boost for_eachbmpl::for_each<mpl::valid_properties<Properties>::type>( FUNCTOR() );struct FUNCTOR{template <typename P>void operator()(P) const;};For each type insequence calls thefunctor
  • ACCU 2007Using Boost for_eachbmpl::for_each<mpl::valid_properties<Properties>::type>( FUNCTOR() );struct FUNCTOR{template <typename P>void operator()(P) const;};Functor must be ableto accommodate eachtype, otherwisecompile-error will occur
  • ACCU 2007Using Boost for_eachstruct print_ip{Properties const& p;print_ip(Properties const& p_): p(p_) {}template <typename P>void operator()(P) const{}void operator()(ip_addr) const{std::cout << p.get<ip_addr>();}};bmpl::for_each<mpl::valid_properties<Properties>::type>( print_ip(my_properties) );
  • ACCU 2007Idiom #4: Type-erasureA known interface irrespective of the typesused
  • ACCU 2007Rule Evaluation Signaturetemplate <typename Properties>bool Functor( Properties const& );boost::function< bool(Properties const&) >
  • ACCU 2007Rule Classtemplate <typename Properties>class Rule{public:// C-tors to follow ...Rule operator || (Rule const&) const;Rule operator && (Rule const&) const;Rule operator !() const;bool operator()(Properties const&) const;private:boost::function< bool(Properties const&) > m_rule;};
  • ACCU 2007Rule Classtemplate <typename Properties>class Rule{public:template <typename Property,typename Operand>Rule( Operand<Property> const& op_ );};
  • ACCU 2007Idiom #5: Hekaton TypelistWorking around limitations in existing typelistlibraries
  • ACCU 2007Limitations in Boost MPLsequencesMaximum size of template parameter list isimplementation-dependantTypically 20GP might require very long lists100 types are not uncommonA special type-list might be needed to convert avery long generated list into a standard BoostMPL sequence.
  • ACCU 2007Hekaton-typelisttemplate <typename T0 = bmpl::na,typename T1 = bmpl::na,...,typename T99 = bmpl::na>struct typelist{typedef bmpl::vector<T0,...,T19> _list0;typedef bmpl::vector<T20,...,T39> _list1;typedef bmpl::vector<T40,...,T59> _list2;// etc.// Join liststypedef bmpl::joint_view<_list0,_list1 > _join0;typedef bmpl::joint_view<_join0,_list2 > _join1;//etc.// until the last join which becomestypedef to-be-defined type;};
  • ACCU 2007Hekaton-typelist (detail)namespace detail{template <typename V0 = bmpl::vector<>,typename V1 = bmpl::vector<>,...,typename V9 = bmpl::vector<>>struct typelist{// detail to follow ...};} // namespace detail
  • ACCU 2007Hekaton-typelist (detail)namespace detail{#define P_LIST(z,n,t) BOOST_PP_COMMA_IF(n) typename V##n = ttemplate < BOOST_PP_REPEAT(10,P_LIST,bmpl::vector<>) >struct typelist{// detail to follow ...};#undef P_LIST} // namespace detail
  • ACCU 2007Hekaton-typelist (detail)namespace detail{#define P_LIST(z,n,t) BOOST_PP_COMMA_IF(n) typename V##n = ttemplate < BOOST_PP_REPEAT(10,P_LIST,bmpl::vector<>)>struct typelist{typedef bmpl::joint_view<_V0,_V1 > _join0;typedef bmpl::joint_view<_join0,V2 > _join1;//etc. until the last join which becomestypedef bmpl::joint_view<_join8,V9 > type;};#undef P_LIST} // namespace detail
  • ACCU 2007Hekaton-typelist (final)#define P_LIST1(z,n,t) BOOST_PP_COMMA_IF(n) typename T##n = t#define P_LIST2(z,n,t) BOOST_PP_COMMA_IF(n) t##n#define P_LIST3(z,n,t) BOOST_PP_COMMA_IF(n) t < BOOST_PP_REPEAT_FROM_TO( BOOST_PP_MUL(n,20), BOOST_PP_ADD(BOOST_PP_MUL(n,20),20), P_LIST2,T ) >template < BOOST_PP_REPEAT( 100,P_LIST1,bmpl::na ) >struct typelist : detail::typelist<BOOST_PP_REPEAT( 5,P_LIST3, bmpl::vector )> ::type{};#undef P_LIST1#undef P_LIST2#undef P_LIST3
  • ACCU 2007Idiom #6: Discriminant Union fromTypelistboost::make_variant_over
  • ACCU 2007Discriminant Uniontypedef mpl::valid_properties<prop>::typeexample_typelist;typedef boost::make_variant_over<example_typelist>::type example_variant;X
  • ACCU 2007Discriminant Unionstruct extract_value_type{template <typename T> : mpl::property_value<T>struct apply{};};typedef boost::transform_view<mpl::valid_properties<prop>::type,extract_value_type>::type example_typelisttypedef boost::make_variant_over<example_typelist>::type example_variant;
  • ACCU 2007Implementation Specifics
  • ACCU 2007Compiler LimitationsFew compilers can handle the deep level oftemplate instantiation very wellgcc 4.x is fastVC 8 (VS2005) is adequategcc 3.x is slow and has big memory footprintIt is not always possible to use the puristictemplate solutionUse the Boost Preprocessor LibraryGenerate code of higher levels of cyclomatic-complexity
  • ACCU 2007Further Reading
  • ACCU 2007Touching the voidPushing C++ skills far beyond the knowledge ofmany C++ practitionersPolitics of introducing a new technologyTeaches very good software skills outside theC++ domainAm I in the wrong language?(Yeah, thanks Kevlin!)Shows requirements for future languagesPowerful syntaxSimplicity of expression