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 // Lazy tuple class (for use in expression templates) 13 // Note that assignment and comparison are performed elementwise, and types 14 // need not match (even for equality) as long as the operations can be performed 15 // on underlying types. 16 17 #ifndef FLINTXX_LTUPLE_H 18 #define FLINTXX_LTUPLE_H 19 20 #ifndef FLINT_LTUPLE_PLACEHOLDER_NAME 21 #define FLINT_LTUPLE_PLACEHOLDER_NAME _ 22 #endif 23 24 #include "expression.h" 25 #include "tuple.h" 26 27 namespace flint { 28 // For lazy get<n>, this operation type is created. 29 namespace operations { 30 template<unsigned n> struct ltuple_get_op { }; 31 } // operations 32 33 namespace detail { 34 // Empty marker type 35 struct INSTANTIATE_FROM_TUPLE { }; 36 37 // Traits for the ltuple expression template get<> operation. If the ltuple is 38 // an immediate, return references. Else if the return type is an expression 39 // template, return an expression template. Otherwise, evaluate the ltuple and 40 // return a copy of the entry. 41 template<unsigned n, class Underlying, class Operation, class Data, class Expr, 42 class Enable = void> 43 struct ltuple_get_traits 44 { 45 typedef unary_op_helper<operations::ltuple_get_op<n>, Expr> uoh; 46 typedef typename uoh::return_t type; 47 typedef type ctype; getltuple_get_traits48 static type get(const Expr& e) 49 { 50 return uoh::make(e); 51 } 52 }; 53 54 template<unsigned n, class Underlying, class Data, class Expr> 55 struct ltuple_get_traits<n, Underlying, operations::immediate, Data, Expr> 56 { 57 typedef mp::tuple_get<Underlying, n> getter; 58 typedef typename getter::type btype; 59 typedef typename traits::forwarding<btype>::type ctype; 60 typedef typename traits::reference<btype>::type type; 61 62 static type get(Expr& t) 63 { 64 return getter::get(t._data().inner); 65 } 66 static ctype get(const Expr& t) 67 { 68 return getter::get(t._data().inner); 69 } 70 }; 71 72 template<unsigned n, class Underlying, class Operation, class Data, class Expr> 73 struct ltuple_get_traits<n, Underlying, Operation, Data, Expr, 74 typename mp::enable_if<mp::and_< 75 mp::not_<mp::equal_types<Operation, operations::immediate> >, 76 mp::not_<traits::is_expression<typename mp::tuple_get<Underlying, n>::type> > 77 > >::type> 78 { 79 typedef mp::tuple_get<Underlying, n> getter; 80 typedef typename getter::type type; 81 typedef type ctype; 82 83 static type get(const Expr& t) 84 { 85 return getter::get(t.evaluate()._data().inner); 86 } 87 }; 88 89 // Instances of this can be passed to ltuple[ref]() and will be replaced by 90 // temporaries of the right type before assigment. 91 struct IGNORED_TYPE { }; 92 template<class Ltuple, class To, class Enable = void> 93 struct ltuple_instantiate_ignored_types; 94 } // detail 95 96 // The ltuple expression template class. Underlying is a tuple type. 97 template<class Underlying, class Operation, class Data> 98 class ltuple_expression 99 : public expression<derived_wrapper2<ltuple_expression, Underlying>, 100 Operation, Data> 101 { 102 public: 103 typedef expression<derived_wrapper2< ::flint::ltuple_expression, Underlying>, 104 Operation, Data> base_t; 105 // internal 106 typedef void IS_LTUPLE_EXPRESSION; 107 108 typedef Underlying underlying_t; 109 110 ltuple_expression() {} 111 112 template<class T> 113 ltuple_expression(detail::INSTANTIATE_FROM_TUPLE i, const T& t) 114 : base_t(i, t) {} 115 116 template<class T> 117 ltuple_expression& operator=(const T& t) 118 { 119 detail::ltuple_instantiate_ignored_types< 120 ltuple_expression, T> inst(*this, t); 121 inst.set(t); 122 return *this; 123 } 124 125 template<unsigned n> 126 typename detail::ltuple_get_traits<n, Underlying, 127 Operation, Data, ltuple_expression>::type get() 128 { 129 return detail::ltuple_get_traits< 130 n, Underlying, Operation, Data, ltuple_expression>::get(*this); 131 } 132 template<unsigned n> 133 typename detail::ltuple_get_traits<n, Underlying, 134 Operation, Data, ltuple_expression>::ctype 135 get() const 136 { 137 return detail::ltuple_get_traits< 138 n, Underlying, Operation, Data, ltuple_expression>::get(*this); 139 } 140 141 typename base_t::evaluated_t create_temporary() const 142 { 143 return typename base_t::evaluated_t(detail::INSTANTIATE_FROM_TUPLE(), 144 mp::htuples::fill<underlying_t>(tools::temporaries_filler(*this))); 145 } 146 147 protected: 148 explicit ltuple_expression(const Data& d) : base_t(d) {} 149 150 template<class D, class O, class Da> 151 friend class expression; 152 }; 153 154 namespace detail { 155 template<class Underlying> 156 struct ltuple_data 157 { 158 Underlying inner; 159 160 ltuple_data() {} 161 162 template<class T> 163 ltuple_data(INSTANTIATE_FROM_TUPLE, const T& t) : inner(t) {} 164 }; 165 166 template<class T> struct to_ref : traits::reference<T> { }; 167 template<class T> struct to_srcref 168 : traits::reference<typename traits::make_const<T>::type> { }; 169 170 template<template<class>class Transform, class Tuple> 171 struct transform_tuple 172 { 173 typedef tuple<typename Transform<typename Tuple::head_t>::type, 174 typename transform_tuple<Transform, typename Tuple::tail_t>::type> 175 type; 176 }; 177 template<template<class>class Transform> 178 struct transform_tuple<Transform, empty_tuple> 179 { 180 typedef empty_tuple type; 181 }; 182 } // detail 183 184 // Helper for building ltuple types. 185 template<class Underlying> 186 struct make_ltuple 187 { 188 typedef ltuple_expression<Underlying, operations::immediate, 189 detail::ltuple_data<Underlying> > type; 190 191 typedef typename detail::transform_tuple<detail::to_ref, Underlying>::type 192 Underlying_ref; 193 typedef typename detail::transform_tuple<detail::to_srcref, Underlying>::type 194 Underlying_srcref; 195 196 typedef ltuple_expression<Underlying_ref, operations::immediate, 197 detail::ltuple_data<Underlying_ref> > ref_type; 198 typedef ltuple_expression<Underlying_srcref, operations::immediate, 199 detail::ltuple_data<Underlying_srcref> > srcref_type; 200 }; 201 202 namespace traits { 203 template<class Tuple, class Enable = void> 204 struct is_ltuple_expr : mp::false_ { }; 205 template<class Tuple> 206 struct is_ltuple_expr<Tuple, typename Tuple::IS_LTUPLE_EXPRESSION> 207 : mp::true_ { }; 208 209 // enable evaluation directly into tuple 210 template<class To, class From> 211 struct can_evaluate_into<To, From, 212 typename mp::enable_if<mp::and_<is_ltuple_expr<From>, 213 is_ltuple_expr<To>, mp::not_<mp::equal_types<To, From> > 214 > >::type> : mp::true_ { }; 215 } // traits 216 217 namespace detail { 218 template<class Ltuple, class To, class Enable> 219 struct ltuple_instantiate_ignored_types 220 { 221 // degenerate case: To is not a tuple 222 Ltuple& saved; 223 ltuple_instantiate_ignored_types(Ltuple& s, const To&) : saved(s) {} 224 void set(const To& to) {saved.set(to);} 225 }; 226 template<class ToTuple, class FromTuple> 227 struct tuple_instantiate_ignored 228 { 229 typedef tuple_instantiate_ignored<typename ToTuple::tail_t, 230 typename FromTuple::tail_t> next_t; 231 typedef typename traits::reference<typename ToTuple::head_t>::type ref_t; 232 typedef tuple<ref_t, typename next_t::type> type; 233 next_t next; 234 ref_t ref; 235 236 template<class From> 237 tuple_instantiate_ignored(ToTuple& to, const From& from) 238 : next(to.tail, from), ref(to.head) {} 239 240 type get() 241 { 242 return type(ref, next.get()); 243 } 244 }; 245 template<> 246 struct tuple_instantiate_ignored<empty_tuple, empty_tuple> 247 { 248 typedef empty_tuple type; 249 template<class F> 250 tuple_instantiate_ignored(empty_tuple, const F&) {} 251 empty_tuple get() {return empty_tuple();} 252 }; 253 template<class ToTail, class From, class FromTail> 254 struct tuple_instantiate_ignored< 255 tuple<IGNORED_TYPE&, ToTail>, tuple<From, FromTail> > 256 { 257 typedef tuple_instantiate_ignored<ToTail, FromTail> next_t; 258 typedef typename traits::reference<From>::type ref_t; 259 typedef tuple<ref_t, typename next_t::type> type; 260 next_t next; 261 From tmp; 262 263 template<class ToTuple, class FromExpr> 264 tuple_instantiate_ignored(ToTuple& to, const FromExpr& from) 265 : next(to.tail, from), 266 tmp(rules::instantiate_temporaries<FromExpr, From>::get(from)) {} 267 268 type get() 269 { 270 return type(tmp, next.get()); 271 } 272 }; 273 template<class Ltuple, class T> 274 struct ltuple_instantiate_ignored_types<Ltuple, T, 275 typename mp::enable_if<traits::is_ltuple_expr<T> >::type> 276 { 277 typedef tuple_instantiate_ignored< 278 typename Ltuple::underlying_t, typename T::underlying_t> tii_t; 279 tii_t tii; 280 ltuple_instantiate_ignored_types(Ltuple& l, const T& t) 281 : tii(l._data().inner, t) {} 282 void set(const T& t) 283 { 284 typename make_ltuple<typename tii_t::type>::type(INSTANTIATE_FROM_TUPLE(), 285 tii.get()).set(t); 286 } 287 }; 288 } 289 290 namespace rules { 291 template<class Tuple1, class Tuple2> 292 struct assignment<Tuple1, Tuple2, 293 typename mp::enable_if<mp::and_< 294 traits::is_ltuple_expr<Tuple2>, 295 traits::is_ltuple_expr<Tuple1> > >::type> 296 { 297 static void doit(Tuple1& to, const Tuple2& from) 298 { 299 to._data().inner.set(from._data().inner); 300 } 301 }; 302 303 template<class Tuple1, class Tuple2> 304 struct equals<Tuple1, Tuple2, 305 typename mp::enable_if<mp::and_< 306 traits::is_ltuple_expr<Tuple2>, 307 traits::is_ltuple_expr<Tuple1> > >::type> 308 { 309 static bool get(const Tuple1& to, const Tuple2& from) 310 { 311 return to._data().inner.equals_elementwise(from._data().inner); 312 } 313 }; 314 315 template<class Tuple, unsigned n> 316 struct unary_expression<operations::ltuple_get_op<n>, Tuple, 317 typename mp::enable_if<mp::and_< 318 traits::is_ltuple_expr<Tuple>, 319 traits::is_immediate<Tuple> > >::type> 320 { 321 typedef typename mp::tuple_get<typename Tuple::underlying_t, n>::type 322 return_t; 323 template<class R> 324 static void doit(R& to, const Tuple& from) 325 { 326 to = from.template get<n>(); 327 } 328 }; 329 } // rules 330 331 // TODO we would really like variadic templates / lvalue references here 332 333 // Helpers to build ltuples from (references to) arguments. 334 335 template<class T> 336 inline typename make_ltuple<typename mp::make_tuple<T>::type>::type 337 ltuple(const T& t) 338 { 339 return typename make_ltuple<typename mp::make_tuple<T>::type>::type( 340 detail::INSTANTIATE_FROM_TUPLE(), 341 mp::make_tuple<T>::make(t)); 342 } 343 template<class T, class U> 344 inline typename make_ltuple<typename mp::make_tuple<T, U>::type>::type 345 ltuple(const T& t, const U& u) 346 { 347 return typename make_ltuple<typename mp::make_tuple<T, U>::type>::type( 348 detail::INSTANTIATE_FROM_TUPLE(), 349 mp::make_tuple<T, U>::make(t, u)); 350 } 351 352 template<class T, class U, class V> 353 inline typename make_ltuple<typename mp::make_tuple<T, U, V>::type>::type 354 ltuple(const T& t, const U& u, const V& v) 355 { 356 return typename make_ltuple<typename mp::make_tuple<T, U, V>::type>::type( 357 detail::INSTANTIATE_FROM_TUPLE(), 358 mp::make_tuple<T, U, V>::make(t, u, v)); 359 } 360 template<class T, class U, class V, class W> 361 inline typename make_ltuple<typename mp::make_tuple<T, U, V, W>::type>::type 362 ltuple(const T& t, const U& u, const V& v, const W& w) 363 { 364 return typename make_ltuple<typename mp::make_tuple<T, U, V, W>::type>::type( 365 detail::INSTANTIATE_FROM_TUPLE(), 366 mp::make_tuple<T, U, V, W>::make(t, u, v, w)); 367 } 368 template<class T> 369 inline typename make_ltuple<typename mp::make_tuple<T&>::type>::type 370 ltupleref(T& t) 371 { 372 return typename make_ltuple<typename mp::make_tuple<T&>::type>::type( 373 detail::INSTANTIATE_FROM_TUPLE(), 374 mp::make_tuple<T&>::make(t)); 375 } 376 template<class T, class U> 377 inline typename make_ltuple<typename mp::make_tuple<T&, U&>::type>::type 378 ltupleref(T& t, U& u) 379 { 380 return typename make_ltuple<typename mp::make_tuple<T&, U&>::type>::type( 381 detail::INSTANTIATE_FROM_TUPLE(), 382 mp::make_tuple<T&, U&>::make(t, u)); 383 } 384 template<class T, class U, class V> 385 inline typename make_ltuple<typename mp::make_tuple<T&, U&, V&>::type>::type 386 ltupleref(T& t, U& u, V& v) 387 { 388 return typename make_ltuple<typename mp::make_tuple<T&, U&, V&>::type>::type( 389 detail::INSTANTIATE_FROM_TUPLE(), 390 mp::make_tuple<T&, U&, V&>::make(t, u, v)); 391 } 392 template<class T, class U, class V, class W> 393 inline typename make_ltuple<typename mp::make_tuple<T&, U&, V&, W&>::type>::type 394 ltupleref(T& t, U& u, V& v, W& w) 395 { 396 return typename make_ltuple<typename mp::make_tuple<T&, U&, V&, W&>::type>::type( 397 detail::INSTANTIATE_FROM_TUPLE(), 398 mp::make_tuple<T&, U&, V&, W&>::make(t, u, v, w)); 399 } 400 401 // static placeholder 402 static detail::IGNORED_TYPE FLINT_LTUPLE_PLACEHOLDER_NAME; 403 404 namespace detail { 405 void remove_compiler_warning( 406 detail::IGNORED_TYPE* = &FLINT_LTUPLE_PLACEHOLDER_NAME); 407 } // detail 408 } // flint 409 410 #endif 411