alternative_function.hpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // Copyright (c) 2001-2011 Hartmut Kaiser
  2. // Copyright (c) 2001-2011 Joel de Guzman
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #if !defined(SPIRIT_KARMA_ALTERNATIVE_MAR_01_2007_1124AM)
  7. #define SPIRIT_KARMA_ALTERNATIVE_MAR_01_2007_1124AM
  8. #if defined(_MSC_VER)
  9. #pragma once
  10. #endif
  11. #include <boost/spirit/home/karma/domain.hpp>
  12. #include <boost/spirit/home/karma/directive/buffer.hpp>
  13. #include <boost/spirit/home/support/unused.hpp>
  14. #include <boost/spirit/home/support/utree/utree_traits_fwd.hpp>
  15. #include <boost/spirit/home/karma/detail/attributes.hpp>
  16. #include <boost/spirit/home/support/detail/hold_any.hpp>
  17. #include <boost/spirit/home/karma/detail/output_iterator.hpp>
  18. #include <boost/spirit/home/support/container.hpp>
  19. #include <boost/utility/enable_if.hpp>
  20. #include <boost/variant.hpp>
  21. #include <boost/detail/workaround.hpp>
  22. ///////////////////////////////////////////////////////////////////////////////
  23. namespace boost { namespace spirit { namespace karma { namespace detail
  24. {
  25. ///////////////////////////////////////////////////////////////////////////
  26. // execute a generator if the given Attribute type is compatible
  27. ///////////////////////////////////////////////////////////////////////////
  28. // this gets instantiated if the Attribute type is _not_ compatible with
  29. // the generator
  30. template <typename Component, typename Attribute, typename Expected
  31. , typename Enable = void>
  32. struct alternative_generate
  33. {
  34. template <typename OutputIterator, typename Context, typename Delimiter>
  35. static bool
  36. call(Component const&, OutputIterator&, Context&, Delimiter const&
  37. , Attribute const&, bool& failed)
  38. {
  39. failed = true;
  40. return false;
  41. }
  42. };
  43. template <typename Component>
  44. struct alternative_generate<Component, unused_type, unused_type>
  45. {
  46. template <typename OutputIterator, typename Context, typename Delimiter>
  47. static bool
  48. call(Component const& component, OutputIterator& sink, Context& ctx
  49. , Delimiter const& d, unused_type, bool&)
  50. {
  51. #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
  52. component; // suppresses warning: C4100: 'component' : unreferenced formal parameter
  53. #endif
  54. // return true if any of the generators succeed
  55. return component.generate(sink, ctx, d, unused);
  56. }
  57. };
  58. // this gets instantiated if there is no Attribute given for the
  59. // alternative generator
  60. template <typename Component, typename Expected>
  61. struct alternative_generate<Component, unused_type, Expected>
  62. : alternative_generate<Component, unused_type, unused_type> {};
  63. // this gets instantiated if the generator does not expect to receive an
  64. // Attribute (the generator is self contained).
  65. template <typename Component, typename Attribute>
  66. struct alternative_generate<Component, Attribute, unused_type>
  67. : alternative_generate<Component, unused_type, unused_type> {};
  68. // this gets instantiated if the Attribute type is compatible to the
  69. // generator
  70. template <typename Component, typename Attribute, typename Expected>
  71. struct alternative_generate<Component, Attribute, Expected
  72. , typename enable_if<
  73. traits::compute_compatible_component<Expected, Attribute, karma::domain> >::type>
  74. {
  75. template <typename OutputIterator, typename Context, typename Delimiter>
  76. static bool
  77. call(Component const& component, OutputIterator& sink
  78. , Context& ctx, Delimiter const& d, Attribute const& attr, bool&)
  79. {
  80. #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
  81. component; // suppresses warning: C4100: 'component' : unreferenced formal parameter
  82. #endif
  83. return call(component, sink, ctx, d, attr
  84. , spirit::traits::not_is_variant_or_variant_in_optional<Attribute, karma::domain>());
  85. }
  86. template <typename OutputIterator, typename Context, typename Delimiter>
  87. static bool
  88. call(Component const& component, OutputIterator& sink
  89. , Context& ctx, Delimiter const& d, Attribute const& attr, mpl::true_)
  90. {
  91. #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
  92. component; // suppresses warning: C4100: 'component' : unreferenced formal parameter
  93. #endif
  94. return component.generate(sink, ctx, d, attr);
  95. }
  96. template <typename OutputIterator, typename Context, typename Delimiter>
  97. static bool
  98. call(Component const& component, OutputIterator& sink
  99. , Context& ctx, Delimiter const& d, Attribute const& attr, mpl::false_)
  100. {
  101. #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
  102. component; // suppresses warning: C4100: 'component' : unreferenced formal parameter
  103. #endif
  104. typedef
  105. traits::compute_compatible_component<Expected, Attribute, domain>
  106. component_type;
  107. // if we got passed an empty optional, just fail generation
  108. if (!traits::has_optional_value(attr))
  109. return false;
  110. // make sure, the content of the passed variant matches our
  111. // expectations
  112. typename traits::optional_attribute<Attribute>::type attr_ =
  113. traits::optional_value(attr);
  114. if (!component_type::is_compatible(spirit::traits::which(attr_)))
  115. return false;
  116. // returns true if any of the generators succeed
  117. typedef typename component_type::compatible_type compatible_type;
  118. return component.generate(sink, ctx, d
  119. , boost::get<compatible_type>(attr_));
  120. }
  121. };
  122. ///////////////////////////////////////////////////////////////////////////
  123. // alternative_generate_function: a functor supplied to fusion::any which
  124. // will be executed for every generator in a given alternative generator
  125. // expression
  126. ///////////////////////////////////////////////////////////////////////////
  127. template <typename OutputIterator, typename Context, typename Delimiter,
  128. typename Attribute, typename Strict>
  129. struct alternative_generate_function
  130. {
  131. alternative_generate_function(OutputIterator& sink_, Context& ctx_
  132. , Delimiter const& d, Attribute const& attr_)
  133. : sink(sink_), ctx(ctx_), delim(d), attr(attr_) {}
  134. template <typename Component>
  135. bool operator()(Component const& component)
  136. {
  137. typedef
  138. typename traits::attribute_of<Component, Context>::type
  139. expected_type;
  140. typedef
  141. alternative_generate<Component, Attribute, expected_type>
  142. generate;
  143. // wrap the given output iterator avoid output as long as one
  144. // component fails
  145. detail::enable_buffering<OutputIterator> buffering(sink);
  146. bool r = false;
  147. bool failed = false; // will be ignored
  148. {
  149. detail::disable_counting<OutputIterator> nocounting(sink);
  150. r = generate::call(component, sink, ctx, delim, attr, failed);
  151. }
  152. if (r)
  153. buffering.buffer_copy();
  154. return r;
  155. }
  156. // avoid double buffering
  157. template <typename Component>
  158. bool operator()(buffer_directive<Component> const& component)
  159. {
  160. typedef typename
  161. traits::attribute_of<Component, Context>::type
  162. expected_type;
  163. typedef alternative_generate<
  164. buffer_directive<Component>, Attribute, expected_type>
  165. generate;
  166. bool failed = false; // will be ignored
  167. return generate::call(component, sink, ctx, delim, attr, failed);
  168. }
  169. OutputIterator& sink;
  170. Context& ctx;
  171. Delimiter const& delim;
  172. Attribute const& attr;
  173. // silence MSVC warning C4512: assignment operator could not be generated
  174. BOOST_DELETED_FUNCTION(alternative_generate_function& operator= (alternative_generate_function const&))
  175. };
  176. // specialization for strict alternatives
  177. template <typename OutputIterator, typename Context, typename Delimiter,
  178. typename Attribute>
  179. struct alternative_generate_function<
  180. OutputIterator, Context, Delimiter, Attribute, mpl::true_>
  181. {
  182. alternative_generate_function(OutputIterator& sink_, Context& ctx_
  183. , Delimiter const& d, Attribute const& attr_)
  184. : sink(sink_), ctx(ctx_), delim(d), attr(attr_), failed(false) {}
  185. template <typename Component>
  186. bool operator()(Component const& component)
  187. {
  188. typedef
  189. typename traits::attribute_of<Component, Context>::type
  190. expected_type;
  191. typedef
  192. alternative_generate<Component, Attribute, expected_type>
  193. generate;
  194. if (failed)
  195. return false; // give up when already failed
  196. // wrap the given output iterator avoid output as long as one
  197. // component fails
  198. detail::enable_buffering<OutputIterator> buffering(sink);
  199. bool r = false;
  200. {
  201. detail::disable_counting<OutputIterator> nocounting(sink);
  202. r = generate::call(component, sink, ctx, delim, attr, failed);
  203. }
  204. if (r && !failed)
  205. {
  206. buffering.buffer_copy();
  207. return true;
  208. }
  209. return false;
  210. }
  211. OutputIterator& sink;
  212. Context& ctx;
  213. Delimiter const& delim;
  214. Attribute const& attr;
  215. bool failed;
  216. // silence MSVC warning C4512: assignment operator could not be generated
  217. BOOST_DELETED_FUNCTION(alternative_generate_function& operator= (alternative_generate_function const&))
  218. };
  219. }}}}
  220. #endif