1 // Copyright (C) 2016-2018 T. Zachary Laine 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See 4 // accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 #ifndef BOOST_YAP_DETAIL_EXPRESSION_HPP_INCLUDED 7 #define BOOST_YAP_DETAIL_EXPRESSION_HPP_INCLUDED 8 9 #include <boost/yap/algorithm_fwd.hpp> 10 11 #include <boost/hana/size.hpp> 12 #include <boost/hana/tuple.hpp> 13 14 #include <memory> 15 #include <type_traits> 16 17 18 namespace boost { namespace yap { namespace detail { 19 20 // static_const 21 22 template<typename T> 23 struct static_const 24 { 25 static constexpr T value{}; 26 }; 27 28 template<typename T> 29 constexpr T static_const<T>::value; 30 31 32 // partial_decay 33 34 template<typename T> 35 struct partial_decay 36 { 37 using type = T; 38 }; 39 40 template<typename T> 41 struct partial_decay<T[]> 42 { 43 using type = T *; 44 }; 45 template<typename T, std::size_t N> 46 struct partial_decay<T[N]> 47 { 48 using type = T *; 49 }; 50 51 template<typename T> 52 struct partial_decay<T (&)[]> 53 { 54 using type = T *; 55 }; 56 template<typename T, std::size_t N> 57 struct partial_decay<T (&)[N]> 58 { 59 using type = T *; 60 }; 61 62 template<typename R, typename... A> 63 struct partial_decay<R(A...)> 64 { 65 using type = R (*)(A...); 66 }; 67 template<typename R, typename... A> 68 struct partial_decay<R(A..., ...)> 69 { 70 using type = R (*)(A..., ...); 71 }; 72 73 template<typename R, typename... A> 74 struct partial_decay<R (&)(A...)> 75 { 76 using type = R (*)(A...); 77 }; 78 template<typename R, typename... A> 79 struct partial_decay<R (&)(A..., ...)> 80 { 81 using type = R (*)(A..., ...); 82 }; 83 84 template<typename R, typename... A> 85 struct partial_decay<R (*&)(A...)> 86 { 87 using type = R (*)(A...); 88 }; 89 template<typename R, typename... A> 90 struct partial_decay<R (*&)(A..., ...)> 91 { 92 using type = R (*)(A..., ...); 93 }; 94 95 96 // operand_value_type_phase_1 97 98 template< 99 typename T, 100 typename U = typename detail::partial_decay<T>::type, 101 bool AddRValueRef = std::is_same<T, U>::value && !std::is_const<U>::value> 102 struct operand_value_type_phase_1; 103 104 template<typename T, typename U> 105 struct operand_value_type_phase_1<T, U, true> 106 { 107 using type = U &&; 108 }; 109 110 template<typename T, typename U> 111 struct operand_value_type_phase_1<T, U, false> 112 { 113 using type = U; 114 }; 115 116 117 // expr_ref 118 119 template<template<expr_kind, class> class ExprTemplate, typename T> 120 struct expr_ref 121 { 122 using type = expression_ref<ExprTemplate, T>; 123 }; 124 125 template<template<expr_kind, class> class ExprTemplate, typename Tuple> 126 struct expr_ref<ExprTemplate, ExprTemplate<expr_kind::expr_ref, Tuple> &> 127 { 128 using type = ExprTemplate<expr_kind::expr_ref, Tuple>; 129 }; 130 131 template<template<expr_kind, class> class ExprTemplate, typename Tuple> 132 struct expr_ref< 133 ExprTemplate, 134 ExprTemplate<expr_kind::expr_ref, Tuple> const &> 135 { 136 using type = ExprTemplate<expr_kind::expr_ref, Tuple>; 137 }; 138 139 template<template<expr_kind, class> class ExprTemplate, typename T> 140 using expr_ref_t = typename expr_ref<ExprTemplate, T>::type; 141 142 template<template<expr_kind, class> class ExprTemplate, typename T> 143 struct expr_ref_tuple; 144 145 template<template<expr_kind, class> class ExprTemplate, typename Tuple> 146 struct expr_ref_tuple< 147 ExprTemplate, 148 ExprTemplate<expr_kind::expr_ref, Tuple>> 149 { 150 using type = Tuple; 151 }; 152 153 template<template<expr_kind, class> class ExprTemplate, typename T> 154 using expr_ref_tuple_t = typename expr_ref_tuple<ExprTemplate, T>::type; 155 156 157 // operand_type 158 159 template< 160 template<expr_kind, class> class ExprTemplate, 161 typename T, 162 typename U = typename operand_value_type_phase_1<T>::type, 163 bool RemoveRefs = std::is_rvalue_reference<U>::value, 164 bool IsExpr = is_expr<T>::value, 165 bool IsLRef = std::is_lvalue_reference<T>::value> 166 struct operand_type; 167 168 template< 169 template<expr_kind, class> class ExprTemplate, 170 typename T, 171 typename U, 172 bool RemoveRefs> 173 struct operand_type<ExprTemplate, T, U, RemoveRefs, true, false> 174 { 175 using type = remove_cv_ref_t<T>; 176 }; 177 178 template< 179 template<expr_kind, class> class ExprTemplate, 180 typename T, 181 typename U, 182 bool RemoveRefs> 183 struct operand_type<ExprTemplate, T, U, RemoveRefs, true, true> 184 { 185 using type = expr_ref_t<ExprTemplate, T>; 186 }; 187 188 template< 189 template<expr_kind, class> class ExprTemplate, 190 typename T, 191 typename U, 192 bool RemoveRefs, 193 bool IsLRef> 194 struct operand_type<ExprTemplate, T, U, RemoveRefs, true, IsLRef> 195 { 196 using type = remove_cv_ref_t<T>; 197 }; 198 199 template< 200 template<expr_kind, class> class ExprTemplate, 201 typename T, 202 typename U, 203 bool IsLRef> 204 struct operand_type<ExprTemplate, T, U, true, false, IsLRef> 205 { 206 using type = terminal<ExprTemplate, std::remove_reference_t<U>>; 207 }; 208 209 template< 210 template<expr_kind, class> class ExprTemplate, 211 typename T, 212 typename U, 213 bool IsLRef> 214 struct operand_type<ExprTemplate, T, U, false, false, IsLRef> 215 { 216 using type = terminal<ExprTemplate, U>; 217 }; 218 219 template<template<expr_kind, class> class ExprTemplate, typename T> 220 using operand_type_t = typename operand_type<ExprTemplate, T>::type; 221 222 223 // make_operand 224 225 template<typename T> 226 struct make_operand 227 { 228 template<typename U> operator ()boost::yap::detail::make_operand229 constexpr auto operator()(U && u) 230 { 231 return T{static_cast<U &&>(u)}; 232 } 233 }; 234 235 template<template<expr_kind, class> class ExprTemplate, typename Tuple> 236 struct make_operand<ExprTemplate<expr_kind::expr_ref, Tuple>> 237 { operator ()boost::yap::detail::make_operand238 constexpr auto operator()(ExprTemplate<expr_kind::expr_ref, Tuple> expr) 239 { 240 return expr; 241 } 242 243 template<typename U> operator ()boost::yap::detail::make_operand244 constexpr auto operator()(U && u) 245 { 246 return ExprTemplate<expr_kind::expr_ref, Tuple>{ 247 Tuple{std::addressof(u)}}; 248 } 249 }; 250 251 252 // free_binary_op_result 253 254 template< 255 template<expr_kind, class> class ExprTemplate, 256 expr_kind OpKind, 257 typename T, 258 typename U, 259 bool TNonExprUExpr = !is_expr<T>::value && is_expr<U>::value, 260 bool ULvalueRef = std::is_lvalue_reference<U>::value> 261 struct free_binary_op_result; 262 263 template< 264 template<expr_kind, class> class ExprTemplate, 265 expr_kind OpKind, 266 typename T, 267 typename U> 268 struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, true> 269 { 270 using lhs_type = operand_type_t<ExprTemplate, T>; 271 using rhs_type = expr_ref_t<ExprTemplate, U>; 272 using rhs_tuple_type = expr_ref_tuple_t<ExprTemplate, rhs_type>; 273 using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>; 274 }; 275 276 template< 277 template<expr_kind, class> class ExprTemplate, 278 expr_kind OpKind, 279 typename T, 280 typename U> 281 struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, false> 282 { 283 using lhs_type = operand_type_t<ExprTemplate, T>; 284 using rhs_type = remove_cv_ref_t<U>; 285 using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>; 286 }; 287 288 template< 289 template<expr_kind, class> class ExprTemplate, 290 expr_kind OpKind, 291 typename T, 292 typename U> 293 using free_binary_op_result_t = 294 typename free_binary_op_result<ExprTemplate, OpKind, T, U>::type; 295 296 297 // ternary_op_result 298 299 template< 300 template<expr_kind, class> class ExprTemplate, 301 typename T, 302 typename U, 303 typename V, 304 bool Valid = 305 is_expr<T>::value || is_expr<U>::value || is_expr<V>::value> 306 struct ternary_op_result; 307 308 template< 309 template<expr_kind, class> class ExprTemplate, 310 typename T, 311 typename U, 312 typename V> 313 struct ternary_op_result<ExprTemplate, T, U, V, true> 314 { 315 using cond_type = operand_type_t<ExprTemplate, T>; 316 using then_type = operand_type_t<ExprTemplate, U>; 317 using else_type = operand_type_t<ExprTemplate, V>; 318 using type = ExprTemplate< 319 expr_kind::if_else, 320 hana::tuple<cond_type, then_type, else_type>>; 321 }; 322 323 template< 324 template<expr_kind, class> class ExprTemplate, 325 typename T, 326 typename U, 327 typename V> 328 using ternary_op_result_t = 329 typename ternary_op_result<ExprTemplate, T, U, V>::type; 330 331 332 // udt_any_ternary_op_result 333 334 template< 335 template<expr_kind, class> class ExprTemplate, 336 typename T, 337 typename U, 338 typename V, 339 template<class> class UdtTrait, 340 bool Valid = !is_expr<T>::value && !is_expr<U>::value && 341 !is_expr<V>::value && 342 (UdtTrait<remove_cv_ref_t<T>>::value || 343 UdtTrait<remove_cv_ref_t<U>>::value || 344 UdtTrait<remove_cv_ref_t<V>>::value)> 345 struct udt_any_ternary_op_result; 346 347 template< 348 template<expr_kind, class> class ExprTemplate, 349 typename T, 350 typename U, 351 typename V, 352 template<class> class UdtTrait> 353 struct udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait, true> 354 { 355 using cond_type = operand_type_t<ExprTemplate, T>; 356 using then_type = operand_type_t<ExprTemplate, U>; 357 using else_type = operand_type_t<ExprTemplate, V>; 358 using type = ExprTemplate< 359 expr_kind::if_else, 360 hana::tuple<cond_type, then_type, else_type>>; 361 }; 362 363 template< 364 template<expr_kind, class> class ExprTemplate, 365 typename T, 366 typename U, 367 typename V, 368 template<class> class UdtTrait> 369 using udt_any_ternary_op_result_t = 370 typename udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait>:: 371 type; 372 373 374 // udt_unary_op_result 375 376 template< 377 template<expr_kind, class> class ExprTemplate, 378 expr_kind OpKind, 379 typename T, 380 template<class> class UdtTrait, 381 bool Valid = !is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value> 382 struct udt_unary_op_result; 383 384 template< 385 template<expr_kind, class> class ExprTemplate, 386 expr_kind OpKind, 387 typename T, 388 template<class> class UdtTrait> 389 struct udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait, true> 390 { 391 using x_type = operand_type_t<ExprTemplate, T>; 392 using type = ExprTemplate<OpKind, hana::tuple<x_type>>; 393 }; 394 395 template< 396 template<expr_kind, class> class ExprTemplate, 397 expr_kind OpKind, 398 typename T, 399 template<class> class UdtTrait> 400 using udt_unary_op_result_t = 401 typename udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait>::type; 402 403 404 // udt_udt_binary_op_result 405 406 template<typename T, template<class> class UdtTrait> 407 struct is_udt_arg 408 { 409 static bool const value = 410 !is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value; 411 }; 412 413 template< 414 template<expr_kind, class> class ExprTemplate, 415 expr_kind OpKind, 416 typename T, 417 typename U, 418 template<class> class TUdtTrait, 419 template<class> class UUdtTrait, 420 bool Valid = 421 is_udt_arg<T, TUdtTrait>::value && is_udt_arg<U, UUdtTrait>::value> 422 struct udt_udt_binary_op_result; 423 424 template< 425 template<expr_kind, class> class ExprTemplate, 426 expr_kind OpKind, 427 typename T, 428 typename U, 429 template<class> class TUdtTrait, 430 template<class> class UUdtTrait> 431 struct udt_udt_binary_op_result< 432 ExprTemplate, 433 OpKind, 434 T, 435 U, 436 TUdtTrait, 437 UUdtTrait, 438 true> 439 { 440 using lhs_type = operand_type_t<ExprTemplate, T>; 441 using rhs_type = operand_type_t<ExprTemplate, U>; 442 using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>; 443 }; 444 445 template< 446 template<expr_kind, class> class ExprTemplate, 447 expr_kind OpKind, 448 typename T, 449 typename U, 450 template<class> class TUdtTrait, 451 template<class> class UUdtTrait> 452 using udt_udt_binary_op_result_t = typename udt_udt_binary_op_result< 453 ExprTemplate, 454 OpKind, 455 T, 456 U, 457 TUdtTrait, 458 UUdtTrait>::type; 459 460 461 // udt_any_binary_op_result 462 463 template< 464 template<expr_kind, class> class ExprTemplate, 465 expr_kind OpKind, 466 typename T, 467 typename U, 468 template<class> class UdtTrait, 469 bool Valid = !is_expr<T>::value && !is_expr<U>::value && 470 (UdtTrait<remove_cv_ref_t<T>>::value || 471 UdtTrait<remove_cv_ref_t<U>>::value)> 472 struct udt_any_binary_op_result; 473 474 template< 475 template<expr_kind, class> class ExprTemplate, 476 expr_kind OpKind, 477 typename T, 478 typename U, 479 template<class> class UdtTrait> 480 struct udt_any_binary_op_result<ExprTemplate, OpKind, T, U, UdtTrait, true> 481 { 482 using lhs_type = operand_type_t<ExprTemplate, T>; 483 using rhs_type = operand_type_t<ExprTemplate, U>; 484 using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>; 485 }; 486 487 template< 488 template<expr_kind, class> class ExprTemplate, 489 expr_kind OpKind, 490 typename T, 491 typename U, 492 template<class> class UdtTrait> 493 using udt_any_binary_op_result_t = typename udt_any_binary_op_result< 494 ExprTemplate, 495 OpKind, 496 T, 497 U, 498 UdtTrait>::type; 499 500 501 // not_copy_or_move 502 503 template<typename LeftT, typename RightT> 504 struct copy_or_move : std::false_type 505 { 506 }; 507 508 template<typename T> 509 struct copy_or_move<T, T const &> : std::true_type 510 { 511 }; 512 513 template<typename T> 514 struct copy_or_move<T, T &> : std::true_type 515 { 516 }; 517 518 template<typename T> 519 struct copy_or_move<T, T &&> : std::true_type 520 { 521 }; 522 523 524 // expr_arity 525 526 enum class expr_arity { invalid, one, two, three, n }; 527 528 template<expr_kind Kind> arity_of()529 constexpr expr_arity arity_of() 530 { 531 switch (Kind) { 532 case expr_kind::expr_ref: 533 534 case expr_kind::terminal: 535 536 // unary 537 case expr_kind::unary_plus: // + 538 case expr_kind::negate: // - 539 case expr_kind::dereference: // * 540 case expr_kind::complement: // ~ 541 case expr_kind::address_of: // & 542 case expr_kind::logical_not: // ! 543 case expr_kind::pre_inc: // ++ 544 case expr_kind::pre_dec: // -- 545 case expr_kind::post_inc: // ++(int) 546 case expr_kind::post_dec: // --(int) 547 return expr_arity::one; 548 549 // binary 550 case expr_kind::shift_left: // << 551 case expr_kind::shift_right: // >> 552 case expr_kind::multiplies: // * 553 case expr_kind::divides: // / 554 case expr_kind::modulus: // % 555 case expr_kind::plus: // + 556 case expr_kind::minus: // - 557 case expr_kind::less: // < 558 case expr_kind::greater: // > 559 case expr_kind::less_equal: // <= 560 case expr_kind::greater_equal: // >= 561 case expr_kind::equal_to: // == 562 case expr_kind::not_equal_to: // != 563 case expr_kind::logical_or: // || 564 case expr_kind::logical_and: // && 565 case expr_kind::bitwise_and: // & 566 case expr_kind::bitwise_or: // | 567 case expr_kind::bitwise_xor: // ^ 568 case expr_kind::comma: // : 569 case expr_kind::mem_ptr: // ->* 570 case expr_kind::assign: // = 571 case expr_kind::shift_left_assign: // <<= 572 case expr_kind::shift_right_assign: // >>= 573 case expr_kind::multiplies_assign: // *= 574 case expr_kind::divides_assign: // /= 575 case expr_kind::modulus_assign: // %= 576 case expr_kind::plus_assign: // += 577 case expr_kind::minus_assign: // -= 578 case expr_kind::bitwise_and_assign: // &= 579 case expr_kind::bitwise_or_assign: // |= 580 case expr_kind::bitwise_xor_assign: // ^= 581 case expr_kind::subscript: // [] 582 return expr_arity::two; 583 584 // ternary 585 case expr_kind::if_else: // (analogous to) ?: 586 return expr_arity::three; 587 588 // n-ary 589 case expr_kind::call: // () 590 return expr_arity::n; 591 592 default: return expr_arity::invalid; 593 } 594 } 595 596 }}} 597 598 #endif 599