1 /*=============================================================================
2 Copyright (c) 2001-2014 Joel de Guzman
3 Copyright (c) 2013 Agustin Berge
4 http://spirit.sourceforge.net/
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
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/size.hpp>
18 #include <boost/fusion/include/move.hpp>
19 #include <boost/fusion/include/is_sequence.hpp>
22 namespace boost { namespace spirit { namespace x3 { namespace traits
24 template <typename Source, typename Dest>
25 inline void move_to(Source&& src, Dest& dest);
28 inline void move_to(T& src, T& dest);
31 inline void move_to(T const& src, T& dest);
34 inline void move_to(T&& src, T& dest);
36 template <typename Iterator, typename Dest>
37 inline void move_to(Iterator first, Iterator last, Dest& dest);
39 template <typename Dest>
40 inline void move_to(unused_type, Dest&) {}
42 template <typename Source>
43 inline void move_to(Source&, unused_type) {}
45 inline void move_to(unused_type, unused_type) {}
47 template <typename Iterator>
49 move_to(Iterator, Iterator, unused_type) {}
53 template <typename Source, typename Dest>
55 move_to(Source&&, Dest&, unused_attribute) {}
57 template <typename Source, typename Dest>
59 move_to_plain(Source&& src, Dest& dest, mpl::false_) // src is not a single-element tuple
61 dest = std::move(src);
64 template <typename Source, typename Dest>
66 move_to_plain(Source&& src, Dest& dest, mpl::true_) // src is a single-element tuple
68 dest = std::move(fusion::front(src));
71 template <typename Source, typename Dest>
73 move_to(Source&& src, Dest& dest, plain_attribute)
76 fusion::traits::is_sequence<Source>,
77 is_size_one_sequence<Source> >
78 is_single_element_sequence;
80 move_to_plain(std::forward<Source>(src), dest, is_single_element_sequence);
83 template <typename Source, typename Dest>
84 inline typename enable_if<is_container<Source>>::type
85 move_to(Source&& src, Dest& dest, container_attribute)
87 traits::move_to(src.begin(), src.end(), dest);
90 template <typename Source, typename Dest>
91 inline typename enable_if<
93 is_same_size_sequence<Dest, Source>,
94 mpl::not_<is_size_one_sequence<Dest> > >
96 move_to(Source&& src, Dest& dest, tuple_attribute)
98 fusion::move(std::forward<Source>(src), dest);
101 template <typename Source, typename Dest>
102 inline typename enable_if<
103 is_size_one_sequence<Dest>
105 move_to(Source&& src, Dest& dest, tuple_attribute)
107 traits::move_to(std::forward<Source>(src), fusion::front(dest));
110 template <typename Source, typename Dest>
112 move_to(Source&& src, Dest& dest, variant_attribute, mpl::false_)
114 dest = std::move(src);
117 template <typename Source, typename Dest>
119 move_to_variant_from_single_element_sequence(Source&& src, Dest& dest, mpl::false_)
121 // dest is a variant, src is a single element fusion sequence that the variant
122 // cannot directly hold. We'll try to unwrap the single element fusion sequence.
124 // Make sure that the Dest variant can really hold Source
125 static_assert(variant_has_substitute<Dest, typename fusion::result_of::front<Source>::type>::value,
126 "Error! The destination variant (Dest) cannot hold the source type (Source)");
128 dest = std::move(fusion::front(src));
131 template <typename Source, typename Dest>
133 move_to_variant_from_single_element_sequence(Source&& src, Dest& dest, mpl::true_)
135 // dest is a variant, src is a single element fusion sequence that the variant
136 // *can* directly hold.
137 dest = std::move(src);
140 template <typename Source, typename Dest>
142 move_to(Source&& src, Dest& dest, variant_attribute, mpl::true_)
144 move_to_variant_from_single_element_sequence(src, dest, variant_has_substitute<Dest, Source>());
147 template <typename Source, typename Dest>
149 move_to(Source&& src, Dest& dest, variant_attribute tag)
151 move_to(src, dest, tag, is_size_one_sequence<Source>());
154 template <typename Source, typename Dest>
156 move_to(Source&& src, Dest& dest, optional_attribute)
158 dest = std::move(src);
161 template <typename Iterator>
163 move_to(Iterator, Iterator, unused_type, unused_attribute) {}
165 template <typename Iterator, typename Dest>
167 move_to(Iterator first, Iterator last, Dest& dest, container_attribute)
170 dest = Dest(first, last);
172 append(dest, first, last);
175 template <typename Iterator, typename Dest>
176 inline typename enable_if<
177 is_size_one_sequence<Dest>
179 move_to(Iterator first, Iterator last, Dest& dest, tuple_attribute)
181 traits::move_to(first, last, fusion::front(dest));
184 template <typename Iterator>
186 move_to(Iterator first, Iterator last, boost::iterator_range<Iterator>& rng, range_attribute)
192 template <typename Source, typename Dest>
193 inline void move_to(Source&& src, Dest& dest)
195 detail::move_to(std::move(src), dest
196 , typename attribute_category<Dest>::type());
199 template <typename T>
200 inline void move_to(T& src, T& dest)
202 if (boost::addressof(src) != boost::addressof(dest))
203 dest = std::move(src);
206 template <typename T>
207 inline void move_to(T const& src, T& dest)
209 if (boost::addressof(src) != boost::addressof(dest))
210 dest = std::move(src);
213 template <typename T>
214 inline void move_to(T&& src, T& dest)
216 if (boost::addressof(src) != boost::addressof(dest))
217 dest = std::move(src);
220 template <typename Iterator, typename Dest>
221 inline void move_to(Iterator first, Iterator last, Dest& dest)
223 // $$$ Use std::move_iterator when iterator is not a const-iterator $$$
224 detail::move_to(first, last, dest, typename attribute_category<Dest>::type());