Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / spirit / home / x3 / support / traits / move_to.hpp
1 /*=============================================================================
2     Copyright (c) 2001-2014 Joel de Guzman
3     Copyright (c) 2013 Agustin Berge
4     http://spirit.sourceforge.net/
5
6     Distributed under the Boost Software License, Version 1.0. (See accompanying
7     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 #if !defined(BOOST_SPIRIT_X3_MOVE_TO_JAN_17_2013_0859PM)
10 #define BOOST_SPIRIT_X3_MOVE_TO_JAN_17_2013_0859PM
11
12 #include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
13 #include <boost/spirit/home/x3/support/traits/tuple_traits.hpp>
14 #include <boost/spirit/home/x3/support/traits/variant_has_substitute.hpp>
15 #include <boost/fusion/include/is_sequence.hpp>
16 #include <boost/fusion/include/front.hpp>
17 #include <boost/fusion/include/move.hpp>
18 #include <boost/fusion/include/is_sequence.hpp>
19 #include <utility>
20
21 namespace boost { namespace spirit { namespace x3 { namespace traits
22 {
23     template <typename Source, typename Dest>
24     inline void move_to(Source&& src, Dest& dest);
25
26     template <typename T>
27     inline void move_to(T& src, T& dest);
28
29     template <typename T>
30     inline void move_to(T const& src, T& dest);
31
32     template <typename T>
33     inline void move_to(T&& src, T& dest);
34
35     template <typename Iterator, typename Dest>
36     inline void move_to(Iterator first, Iterator last, Dest& dest);
37
38     template <typename Dest>
39     inline void move_to(unused_type, Dest&) {}
40
41     template <typename Source>
42     inline void move_to(Source&, unused_type) {}
43
44     inline void move_to(unused_type, unused_type) {}
45
46     template <typename Iterator>
47     inline void
48     move_to(Iterator, Iterator, unused_type) {}
49
50     namespace detail
51     {
52         template <typename Source, typename Dest>
53         inline void
54         move_to(Source&&, Dest&, unused_attribute) {}
55         
56         template <typename Source, typename Dest>
57         inline void
58         move_to_plain(Source&& src, Dest& dest, mpl::false_) // src is not a single-element tuple
59         {
60             dest = std::move(src);
61         }
62         
63         template <typename Source, typename Dest>
64         inline void
65         move_to_plain(Source&& src, Dest& dest, mpl::true_) // src is a single-element tuple
66         {
67             dest = std::move(fusion::front(src));
68         }
69
70         template <typename Source, typename Dest>
71         inline void
72         move_to(Source&& src, Dest& dest, plain_attribute)
73         {
74             typename mpl::and_<
75                 fusion::traits::is_sequence<Source>,
76                 is_size_one_sequence<Source> >
77             is_single_element_sequence;
78         
79             move_to_plain(std::forward<Source>(src), dest, is_single_element_sequence);
80         }
81
82         template <typename Source, typename Dest>
83         inline typename enable_if<is_container<Source>>::type
84         move_to(Source&& src, Dest& dest, container_attribute)
85         {
86             traits::move_to(src.begin(), src.end(), dest);
87         }
88
89         template <typename Source, typename Dest>
90         inline typename enable_if<
91             mpl::and_<
92                 is_same_size_sequence<Dest, Source>,
93                 mpl::not_<is_size_one_sequence<Dest> > >
94         >::type
95         move_to(Source&& src, Dest& dest, tuple_attribute)
96         {
97             fusion::move(std::forward<Source>(src), dest);
98         }
99
100         template <typename Source, typename Dest>
101         inline typename enable_if<
102             is_size_one_sequence<Dest>
103         >::type
104         move_to(Source&& src, Dest& dest, tuple_attribute)
105         {
106             traits::move_to(std::forward<Source>(src), fusion::front(dest));
107         }
108
109         template <typename Source, typename Dest>
110         inline void
111         move_to(Source&& src, Dest& dest, variant_attribute, mpl::false_)
112         {
113             dest = std::move(src);
114         }
115         
116         template <typename Source, typename Dest>
117         inline void
118         move_to_variant_from_single_element_sequence(Source&& src, Dest& dest, mpl::false_)
119         {
120             // dest is a variant, src is a single element fusion sequence that the variant
121             // cannot directly hold. We'll try to unwrap the single element fusion sequence.
122             
123             // Make sure that the Dest variant can really hold Source
124             static_assert(variant_has_substitute<Dest, typename fusion::result_of::front<Source>::type>::value,
125                 "Error! The destination variant (Dest) cannot hold the source type (Source)");
126             
127             dest = std::move(fusion::front(src));
128         }
129         
130         template <typename Source, typename Dest>
131         inline void
132         move_to_variant_from_single_element_sequence(Source&& src, Dest& dest, mpl::true_)
133         {
134             // dest is a variant, src is a single element fusion sequence that the variant
135             // *can* directly hold.
136             dest = std::move(src);
137         }
138
139         template <typename Source, typename Dest>
140         inline void
141         move_to(Source&& src, Dest& dest, variant_attribute, mpl::true_)
142         {
143             move_to_variant_from_single_element_sequence(src, dest, variant_has_substitute<Dest, Source>());
144         }
145
146         template <typename Source, typename Dest>
147         inline void
148         move_to(Source&& src, Dest& dest, variant_attribute tag)
149         {
150             move_to(src, dest, tag, is_size_one_sequence<Source>());
151         }
152
153         template <typename Source, typename Dest>
154         inline void
155         move_to(Source&& src, Dest& dest, optional_attribute)
156         {
157             dest = std::move(src);
158         }
159
160         template <typename Iterator>
161         inline void
162         move_to(Iterator, Iterator, unused_type, unused_attribute) {}
163
164         template <typename Iterator, typename Dest>
165         inline void
166         move_to(Iterator first, Iterator last, Dest& dest, container_attribute)
167         {
168             if (is_empty(dest))
169                 dest = Dest(first, last);
170             else
171                 append(dest, first, last);
172         }
173
174         template <typename Iterator, typename Dest>
175         inline typename enable_if<
176             is_size_one_sequence<Dest>
177         >::type
178         move_to(Iterator first, Iterator last, Dest& dest, tuple_attribute)
179         {
180             traits::move_to(first, last, fusion::front(dest));
181         }
182         
183         template <typename Iterator>
184         inline void
185         move_to(Iterator first, Iterator last, boost::iterator_range<Iterator>& rng, range_attribute)
186         {
187             rng = {first, last};
188         }
189     }
190
191     template <typename Source, typename Dest>
192     inline void move_to(boost::optional<Source>&& src, Dest& dest)
193     {
194         if (src) detail::move_to(std::move(*src), dest
195           , typename attribute_category<Dest>::type());
196     }
197
198     template <typename Source, typename Dest>
199     inline void move_to(Source&& src, Dest& dest)
200     {
201         detail::move_to(std::move(src), dest
202           , typename attribute_category<Dest>::type());
203     }
204
205     template <typename T>
206     inline void move_to(T& src, T& dest)
207     {
208         if (boost::addressof(src) != boost::addressof(dest))
209             dest = std::move(src);
210     }
211
212     template <typename T>
213     inline void move_to(T const& src, T& dest)
214     {
215         if (boost::addressof(src) != boost::addressof(dest))
216             dest = std::move(src);
217     }
218
219     template <typename T>
220     inline void move_to(T&& src, T& dest)
221     {
222         if (boost::addressof(src) != boost::addressof(dest))
223             dest = std::move(src);
224     }
225
226     template <typename Iterator, typename Dest>
227     inline void move_to(Iterator first, Iterator last, Dest& dest)
228     {
229         // $$$ Use std::move_iterator when iterator is not a const-iterator $$$
230         detail::move_to(first, last, dest, typename attribute_category<Dest>::type());
231     }
232 }}}}
233
234 #endif