1 /*=============================================================================
2     Copyright (c) 2001-2014 Joel de Guzman
3 
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 #if !defined(BOOST_SPIRIT_X3_VARIANT_AUGUST_6_2011_0859AM)
8 #define BOOST_SPIRIT_X3_VARIANT_AUGUST_6_2011_0859AM
9 
10 #include <boost/config.hpp>
11 #include <boost/variant.hpp>
12 #include <boost/mpl/list.hpp>
13 #include <utility>
14 #include <type_traits>
15 
16 ///////////////////////////////////////////////////////////////////////////////
17 namespace boost { namespace spirit { namespace x3
18 {
19     template <typename T>
20     class forward_ast
21     {
22     public:
23 
24         typedef T type;
25 
26     public:
27 
forward_ast()28         forward_ast() : p_(new T) {}
29 
forward_ast(forward_ast const & operand)30         forward_ast(forward_ast const& operand)
31             : p_(new T(operand.get())) {}
32 
forward_ast(forward_ast && operand)33         forward_ast(forward_ast&& operand) BOOST_NOEXCEPT
34             : p_(operand.p_)
35         {
36             operand.p_ = 0;
37         }
38 
forward_ast(T const & operand)39         forward_ast(T const& operand)
40             : p_(new T(operand)) {}
41 
forward_ast(T && operand)42         forward_ast(T&& operand)
43             : p_(new T(std::move(operand))) {}
44 
~forward_ast()45         ~forward_ast()
46         {
47             boost::checked_delete(p_);
48         }
49 
operator =(forward_ast const & rhs)50         forward_ast& operator=(forward_ast const& rhs) BOOST_NOEXCEPT_IF(std::is_nothrow_copy_assignable<T>::value)
51         {
52             assign(rhs.get());
53             return *this;
54         }
55 
swap(forward_ast & operand)56         void swap(forward_ast& operand) BOOST_NOEXCEPT
57         {
58             T* temp = operand.p_;
59             operand.p_ = p_;
60             p_ = temp;
61         }
62 
operator =(T const & rhs)63         forward_ast& operator=(T const& rhs) BOOST_NOEXCEPT_IF(std::is_nothrow_copy_assignable<T>::value)
64         {
65             assign(rhs);
66             return *this;
67         }
68 
operator =(forward_ast && rhs)69         forward_ast& operator=(forward_ast&& rhs) BOOST_NOEXCEPT
70         {
71             swap(rhs);
72             return *this;
73         }
74 
operator =(T && rhs)75         forward_ast& operator=(T&& rhs) BOOST_NOEXCEPT_IF(std::is_nothrow_move_assignable<T>::value)
76         {
77             get() = std::move(rhs);
78             return *this;
79         }
80 
get()81         T& get() BOOST_NOEXCEPT { return *get_pointer(); }
get() const82         const T& get() const BOOST_NOEXCEPT { return *get_pointer(); }
83 
get_pointer()84         T* get_pointer() BOOST_NOEXCEPT { return p_; }
get_pointer() const85         const T* get_pointer() const BOOST_NOEXCEPT { return p_; }
86 
operator T const&() const87         operator T const&() const BOOST_NOEXCEPT { return this->get(); }
operator T&()88         operator T&() BOOST_NOEXCEPT { return this->get(); }
89 
90     private:
91 
assign(const T & rhs)92         void assign(const T& rhs) BOOST_NOEXCEPT_IF(std::is_nothrow_copy_assignable<T>::value)
93         {
94             this->get() = rhs;
95         }
96 
97         T* p_;
98     };
99 
100     // function template swap
101     //
102     // Swaps two forward_ast<T> objects of the same type T.
103     //
104     template <typename T>
swap(forward_ast<T> & lhs,forward_ast<T> & rhs)105     inline void swap(forward_ast<T>& lhs, forward_ast<T>& rhs) BOOST_NOEXCEPT
106     {
107         lhs.swap(rhs);
108     }
109 
110     namespace detail
111     {
112         template <typename T>
113         struct remove_forward : mpl::identity<T>
114         {};
115 
116         template <typename T>
117         struct remove_forward<forward_ast<T>> : mpl::identity<T>
118         {};
119     }
120 
121 #if defined(BOOST_MSVC)
122 # pragma warning(push)
123 # pragma warning(disable: 4521) // multiple copy constructors specified
124 #endif
125     template <typename ...Types>
126     struct variant
127     {
128         // tell spirit that this is an adapted variant
129         struct adapted_variant_tag;
130 
131         using variant_type = boost::variant<Types...>;
132         using types        = mpl::list<typename detail::remove_forward<Types>::type...>;
133         using base_type    = variant; // The current instantiation
134 
135         template<typename T>
136         using non_self_t // used only for SFINAE checks below
137             = std::enable_if_t<!(std::is_base_of<base_type
138                                                 ,std::remove_reference_t<T>
139                                                 >
140                                                 ::value)
141                               >;
142 
BOOST_NOEXCEPT_IFboost::spirit::x3::variant143         variant() BOOST_NOEXCEPT_IF(std::is_nothrow_default_constructible<variant_type>::value) : var() {}
144 
145         template <typename T, class = non_self_t<T>>
146         explicit variant(T const& rhs) BOOST_NOEXCEPT_IF((std::is_nothrow_constructible<variant_type, T const&>::value))
147             : var(rhs) {}
148 
149         template <typename T, class = non_self_t<T>>
150         explicit variant(T&& rhs) BOOST_NOEXCEPT_IF((std::is_nothrow_constructible<variant_type, T&&>::value))
151             : var(std::forward<T>(rhs)) {}
152 
BOOST_NOEXCEPT_IFboost::spirit::x3::variant153         variant(variant const& rhs) BOOST_NOEXCEPT_IF(std::is_nothrow_copy_constructible<variant_type>::value)
154             : var(rhs.var) {}
155 
156         variant(variant& rhs) BOOST_NOEXCEPT_IF((std::is_nothrow_constructible<variant_type, variant_type&>::value))
157             : var(rhs.var) {}
158 
BOOST_NOEXCEPT_IFboost::spirit::x3::variant159         variant(variant&& rhs) BOOST_NOEXCEPT_IF(std::is_nothrow_move_constructible<variant_type>::value)
160             : var(std::move(rhs.var)) {}
161 
operator =boost::spirit::x3::variant162         variant& operator=(variant const& rhs) BOOST_NOEXCEPT_IF(std::is_nothrow_copy_assignable<variant_type>::value)
163         {
164             var = rhs.get();
165             return *this;
166         }
167 
operator =boost::spirit::x3::variant168         variant& operator=(variant&& rhs) BOOST_NOEXCEPT_IF(std::is_nothrow_move_assignable<variant_type>::value)
169         {
170             var = std::move(rhs.get());
171             return *this;
172         }
173 
174         template <typename T, class = non_self_t<T>>
operator =boost::spirit::x3::variant175         variant& operator=(T const& rhs) BOOST_NOEXCEPT_IF((std::is_nothrow_assignable<variant_type, T const&>::value))
176         {
177             var = rhs;
178             return *this;
179         }
180 
181         template <typename T, class = non_self_t<T>>
operator =boost::spirit::x3::variant182         variant& operator=(T&& rhs) BOOST_NOEXCEPT_IF((std::is_nothrow_assignable<variant_type, T&&>::value))
183         {
184             var = std::forward<T>(rhs);
185             return *this;
186         }
187 
188         template <typename F>
apply_visitorboost::spirit::x3::variant189         typename F::result_type apply_visitor(F const& v)
190         {
191             return var.apply_visitor(v);
192         }
193 
194         template <typename F>
apply_visitorboost::spirit::x3::variant195         typename F::result_type apply_visitor(F const& v) const
196         {
197             return var.apply_visitor(v);
198         }
199 
200         template <typename F>
apply_visitorboost::spirit::x3::variant201         typename F::result_type apply_visitor(F& v)
202         {
203             return var.apply_visitor(v);
204         }
205 
206         template <typename F>
apply_visitorboost::spirit::x3::variant207         typename F::result_type apply_visitor(F& v) const
208         {
209             return var.apply_visitor(v);
210         }
211 
getboost::spirit::x3::variant212         variant_type const& get() const BOOST_NOEXCEPT
213         {
214             return var;
215         }
216 
getboost::spirit::x3::variant217         variant_type& get() BOOST_NOEXCEPT
218         {
219             return var;
220         }
221 
swapboost::spirit::x3::variant222         void swap(variant& rhs) BOOST_NOEXCEPT
223         {
224             var.swap(rhs.var);
225         }
226 
227         variant_type var;
228     };
229 #if defined(BOOST_MSVC)
230 # pragma warning(pop)
231 #endif
232 }}}
233 
234 namespace boost
235 {
236     template <typename T, typename ...Types>
237     inline T const&
get(boost::spirit::x3::variant<Types...> const & x)238     get(boost::spirit::x3::variant<Types...> const& x) BOOST_NOEXCEPT
239     {
240         return boost::get<T>(x.get());
241     }
242 
243     template <typename T, typename ...Types>
244     inline T&
get(boost::spirit::x3::variant<Types...> & x)245     get(boost::spirit::x3::variant<Types...>& x) BOOST_NOEXCEPT
246     {
247         return boost::get<T>(x.get());
248     }
249 
250     template <typename T, typename ...Types>
251     inline T const*
get(boost::spirit::x3::variant<Types...> const * x)252     get(boost::spirit::x3::variant<Types...> const* x) BOOST_NOEXCEPT
253     {
254         return boost::get<T>(&x->get());
255     }
256 
257     template <typename T, typename ...Types>
258     inline T*
get(boost::spirit::x3::variant<Types...> * x)259     get(boost::spirit::x3::variant<Types...>* x) BOOST_NOEXCEPT
260     {
261         return boost::get<T>(&x->get());
262     }
263 }
264 
265 #endif
266