1 /*=============================================================================
2     Copyright (c) 2015 Paul Fultz II
3     compressed_pair.h
4     Distributed under the Boost Software License, Version 1.0. (See accompanying
5     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7 
8 #ifndef BOOST_HOF_GUARD_COMPRESSED_PAIR_H
9 #define BOOST_HOF_GUARD_COMPRESSED_PAIR_H
10 
11 #include <boost/hof/detail/delegate.hpp>
12 #include <boost/hof/detail/move.hpp>
13 #include <boost/hof/detail/forward.hpp>
14 #include <boost/hof/config.hpp>
15 #include <boost/hof/always.hpp>
16 #include <boost/hof/alias.hpp>
17 
18 #ifndef BOOST_HOF_COMPRESSED_PAIR_USE_EBO_WORKAROUND
19 #define BOOST_HOF_COMPRESSED_PAIR_USE_EBO_WORKAROUND !BOOST_HOF_HAS_EBO
20 #endif
21 
22 namespace boost { namespace hof { namespace detail {
23 
24 template<class First, class Second, class=void>
25 struct compressed_pair;
26 
27 template<int I, class T, class U>
28 struct pair_tag
29 {};
30 
31 #if BOOST_HOF_COMPRESSED_PAIR_USE_EBO_WORKAROUND
32 
33 template<class T, class U>
34 struct is_same_template
35 : std::false_type
36 {};
37 
38 template<template<class...> class X, class... Ts, class... Us>
39 struct is_same_template<X<Ts...>, X<Us...>>
40 : std::true_type
41 {};
42 
43 #if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7)
44 
45 template<class T, class U>
46 struct is_related_template
47 : std::false_type
48 {};
49 
50 #else
51 
52 template<class T, class U>
53 struct is_related_template
54 : is_same_template<T, U>
55 {};
56 
57 #endif
58 
59 template<class T, class U>
60 struct is_related
61 : std::integral_constant<bool, std::is_base_of<T, U>::value || std::is_base_of<U, T>::value || is_related_template<T, U>::value>
62 {};
63 
64 template<int I, class T, class U>
65 struct pair_holder
66 : std::conditional<(
67     is_related<T, U>::value),
68     detail::alias_empty<T, pair_tag<I, T, U>>,
69     detail::alias_try_inherit<T, pair_tag<I, T, U>>
70 >::type
71 {};
72 #else
73 template<int I, class T, class U>
74 struct pair_holder
75 : detail::alias_try_inherit<T, pair_tag<I, T, U>>
76 {};
77 #endif
78 
79 // TODO: Empty optimizations for MSVC
80 template<
81     class First,
82     class Second
83 >
84 struct compressed_pair<First, Second>
85 : pair_holder<0, First, Second>::type, pair_holder<1, Second, First>::type
86 {
87     typedef typename pair_holder<0, First, Second>::type first_base;
88     typedef typename pair_holder<1, Second, First>::type second_base;
89     template<class X, class Y,
90         BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(First, X&&),
91         BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(Second, Y&&)
92     >
compressed_pairboost::hof::detail::compressed_pair93     constexpr compressed_pair(X&& x, Y&& y)
94     noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(first_base, X&&) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(second_base, Y&&))
95     : first_base(BOOST_HOF_FORWARD(X)(x)), second_base(BOOST_HOF_FORWARD(Y)(y))
96     {}
97 
BOOST_HOF_INHERIT_DEFAULTboost::hof::detail::compressed_pair98     BOOST_HOF_INHERIT_DEFAULT(compressed_pair, first_base, second_base)
99 
100     template<class Base, class... Xs>
101     constexpr const Base& get_alias_base(Xs&&... xs) const noexcept
102     {
103         return boost::hof::always_ref(*this)(xs...);
104     }
105 
106     template<class... Xs>
firstboost::hof::detail::compressed_pair107     constexpr const First& first(Xs&&... xs) const noexcept
108     {
109         return boost::hof::alias_value(this->get_alias_base<first_base>(xs...), xs...);
110     }
111 
112     template<class... Xs>
secondboost::hof::detail::compressed_pair113     constexpr const Second& second(Xs&&... xs) const noexcept
114     {
115         return boost::hof::alias_value(this->get_alias_base<second_base>(xs...), xs...);
116     }
117 
118 };
119 
120 template<class T, class U>
make_compressed_pair(T x,U y)121 constexpr compressed_pair<T, U> make_compressed_pair(T x, U y)
122 noexcept(BOOST_HOF_IS_NOTHROW_MOVE_CONSTRUCTIBLE(T) && BOOST_HOF_IS_NOTHROW_MOVE_CONSTRUCTIBLE(U))
123 {
124     return {static_cast<T&&>(x), static_cast<U&&>(y)};
125 }
126 
127 
128 }}} // namespace boost::hof
129 
130 #endif
131