move_to.hpp 7.5 KB

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