]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | //----------------------------------------------------------------------------- |
2 | // boost variant/polymorphic_get.hpp header file | |
3 | // See http://www.boost.org for updates, documentation, and revision history. | |
4 | //----------------------------------------------------------------------------- | |
5 | // | |
6 | // Copyright (c) 2013-2015 Antony Polukhin | |
7 | // | |
8 | // Distributed under the Boost Software License, Version 1.0. (See | |
9 | // accompanying file LICENSE_1_0.txt or copy at | |
10 | // http://www.boost.org/LICENSE_1_0.txt) | |
11 | ||
12 | #ifndef BOOST_VARIANT_POLYMORPHIC_GET_HPP | |
13 | #define BOOST_VARIANT_POLYMORPHIC_GET_HPP | |
14 | ||
15 | #include <exception> | |
16 | ||
17 | #include <boost/config.hpp> | |
18 | #include <boost/detail/workaround.hpp> | |
19 | #include <boost/static_assert.hpp> | |
20 | #include <boost/throw_exception.hpp> | |
21 | #include <boost/utility/addressof.hpp> | |
22 | #include <boost/variant/variant_fwd.hpp> | |
23 | #include <boost/variant/get.hpp> | |
24 | ||
25 | #include <boost/type_traits/add_reference.hpp> | |
26 | #include <boost/type_traits/add_pointer.hpp> | |
27 | #include <boost/type_traits/is_base_of.hpp> | |
28 | ||
29 | namespace boost { | |
30 | ||
31 | ////////////////////////////////////////////////////////////////////////// | |
32 | // class bad_polymorphic_get | |
33 | // | |
34 | // The exception thrown in the event of a failed get of a value. | |
35 | // | |
36 | class BOOST_SYMBOL_VISIBLE bad_polymorphic_get | |
37 | : public bad_get | |
38 | { | |
39 | public: // std::exception implementation | |
40 | ||
41 | virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW | |
42 | { | |
43 | return "boost::bad_polymorphic_get: " | |
44 | "failed value get using boost::polymorphic_get"; | |
45 | } | |
46 | ||
47 | }; | |
48 | ||
49 | ////////////////////////////////////////////////////////////////////////// | |
50 | // function template get<T> | |
51 | // | |
52 | // Retrieves content of given variant object if content is of type T. | |
53 | // Otherwise: pointer ver. returns 0; reference ver. throws bad_get. | |
54 | // | |
55 | ||
56 | namespace detail { namespace variant { | |
57 | ||
58 | ||
59 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
60 | // polymorphic metafunctions to detect index of a value | |
61 | // | |
62 | ||
63 | template <class Types, class T> | |
64 | struct element_polymorphic_iterator_impl : | |
65 | boost::mpl::find_if< | |
66 | Types, | |
67 | boost::mpl::or_< | |
68 | variant_element_functor<boost::mpl::_1, T>, | |
69 | variant_element_functor<boost::mpl::_1, typename boost::remove_cv<T>::type >, | |
70 | boost::is_base_of<T, boost::mpl::_1> | |
71 | > | |
72 | > | |
73 | {}; | |
74 | ||
75 | template <class Variant, class T> | |
76 | struct holds_element_polymorphic : | |
77 | boost::mpl::not_< | |
78 | boost::is_same< | |
79 | typename boost::mpl::end<typename Variant::types>::type, | |
80 | typename element_polymorphic_iterator_impl<typename Variant::types, typename boost::remove_reference<T>::type >::type | |
81 | > | |
82 | > | |
83 | {}; | |
84 | ||
85 | // (detail) class template get_polymorphic_visitor | |
86 | // | |
87 | // Generic static visitor that: if the value is of the specified | |
88 | // type or of a type derived from specified, returns a pointer | |
89 | // to the value it visits; else a null pointer. | |
90 | // | |
91 | template <typename Base> | |
92 | struct get_polymorphic_visitor | |
93 | { | |
94 | private: // private typedefs | |
95 | typedef get_polymorphic_visitor<Base> this_type; | |
96 | typedef typename add_pointer<Base>::type pointer; | |
97 | typedef typename add_reference<Base>::type reference; | |
98 | ||
99 | pointer get(reference operand, boost::true_type) const BOOST_NOEXCEPT | |
100 | { | |
101 | return boost::addressof(operand); | |
102 | } | |
103 | ||
104 | template <class T> | |
105 | pointer get(T&, boost::false_type) const BOOST_NOEXCEPT | |
106 | { | |
107 | return static_cast<pointer>(0); | |
108 | } | |
109 | ||
110 | public: // visitor interfaces | |
111 | typedef pointer result_type; | |
112 | ||
113 | template <typename U> | |
114 | pointer operator()(U& operand) const BOOST_NOEXCEPT | |
115 | { | |
116 | typedef boost::integral_constant< | |
117 | bool, | |
118 | boost::mpl::or_< | |
119 | boost::is_base_of<Base, U>, | |
120 | boost::is_same<Base, U>, | |
121 | boost::is_same<typename boost::remove_cv<Base>::type, U > | |
122 | >::value | |
123 | > tag_t; | |
124 | ||
125 | return this_type::get(operand, tag_t()); | |
126 | } | |
127 | }; | |
128 | ||
129 | }} // namespace detail::variant | |
130 | ||
131 | #ifndef BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE | |
132 | # if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0551)) | |
133 | # define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t) | |
134 | # else | |
135 | # define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t) \ | |
136 | , t* = 0 | |
137 | # endif | |
138 | #endif | |
139 | ||
140 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
141 | // polymorphic_relaxed_get | |
142 | // | |
143 | ||
144 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
145 | inline | |
146 | typename add_pointer<U>::type | |
147 | polymorphic_relaxed_get( | |
148 | boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand | |
149 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
150 | ) BOOST_NOEXCEPT | |
151 | { | |
152 | typedef typename add_pointer<U>::type U_ptr; | |
153 | if (!operand) return static_cast<U_ptr>(0); | |
154 | ||
155 | detail::variant::get_polymorphic_visitor<U> v; | |
156 | return operand->apply_visitor(v); | |
157 | } | |
158 | ||
159 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
160 | inline | |
161 | typename add_pointer<const U>::type | |
162 | polymorphic_relaxed_get( | |
163 | const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand | |
164 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
165 | ) BOOST_NOEXCEPT | |
166 | { | |
167 | typedef typename add_pointer<const U>::type U_ptr; | |
168 | if (!operand) return static_cast<U_ptr>(0); | |
169 | ||
170 | detail::variant::get_polymorphic_visitor<const U> v; | |
171 | return operand->apply_visitor(v); | |
172 | } | |
173 | ||
174 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
175 | inline | |
176 | typename add_reference<U>::type | |
177 | polymorphic_relaxed_get( | |
178 | boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand | |
179 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
180 | ) | |
181 | { | |
182 | typedef typename add_pointer<U>::type U_ptr; | |
183 | U_ptr result = polymorphic_relaxed_get<U>(&operand); | |
184 | ||
185 | if (!result) | |
186 | boost::throw_exception(bad_polymorphic_get()); | |
187 | return *result; | |
188 | } | |
189 | ||
190 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
191 | inline | |
192 | typename add_reference<const U>::type | |
193 | polymorphic_relaxed_get( | |
194 | const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand | |
195 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
196 | ) | |
197 | { | |
198 | typedef typename add_pointer<const U>::type U_ptr; | |
199 | U_ptr result = polymorphic_relaxed_get<const U>(&operand); | |
200 | ||
201 | if (!result) | |
202 | boost::throw_exception(bad_polymorphic_get()); | |
203 | return *result; | |
204 | } | |
205 | ||
206 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
207 | // polymorphic_strict_get | |
208 | // | |
209 | ||
210 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
211 | inline | |
212 | typename add_pointer<U>::type | |
213 | polymorphic_strict_get( | |
214 | boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand | |
215 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
216 | ) BOOST_NOEXCEPT | |
217 | { | |
218 | BOOST_STATIC_ASSERT_MSG( | |
219 | (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value), | |
220 | "boost::variant does not contain specified type U, " | |
221 | "call to boost::polymorphic_get<U>(boost::variant<T...>*) will always return NULL" | |
222 | ); | |
223 | ||
224 | return polymorphic_relaxed_get<U>(operand); | |
225 | } | |
226 | ||
227 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
228 | inline | |
229 | typename add_pointer<const U>::type | |
230 | polymorphic_strict_get( | |
231 | const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand | |
232 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
233 | ) BOOST_NOEXCEPT | |
234 | { | |
235 | BOOST_STATIC_ASSERT_MSG( | |
236 | (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value), | |
237 | "boost::variant does not contain specified type U, " | |
238 | "call to boost::polymorphic_get<U>(const boost::variant<T...>*) will always return NULL" | |
239 | ); | |
240 | ||
241 | return polymorphic_relaxed_get<U>(operand); | |
242 | } | |
243 | ||
244 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
245 | inline | |
246 | typename add_reference<U>::type | |
247 | polymorphic_strict_get( | |
248 | boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand | |
249 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
250 | ) | |
251 | { | |
252 | BOOST_STATIC_ASSERT_MSG( | |
253 | (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value), | |
254 | "boost::variant does not contain specified type U, " | |
255 | "call to boost::polymorphic_get<U>(boost::variant<T...>&) will always throw boost::bad_polymorphic_get exception" | |
256 | ); | |
257 | ||
258 | return polymorphic_relaxed_get<U>(operand); | |
259 | } | |
260 | ||
261 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
262 | inline | |
263 | typename add_reference<const U>::type | |
264 | polymorphic_strict_get( | |
265 | const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand | |
266 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
267 | ) | |
268 | { | |
269 | BOOST_STATIC_ASSERT_MSG( | |
270 | (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value), | |
271 | "boost::variant does not contain specified type U, " | |
272 | "call to boost::polymorphic_get<U>(const boost::variant<T...>&) will always throw boost::bad_polymorphic_get exception" | |
273 | ); | |
274 | ||
275 | return polymorphic_relaxed_get<U>(operand); | |
276 | } | |
277 | ||
278 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
279 | // polymorphic_get<U>(variant) methods | |
280 | // | |
281 | ||
282 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
283 | inline | |
284 | typename add_pointer<U>::type | |
285 | polymorphic_get( | |
286 | boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand | |
287 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
288 | ) BOOST_NOEXCEPT | |
289 | { | |
290 | #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT | |
291 | return polymorphic_relaxed_get<U>(operand); | |
292 | #else | |
293 | return polymorphic_strict_get<U>(operand); | |
294 | #endif | |
295 | ||
296 | } | |
297 | ||
298 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
299 | inline | |
300 | typename add_pointer<const U>::type | |
301 | polymorphic_get( | |
302 | const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand | |
303 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
304 | ) BOOST_NOEXCEPT | |
305 | { | |
306 | #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT | |
307 | return polymorphic_relaxed_get<U>(operand); | |
308 | #else | |
309 | return polymorphic_strict_get<U>(operand); | |
310 | #endif | |
311 | } | |
312 | ||
313 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
314 | inline | |
315 | typename add_reference<U>::type | |
316 | polymorphic_get( | |
317 | boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand | |
318 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
319 | ) | |
320 | { | |
321 | #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT | |
322 | return polymorphic_relaxed_get<U>(operand); | |
323 | #else | |
324 | return polymorphic_strict_get<U>(operand); | |
325 | #endif | |
326 | } | |
327 | ||
328 | template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) > | |
329 | inline | |
330 | typename add_reference<const U>::type | |
331 | polymorphic_get( | |
332 | const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand | |
333 | BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) | |
334 | ) | |
335 | { | |
336 | #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT | |
337 | return polymorphic_relaxed_get<U>(operand); | |
338 | #else | |
339 | return polymorphic_strict_get<U>(operand); | |
340 | #endif | |
341 | } | |
342 | } // namespace boost | |
343 | ||
344 | #endif // BOOST_VARIANT_POLYMORPHIC_GET_HPP |