/*
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