/*
Copyright (C) 2013 Tom Bachmann
This file is part of FLINT.
FLINT is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See .
*/
// 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