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 
28         forward_ast() : p_(new T) {}
29 
30         forward_ast(forward_ast const& operand)
31             : p_(new T(operand.get())) {}
position_cache(iterator_type first,iterator_type last)32 
33         forward_ast(forward_ast&& operand) BOOST_NOEXCEPT
34             : p_(operand.p_)
35         {
36             operand.p_ = 0;
37         }
38 
position_of(position_tagged const & ast) const39         forward_ast(T const& operand)
40             : p_(new T(operand)) {}
41 
42         forward_ast(T&& operand)
43             : p_(new T(std::move(operand))) {}
44 
45         ~forward_ast()
46         {
47             boost::checked_delete(p_);
48         }
49 
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;
position_of(AST const &) const54         }
55 
56         void swap(forward_ast& operand) BOOST_NOEXCEPT
57         {
58             T* temp = operand.p_;
59             operand.p_ = p_;
60             p_ = temp;
61         }
annotate(AST &,iterator_type,iterator_type,mpl::false_)62 
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         }
annotate(position_tagged & ast,iterator_type first,iterator_type last,mpl::true_)68 
69         forward_ast& operator=(forward_ast&& rhs) BOOST_NOEXCEPT
70         {
71             swap(rhs);
72             return *this;
73         }
74 
75         forward_ast& operator=(T&& rhs) BOOST_NOEXCEPT_IF(std::is_nothrow_move_assignable<T>::value)
76         {
annotate(AST & ast,iterator_type first,iterator_type last)77             get() = std::move(rhs);
78             return *this;
79         }
80 
81         T& get() BOOST_NOEXCEPT { return *get_pointer(); }
82         const T& get() const BOOST_NOEXCEPT { return *get_pointer(); }
get_positions() const83 
84         T* get_pointer() BOOST_NOEXCEPT { return p_; }
85         const T* get_pointer() const BOOST_NOEXCEPT { return p_; }
86 
87         operator T const&() const BOOST_NOEXCEPT { return this->get(); }
first() const88         operator T&() BOOST_NOEXCEPT { return this->get(); }
last() const89 
90     private:
91 
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>
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 
143         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 
153         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 
159         variant(variant&& rhs) BOOST_NOEXCEPT_IF(std::is_nothrow_move_constructible<variant_type>::value)
160             : var(std::move(rhs.var)) {}
161 
162         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 
168         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>>
175         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>>
182         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>
189         typename F::result_type apply_visitor(F const& v)
190         {
191             return var.apply_visitor(v);
192         }
193 
194         template <typename F>
195         typename F::result_type apply_visitor(F const& v) const
196         {
197             return var.apply_visitor(v);
198         }
199 
200         template <typename F>
201         typename F::result_type apply_visitor(F& v)
202         {
203             return var.apply_visitor(v);
204         }
205 
206         template <typename F>
207         typename F::result_type apply_visitor(F& v) const
208         {
209             return var.apply_visitor(v);
210         }
211 
212         variant_type const& get() const BOOST_NOEXCEPT
213         {
214             return var;
215         }
216 
217         variant_type& get() BOOST_NOEXCEPT
218         {
219             return var;
220         }
221 
222         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&
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&
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*
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*
259     get(boost::spirit::x3::variant<Types...>* x) BOOST_NOEXCEPT
260     {
261         return boost::get<T>(&x->get());
262     }
263 }
264 
265 #endif
266