extract_from.hpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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
  40. , bool IsOneElemSeq = traits::one_element_sequence<Attribute>::value>
  41. struct extract_from_attribute_base
  42. {
  43. typedef Attribute const& type;
  44. template <typename Context>
  45. static type call(Attribute const& attr, Context&)
  46. {
  47. return attr;
  48. }
  49. };
  50. // This handles the case where the attribute is a single element fusion
  51. // sequence. We silently extract the only element and treat it as the
  52. // attribute to generate output from.
  53. template <typename Attribute, typename Exposed>
  54. struct extract_from_attribute_base<Attribute, Exposed, true>
  55. {
  56. typedef typename remove_const<
  57. typename remove_reference<
  58. typename fusion::result_of::at_c<Attribute, 0>::type
  59. >::type
  60. >::type elem_type;
  61. typedef typename result_of::extract_from<Exposed, elem_type>::type type;
  62. template <typename Context>
  63. static type call(Attribute const& attr, Context& ctx)
  64. {
  65. return extract_from<Exposed>(fusion::at_c<0>(attr), ctx);
  66. }
  67. };
  68. template <typename Attribute, typename Exposed, typename Enable/*= void*/>
  69. struct extract_from_attribute
  70. : extract_from_attribute_base<Attribute, Exposed>
  71. {};
  72. // This handles optional attributes.
  73. template <typename Attribute, typename Exposed>
  74. struct extract_from_attribute<boost::optional<Attribute>, Exposed>
  75. {
  76. typedef Attribute const& type;
  77. template <typename Context>
  78. static type call(boost::optional<Attribute> const& attr, Context& ctx)
  79. {
  80. return extract_from<Exposed>(boost::get<Attribute>(attr), ctx);
  81. }
  82. };
  83. template <typename Attribute, typename Exposed>
  84. struct extract_from_attribute<boost::optional<Attribute const>, Exposed>
  85. {
  86. typedef Attribute const& type;
  87. template <typename Context>
  88. static type call(boost::optional<Attribute const> const& attr, Context& ctx)
  89. {
  90. return extract_from<Exposed>(boost::get<Attribute const>(attr), ctx);
  91. }
  92. };
  93. // This handles attributes wrapped inside a boost::ref().
  94. template <typename Attribute, typename Exposed>
  95. struct extract_from_attribute<reference_wrapper<Attribute>, Exposed>
  96. {
  97. typedef Attribute const& type;
  98. template <typename Context>
  99. static type call(reference_wrapper<Attribute> const& attr, Context& ctx)
  100. {
  101. return extract_from<Exposed>(attr.get(), ctx);
  102. }
  103. };
  104. ///////////////////////////////////////////////////////////////////////////
  105. template <typename Attribute, typename Exposed, typename Enable>
  106. struct extract_from_container
  107. {
  108. typedef typename traits::container_value<Attribute const>::type
  109. value_type;
  110. typedef typename is_convertible<value_type, Exposed>::type
  111. is_convertible_to_value_type;
  112. typedef typename mpl::if_<
  113. mpl::or_<
  114. is_same<value_type, Exposed>, is_same<Attribute, Exposed> >
  115. , Exposed const&, Exposed
  116. >::type type;
  117. // handle case where container value type is convertible to result type
  118. // we simply return the front element of the container
  119. template <typename Context, typename Pred>
  120. static type call(Attribute const& attr, Context&, mpl::true_, Pred)
  121. {
  122. // return first element from container
  123. typedef typename traits::container_iterator<Attribute const>::type
  124. iterator_type;
  125. iterator_type it = traits::begin(attr);
  126. type result = *it;
  127. ++it;
  128. return result;
  129. }
  130. // handle strings
  131. template <typename Iterator>
  132. static void append_to_string(Exposed& result, Iterator begin, Iterator end)
  133. {
  134. for (Iterator i = begin; i != end; ++i)
  135. push_back(result, *i);
  136. }
  137. template <typename Context>
  138. static type call(Attribute const& attr, Context&, mpl::false_, mpl::true_)
  139. {
  140. typedef typename char_type_of<Attribute>::type char_type;
  141. Exposed result;
  142. append_to_string(result, traits::get_begin<char_type>(attr)
  143. , traits::get_end<char_type>(attr));
  144. return result;
  145. }
  146. // everything else gets just passed through
  147. template <typename Context>
  148. static type call(Attribute const& attr, Context&, mpl::false_, mpl::false_)
  149. {
  150. return type(attr);
  151. }
  152. template <typename Context>
  153. static type call(Attribute const& attr, Context& ctx)
  154. {
  155. typedef typename mpl::and_<
  156. traits::is_string<Exposed>, traits::is_string<Attribute>
  157. >::type handle_strings;
  158. // return first element from container
  159. return call(attr, ctx, is_convertible_to_value_type()
  160. , handle_strings());
  161. }
  162. };
  163. template <typename Attribute>
  164. struct extract_from_container<Attribute, Attribute>
  165. {
  166. typedef Attribute const& type;
  167. template <typename Context>
  168. static type call(Attribute const& attr, Context&)
  169. {
  170. return attr;
  171. }
  172. };
  173. ///////////////////////////////////////////////////////////////////////////
  174. namespace detail
  175. {
  176. // overload for non-container attributes
  177. template <typename Exposed, typename Attribute, typename Context>
  178. inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
  179. extract_from(Attribute const& attr, Context& ctx, mpl::false_)
  180. {
  181. return extract_from_attribute<Attribute, Exposed>::call(attr, ctx);
  182. }
  183. // overload for containers (but not for variants or optionals
  184. // holding containers)
  185. template <typename Exposed, typename Attribute, typename Context>
  186. inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
  187. extract_from(Attribute const& attr, Context& ctx, mpl::true_)
  188. {
  189. return extract_from_container<Attribute, Exposed>::call(attr, ctx);
  190. }
  191. }
  192. template <typename Exposed, typename Attribute, typename Context>
  193. inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
  194. extract_from(Attribute const& attr, Context& ctx
  195. #if (defined(__GNUC__) && (__GNUC__ < 4)) || \
  196. (defined(__APPLE__) && defined(__INTEL_COMPILER))
  197. , typename enable_if<traits::not_is_unused<Attribute> >::type*
  198. #endif
  199. )
  200. {
  201. typedef typename mpl::and_<
  202. traits::is_container<Attribute>
  203. , traits::not_is_variant<Attribute>
  204. , traits::not_is_optional<Attribute>
  205. >::type is_not_wrapped_container;
  206. return detail::extract_from<Exposed>(attr, ctx
  207. , is_not_wrapped_container());
  208. }
  209. template <typename Exposed, typename Context>
  210. inline unused_type extract_from(unused_type, Context&)
  211. {
  212. return unused;
  213. }
  214. }}}
  215. ///////////////////////////////////////////////////////////////////////////////
  216. namespace boost { namespace spirit { namespace result_of
  217. {
  218. template <typename Exposed, typename Attribute>
  219. struct extract_from
  220. : mpl::if_<
  221. mpl::and_<
  222. traits::is_container<Attribute>
  223. , traits::not_is_variant<Attribute>
  224. , traits::not_is_optional<Attribute> >
  225. , traits::extract_from_container<Attribute, Exposed>
  226. , traits::extract_from_attribute<Attribute, Exposed> >::type
  227. {};
  228. template <typename Exposed>
  229. struct extract_from<Exposed, unused_type>
  230. {
  231. typedef unused_type type;
  232. };
  233. template <typename Exposed>
  234. struct extract_from<Exposed, unused_type const>
  235. {
  236. typedef unused_type type;
  237. };
  238. }}}
  239. #endif