extract_from.hpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // Copyright (c) 2001-2011 Hartmut Kaiser
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #if !defined(BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM)
  6. #define BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM
  7. #if defined(_MSC_VER)
  8. #pragma once
  9. #endif
  10. #include <boost/spirit/include/phoenix_core.hpp>
  11. #include <boost/spirit/home/support/unused.hpp>
  12. #include <boost/spirit/home/support/attributes_fwd.hpp>
  13. #include <boost/spirit/home/karma/detail/attributes.hpp>
  14. #include <boost/spirit/home/support/container.hpp>
  15. #include <boost/ref.hpp>
  16. #include <boost/optional.hpp>
  17. ///////////////////////////////////////////////////////////////////////////////
  18. namespace boost { namespace spirit { namespace traits
  19. {
  20. ///////////////////////////////////////////////////////////////////////////
  21. // This file contains attribute extraction utilities. The utilities
  22. // provided also accept spirit's unused_type; all no-ops. Compiler
  23. // optimization will easily strip these away.
  24. ///////////////////////////////////////////////////////////////////////////
  25. namespace detail
  26. {
  27. ///////////////////////////////////////////////////////////////////////
  28. // extract first and second element of a fusion sequence
  29. template <typename T>
  30. struct add_const_ref
  31. : add_reference<typename add_const<T>::type>
  32. {};
  33. template <typename T, int N>
  34. struct value_at_c
  35. : add_const_ref<typename fusion::result_of::value_at_c<T, N>::type>
  36. {};
  37. }
  38. // This is the default case: the plain attribute values
  39. template <typename Attribute, typename Exposed, typename Enable/*= void*/>
  40. struct extract_from_attribute
  41. {
  42. typedef typename traits::one_element_sequence<Attribute>::type
  43. is_one_element_sequence;
  44. typedef typename mpl::eval_if<
  45. is_one_element_sequence
  46. , detail::value_at_c<Attribute, 0>
  47. , mpl::identity<Attribute const&>
  48. >::type type;
  49. template <typename Context>
  50. static type call(Attribute const& attr, Context&, mpl::false_)
  51. {
  52. return attr;
  53. }
  54. // This handles the case where the attribute is a single element fusion
  55. // sequence. We silently extract the only element and treat it as the
  56. // attribute to generate output from.
  57. template <typename Context>
  58. static type call(Attribute const& attr, Context& ctx, mpl::true_)
  59. {
  60. return extract_from<Exposed>(fusion::at_c<0>(attr), ctx);
  61. }
  62. template <typename Context>
  63. static type call(Attribute const& attr, Context& ctx)
  64. {
  65. return call(attr, ctx, is_one_element_sequence());
  66. }
  67. };
  68. // This handles optional attributes.
  69. template <typename Attribute, typename Exposed>
  70. struct extract_from_attribute<boost::optional<Attribute>, Exposed>
  71. {
  72. typedef Attribute const& type;
  73. template <typename Context>
  74. static type call(boost::optional<Attribute> const& attr, Context& ctx)
  75. {
  76. return extract_from<Exposed>(boost::get<Attribute>(attr), ctx);
  77. }
  78. };
  79. template <typename Attribute, typename Exposed>
  80. struct extract_from_attribute<boost::optional<Attribute const>, Exposed>
  81. {
  82. typedef Attribute const& type;
  83. template <typename Context>
  84. static type call(boost::optional<Attribute const> const& attr, Context& ctx)
  85. {
  86. return extract_from<Exposed>(boost::get<Attribute const>(attr), ctx);
  87. }
  88. };
  89. // This handles attributes wrapped inside a boost::ref().
  90. template <typename Attribute, typename Exposed>
  91. struct extract_from_attribute<reference_wrapper<Attribute>, Exposed>
  92. {
  93. typedef Attribute const& type;
  94. template <typename Context>
  95. static type call(reference_wrapper<Attribute> const& attr, Context& ctx)
  96. {
  97. return extract_from<Exposed>(attr.get(), ctx);
  98. }
  99. };
  100. ///////////////////////////////////////////////////////////////////////////
  101. template <typename Attribute, typename Exposed, typename Enable>
  102. struct extract_from_container
  103. {
  104. typedef typename traits::container_value<Attribute const>::type
  105. value_type;
  106. typedef typename is_convertible<value_type, Exposed>::type
  107. is_convertible_to_value_type;
  108. typedef typename mpl::if_<
  109. mpl::or_<
  110. is_same<value_type, Exposed>, is_same<Attribute, Exposed> >
  111. , Exposed const&, Exposed
  112. >::type type;
  113. // handle case where container value type is convertible to result type
  114. // we simply return the front element of the container
  115. template <typename Context, typename Pred>
  116. static type call(Attribute const& attr, Context&, mpl::true_, Pred)
  117. {
  118. // return first element from container
  119. typedef typename traits::container_iterator<Attribute const>::type
  120. iterator_type;
  121. iterator_type it = traits::begin(attr);
  122. type result = *it;
  123. ++it;
  124. return result;
  125. }
  126. // handle strings
  127. template <typename Iterator>
  128. static void append_to_string(Exposed& result, Iterator begin, Iterator end)
  129. {
  130. for (Iterator i = begin; i != end; ++i)
  131. push_back(result, *i);
  132. }
  133. template <typename Context>
  134. static type call(Attribute const& attr, Context&, mpl::false_, mpl::true_)
  135. {
  136. typedef typename char_type_of<Attribute>::type char_type;
  137. Exposed result;
  138. append_to_string(result, traits::get_begin<char_type>(attr)
  139. , traits::get_end<char_type>(attr));
  140. return result;
  141. }
  142. // everything else gets just passed through
  143. template <typename Context>
  144. static type call(Attribute const& attr, Context&, mpl::false_, mpl::false_)
  145. {
  146. return type(attr);
  147. }
  148. template <typename Context>
  149. static type call(Attribute const& attr, Context& ctx)
  150. {
  151. typedef typename mpl::and_<
  152. traits::is_string<Exposed>, traits::is_string<Attribute>
  153. >::type handle_strings;
  154. // return first element from container
  155. return call(attr, ctx, is_convertible_to_value_type()
  156. , handle_strings());
  157. }
  158. };
  159. template <typename Attribute>
  160. struct extract_from_container<Attribute, Attribute>
  161. {
  162. typedef Attribute const& type;
  163. template <typename Context>
  164. static type call(Attribute const& attr, Context&)
  165. {
  166. return attr;
  167. }
  168. };
  169. ///////////////////////////////////////////////////////////////////////////
  170. namespace detail
  171. {
  172. // overload for non-container attributes
  173. template <typename Exposed, typename Attribute, typename Context>
  174. inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
  175. extract_from(Attribute const& attr, Context& ctx, mpl::false_)
  176. {
  177. return extract_from_attribute<Attribute, Exposed>::call(attr, ctx);
  178. }
  179. // overload for containers (but not for variants or optionals
  180. // holding containers)
  181. template <typename Exposed, typename Attribute, typename Context>
  182. inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
  183. extract_from(Attribute const& attr, Context& ctx, mpl::true_)
  184. {
  185. return extract_from_container<Attribute, Exposed>::call(attr, ctx);
  186. }
  187. }
  188. template <typename Exposed, typename Attribute, typename Context>
  189. inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
  190. extract_from(Attribute const& attr, Context& ctx
  191. #if (defined(__GNUC__) && (__GNUC__ < 4)) || \
  192. (defined(__APPLE__) && defined(__INTEL_COMPILER))
  193. , typename enable_if<traits::not_is_unused<Attribute> >::type*
  194. #endif
  195. )
  196. {
  197. typedef typename mpl::and_<
  198. traits::is_container<Attribute>
  199. , traits::not_is_variant<Attribute>
  200. , traits::not_is_optional<Attribute>
  201. >::type is_not_wrapped_container;
  202. return detail::extract_from<Exposed>(attr, ctx
  203. , is_not_wrapped_container());
  204. }
  205. template <typename Exposed, typename Context>
  206. inline unused_type extract_from(unused_type, Context&)
  207. {
  208. return unused;
  209. }
  210. }}}
  211. ///////////////////////////////////////////////////////////////////////////////
  212. namespace boost { namespace spirit { namespace result_of
  213. {
  214. template <typename Exposed, typename Attribute>
  215. struct extract_from
  216. : mpl::if_<
  217. mpl::and_<
  218. traits::is_container<Attribute>
  219. , traits::not_is_variant<Attribute>
  220. , traits::not_is_optional<Attribute> >
  221. , traits::extract_from_container<Attribute, Exposed>
  222. , traits::extract_from_attribute<Attribute, Exposed> >::type
  223. {};
  224. template <typename Exposed>
  225. struct extract_from<Exposed, unused_type>
  226. {
  227. typedef unused_type type;
  228. };
  229. template <typename Exposed>
  230. struct extract_from<Exposed, unused_type const>
  231. {
  232. typedef unused_type type;
  233. };
  234. }}}
  235. #endif