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