unpack.hpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /*!
  2. @file
  3. Defines `boost::hana::unpack`.
  4. @copyright Louis Dionne 2013-2017
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_UNPACK_HPP
  9. #define BOOST_HANA_UNPACK_HPP
  10. #include <boost/hana/fwd/unpack.hpp>
  11. #include <boost/hana/accessors.hpp>
  12. #include <boost/hana/at.hpp>
  13. #include <boost/hana/concept/foldable.hpp>
  14. #include <boost/hana/concept/iterable.hpp>
  15. #include <boost/hana/concept/struct.hpp>
  16. #include <boost/hana/config.hpp>
  17. #include <boost/hana/core/dispatch.hpp>
  18. #include <boost/hana/first.hpp>
  19. #include <boost/hana/functional/partial.hpp>
  20. #include <boost/hana/fwd/fold_left.hpp>
  21. #include <boost/hana/length.hpp>
  22. #include <boost/hana/pair.hpp>
  23. #include <boost/hana/second.hpp>
  24. #include <cstddef>
  25. #include <utility>
  26. BOOST_HANA_NAMESPACE_BEGIN
  27. //! @cond
  28. template <typename Xs, typename F>
  29. constexpr decltype(auto) unpack_t::operator()(Xs&& xs, F&& f) const {
  30. using S = typename hana::tag_of<Xs>::type;
  31. using Unpack = BOOST_HANA_DISPATCH_IF(unpack_impl<S>,
  32. hana::Foldable<S>::value
  33. );
  34. #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
  35. static_assert(hana::Foldable<S>::value,
  36. "hana::unpack(xs, f) requires 'xs' to be Foldable");
  37. #endif
  38. return Unpack::apply(static_cast<Xs&&>(xs), static_cast<F&&>(f));
  39. }
  40. //! @endcond
  41. template <typename T, bool condition>
  42. struct unpack_impl<T, when<condition>> : default_ {
  43. template <typename Xs, typename F>
  44. static constexpr decltype(auto) apply(Xs&& xs, F&& f) {
  45. return hana::fold_left(static_cast<Xs&&>(xs),
  46. static_cast<F&&>(f),
  47. hana::partial)();
  48. }
  49. };
  50. template <typename It>
  51. struct unpack_impl<It, when<
  52. hana::Iterable<It>::value && !is_default<length_impl<It>>::value
  53. >> {
  54. template <typename Xs, typename F, std::size_t ...i>
  55. static constexpr decltype(auto)
  56. unpack_helper(Xs&& xs, F&& f, std::index_sequence<i...>) {
  57. return static_cast<F&&>(f)(hana::at_c<i>(static_cast<Xs&&>(xs))...);
  58. }
  59. template <typename Xs, typename F>
  60. static constexpr decltype(auto) apply(Xs&& xs, F&& f) {
  61. constexpr std::size_t N = decltype(hana::length(xs))::value;
  62. return unpack_helper(static_cast<Xs&&>(xs), static_cast<F&&>(f),
  63. std::make_index_sequence<N>{});
  64. }
  65. };
  66. template <typename T, std::size_t N>
  67. struct unpack_impl<T[N]> {
  68. template <typename Xs, typename F, std::size_t ...i>
  69. static constexpr decltype(auto)
  70. unpack_helper(Xs&& xs, F&& f, std::index_sequence<i...>) {
  71. return static_cast<F&&>(f)(static_cast<Xs&&>(xs)[i]...);
  72. }
  73. template <typename Xs, typename F>
  74. static constexpr decltype(auto) apply(Xs&& xs, F&& f) {
  75. return unpack_impl::unpack_helper(static_cast<Xs&&>(xs),
  76. static_cast<F&&>(f),
  77. std::make_index_sequence<N>{});
  78. }
  79. };
  80. //////////////////////////////////////////////////////////////////////////
  81. // Model for Products
  82. //////////////////////////////////////////////////////////////////////////
  83. template <typename T>
  84. struct unpack_impl<T, when<hana::Product<T>::value>> {
  85. template <typename P, typename F>
  86. static constexpr decltype(auto) apply(P&& p, F&& f) {
  87. return static_cast<F&&>(f)(
  88. hana::first(static_cast<P&&>(p)),
  89. hana::second(static_cast<P&&>(p))
  90. );
  91. }
  92. };
  93. //////////////////////////////////////////////////////////////////////////
  94. // Model for Structs
  95. //////////////////////////////////////////////////////////////////////////
  96. namespace struct_detail {
  97. // This is equivalent to `demux`, except that `demux` can't forward
  98. // the `udt` because it does not know the `g`s are accessors. Hence,
  99. // this can result in faster code.
  100. struct almost_demux {
  101. template <typename F, typename Udt, typename ...Members>
  102. constexpr decltype(auto)
  103. operator()(F&& f, Udt&& udt, Members&& ...g) const {
  104. return static_cast<F&&>(f)(hana::make_pair(
  105. hana::first(static_cast<Members&&>(g)),
  106. hana::second(static_cast<Members&&>(g))
  107. (static_cast<Udt&&>(udt))
  108. )...);
  109. }
  110. };
  111. }
  112. template <typename S>
  113. struct unpack_impl<S, when<hana::Struct<S>::value>> {
  114. template <typename Udt, typename F>
  115. static constexpr decltype(auto) apply(Udt&& udt, F&& f) {
  116. return hana::unpack(hana::accessors<S>(),
  117. hana::partial(struct_detail::almost_demux{},
  118. static_cast<F&&>(f),
  119. static_cast<Udt&&>(udt)));
  120. }
  121. };
  122. BOOST_HANA_NAMESPACE_END
  123. #endif // !BOOST_HANA_UNPACK_HPP