extract_from.hpp 9.4 KB

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