1 /*
2     Copyright (C) 2013 Tom Bachmann
3 
4     This file is part of FLINT.
5 
6     FLINT is free software: you can redistribute it and/or modify it under
7     the terms of the GNU Lesser General Public License (LGPL) as published
8     by the Free Software Foundation; either version 2.1 of the License, or
9     (at your option) any later version.  See <http://www.gnu.org/licenses/>.
10 */
11 
12 #ifndef CXX_EXPRESSION_H
13 #define CXX_EXPRESSION_H
14 
15 // TODO
16 // * static asserts
17 
18 #include <iosfwd>
19 #include <string>
20 #include <cstdio>
21 
22 #include "evaluation_tools.h"
23 #include "expression_traits.h"
24 #include "mp.h"
25 #include "rules.h"
26 #include "traits.h"
27 #include "tuple.h"
28 
29 namespace flint {
30 namespace detail {
31 // Helper traits used by the "expression" class, in particular the evaluate()
32 // method. This is the general (i.e. non-immediate) case,
33 // which requires actual work.
34 template<class Operation, class Expr, class Data>
35 struct evaluation_traits
36 {
37     typedef typename Expr::derived_t derived_t;
38     typedef typename mp::find_evaluation<
39         Operation, Data, false>::type rule_t;
40     typedef typename mp::find_evaluation<
41         Operation, Data, true>::type temp_rule_t;
42     typedef typename rule_t::return_t evaluation_return_t;
43     typedef evaluation_return_t evaluated_t;
44 
evaluateevaluation_traits45     static evaluation_return_t evaluate(const derived_t& from)
46     {
47         evaluated_t res =
48             rules::instantiate_temporaries<derived_t, evaluated_t>::get(from);
49         evaluate_into_fresh(res, from);
50         return res;
51     }
52 
53     template<class T>
evaluate_intoevaluation_traits54     static void evaluate_into(T& to, const derived_t& from)
55     {
56         typedef mp::back_tuple<typename rule_t::temporaries_t> back_t;
57         typename back_t::type temps_backing =
58             mp::htuples::fill<typename back_t::type>(
59                 tools::temporaries_filler(from));
60         typename rule_t::temporaries_t temps;
61         back_t::init(temps, temps_backing, 0);
62         rule_t::doit(from._data(), temps, &to);
63     }
64 
evaluate_into_freshevaluation_traits65     static void evaluate_into_fresh(evaluation_return_t& to, const derived_t& from)
66     {
67         typedef mp::back_tuple<
68             typename temp_rule_t::temporaries_t,
69             evaluation_return_t
70           > back_t;
71         typename back_t::type temps_backing =
72             mp::htuples::fill<typename back_t::type>(
73                 tools::temporaries_filler(from));
74         typename temp_rule_t::temporaries_t temps;
75         back_t::init(temps, temps_backing, &to);
76         temp_rule_t::doit(from._data(), temps, &to);
77     }
78 };
79 
80 // This is the special case of an immediate argument, where "evaluation" is
81 // at most assignment.
82 template<class Expr, class Data>
83 struct evaluation_traits<operations::immediate, Expr, Data>
84 {
85     typedef typename Expr::derived_t derived_t;
86     typedef typename Expr::derived_t evaluated_t;
87     typedef evaluated_t& evaluation_return_t;
88 
89     static evaluated_t& evaluate(derived_t& d) {return d;}
90     static const evaluated_t& evaluate(const derived_t& d) {return d;}
91 
92     template<class T>
93     static void evaluate_into(T& to, const derived_t& from)
94     {
95         rules::assignment<T, derived_t>::doit(to, from);
96     }
97 
98     static void evaluate_into_fresh(derived_t& to, const derived_t& from)
99     {
100         evaluate_into(to, from);
101     }
102 };
103 } // detail
104 
105 // The main expression template class.
106 //
107 // The argument Derived must have the following form:
108 // struct derived
109 // {
110 //     template<class Operation, class Data>
111 //     struct type
112 //     {
113 //         typedef XYZ result;
114 //     };
115 // };
116 // See derived_wrapper below for a common example.
117 //
118 // Note that, while Data does not have to be default constructible,
119 // it *does* need to be copy-constructible, and have a working destructor.
120 template<class Derived, class Operation, class Data>
121 class expression
122 {
123 private:
124     Data data;
125 
126 protected:
127     explicit expression(const Data& d) : data(d) {}
128 
129 public:
130     // internal -- see is_expression implementation.
131     typedef void IS_EXPRESSION_MARKER;
132 
133     typedef detail::evaluation_traits<Operation, expression, Data> ev_traits_t;
134     typedef typename Derived::template type<Operation, Data>::result derived_t;
135     typedef typename ev_traits_t::evaluated_t evaluated_t;
136     typedef typename ev_traits_t::evaluation_return_t evaluation_return_t;
137     typedef Data data_t;
138     typedef Operation operation_t;
139 
140 private:
141     derived_t& downcast() {return *static_cast<derived_t*>(this);}
142     const derived_t& downcast() const
143     {
144         return *static_cast<const derived_t*>(this);
145     }
146 
147     // Some helpers for initialization, since it is not possible to
148     // conditionally enable constructors in C++98
149     template<class T>
150     static data_t get_data(const T& t,
151         typename mp::disable_if<traits::is_lazy_expr<T> >::type* = 0)
152     {
153         return data_t(t);
154     }
155     template<class T>
156     static data_t get_data(T& t,
157         typename mp::disable_if<traits::is_lazy_expr<T> >::type* = 0)
158     {
159         return data_t(t);
160     }
161     template<class T>
162     static data_t get_data(const T& t,
163         typename mp::enable_if<traits::is_lazy_expr<T> >::type* = 0,
164         typename mp::disable_if<
165             mp::equal_types<typename T::evaluated_t, derived_t> >::type* = 0)
166     {
167         return data_t(t.evaluate());
168     }
169     template<class T>
170     static data_t get_data(const T& t,
171         typename mp::enable_if<traits::is_lazy_expr<T> >::type* = 0,
172         typename mp::enable_if<
173             mp::equal_types<typename T::evaluated_t, derived_t> >::type* = 0)
174     {
175         return data_t(t.evaluate()._data());
176     }
177 
178     // Invoke the data copy constructor when appropriate
179     static data_t get_data(const derived_t& o)
180     {
181         return data_t(o._data());
182     }
183     static data_t get_data(derived_t& o)
184     {
185         return data_t(o._data());
186     }
187 
188     // Having the empty constructor here delays its instantiation, and allows
189     // compiling even if data is *not* default constructible.
190     static data_t get_data() {return data_t();}
191 
192 public:
193     // forwarded constructors
194     template<class T>
195     explicit expression(const T& t)
196         : data(get_data(t)) {}
197 
198     template<class T>
199     explicit expression(T& t)
200         : data(get_data(t)) {}
201 
202     template<class T, class U>
203     expression(const T& t, const U& u)
204         : data(t, u) {}
205     template<class T, class U>
206     expression(T& t, const U& u)
207         : data(t, u) {}
208 
209     template<class T, class U, class V>
210     expression(const T& t, const U& u, const V& v)
211         : data(t, u, v) {}
212     template<class T, class U, class V>
213     expression(T& t, const U& u, const V& v)
214         : data(t, u, v) {}
215     template<class T, class U, class V, class W>
216     expression(const T& t, const U& u, const V& v, const W& w)
217         : data(t, u, v, w) {}
218     template<class T, class U, class V, class W>
219     expression(T& t, const U& u, const V& v, const W& w)
220         : data(t, u, v, w) {}
221 
222     expression() : data(get_data()) {}
223 
224     expression& operator=(const expression& o)
225     {
226         this->set(o.downcast());
227         return *this;
228     }
229 
230     // See rules::instantiate_temporaries for explanation.
231     evaluated_t create_temporary() const
232     {
233         return evaluated_t();
234     }
235 
236     Data& _data() {return data;}
237     const Data& _data() const {return data;}
238 
239     void print(std::ostream& o) const
240     {
241         tools::print_using_str<evaluated_t>::doit(evaluate(), o);
242     }
243 
244     std::string to_string(int base = 10) const
245     {
246         return rules::to_string<evaluated_t>::get(evaluate(), base);
247     }
248 
249     template<class T>
250     T to() const
251     {
252         return rules::conversion<T, evaluated_t>::get(evaluate());
253     }
254 
255     int print(FILE* f = stdout) const
256     {
257         return rules::cprint<evaluated_t>::doit(f, evaluate());
258     }
259     int print_pretty(FILE* f = stdout) const
260     {
261         return rules::print_pretty<evaluated_t>::doit(f, evaluate());
262     }
263     template<class T>
264     int print_pretty(const T& extra, FILE* f = stdout) const
265     {
266         return rules::print_pretty<evaluated_t>::doit(f, evaluate(), extra);
267     }
268     int read(FILE* f = stdin)
269     {
270         return rules::read<derived_t>::doit(f, downcast());
271     }
272 
273     typename traits::make_const<evaluation_return_t>::type evaluate() const
274     {
275         return ev_traits_t::evaluate(downcast());
276     }
277     evaluation_return_t evaluate() {return ev_traits_t::evaluate(downcast());}
278 
279     template<class T>
280     void set(const T& t,
281             typename mp::enable_if<traits::is_expression<T> >::type* = 0,
282             typename mp::enable_if<traits::can_evaluate_into<
283                 derived_t, typename T::evaluated_t> >::type* = 0)
284     {
285         T::ev_traits_t::evaluate_into(downcast(), t);
286     }
287     template<class T>
288     void set(const T& t,
289             typename mp::enable_if<traits::is_expression<T> >::type* = 0,
290             typename mp::disable_if<traits::can_evaluate_into<
291                 derived_t, typename T::evaluated_t> >::type* = 0)
292     {
293         rules::assignment<derived_t, typename T::evaluated_t>::doit(
294             downcast(), t.evaluate());
295     }
296     template<class T>
297     void set(const T& t,
298             typename mp::disable_if<traits::is_expression<T> >::type* = 0)
299     {
300         rules::assignment<derived_t, T>::doit(downcast(), t);
301     }
302 
303     template<class T>
304     bool equals(const T& t,
305             typename mp::enable_if<traits::is_lazy_expr<T> >::type* = 0) const
306     {
307         return equals(t.evaluate());
308     }
309     template<class T>
310     bool equals(const T& t,
311             typename mp::disable_if<traits::is_lazy_expr<T> >::type* = 0) const
312     {
313         return tools::equals_using_cmp<evaluated_t, T>::get(evaluate(), t);
314     }
315 
316     template<class Op, class NData>
317     struct make_helper
318     {
319         typedef typename Derived::template type<Op, NData>::result type;
320         static type make(const NData& ndata)
321         {
322             return type(ndata);
323         }
324     };
325 };
326 
327 // If your expression template is of the form
328 //   template<class Operation, class Data>
329 //   class my_expression ...
330 // then derived_wrapper<my_expression> is a valid argument for Derived in
331 // the expression class above.
332 template<template<class O, class D> class Derived>
333 struct derived_wrapper
334 {
335     template<class Operation, class Data>
336     struct type
337     {
338         typedef Derived<Operation, Data> result;
339     };
340 };
341 
342 // If your expression template is of the form
343 //   template<class Extra, class Opeartion, class Data>
344 //   class my_expression2 ...
345 // where Extra is some extra information which should be passed on unchanged,
346 // then derived_wrapper2<my_expression2, Extra> is a valid argument for Derived
347 // in the expression class above.
348 template<template<class E, class O, class D> class Derived, class Extra>
349 struct derived_wrapper2
350 {
351     template<class Operation, class Data>
352     struct type
353     {
354         typedef Derived<Extra, Operation, Data> result;
355     };
356 };
357 
358 
359 // operators
360 
361 namespace detail {
362 // These traits determine how arguments of an expression template are stored.
363 // E.g. (e1 + e2) yields a new expression template with a two-argument tuple
364 // as Data. If e1 is an immediate, then we want to (usually) store it by
365 // reference, to avoid copies. If not, we can just store by value (since
366 // copying e1 just copies the references anyway) and avoid indirection.
367 // (Similarly for e2.)
368 template<class Expr>
369 struct storage_traits
370     : mp::if_<
371           traits::is_immediate<Expr>,
372           typename traits::forwarding<Expr>::type,
373           Expr
374         > { };
375 // See tuple.h.
376 template<>
377 struct storage_traits<detail::UNUSED> {typedef detail::UNUSED type;};
378 
379 template<class ev_t, class Op, class type>
380 struct nary_op_helper_step2
381 {
382     typedef typename ev_t::return_t Expr;
383     typedef typename Expr::template make_helper<Op, type> make_helper;
384     typedef typename make_helper::type return_t;
385 };
386 template<class Op, class type>
387 struct nary_op_helper_step2<rules::UNIMPLEMENTED, Op, type>
388 {
389     struct return_t { };
390     struct make_helper { };
391 };
392 
393 // Helper to determine the return type of an expression, where Data is already
394 // the correct tuple type.
395 // The step1/step2 splitting above is necessary to avoid compiler errors in
396 // case there is not actually any rule.
397 template<class Op, class Data>
398 struct nary_op_helper
399 {
400     typedef typename mp::find_evaluation<Op, Data, true>::type ev_t;
401     typedef nary_op_helper_step2<ev_t, Op, Data> nohs2;
402     typedef typename nohs2::return_t return_t;
403     typedef typename nohs2::make_helper make_helper;
404 
405     typedef traits::is_implemented<ev_t> cond;
406     typedef mp::enable_if<cond, return_t> enable;
407 };
408 
409 template<class Op, class Maker>
410 struct nary_op_helper_maker
411     : nary_op_helper<Op, typename Maker::type>
412 {
413     typedef Maker maker;
414 };
415 
416 #define FLINTXX_NARY_OP_HELPER_MACRO(arg) typename storage_traits< arg >::type
417 
418 // nary_op_helper<Op, Arg1, Arg2, ...> invokes nary_op_helper with the correct
419 // tuple type as argument.
420 template<class Op, FLINTXX_MAKE_TUPLE_TEMPLATE_ARGS>
421 struct nary_op_helper2
422     : nary_op_helper_maker<Op, mp::make_tuple<
423           FLINTXX_MAKE_TUPLE_TYPES_APPLYMACRO(FLINTXX_NARY_OP_HELPER_MACRO) > >
424 {
425     typedef nary_op_helper2 noh2;
426     static typename noh2::return_t make(FLINTXX_MAKE_TUPLE_FUNC_ARGS)
427     {
428         return noh2::make_helper::make(noh2::maker::make(
429               FLINTXX_MAKE_TUPLE_FUNC_ARG_NAMES));
430     }
431 };
432 
433 // Special casing for binary operators.
434 template<class Expr1, class Op, class Expr2>
435 struct binary_op_helper
436     : nary_op_helper2<Op, Expr1, Expr2>
437 { };
438 
439 // Special casing for unary operations.
440 template<class Op, class Expr>
441 struct unary_op_helper : nary_op_helper2<Op, Expr> { };
442 
443 // For unary member operators, determining the return type the normal way can
444 // lead to cyclic dependencies. See FLINTXX_DEFINE_MEMBER_UNOP_RTYPE.
445 template<class Ret, class Op, class Expr>
446 struct unary_op_helper_with_rettype
447 {
448     typedef mp::make_tuple<typename storage_traits<Expr>::type> maker;
449     typedef typename Ret::template make_helper<
450         Op, typename maker::type>::type return_t;
451 };
452 
453 // Common helper for implementing comparison operators.
454 template<class Expr1, class Expr2>
455 struct order_op_helper
456 {
457     typedef typename tools::evaluation_helper<Expr1>::type ev1_t;
458     typedef typename tools::evaluation_helper<Expr2>::type ev2_t;
459     typedef tools::symmetric_cmp<ev1_t, ev2_t> scmp;
460 
461     typedef mp::enable_if<
462           mp::and_<
463             traits::is_implemented<scmp>,
464             mp::or_<
465                 traits::is_expression<Expr1>,
466                 traits::is_expression<Expr2>
467               >
468           >,
469           bool> enable;
470 
471     static int get(const Expr1& e1, const Expr2& e2)
472     {
473         return scmp::get(tools::evaluation_helper<Expr1>::get(e1),
474             tools::evaluation_helper<Expr2>::get(e2));
475     }
476 };
477 } // detail
478 
479 template<class Expr>
480 inline typename mp::enable_if<traits::is_expression<Expr>, std::ostream&>::type
481 operator<<(std::ostream& o, const Expr& e)
482 {
483     e.print(o);
484     return o;
485 }
486 
487 template<class Expr1, class Expr2>
488 inline typename mp::enable_if<traits::is_expression<Expr1>, bool>::type
489 operator==(const Expr1& e1, const Expr2& e2)
490 {
491   return e1.equals(e2);
492 }
493 
494 template<class Expr1, class Expr2>
495 inline typename mp::enable_if<mp::and_<
496         mp::not_<traits::is_expression<Expr1> >,
497         traits::is_expression<Expr2> >,
498     bool>::type
499 operator==(const Expr1& e1, const Expr2& e2)
500 {
501   return e2.equals(e1);
502 }
503 
504 template<class Expr1, class Expr2>
505 inline typename mp::enable_if<mp::or_<
506         traits::is_expression<Expr1>,
507         traits::is_expression<Expr2> >,
508     bool>::type
509 operator!=(const Expr1& e1, const Expr2& e2)
510 {
511   return !(e1 == e2);
512 }
513 
514 template<class Expr1, class Expr2>
515 inline typename detail::order_op_helper<Expr1, Expr2>::enable::type
516 operator<(const Expr1& e1, const Expr2& e2)
517 {
518     return detail::order_op_helper<Expr1, Expr2>::get(e1, e2) < 0;
519 }
520 
521 template<class Expr1, class Expr2>
522 inline typename detail::order_op_helper<Expr1, Expr2>::enable::type
523 operator<=(const Expr1& e1, const Expr2& e2)
524 {
525     return detail::order_op_helper<Expr1, Expr2>::get(e1, e2) <= 0;
526 }
527 
528 template<class Expr1, class Expr2>
529 inline typename detail::order_op_helper<Expr1, Expr2>::enable::type
530 operator>(const Expr1& e1, const Expr2& e2)
531 {
532     return detail::order_op_helper<Expr1, Expr2>::get(e1, e2) > 0;
533 }
534 
535 template<class Expr1, class Expr2>
536 inline typename detail::order_op_helper<Expr1, Expr2>::enable::type
537 operator>=(const Expr1& e1, const Expr2& e2)
538 {
539     return detail::order_op_helper<Expr1, Expr2>::get(e1, e2) >= 0;
540 }
541 
542 template<class Expr1, class Expr2>
543 inline typename detail::binary_op_helper<
544     Expr1, operations::plus, Expr2>::enable::type
545 operator+(const Expr1& e1, const Expr2& e2)
546 {
547     return detail::binary_op_helper<Expr1, operations::plus, Expr2>::make(e1, e2);
548 }
549 
550 template<class Expr1, class Expr2>
551 inline typename detail::binary_op_helper<
552     Expr1, operations::minus, Expr2>::enable::type
553 operator-(const Expr1& e1, const Expr2& e2)
554 {
555     return detail::binary_op_helper<Expr1, operations::minus, Expr2>::make(e1, e2);
556 }
557 
558 template<class Expr1, class Expr2>
559 inline typename detail::binary_op_helper<
560     Expr1, operations::times, Expr2>::enable::type
561 operator*(const Expr1& e1, const Expr2& e2)
562 {
563     return detail::binary_op_helper<Expr1, operations::times, Expr2>::make(e1, e2);
564 }
565 
566 template<class Expr1, class Expr2>
567 inline typename detail::binary_op_helper<
568     Expr1, operations::divided_by, Expr2>::enable::type
569 operator/(const Expr1& e1, const Expr2& e2)
570 {
571     return detail::binary_op_helper<Expr1, operations::divided_by, Expr2>::make(e1, e2);
572 }
573 
574 template<class Expr1, class Expr2>
575 inline typename detail::binary_op_helper<
576     Expr1, operations::modulo, Expr2>::enable::type
577 operator%(const Expr1& e1, const Expr2& e2)
578 {
579     return detail::binary_op_helper<Expr1, operations::modulo, Expr2>::make(e1, e2);
580 }
581 
582 template<class Expr1, class Expr2>
583 inline typename detail::binary_op_helper<
584     Expr1, operations::binary_and, Expr2>::enable::type
585 operator&(const Expr1& e1, const Expr2& e2)
586 {
587     return detail::binary_op_helper<Expr1, operations::binary_and, Expr2>::make(e1, e2);
588 }
589 
590 template<class Expr1, class Expr2>
591 inline typename detail::binary_op_helper<
592     Expr1, operations::binary_or, Expr2>::enable::type
593 operator|(const Expr1& e1, const Expr2& e2)
594 {
595     return detail::binary_op_helper<Expr1, operations::binary_or, Expr2>::make(e1, e2);
596 }
597 
598 template<class Expr1, class Expr2>
599 inline typename detail::binary_op_helper<
600     Expr1, operations::binary_xor, Expr2>::enable::type
601 operator^(const Expr1& e1, const Expr2& e2)
602 {
603     return detail::binary_op_helper<Expr1, operations::binary_xor, Expr2>::make(e1, e2);
604 }
605 
606 template<class Expr1, class Expr2>
607 inline typename detail::binary_op_helper<
608     Expr1, operations::shift, Expr2>::enable::type
609 operator<<(const Expr1& e1, const Expr2& e2)
610 {
611     return detail::binary_op_helper<Expr1, operations::shift, Expr2>::make(e1, e2);
612 }
613 
614 template<class Expr1, class Expr2>
615 inline typename detail::binary_op_helper<
616     Expr1, operations::shift, Expr2>::enable::type
617 operator>>(const Expr1& e1, const Expr2& e2)
618 {
619     return detail::binary_op_helper<Expr1, operations::shift, Expr2>::make(e1, -e2);
620 }
621 
622 template<class Expr>
623 inline typename detail::unary_op_helper<operations::negate, Expr>::enable::type
624 operator-(const Expr& e)
625 {
626     return detail::unary_op_helper<operations::negate, Expr>::make(e);
627 }
628 
629 template<class Expr>
630 inline typename detail::unary_op_helper<operations::complement, Expr>::enable::type
631 operator~(const Expr& e)
632 {
633     return detail::unary_op_helper<operations::complement, Expr>::make(e);
634 }
635 
636 template<class Expr1, class Expr2>
637 inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type
638 operator+=(Expr1& e1, const Expr2& e2)
639 {
640     e1.set(e1 + e2);
641     return e1;
642 }
643 
644 template<class Expr1, class Expr2>
645 inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type
646 operator-=(Expr1& e1, const Expr2& e2)
647 {
648     e1.set(e1 - e2);
649     return e1;
650 }
651 
652 template<class Expr1, class Expr2>
653 inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type
654 operator*=(Expr1& e1, const Expr2& e2)
655 {
656     e1.set(e1 * e2);
657     return e1;
658 }
659 
660 template<class Expr1, class Expr2>
661 inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type
662 operator/=(Expr1& e1, const Expr2& e2)
663 {
664     e1.set(e1 / e2);
665     return e1;
666 }
667 
668 template<class Expr1, class Expr2>
669 inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type
670 operator%=(Expr1& e1, const Expr2& e2)
671 {
672     e1.set(e1 % e2);
673     return e1;
674 }
675 
676 template<class Expr1, class Expr2>
677 inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type
678 operator|=(Expr1& e1, const Expr2& e2)
679 {
680     e1.set(e1 | e2);
681     return e1;
682 }
683 
684 template<class Expr1, class Expr2>
685 inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type
686 operator&=(Expr1& e1, const Expr2& e2)
687 {
688     e1.set(e1 & e2);
689     return e1;
690 }
691 
692 template<class Expr1, class Expr2>
693 inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type
694 operator^=(Expr1& e1, const Expr2& e2)
695 {
696     e1.set(e1 ^ e2);
697     return e1;
698 }
699 
700 // c-style IO
701 template<class T>
702 typename mp::enable_if<traits::is_implemented<
703     rules::cprint<typename T::evaluated_t> >, int>::type
704 print(const T& t)
705 {
706     return t.print();
707 }
708 template<class T>
709 typename mp::enable_if<traits::is_implemented<
710     rules::cprint<typename T::evaluated_t> >, int>::type
711 print(FILE* f, const T& t)
712 {
713     return t.print(f);
714 }
715 template<class T, class U>
716 typename mp::enable_if<traits::is_implemented<
717     rules::print_pretty<typename T::evaluated_t> >, int>::type
718 print_pretty(const T& t, const U& extra)
719 {
720     return t.print_pretty(extra);
721 }
722 template<class T, class U>
723 typename mp::enable_if<traits::is_implemented<
724     rules::print_pretty<typename T::evaluated_t> >, int>::type
725 print_pretty(FILE* f, const T& t, const U& extra)
726 {
727     return t.print_pretty(extra, f);
728 }
729 template<class T>
730 typename mp::enable_if<traits::is_implemented<
731     rules::print_pretty<typename T::evaluated_t> >, int>::type
732 print_pretty(const T& t)
733 {
734     return t.print_pretty();
735 }
736 template<class T>
737 typename mp::enable_if<traits::is_implemented<
738     rules::print_pretty<typename T::evaluated_t> >, int>::type
739 print_pretty(FILE* f, const T& t)
740 {
741     return t.print_pretty(f);
742 }
743 template<class T>
744 typename mp::enable_if<traits::is_implemented<
745     rules::read<typename T::evaluated_t> >, int>::type
746 read(T& t)
747 {
748     return t.read();
749 }
750 template<class T>
751 typename mp::enable_if<traits::is_implemented<
752     rules::read<typename T::evaluated_t> >, int>::type
753 read(FILE* f, T& t)
754 {
755     return t.read(f);
756 }
757 
758 // TODO move to std?
759 template<class Expr1, class Expr2>
760 inline typename mp::enable_if<typename traits::is_implemented<
761     rules::swap<Expr1, Expr2> > >::type swap(Expr1& e1, Expr2& e2)
762 {
763     rules::swap<Expr1, Expr2>::doit(e1, e2);
764 }
765 }
766 
767 // TODO remove this?
768 #include "default_rules.h"
769 
770 
771 ////////////////////////////////////////////////////////////////////////
772 // HELPER MACROS
773 ////////////////////////////////////////////////////////////////////////
774 
775 // To be called in any namespace
776 
777 // Make the binary operation "name" available in current namespace
778 #define FLINT_DEFINE_BINOP_HERE(name) \
779 template<class T1, class T2> \
780 inline typename ::flint::detail::binary_op_helper<\
781     T1, ::flint::operations::name##_op, T2>::enable::type \
782 name(const T1& t1, const T2& t2) \
783 { \
784   return ::flint::detail::binary_op_helper< \
785       T1, ::flint::operations::name##_op, T2>::make(t1, t2); \
786 }
787 
788 // Make the unary operation "name" available in current namespace
789 #define FLINT_DEFINE_UNOP_HERE(name) \
790 template<class T1> \
791 inline typename ::flint::detail::unary_op_helper<\
792     ::flint::operations::name##_op, T1>::enable::type \
793 name(const T1& t1) \
794 { \
795   return ::flint::detail::unary_op_helper< ::flint::operations::name##_op, T1>::make(t1); \
796 }
797 
798 // Make the threeary operation "name" available in current namespace
799 #define FLINT_DEFINE_THREEARY_HERE(name) \
800 template<class T1, class T2, class T3> \
801 inline typename ::flint::detail::nary_op_helper2<\
802     ::flint::operations::name##_op, T1, T2, T3>::enable::type \
803 name(const T1& t1, const T2& t2, const T3& t3) \
804 { \
805   return ::flint::detail::nary_op_helper2< \
806       ::flint::operations::name##_op, T1, T2, T3>::make(t1, t2, t3); \
807 }
808 
809 // Make the threeary operation "name" available in current namespace,
810 // but with only two arguments, the second of which is of type type1 and
811 // defaults to val1, and the third argument always (implicitly) of type type2
812 // and value val2.
813 // The suggested usage of this macro is to first call FLINT_DEFINE_THREEARY_HERE,
814 // and then call FLINT_DEFINE_THREEARY_HERE_2DEFAULT. The effect will be an
815 // operation which can be invoked with 1, 2 or 3 arguments.
816 #define FLINT_DEFINE_THREEARY_HERE_2DEFAULT(name, type1, val1, type2, val2) \
817 template<class T1> \
818 inline typename ::flint::detail::nary_op_helper2<\
819     ::flint::operations::name##_op, T1, type1, type2 >::enable::type \
820 name(const T1& t1, type1 t2 = val1) \
821 { \
822   return ::flint::detail::nary_op_helper2< \
823       ::flint::operations::name##_op, T1, type1, type2>::make(t1, t2, val2); \
824 }
825 
826 // Make the fourary operation "name" available in current namespace
827 #define FLINT_DEFINE_FOURARY_HERE(name) \
828 template<class T1, class T2, class T3, class T4> \
829 inline typename ::flint::detail::nary_op_helper2<\
830     ::flint::operations::name##_op, T1, T2, T3, T4>::enable::type \
831 name(const T1& t1, const T2& t2, const T3& t3, const T4& t4) \
832 { \
833   return ::flint::detail::nary_op_helper2< \
834       ::flint::operations::name##_op, T1, T2, T3, T4>::make(t1, t2, t3, t4); \
835 }
836 
837 // Make the fiveary operation "name" available in current namespace
838 #define FLINT_DEFINE_FIVEARY_HERE(name) \
839 template<class T1, class T2, class T3, class T4, class T5> \
840 inline typename ::flint::detail::nary_op_helper2<\
841     ::flint::operations::name##_op, T1, T2, T3, T4, T5>::enable::type \
842 name(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) \
843 { \
844   return ::flint::detail::nary_op_helper2< \
845       ::flint::operations::name##_op, T1, T2, T3, T4, T5>::make(t1, t2, t3, t4, t5); \
846 }
847 
848 // Make the sixary operation "name" available in current namespace
849 #define FLINT_DEFINE_SIXARY_HERE(name) \
850 template<class T1, class T2, class T3, class T4, class T5, class T6> \
851 inline typename ::flint::detail::nary_op_helper2<\
852     ::flint::operations::name##_op, T1, T2, T3, T4, T5, T6>::enable::type \
853 name(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6) \
854 { \
855   return ::flint::detail::nary_op_helper2< \
856       ::flint::operations::name##_op, T1, T2, T3, T4, T5, T6>::make(t1, t2, t3, t4, t5, t6); \
857 }
858 
859 // Make the sevenary operation "name" available in current namespace
860 #define FLINT_DEFINE_SEVENARY_HERE(name) \
861 template<class T1, class T2, class T3, class T4, class T5, class T6, class T7> \
862 inline typename ::flint::detail::nary_op_helper2<\
863     ::flint::operations::name##_op, T1, T2, T3, T4, T5, T6, T7>::enable::type \
864 name(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7) \
865 { \
866   return ::flint::detail::nary_op_helper2< \
867       ::flint::operations::name##_op, T1, T2, T3, T4, T5, T6, T7>::make(t1, t2, t3, t4, t5, t6, t7); \
868 }
869 
870 // This set of macros should be called in namespace flint.
871 
872 // Introduce a new binary operation called "name"
873 // NB: because of ADL bugs in g++ <= 4.4, the operation tag is called "name_op",
874 // whereas the function corresponding to it is just called "name"
875 #define FLINT_DEFINE_BINOP(name) \
876 namespace operations { \
877 struct name##_op { }; \
878 } \
879 FLINT_DEFINE_BINOP_HERE(name)
880 
881 // This macro can be used to conditionally enable a function, and is mostly
882 // used for forwarding.
883 // A typical usage is
884 //   template<class T, class U>
885 //   FLINT_BINOP_ENABLE_RETTYPE(myop, T, U) myop_other(const T& t, const U& u)
886 //   {
887 //       // perhaps something more interesting
888 //       return myop(t, u);
889 //   }
890 #define FLINT_BINOP_ENABLE_RETTYPE(name, T1, T2) \
891     typename detail::binary_op_helper<T1, operations::name##_op, T2>::enable::type
892 
893 // Introduce a new unary operation called "name"
894 #define FLINT_DEFINE_UNOP(name) \
895 namespace operations { \
896 struct name##_op { }; \
897 } \
898 FLINT_DEFINE_UNOP_HERE(name)
899 
900 #define FLINT_UNOP_ENABLE_RETTYPE(name, T) \
901     typename detail::unary_op_helper<operations::name##_op, T>::return_t
902 
903 // See FLINTXX_DEFINE_MEMBER_UNOP_RTYPE
904 #define FLINT_UNOP_BUILD_RETTYPE(name, rettype, T) \
905     typename detail::unary_op_helper_with_rettype<rettype, \
906         operations::name##_op, T>::return_t
907 
908 #define FLINT_DEFINE_THREEARY(name) \
909 namespace operations { \
910 struct name##_op { }; \
911 } \
912 FLINT_DEFINE_THREEARY_HERE(name)
913 
914 #define FLINT_THREEARY_ENABLE_RETTYPE(name, T1, T2, T3) \
915     typename detail::nary_op_helper2<operations::name##_op, T1, T2, T3>::enable::type
916 
917 #define FLINT_DEFINE_FOURARY(name) \
918 namespace operations { \
919 struct name##_op { }; \
920 } \
921 FLINT_DEFINE_FOURARY_HERE(name)
922 
923 #define FLINT_FOURARY_ENABLE_RETTYPE(name, T1, T2, T3, T4) \
924     typename detail::nary_op_helper2<operations::name##_op, T1, T2, T3, T4>::enable::type
925 
926 #define FLINT_DEFINE_FIVEARY(name) \
927 namespace operations { \
928 struct name##_op { }; \
929 } \
930 FLINT_DEFINE_FIVEARY_HERE(name)
931 
932 #define FLINT_FIVEARY_ENABLE_RETTYPE(name, T1, T2, T3, T4, T5) \
933     typename detail::nary_op_helper2<operations::name##_op, T1, T2, T3, T4, T5>::enable::type
934 
935 #define FLINT_DEFINE_SIXARY(name) \
936 namespace operations { \
937 struct name##_op { }; \
938 } \
939 FLINT_DEFINE_SIXARY_HERE(name)
940 
941 #define FLINT_DEFINE_SEVENARY(name) \
942 namespace operations { \
943 struct name##_op { }; \
944 } \
945 FLINT_DEFINE_SEVENARY_HERE(name)
946 
947 #endif
948