/* 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 . */ // Lazy tuple class (for use in expression templates) // Note that assignment and comparison are performed elementwise, and types // need not match (even for equality) as long as the operations can be performed // on underlying types. #ifndef FLINTXX_LTUPLE_H #define FLINTXX_LTUPLE_H #ifndef FLINT_LTUPLE_PLACEHOLDER_NAME #define FLINT_LTUPLE_PLACEHOLDER_NAME _ #endif #include "expression.h" #include "tuple.h" namespace flint { // For lazy get, this operation type is created. namespace operations { template struct ltuple_get_op { }; } // operations namespace detail { // Empty marker type struct INSTANTIATE_FROM_TUPLE { }; // Traits for the ltuple expression template get<> operation. If the ltuple is // an immediate, return references. Else if the return type is an expression // template, return an expression template. Otherwise, evaluate the ltuple and // return a copy of the entry. template struct ltuple_get_traits { typedef unary_op_helper, Expr> uoh; typedef typename uoh::return_t type; typedef type ctype; static type get(const Expr& e) { return uoh::make(e); } }; template struct ltuple_get_traits { typedef mp::tuple_get getter; typedef typename getter::type btype; typedef typename traits::forwarding::type ctype; typedef typename traits::reference::type type; static type get(Expr& t) { return getter::get(t._data().inner); } static ctype get(const Expr& t) { return getter::get(t._data().inner); } }; template struct ltuple_get_traits >, mp::not_::type> > > >::type> { typedef mp::tuple_get getter; typedef typename getter::type type; typedef type ctype; static type get(const Expr& t) { return getter::get(t.evaluate()._data().inner); } }; // Instances of this can be passed to ltuple[ref]() and will be replaced by // temporaries of the right type before assigment. struct IGNORED_TYPE { }; template struct ltuple_instantiate_ignored_types; } // detail // The ltuple expression template class. Underlying is a tuple type. template class ltuple_expression : public expression, Operation, Data> { public: typedef expression, Operation, Data> base_t; // internal typedef void IS_LTUPLE_EXPRESSION; typedef Underlying underlying_t; ltuple_expression() {} template ltuple_expression(detail::INSTANTIATE_FROM_TUPLE i, const T& t) : base_t(i, t) {} template ltuple_expression& operator=(const T& t) { detail::ltuple_instantiate_ignored_types< ltuple_expression, T> inst(*this, t); inst.set(t); return *this; } template typename detail::ltuple_get_traits::type get() { return detail::ltuple_get_traits< n, Underlying, Operation, Data, ltuple_expression>::get(*this); } template typename detail::ltuple_get_traits::ctype get() const { return detail::ltuple_get_traits< n, Underlying, Operation, Data, ltuple_expression>::get(*this); } typename base_t::evaluated_t create_temporary() const { return typename base_t::evaluated_t(detail::INSTANTIATE_FROM_TUPLE(), mp::htuples::fill(tools::temporaries_filler(*this))); } protected: explicit ltuple_expression(const Data& d) : base_t(d) {} template friend class expression; }; namespace detail { template struct ltuple_data { Underlying inner; ltuple_data() {} template ltuple_data(INSTANTIATE_FROM_TUPLE, const T& t) : inner(t) {} }; template struct to_ref : traits::reference { }; template struct to_srcref : traits::reference::type> { }; templateclass Transform, class Tuple> struct transform_tuple { typedef tuple::type, typename transform_tuple::type> type; }; templateclass Transform> struct transform_tuple { typedef empty_tuple type; }; } // detail // Helper for building ltuple types. template struct make_ltuple { typedef ltuple_expression > type; typedef typename detail::transform_tuple::type Underlying_ref; typedef typename detail::transform_tuple::type Underlying_srcref; typedef ltuple_expression > ref_type; typedef ltuple_expression > srcref_type; }; namespace traits { template struct is_ltuple_expr : mp::false_ { }; template struct is_ltuple_expr : mp::true_ { }; // enable evaluation directly into tuple template struct can_evaluate_into, is_ltuple_expr, mp::not_ > > >::type> : mp::true_ { }; } // traits namespace detail { template struct ltuple_instantiate_ignored_types { // degenerate case: To is not a tuple Ltuple& saved; ltuple_instantiate_ignored_types(Ltuple& s, const To&) : saved(s) {} void set(const To& to) {saved.set(to);} }; template struct tuple_instantiate_ignored { typedef tuple_instantiate_ignored next_t; typedef typename traits::reference::type ref_t; typedef tuple type; next_t next; ref_t ref; template tuple_instantiate_ignored(ToTuple& to, const From& from) : next(to.tail, from), ref(to.head) {} type get() { return type(ref, next.get()); } }; template<> struct tuple_instantiate_ignored { typedef empty_tuple type; template tuple_instantiate_ignored(empty_tuple, const F&) {} empty_tuple get() {return empty_tuple();} }; template struct tuple_instantiate_ignored< tuple, tuple > { typedef tuple_instantiate_ignored next_t; typedef typename traits::reference::type ref_t; typedef tuple type; next_t next; From tmp; template tuple_instantiate_ignored(ToTuple& to, const FromExpr& from) : next(to.tail, from), tmp(rules::instantiate_temporaries::get(from)) {} type get() { return type(tmp, next.get()); } }; template struct ltuple_instantiate_ignored_types >::type> { typedef tuple_instantiate_ignored< typename Ltuple::underlying_t, typename T::underlying_t> tii_t; tii_t tii; ltuple_instantiate_ignored_types(Ltuple& l, const T& t) : tii(l._data().inner, t) {} void set(const T& t) { typename make_ltuple::type(INSTANTIATE_FROM_TUPLE(), tii.get()).set(t); } }; } namespace rules { template struct assignment, traits::is_ltuple_expr > >::type> { static void doit(Tuple1& to, const Tuple2& from) { to._data().inner.set(from._data().inner); } }; template struct equals, traits::is_ltuple_expr > >::type> { static bool get(const Tuple1& to, const Tuple2& from) { return to._data().inner.equals_elementwise(from._data().inner); } }; template struct unary_expression, Tuple, typename mp::enable_if, traits::is_immediate > >::type> { typedef typename mp::tuple_get::type return_t; template static void doit(R& to, const Tuple& from) { to = from.template get(); } }; } // rules // TODO we would really like variadic templates / lvalue references here // Helpers to build ltuples from (references to) arguments. template inline typename make_ltuple::type>::type ltuple(const T& t) { return typename make_ltuple::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple::make(t)); } template inline typename make_ltuple::type>::type ltuple(const T& t, const U& u) { return typename make_ltuple::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple::make(t, u)); } template inline typename make_ltuple::type>::type ltuple(const T& t, const U& u, const V& v) { return typename make_ltuple::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple::make(t, u, v)); } template inline typename make_ltuple::type>::type ltuple(const T& t, const U& u, const V& v, const W& w) { return typename make_ltuple::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple::make(t, u, v, w)); } template inline typename make_ltuple::type>::type ltupleref(T& t) { return typename make_ltuple::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple::make(t)); } template inline typename make_ltuple::type>::type ltupleref(T& t, U& u) { return typename make_ltuple::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple::make(t, u)); } template inline typename make_ltuple::type>::type ltupleref(T& t, U& u, V& v) { return typename make_ltuple::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple::make(t, u, v)); } template inline typename make_ltuple::type>::type ltupleref(T& t, U& u, V& v, W& w) { return typename make_ltuple::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple::make(t, u, v, w)); } // static placeholder static detail::IGNORED_TYPE FLINT_LTUPLE_PLACEHOLDER_NAME; namespace detail { void remove_compiler_warning( detail::IGNORED_TYPE* = &FLINT_LTUPLE_PLACEHOLDER_NAME); } // detail } // flint #endif