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