/*============================================================================= This file is part of FLINT. FLINT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. FLINT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with FLINT; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =============================================================================*/ /****************************************************************************** Copyright (C) 2013 Tom Bachmann ******************************************************************************/ // This file contains the definitions of all rules used by the expression class. // (Some generally useful implementations can be found in default_rules.h.) // This file also contains some helper traits, metaprogramming tools and macros. #ifndef CXX_RULES_H #define CXX_RULES_H #include "mp.h" #include "traits.h" namespace flint { namespace rules { struct no_op { template static void doit(const U&) {} }; struct UNIMPLEMENTED { static const bool unimplemented_marker = true; }; template struct print : UNIMPLEMENTED { }; template struct to_string : UNIMPLEMENTED { }; // static std::string get(const T&, int base) template struct assignment : UNIMPLEMENTED { }; // C-style cmp. template struct cmp : UNIMPLEMENTED { }; // Rule for equals. Implemented in terms of cmp by default. template struct equals : UNIMPLEMENTED { }; // Rule for type conversion. template struct conversion { static To get(const From& from) { return To(from); } }; // Rule for c-style printing template struct cprint : UNIMPLEMENTED { }; // static int doit(FILE*, const T&) template struct print_pretty : UNIMPLEMENTED { }; // static int doit(FILE*, const T&) template struct read : UNIMPLEMENTED { }; // static int doit(FILE*, T&) // Rule for swapping template struct swap : UNIMPLEMENTED { }; // If result_is_temporary is true, then the result coincides with the // first temporary (provided these have the same type) // Priorities 2, 1, 0 can be used to resolve conflicts. template< class Op, class Data, bool result_is_temporary, unsigned priority, class Enable = void> struct evaluation : UNIMPLEMENTED { }; //{ // typedef X return_t; // typedef Y temporaries_t; // a tuple of *pointers* // static void doit(const T& input, temporaries_t temps, return_t* output); //}; // Instantiate temporaries for evaluation. The default implementation does the // following: // - find a subexpression t of e which evaluates to type T // -- return t.create_temporary() // - if no such subexpression can be found, return T() // Additionally, the expression class implements a version of create_temporary // which just returns T(), so if your class is default constructible, // everything works automatically. template struct instantiate_temporaries; //{ // static T get(const Expr& e); //}; // Convenience helpers, instantiate by evaluation if necessary // (needs default rules) template struct binary_expression : UNIMPLEMENTED { }; // typedef X return_t; // static void doit(return_t& to, const T&, const U&); template struct commutative_binary_expression : UNIMPLEMENTED { }; // similarly template struct unary_expression : UNIMPLEMENTED { }; // similarly // Rules for more arguments. template struct threeary_expression : UNIMPLEMENTED { }; template struct fourary_expression : UNIMPLEMENTED { }; template struct fiveary_expression : UNIMPLEMENTED { }; template struct sixary_expression : UNIMPLEMENTED { }; template struct sevenary_expression : UNIMPLEMENTED { }; } // rules /////////////////////////////////////////////////////////////////////////////////// // HELPER TRAITS /////////////////////////////////////////////////////////////////////////////////// namespace traits { // Compute if the rule T is implemented. template struct is_implemented : mp::not_<_is_convertible > { }; } // traits } // flint /////////////////////////////////////////////////////////////////////////////////// // HELPER MACROS /////////////////////////////////////////////////////////////////////////////////// // These macros should be called in namespace flint::rules // In general the easiest way to find out what they do is to read the // definition directly. // Specialise a getter called "name". The getter has one argument called "from" // of type "fromtype", and "eval" which should yield "totype". #define FLINT_DEFINE_GET2(name, totype, fromtype1, fromtype2, eval) \ template<> \ struct name \ { \ static totype get(const fromtype1& e1, const fromtype2& e2) \ { \ return eval; \ } \ }; #define FLINT_DEFINE_GET(name, totype, fromtype, eval) \ FLINT_DEFINE_GET2(name, totype, fromtype, fromtype, eval) #define FLINT_DEFINE_GET_COND(name, totype, cond, eval) \ template \ struct name >::type> \ { \ static totype get(const T& from) \ { \ return eval; \ } \ }; // Specialise a doit rule called "name" #define FLINT_DEFINE_DOIT(name, totype, fromtype, eval) \ template<> \ struct name \ { \ static void doit(totype& to, const fromtype& from) \ { \ eval; \ } \ }; // Specialise a doit rule called "name" which yields totype. It will // accept any type "T" which satisfies "cond". #define FLINT_DEFINE_DOIT_COND(name, totype, cond, eval) \ template \ struct name >::type> \ { \ static void doit(totype& to, const T& from) \ { \ eval; \ } \ }; #define FLINT_DEFINE_DOIT_COND2(name, cond1, cond2, eval) \ template \ struct name, cond2 > >::type> \ { \ static void doit(T& to, const U& from) \ { \ eval; \ } \ }; #define FLINT_DEFINE_PRINT_COND_(name, cond, eval) \ template \ struct name >::type> \ { \ static int doit(FILE* to, const T& from) \ { \ return eval; \ } \ }; #define FLINT_DEFINE_READ_COND_(name, cond, eval) \ template \ struct name >::type> \ { \ static int doit(FILE* from, T& to) \ { \ return eval; \ } \ }; #define FLINT_DEFINE_PRINT_COND(cond, eval) \ FLINT_DEFINE_PRINT_COND_(cprint, cond, eval) #define FLINT_DEFINE_PRINT_PRETTY_COND(cond, eval) \ FLINT_DEFINE_PRINT_COND_(print_pretty, cond, eval) #define FLINT_DEFINE_READ_COND(cond, eval) \ FLINT_DEFINE_READ_COND_(read, cond, eval) #define FLINT_DEFINE_PRINT_PRETTY_COND_2(cond, extratype, eval) \ template \ struct print_pretty >::type> \ { \ static int doit(FILE* to, const T& from, extratype extra) \ { \ return eval; \ } \ }; // Specialise the unary expression rule type->type. #define FLINT_DEFINE_UNARY_EXPR_(name, rtype, type, eval) \ template<> \ struct unary_expression \ { \ typedef rtype return_t; \ template \ static void doit(V& to, const type& from) \ { \ eval; \ } \ }; #define FLINT_DEFINE_UNARY_EXPR(name, type, eval) \ FLINT_DEFINE_UNARY_EXPR_(name, type, type, eval) #define FLINT_DEFINE_UNARY_EXPR_COND(name, ret_type, cond, eval) \ template \ struct unary_expression >::type> \ { \ typedef ret_type return_t; \ template \ static void doit(V& to, const T& from) \ { \ eval; \ } \ }; // Specialise the binary expression rule (type, type) -> type #define FLINT_DEFINE_BINARY_EXPR2(name, rtype, type1, type2, eval) \ template<> \ struct binary_expression \ { \ typedef rtype return_t; \ template \ static void doit(V& to, const type1& e1, const type2& e2) \ { \ eval; \ } \ }; #define FLINT_DEFINE_BINARY_EXPR(name, type, eval) \ FLINT_DEFINE_BINARY_EXPR2(name, type, type, type, eval) // Specialise the commutative binary expression rule (type, type) -> type #define FLINT_DEFINE_CBINARY_EXPR(name, type, eval) \ template<> \ struct commutative_binary_expression \ { \ typedef type return_t; \ template \ static void doit(V& to, const type& e1, const type& e2) \ { \ eval; \ } \ }; // Specialise the commutative binary expression rule (Type, T) -> Type, // where T must satisfy "cond". #define FLINT_DEFINE_CBINARY_EXPR_COND(name, Type, cond, eval) \ template \ struct commutative_binary_expression >::type> \ { \ typedef Type return_t; \ template \ static void doit(V& to, const Type& e1, const T& e2) \ { \ eval; \ } \ }; #define FLINT_DEFINE_CBINARY_EXPR_COND2(name, rettype, cond1, cond2, eval) \ template \ struct commutative_binary_expression, cond2 > >::type> \ { \ typedef rettype return_t; \ template \ static void doit(V& to, const T& e1, const U& e2) \ { \ eval; \ } \ }; // Specialise the (non-commutative) binary expression rule (Type, T) -> Type, // where T must satisfy "cond". #define FLINT_DEFINE_BINARY_EXPR_COND(name, Type, cond, eval) \ template \ struct binary_expression >::type> \ { \ typedef Type return_t; \ template \ static void doit(V& to, const Type& e1, const T& e2) \ { \ eval; \ } \ }; #define FLINT_DEFINE_BINARY_EXPR_COND2(name, rettype, cond1, cond2, eval) \ template \ struct binary_expression, cond2 > >::type> \ { \ typedef rettype return_t; \ template \ static void doit(V& to, const T& e1, const U& e2) \ { \ eval; \ } \ }; #define FLINT_DEFINE_THREEARY_EXPR_COND3(name, rettype, cond1, cond2, cond3, eval) \ template \ struct threeary_expression, cond2 , cond3 > >::type> \ { \ typedef rettype return_t; \ template \ static void doit(R& to, const T& e1, const U& e2, const V& e3) \ { \ eval; \ } \ }; #define FLINT_DEFINE_THREEARY_EXPR(name, rettype, T1, T2, T3, eval) \ template<> \ struct threeary_expression \ { \ typedef rettype return_t; \ template \ static void doit(R& to, const T1& e1, const T2& e2, const T3& e3) \ { \ eval; \ } \ }; #define FLINT_DEFINE_FOURARY_EXPR_COND4(name, rettype, cond1, cond2, cond3, cond4, eval) \ template \ struct fourary_expression, cond2 , cond3 , cond4 > >::type> \ { \ typedef rettype return_t; \ template \ static void doit(R& to, const T& e1, const U& e2, const V& e3, const W& e4) \ { \ eval; \ } \ }; #define FLINT_DEFINE_FIVEARY_EXPR_COND5(name, rettype, cond1, cond2, cond3, cond4, cond5, eval) \ template \ struct fiveary_expression, cond2 , cond3 , cond4 , cond5 > >::type> \ { \ typedef rettype return_t; \ template \ static void doit(R& to, const T& e1, const U& e2, const V& e3, const W& e4, const X& e5) \ { \ eval; \ } \ }; #define FLINT_DEFINE_SIXARY_EXPR_COND6(name, rettype, cond1, cond2, cond3, cond4, cond5, cond6, eval) \ template \ struct sixary_expression, cond2 , cond3 , cond4 , cond5 , cond6 > >::type> \ { \ typedef rettype return_t; \ template \ static void doit(R& to, const T& e1, const U& e2, const V& e3, const W& e4, const X& e5, const Y& e6) \ { \ eval; \ } \ }; #define FLINT_DEFINE_SEVENARY_EXPR_COND7(name, rettype, cond1, cond2, cond3, cond4, cond5, cond6, cond7, eval) \ template \ struct sevenary_expression, cond2 , cond3 , cond4 , cond5 , cond6, cond7 > >::type> \ { \ typedef rettype return_t; \ template \ static void doit(R& to, const T& e1, const U& e2, const V& e3, const W& e4, const X& e5, const Y& e6, const Z& e7) \ { \ eval; \ } \ }; #endif