1 /*=============================================================================
2     Copyright (c) 2015 Paul Fultz II
3     alias.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_ALIAS_H
9 #define BOOST_HOF_GUARD_ALIAS_H
10 
11 #include <boost/hof/returns.hpp>
12 #include <boost/hof/detail/delegate.hpp>
13 #include <boost/hof/detail/move.hpp>
14 #include <boost/hof/detail/holder.hpp>
15 #include <boost/hof/config.hpp>
16 
17 /// alias
18 /// =====
19 ///
20 /// Description
21 /// -----------
22 ///
23 /// The `alias` class wraps a type with a new type that can be tagged by the
24 /// user. This allows defining extra attributes about the type outside of the
25 /// type itself. There are three different ways the value can be stored: as a
26 /// member variable, by inheritance, or as a static member variable. The value
27 /// can be retrieved uniformily using the `alias_value` function.
28 ///
29 /// Synopsis
30 /// --------
31 ///
32 ///     // Alias the type using a member variable
33 ///     template<class T, class Tag=void>
34 ///     class alias;
35 ///
36 ///     // Alias the type by inheriting
37 ///     template<class T, class Tag=void>
38 ///     class alias_inherit;
39 ///
40 ///     // Alias the type using a static variable
41 ///     template<class T, class Tag=void>
42 ///     class alias_static;
43 ///
44 ///     // Retrieve tag from alias
45 ///     template<class Alias>
46 ///     class alias_tag;
47 ///
48 ///     // Check if type has a certian tag
49 ///     template<class T, class Tag>
50 ///     class has_tag;
51 ///
52 ///     // Retrieve value from alias
53 ///     template<class Alias>
54 ///     constexpr auto alias_value(Alias&&);
55 ///
56 
57 #ifdef _MSC_VER
58 #pragma warning(push)
59 #pragma warning(disable: 4579)
60 #endif
61 
62 namespace boost { namespace hof {
63 
64 template<class T>
65 struct alias_tag;
66 
67 template<class T, class Tag, class=void>
68 struct has_tag
69 : std::false_type
70 {};
71 
72 template<class T, class Tag>
73 struct has_tag<T, Tag, typename detail::holder<
74     typename alias_tag<T>::type
75 >::type>
76 : std::is_same<typename alias_tag<T>::type, Tag>
77 {};
78 
79 namespace detail {
80 
81 template<class T>
lvalue(T & x)82 constexpr T& lvalue(T& x) noexcept
83 {
84     return x;
85 }
86 
87 template<class T>
lvalue(const T & x)88 constexpr const T& lvalue(const T& x) noexcept
89 {
90     return x;
91 }
92 
93 }
94 
95 #define BOOST_HOF_UNARY_PERFECT_FOREACH(m) \
96     m(const&, boost::hof::detail::lvalue) \
97     m(&, boost::hof::detail::lvalue) \
98     m(&&, boost::hof::move) \
99 
100 template<class T, class Tag=void>
101 struct alias
102 {
103     T value;
104     BOOST_HOF_DELEGATE_CONSTRUCTOR(alias, T, value)
105 };
106 
107 #define BOOST_HOF_DETAIL_ALIAS_GET_VALUE(ref, move) \
108 template<class Tag, class T, class... Ts> \
109 constexpr auto alias_value(alias<T, Tag> ref a, Ts&&...) BOOST_HOF_RETURNS(move(a.value))
110 BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_ALIAS_GET_VALUE)
111 
112 template<class T, class Tag>
113 struct alias_tag<alias<T, Tag>>
114 { typedef Tag type; };
115 
116 
117 template<class T, class Tag=void>
118 struct alias_inherit
119 #if (defined(__GNUC__) && !defined (__clang__))
120 : std::conditional<(std::is_class<T>::value), T, alias<T>>::type
121 #else
122 : T
123 #endif
124 {
125     BOOST_HOF_INHERIT_CONSTRUCTOR(alias_inherit, T)
126 };
127 
128 #define BOOST_HOF_DETAIL_ALIAS_INHERIT_GET_VALUE(ref, move) \
129 template<class Tag, class T, class... Ts, class=typename std::enable_if<(BOOST_HOF_IS_CLASS(T))>::type> \
130 constexpr T ref alias_value(alias_inherit<T, Tag> ref a, Ts&&...) BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(move(a)) \
131 { \
132     return move(a); \
133 }
134 BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_ALIAS_INHERIT_GET_VALUE)
135 
136 template<class T, class Tag>
137 struct alias_tag<alias_inherit<T, Tag>>
138 { typedef Tag type; };
139 
140 namespace detail {
141 
142 template<class T, class Tag>
143 struct alias_static_storage
144 {
145 #ifdef _MSC_VER
146     // Since we disable the error for 4579 on MSVC, which leaves the static
147     // member unitialized at runtime, it is, therefore, only safe to use this
148     // class on types that are empty with constructors that have no possible
149     // side effects.
150     static_assert(BOOST_HOF_IS_EMPTY(T) &&
151         BOOST_HOF_IS_LITERAL(T) &&
152         BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(T), "In-class initialization is not yet implemented on MSVC");
153 #endif
154     static constexpr T value = T();
155 };
156 
157 template<class T, class Tag>
158 constexpr T alias_static_storage<T, Tag>::value;
159 
160 }
161 
162 template<class T, class Tag=void>
163 struct alias_static
164 {
165     template<class... Ts, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, Ts...)>
alias_staticboost::hof::alias_static166     constexpr alias_static(Ts&&...) noexcept
167     {}
168 };
169 
170 template<class Tag, class T, class... Ts>
alias_value(const alias_static<T,Tag> &,Ts &&...)171 constexpr const T& alias_value(const alias_static<T, Tag>&, Ts&&...) noexcept
172 {
173     return detail::alias_static_storage<T, Tag>::value;
174 }
175 
176 template<class T, class Tag>
177 struct alias_tag<alias_static<T, Tag>>
178 { typedef Tag type; };
179 
180 namespace detail {
181 
182 template<class T, class Tag>
183 struct alias_try_inherit
184 : std::conditional<(BOOST_HOF_IS_CLASS(T) && !BOOST_HOF_IS_FINAL(T) && !BOOST_HOF_IS_POLYMORPHIC(T)),
185     alias_inherit<T, Tag>,
186     alias<T, Tag>
187 >
188 {};
189 
190 #if BOOST_HOF_HAS_EBO
191 template<class T, class Tag>
192 struct alias_empty
193 : std::conditional<(BOOST_HOF_IS_EMPTY(T)),
194     typename alias_try_inherit<T, Tag>::type,
195     alias<T, Tag>
196 >
197 {};
198 #else
199 template<class T, class Tag>
200 struct alias_empty
201 : std::conditional<
202         BOOST_HOF_IS_EMPTY(T) &&
203         BOOST_HOF_IS_LITERAL(T) &&
204         BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(T),
205     alias_static<T, Tag>,
206     alias<T, Tag>
207 >
208 {};
209 #endif
210 
211 }
212 
213 }} // namespace boost::hof
214 
215 #ifdef _MSC_VER
216 #pragma warning(pop)
217 #endif
218 
219 #endif
220