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 // Helpers to define concrete subclasses of expression.
13 // Contrary to other parts of this library, they are tailored very
14 // specifically towards FLINT.
15 
16 #include "../flint.h"
17 #include "mp.h"
18 #include "expression.h"
19 #include "expression_traits.h"
20 #include "evaluation_tools.h"
21 #include "tuple.h"
22 
23 #ifndef CXX_FLINT_CLASSES_H
24 #define CXX_FLINT_CLASSES_H
25 
26 // Flint classes distinguish themselves from "ordinary" expression template
27 // classes by a public typedef IS_FLINT_CLASS (see also FLINTXX_DEFINE_BASICS
28 // below). Most functionality in this header disables itself when used on a
29 // non-flint class.
30 
31 // For all flint classes, Data of immediates must have typedefs data_ref_t and
32 // data_srcref_t.
33 
34 // The immediates of any flint class come in three "flavours": ordinary, ref
35 // and srcref. Most of the classes below are used to convert these flavours.
36 // In order for this to work, the expression template class must contain a
37 // public typedef c_base_t which is the underlying "basic" C type (so not the
38 // length one array that is usually used), e.g. fmpz_poly_struct. Conversion to
39 // reference type then yields expression templates which have Data set to
40 // ref_data<Wrapped, c_base_t> or srcref_data. These implementation work as
41 // long as all data is stored in c_base_t. If not (e.g. for padic, where there
42 // is an additional reference to the context), ref_data and srcref_data have to
43 // be specialised appropriately.
44 
45 namespace flint {
46 namespace flint_classes {
47 template<class Wrapped, class Inner>
48 struct ref_data
49 {
50     typedef void IS_REF_OR_CREF;
51     typedef Wrapped wrapped_t;
52 
53     typedef Inner* data_ref_t;
54     typedef const Inner* data_srcref_t;
55 
56     Inner* inner;
57 
ref_dataref_data58     ref_data(Wrapped& o) : inner(o._data().inner) {}
59 
makeref_data60     static ref_data make(Inner* f) {return ref_data(f);}
61 
62 private:
ref_dataref_data63     ref_data(Inner* fp) : inner(fp) {}
64 };
65 
66 template<class Wrapped, class Ref, class Inner>
67 struct srcref_data
68 {
69     typedef void IS_REF_OR_CREF;
70     typedef Wrapped wrapped_t;
71 
72     typedef const Inner* data_ref_t;
73     typedef const Inner* data_srcref_t;
74 
75     const Inner* inner;
76 
srcref_datasrcref_data77     srcref_data(const Wrapped& o) : inner(o._data().inner) {}
srcref_datasrcref_data78     srcref_data(Ref o) : inner(o._data().inner) {}
79 
makesrcref_data80     static srcref_data make(const Inner* f) {return srcref_data(f);}
81 
82 private:
srcref_datasrcref_data83     srcref_data(const Inner* fp) : inner(fp) {}
84 };
85 
86 // Helper to determine if T is a flint class.
87 template<class T, class Enable = void> struct is_flint_class : mp::false_ { };
88 template<class T>
89 struct is_flint_class<T, typename T::IS_FLINT_CLASS> : mp::true_ { };
90 
91 // From a lazy or immediate flint expression, obtain the evaluated
92 // non-reference type.
93 // Examples: fmpzxx -> fmpzxx
94 //           fmpzxx_ref -> fmpzxx
95 //           fmpzxx + fmpzxx -> fmpzxx
96 template<class T, class Enable = void>
97 struct to_nonref {typedef typename T::evaluated_t type;};
98 
99 template<class T>
100 struct to_nonref<T, typename T::data_t::IS_REF_OR_CREF>
101 {
102     typedef typename T::data_t::wrapped_t type;
103 };
104 
105 template<class T>
106 struct c_base_t
107 {
108     typedef typename T::c_base_t type;
109 };
110 
111 // Given a lazy or non-lazy flint expression, obtain th evaluated reference
112 // type.
113 // Examples: fmpzxx -> fmpzxx_ref
114 //           fmpzxx_ref -> fmpzxx_ref
115 //           fmpzxx + fmpzxx -> fmpzxx_ref
116 template<class T>
117 struct to_ref
118 {
119     typedef typename T::template make_helper<operations::immediate, ref_data<
120         typename to_nonref<T>::type, typename c_base_t<T>::type> >::type type;
121 };
122 // Similarly for srcref.
123 template<class T>
124 struct to_srcref
125 {
126     typedef typename T::template make_helper<operations::immediate, srcref_data<
127         typename to_nonref<T>::type, typename to_ref<T>::type,
128         typename c_base_t<T>::type> >::type type;
129 };
130 
131 // Compute if Ref if the reference type belonging to compare.
132 // Examples: fmpzxx_ref, fmpzxx + fmpzxx -> true_
133 //           fmpzxx_srcref, fmpzxx -> false_
134 template<class Compare, class Ref>
135 struct is_ref : mp::equal_types<Ref, typename to_ref<Compare>::type> { };
136 
137 // Similarly for srcref.
138 template<class Compare, class Ref>
139 struct is_srcref : mp::equal_types<Ref, typename to_srcref<Compare>::type> { };
140 
141 // Similarly for non-ref.
142 template<class T>
143 struct is_nonref : mp::equal_types<T, typename to_nonref<T>::type > { };
144 
145 // Flint classes allow implicit conversion only in very special situations.
146 // This template determines when. Currently, it is used exclusively to allow
147 // implicit conversion to reference types.
148 template<class T, class U, class Enable = void>
149 struct enableimplicit : mp::false_ { };
150 
151 template<class T, class U>
152 struct enableimplicit<T, U, typename mp::enable_if<mp::and_<
153         is_flint_class<T>, is_flint_class<U>
154       > >::type>
155     : mp::and_<
156         traits::is_immediate_expr<T>,
157         traits::is_immediate_expr<U>,
158         mp::or_<
159             mp::and_<is_ref<U, T>, is_nonref<U> >,
160             mp::and_<is_srcref<U, T>, is_nonref<U> >,
161             mp::and_<is_srcref<U, T>, is_ref<U, U> >
162       > > { };
163 
164 // Helper template which allows accessing data_(src)ref_t on immediates,
165 // without causing a compiler error on non-immediates.
166 // The main use for this are the _fmpz(), _fmpq() etc methods, which only
167 // work on immediates (but are defined on all instances).
168 template<class Expr, class Enable = void>
169 struct maybe_data_ref
170 {
171     typedef void data_ref_t;
172     typedef void data_srcref_t;
173 };
174 template<class Expr>
175 struct maybe_data_ref<Expr,
176     typename mp::enable_if<
177         // NB: cannot use is_immediate, since Expr may be incomplete type!
178         mp::equal_types<typename Expr::operation_t, operations::immediate> >::type>
179 {
180     typedef typename Expr::data_t::data_ref_t data_ref_t;
181     typedef typename Expr::data_t::data_srcref_t data_srcref_t;
182 };
183 
184 // If Base is a non-ref flint class, determine if T is a source operand
185 // (i.e. non-ref, ref or srcref type belong to Base)
186 // Examples: fmpzxx, fmpzxx_srcref -> true
187 //           fmpzxx, fmpzxx -> true
188 //           fmpzxx, fmpqxx -> false
189 template<class Base, class T, class Enable = void>
190 struct is_source : mp::false_ { };
191 template<class Base, class T>
192 struct is_source<Base, T, typename mp::enable_if<
193     mp::and_<is_flint_class<T>, is_flint_class<Base> > >::type>
194     : mp::or_<mp::equal_types<T, Base>, is_ref<Base, T>, is_srcref<Base, T> > { };
195 
196 // Same with target (i.e. disallow srcref).
197 template<class Base, class T, class Enable = void>
198 struct is_target : mp::false_ { };
199 template<class Base, class T>
200 struct is_target<Base, T, typename mp::enable_if<
201     mp::and_<is_flint_class<T>, is_flint_class<Base> > >::type>
202     : mp::or_<mp::equal_types<T, Base>, is_ref<Base, T> > { };
203 
204 // Predicate version of the above. Useful for FLINT_DEFINE_*_COND.
205 // See FLINTXX_COND_S and FLINTXX_COND_T
206 template<class Base>
207 struct is_source_base
208 {
209     template<class T> struct type : is_source<Base, T> { };
210 };
211 template<class Base>
212 struct is_target_base
213 {
214     template<class T> struct type : is_target<Base, T> { };
215 };
216 
217 // Helper for implementing x += y*z etc
218 template<class T, class Right1, class Right2>
219 struct ternary_assign_helper
220 {
221     typedef typename mp::make_tuple<Right1, Right2>::type tup_t;
222     typedef tools::evaluate_n<tup_t> ev2_t;
223     typedef typename ev2_t::temporaries_t temporaries_t;
224     typedef mp::back_tuple<temporaries_t> back_t;
225 
226     typename back_t::type backing;
227     ev2_t ev2;
228 
229     static temporaries_t backtemps(typename back_t::type& backing)
230     {
231         temporaries_t temps;
232         back_t::init(temps, backing);
233         return temps;
234     }
235 
236     ternary_assign_helper(const tup_t& tup)
237         : backing(mp::htuples::fill<typename back_t::type>(
238                     tools::temporaries_filler(
239                         tup.first()+tup.second() /* XXX */))),
240           ev2(tup, backtemps(backing)) {}
241     const T& getleft() {return ev2.template get<0>();}
242     const T& getright() {return ev2.template get<1>();}
243 };
244 
245 template<class T, class Right1, class Right2>
246 struct enable_ternary_assign
247     : mp::enable_if<mp::and_<
248           traits::is_T_expr<typename traits::basetype<Right1>::type, T>,
249           traits::is_T_expr<typename traits::basetype<Right2>::type, T> >, T&> { };
250 
251 // convenience helper
252 template<class Base, class T> struct is_Base : mp::or_<
253      traits::is_T_expr<T, Base>,
254      is_source<Base, T> > { };
255 } // flint_classes
256 
257 namespace traits {
258 // Enable evaluation into reference types. See can_evaluate_into in
259 // expression_traits.h.
260 // XXX why do we need to disable the case where T, U are equal?
261 // Is <T, T> not more special?
262 template<class T, class U>
263 struct can_evaluate_into<T, U,
264     typename mp::enable_if<mp::and_<flint_classes::is_flint_class<T>,
265         flint_classes::is_flint_class<U>,
266         mp::not_<mp::equal_types<T, U> > > >::type>
267     : flint_classes::is_ref<U, T> { };
268 } // traits
269 
270 
271 namespace detail {
272 template<class Expr, class Enable = void>
273 struct should_enable_extra_ternop : mp::false_ { };
274 template<class Expr>
275 struct should_enable_extra_ternop<Expr, typename mp::enable_if<
276     flint_classes::is_flint_class<Expr> >::type>
277     : mp::equal_types<Expr, typename flint_classes::to_ref<
278         typename flint_classes::to_nonref<Expr>::type>::type> { };
279 } // detail
280 
281 // We add additional overloads for when the LHS is a reference type. The
282 // problem is that the standard overloads take LHS via reference, and rvalues
283 // (such as coming from fmpz_polyxx::get_coeff())
284 // cannot bind to this. In this case instead objects should be taken by value.
285 // However, this will make the overload ambiguous. Hence we take by const
286 // reference and then make an additional copy.
287 template<class Expr1, class Expr2>
288 inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type
289 operator+=(const Expr1& e1, const Expr2& e2)
290 {
291     Expr1(e1).set(e1 + e2);
292     return e1;
293 }
294 template<class Expr1, class Expr2>
295 inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type
296 operator-=(const Expr1& e1, const Expr2& e2)
297 {
298     Expr1(e1).set(e1 - e2);
299     return e1;
300 }
301 template<class Expr1, class Expr2>
302 inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type
303 operator*=(const Expr1& e1, const Expr2& e2)
304 {
305     Expr1(e1).set(e1 * e2);
306     return e1;
307 }
308 template<class Expr1, class Expr2>
309 inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type
310 operator/=(const Expr1& e1, const Expr2& e2)
311 {
312     Expr1(e1).set(e1 / e2);
313     return e1;
314 }
315 template<class Expr1, class Expr2>
316 inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type
317 operator%=(const Expr1& e1, const Expr2& e2)
318 {
319     Expr1(e1).set(e1 % e2);
320     return e1;
321 }
322 template<class Expr1, class Expr2>
323 inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type
324 operator<<=(const Expr1& e1, const Expr2& e2)
325 {
326     Expr1(e1).set(e1 << e2);
327     return e1;
328 }
329 template<class Expr1, class Expr2>
330 inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type
331 operator>>=(const Expr1& e1, const Expr2& e2)
332 {
333     Expr1(e1).set(e1 >> e2);
334     return e1;
335 }
336 } // flint
337 
338 // macros that help defining flint classes
339 
340 #define FLINTXX_DEFINE_BASICS_NOFLINTCLASS(name)                              \
341 public:                                                                       \
342     typedef typename base_t::evaluated_t evaluated_t;                         \
343                                                                               \
344     template<class T>                                                         \
345     struct doimplicit                                                         \
346         : flint_classes::enableimplicit<name, T> { };                         \
347                                                                               \
348     template<class T>                                                         \
349     name& operator=(const T& t)                                               \
350     {                                                                         \
351         this->set(t);                                                         \
352         return *this;                                                         \
353     }                                                                         \
354                                                                               \
355 protected:                                                                    \
356     explicit name(const Data& d) : base_t(d) {}                               \
357                                                                               \
358     template<class D, class O, class Da>                                      \
359     friend class expression;
360 
361 // all flint classes should have this
362 #define FLINTXX_DEFINE_BASICS(name)                                           \
363 public:                                                                       \
364     typedef void IS_FLINT_CLASS;                                              \
365     FLINTXX_DEFINE_BASICS_NOFLINTCLASS(name)                                  \
366 
367 // all flint classes should have this
368 #define FLINTXX_DEFINE_CTORS(name)                                            \
369 public:                                                                       \
370     name() : base_t() {}                                                      \
371     template<class T>                                                         \
372     explicit name(const T& t,                                                 \
373             typename mp::disable_if<doimplicit<T> >::type* = 0)               \
374         : base_t(t) {}                                                        \
375     template<class T>                                                         \
376     explicit name(T& t,                                                       \
377             typename mp::disable_if<doimplicit<T> >::type* = 0)               \
378         : base_t(t) {}                                                        \
379     template<class T>                                                         \
380     name(const T& t,                                                          \
381             typename mp::enable_if<doimplicit<T> >::type* = 0)                \
382         : base_t(t) {}                                                        \
383     template<class T>                                                         \
384     name(T& t,                                                                \
385             typename mp::enable_if<doimplicit<T> >::type* = 0)                \
386         : base_t(t) {}                                                        \
387     template<class T, class U>                                                \
388     name(const T& t, const U& u) : base_t(t, u) {}                            \
389     template<class T, class U>                                                \
390     name(T& t, const U& u) : base_t(t, u) {}                            \
391     template<class T, class U, class V>                                       \
392     name(const T& t, const U& u, const V& v) : base_t(t, u, v) {}             \
393     template<class T, class U, class V>                                       \
394     name(T& t, const U& u, const V& v) : base_t(t, u, v) {}             \
395     template<class T, class U, class V, class W>                              \
396     name(const T& t, const U& u, const V& v, const W& w)                      \
397         : base_t(t, u, v, w) {}                                               \
398     template<class T, class U, class V, class W>                              \
399     name(T& t, const U& u, const V& v, const W& w)                      \
400         : base_t(t, u, v, w) {}
401 
402 // Enable the flint reference type scheme. This typedefs c_base_t to ctype,
403 // and adds the data access wrapper (like _fmpz(), _fmpq()) called accessname.
404 // It also provides reference constructors from C types.
405 // All flint classes should have this.
406 #define FLINTXX_DEFINE_C_REF(name, ctype, accessname)                         \
407 public:                                                                       \
408     typedef ctype c_base_t;                                                   \
409     typedef flint_classes::maybe_data_ref<name> wrapped_traits;               \
410     typename wrapped_traits::data_ref_t accessname()                          \
411     {                                                                         \
412         return this->_data().inner;                                           \
413     }                                                                         \
414     typename wrapped_traits::data_srcref_t accessname() const                 \
415     {                                                                         \
416         return this->_data().inner;                                           \
417     }                                                                         \
418                                                                               \
419     /* These only make sense with the reference types */                      \
420     template<class T>                                                         \
421     static name make(T& f)                                                    \
422     {                                                                         \
423         return name(Data::make(f));                                           \
424     }                                                                         \
425     template<class T>                                                         \
426     static name make(const T& f)                                              \
427     {                                                                         \
428         return name(Data::make(f));                                           \
429     }                                                                         \
430     template<class T, class U>                                                \
431     static name make(T& f, const U& u)                                        \
432     {                                                                         \
433         return name(Data::make(f, u));                                        \
434     }                                                                         \
435     template<class T, class U>                                                \
436     static name make(const T& f, const U& u)                                  \
437     {                                                                         \
438         return name(Data::make(f, u));                                        \
439     }                                                                         \
440     template<class T, class U, class V>                                       \
441     static name make(const T& f, const U& u, const V& v)                      \
442     {                                                                         \
443         return name(Data::make(f, u, v));                                     \
444     }
445 
446 // Add a statically forwarded constructor called name. (Forwarded to data_t).
447 #define FLINTXX_DEFINE_FORWARD_STATIC(name)                                   \
448     template<class T>                                                         \
449     static typename base_t::derived_t name(const T& f)                        \
450     {                                                                         \
451         return typename base_t::derived_t(Data::name(f));                     \
452     }                                                                         \
453     template<class T, class U>                                                \
454     static typename base_t::derived_t name(const T& f, const U& u)            \
455     {                                                                         \
456         return typename base_t::derived_t(Data::name(f, u));                  \
457     }
458 
459 // Add a static randomisation function.
460 // XXX this is not really useful because the arguments are often different.
461 #define FLINTXX_DEFINE_RANDFUNC(CBase, name) \
462 static CBase##xx_expression name(frandxx& state, flint_bitcnt_t bits) \
463 { \
464     CBase##xx_expression res; \
465     CBase##_##name(res._data().inner, state._data(), bits); \
466     return res; \
467 }
468 
469 // Add a forwarded unary operation to the class. Suppose there is a unary
470 // operation foo() which returns my_typeA, and takes an argument of type
471 // my_typeB. Now on instances my_typeB, you want to write x.bar() for foo(x).
472 // Then add FLINTXX_DEFINE_MEMBER_UNOP_RTYPE_(my_typeA, bar, foo) to my_typeB.
473 //
474 // XXX due to circular definition problems, this cannot use the usual
475 // unary_op_helper type approach, and the unop must return the same type
476 // of expression
477 #define FLINTXX_DEFINE_MEMBER_UNOP_RTYPE_(rettype, name, funcname) \
478 FLINT_UNOP_BUILD_RETTYPE(funcname, rettype, typename base_t::derived_t) \
479 name() const \
480 { \
481     return flint::funcname(*this); \
482 }
483 
484 // Convenience version when name==funcname
485 #define FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(rettype, name) \
486     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE_(rettype, name, name)
487 
488 // Convenience version when rettype==argtype
489 #define FLINTXX_DEFINE_MEMBER_UNOP_(name, funcname) \
490     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE_(typename base_t::derived_t, name, funcname)
491 
492 // Convenience version when rettype==argtype and name==funcname
493 #define FLINTXX_DEFINE_MEMBER_UNOP(name) FLINTXX_DEFINE_MEMBER_UNOP_(name, name)
494 
495 // Add a forwarded binary operation. It is not necessary to specify the return
496 // type.
497 #define FLINTXX_DEFINE_MEMBER_BINOP_(name, funcname) \
498 template<class T> \
499 typename detail::binary_op_helper<typename base_t::derived_t, \
500     operations::funcname##_op, T>::enable::type \
501 name(const T& t) const \
502 { \
503     return flint::funcname(*this, t); \
504 }
505 
506 // Convenience version when funcname==name.
507 #define FLINTXX_DEFINE_MEMBER_BINOP(name) \
508     FLINTXX_DEFINE_MEMBER_BINOP_(name, name)
509 
510 #define FLINTXX_DEFINE_MEMBER_3OP_(name, funcname) \
511 template<class T, class U> \
512 typename detail::nary_op_helper2<operations::funcname##_op, \
513     typename base_t::derived_t, T, U>::enable::type \
514 name(const T& t, const U& u) const \
515 { \
516     return flint::funcname(*this, t, u); \
517 }
518 
519 #define FLINTXX_DEFINE_MEMBER_3OP(name) \
520     FLINTXX_DEFINE_MEMBER_3OP_(name, name)
521 
522 #define FLINTXX_DEFINE_MEMBER_4OP_(name, funcname) \
523 template<class T, class U, class V> \
524 typename detail::nary_op_helper2<operations::funcname##_op, \
525     typename base_t::derived_t, T, U, V>::enable::type \
526 name(const T& t, const U& u, const V& v) const \
527 { \
528     return flint::funcname(*this, t, u, v); \
529 }
530 
531 #define FLINTXX_DEFINE_MEMBER_4OP(name) \
532     FLINTXX_DEFINE_MEMBER_4OP_(name, name)
533 
534 #define FLINTXX_DEFINE_MEMBER_5OP_(name, funcname) \
535 template<class T, class U, class V, class W> \
536 typename detail::nary_op_helper2<operations::funcname##_op, \
537     typename base_t::derived_t, T, U, V, W>::enable::type \
538 name(const T& t, const U& u, const V& v, const W& w) const \
539 { \
540     return flint::funcname(*this, t, u, v, w); \
541 }
542 
543 #define FLINTXX_DEFINE_MEMBER_5OP(name) \
544     FLINTXX_DEFINE_MEMBER_5OP_(name, name)
545 
546 // Helper macros for FLINT_DEFINE_*_COND?.
547 #define FLINTXX_COND_S(Base) flint_classes::is_source_base<Base>::template type
548 #define FLINTXX_COND_T(Base) flint_classes::is_target_base<Base>::template type
549 
550 // Convenience rules. These all take a Base class as argument, and will
551 // automatically apply to the related reference types as well.
552 
553 // Add a to_string() conversion rule, empolying the common flint idiom where
554 // the string is allocated by the to_string function.
555 #define FLINTXX_DEFINE_TO_STR(Base, eval) \
556 template<class T> \
557 struct to_string<T, \
558     typename mp::enable_if< FLINTXX_COND_S(Base)<T> >::type> \
559 { \
560     static std::string get(const T& from, int base) \
561     { \
562         char* str = eval; \
563         std::string res(str); \
564         flint_free(str); \
565         return res; \
566     } \
567 };
568 
569 // Add a swap rule.
570 #define FLINTXX_DEFINE_SWAP(Base, eval) \
571 template<class T, class U> \
572 struct swap<T, U, typename mp::enable_if< mp::and_< \
573     FLINTXX_COND_T(Base)<T>, FLINTXX_COND_T(Base)<U> > >::type> \
574 { \
575     static void doit(T& e1, U& e2) \
576     { \
577         eval; \
578     } \
579 };
580 
581 // Define a conversion rule through a default-constructed temporary object.
582 #define FLINTXX_DEFINE_CONVERSION_TMP(totype, Base, eval) \
583 template<class T> \
584 struct conversion<totype, T, \
585     typename mp::enable_if< FLINTXX_COND_S(Base)<T> >::type> \
586 { \
587     static totype get(const T& from) \
588     { \
589         totype to; \
590         eval; \
591         return to; \
592     } \
593 };
594 
595 // Define a cmp rule.
596 #define FLINTXX_DEFINE_CMP(Base, eval) \
597 template<class T, class U> \
598 struct cmp<T, U, \
599     typename mp::enable_if<mp::and_<FLINTXX_COND_S(Base)<T>, \
600         FLINTXX_COND_S(Base)<U> > >::type> \
601 { \
602     static int get(const T& e1, const U& e2) \
603     { \
604         return eval; \
605     } \
606 };
607 
608 // Define an equals rule.
609 #define FLINTXX_DEFINE_EQUALS(Base, eval) \
610 template<class T, class U> \
611 struct equals<T, U, typename mp::enable_if<mp::and_< \
612     FLINTXX_COND_S(Base)<T>, FLINTXX_COND_S(Base)<U> > >::type> \
613 { \
614     static bool get(const T& e1, const U& e2) \
615     { \
616         return eval; \
617     } \
618 };
619 
620 // Define a string assignment rule (c/f many polynomial classes).
621 #define FLINTXX_DEFINE_ASSIGN_STR(Base, eval) \
622 template<class T, class U> \
623 struct assignment<T, U, \
624     typename mp::enable_if<mp::and_< \
625         FLINTXX_COND_T(Base)<T>, traits::is_string<U> > >::type> \
626 { \
627     static void doit(T& to, const char* from) \
628     { \
629         eval; \
630     } \
631 };
632 
633 #define FLINTXX_UNADORNED_MAKETYPES(Base, left, op, right) \
634     Base##_expression< op, tuple< left, tuple< right, empty_tuple> > >
635 
636 // Optimized evaluation rules using ternary arithmetic (addmul, submul)
637 // NB: this has to be called in namespace flint, not flint::rules!
638 #define FLINTXX_DEFINE_TERNARY(Base, addmuleval, submuleval, maketypes)       \
639 namespace rules {                                                             \
640 /* a +- b*c */                                                                \
641 template<class Op, class Left, class Right1, class Right2>                    \
642 struct evaluation<Op,                                                         \
643     tuple<Left, tuple<                                                        \
644         maketypes(Base, Right1, operations::times, Right2),                   \
645         /* NB: there is no particular reason to have the enable_if here,      \
646                many other similar places would do */                          \
647         typename mp::enable_if<mp::or_<                                       \
648                 mp::equal_types<Op, operations::plus>,                        \
649                 mp::equal_types<Op, operations::minus> >,                     \
650             empty_tuple>::type> >,                                            \
651     true, 1,                                                                  \
652     typename tools::ternary_helper<Base, Left, Right1, Right2>::enable::type> \
653 {                                                                             \
654     /* Helpful for testing. */                                                \
655     static const unsigned TERNARY_OP_MARKER = 0;                              \
656                                                                               \
657     typedef Base return_t;                                                    \
658     typedef tools::ternary_helper<Base, Left, Right1, Right2> th;             \
659     typedef typename th::temporaries_t temporaries_t;                         \
660     typedef tuple<Left, tuple<                                                \
661         maketypes(Base, Right1, operations::times, Right2),                   \
662         empty_tuple> > data_t;                                                \
663     static const bool is_add = mp::equal_types<Op, operations::plus>::val;    \
664                                                                               \
665     static void doit(const data_t& input, temporaries_t temps, return_t* res) \
666     {                                                                         \
667         const Base* left = 0;                                                 \
668         const Base* right = 0;                                                \
669         th::doit(input.first(), input.second()._data().first(),               \
670                 input.second()._data().second(), temps, res, right, left);    \
671         const Base& e1 = *left;                                               \
672         const Base& e2 = *right;                                              \
673         Base& to = *res;                                                      \
674         if(is_add)                                                            \
675         {                                                                     \
676             addmuleval;                                                       \
677         }                                                                     \
678         else                                                                  \
679         {                                                                     \
680             submuleval;                                                       \
681         }                                                                     \
682     }                                                                         \
683 };                                                                            \
684                                                                               \
685 /* b*c + a */                                                                 \
686 template<class Right, class Left1, class Left2>                               \
687 struct evaluation<operations::plus,                                           \
688     tuple<maketypes(Base, Left1, operations::times, Left2),                   \
689         tuple<Right, empty_tuple> >,                                          \
690     true, 1,                                                                  \
691     typename tools::ternary_helper<Base,                                      \
692         Right, Left1, Left2, operations::times>::enable::type>                \
693 {                                                                             \
694     /* Helpful for testing. */                                                \
695     static const unsigned TERNARY_OP_MARKER = 0;                              \
696                                                                               \
697     typedef Base return_t;                                                    \
698     typedef tools::ternary_helper<Base, Right, Left1, Left2> th;              \
699     typedef typename th::temporaries_t temporaries_t;                         \
700     typedef tuple<maketypes(Base, Left1, operations::times, Left2),           \
701         tuple<Right, empty_tuple> > data_t;                                   \
702                                                                               \
703     static void doit(const data_t& input, temporaries_t temps, return_t* res) \
704     {                                                                         \
705         const Base* left = 0;                                                 \
706         const Base* right = 0;                                                \
707         th::doit(input.second(), input.first()._data().first(),               \
708                 input.first()._data().second(), temps, res, right, left);     \
709         const Base& e1 = *left;                                               \
710         const Base& e2 = *right;                                              \
711         Base& to = *res;                                                      \
712         addmuleval;                                                           \
713     }                                                                         \
714 };                                                                            \
715 } /* rules */                                                                 \
716                                                                               \
717 /* TODO enable these with references on left hand side(?) */                  \
718 /* a += b*c */                                                                \
719 template<class Right1, class Right2>                                          \
720 inline typename flint_classes::enable_ternary_assign<Base, Right1, Right2>::type \
721 operator+=(Base& to,                                                          \
722         const maketypes(Base, Right1, operations::times, Right2)& other)      \
723 {                                                                             \
724     flint_classes::ternary_assign_helper<Base, Right1, Right2> tah(           \
725             other._data());                                                   \
726     const Base& e1 = tah.getleft();                                           \
727     const Base& e2 = tah.getright();                                          \
728     addmuleval;                                                               \
729     return to;                                                                \
730 }                                                                             \
731                                                                               \
732 /* a -= b*c */                                                                \
733 template<class Right1, class Right2>                                          \
734 inline typename flint_classes::enable_ternary_assign<Base, Right1, Right2>::type \
735 operator-=(Base& to,                                                          \
736         const maketypes(Base, Right1, operations::times, Right2)& other)      \
737 {                                                                             \
738     flint_classes::ternary_assign_helper<Base, Right1, Right2> tah(           \
739             other._data());                                                   \
740     const Base& e1 = tah.getleft();                                           \
741     const Base& e2 = tah.getright();                                          \
742     submuleval;                                                               \
743     return to;                                                                \
744 }
745 
746 #endif
747