list.hpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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_LIST_MAY_01_2007_0229PM)
  7. #define SPIRIT_KARMA_LIST_MAY_01_2007_0229PM
  8. #if defined(_MSC_VER)
  9. #pragma once
  10. #endif
  11. #include <boost/spirit/home/karma/domain.hpp>
  12. #include <boost/spirit/home/karma/generator.hpp>
  13. #include <boost/spirit/home/karma/meta_compiler.hpp>
  14. #include <boost/spirit/home/karma/detail/output_iterator.hpp>
  15. #include <boost/spirit/home/karma/detail/indirect_iterator.hpp>
  16. #include <boost/spirit/home/karma/detail/get_stricttag.hpp>
  17. #include <boost/spirit/home/karma/detail/pass_container.hpp>
  18. #include <boost/spirit/home/karma/detail/fail_function.hpp>
  19. #include <boost/spirit/home/support/info.hpp>
  20. #include <boost/spirit/home/support/unused.hpp>
  21. #include <boost/spirit/home/support/container.hpp>
  22. #include <boost/spirit/home/support/handles_container.hpp>
  23. #include <boost/spirit/home/karma/detail/attributes.hpp>
  24. namespace boost { namespace spirit
  25. {
  26. ///////////////////////////////////////////////////////////////////////////
  27. // Enablers
  28. ///////////////////////////////////////////////////////////////////////////
  29. template <>
  30. struct use_operator<karma::domain, proto::tag::modulus> // enables g % d
  31. : mpl::true_ {};
  32. }}
  33. ///////////////////////////////////////////////////////////////////////////////
  34. namespace boost { namespace spirit { namespace karma
  35. {
  36. template <typename Left, typename Right, typename Strict, typename Derived>
  37. struct base_list : binary_generator<Derived>
  38. {
  39. private:
  40. // iterate over the given container until its exhausted or the embedded
  41. // (left) generator succeeds
  42. template <typename F, typename Attribute>
  43. bool generate_left(F f, Attribute const&, mpl::false_) const
  44. {
  45. // Failing subject generators are just skipped. This allows to
  46. // selectively generate items in the provided attribute.
  47. while (!f.is_at_end())
  48. {
  49. bool r = !f(left);
  50. if (r)
  51. return true;
  52. if (!f.is_at_end())
  53. f.next();
  54. }
  55. return false;
  56. }
  57. template <typename F, typename Attribute>
  58. bool generate_left(F f, Attribute const&, mpl::true_) const
  59. {
  60. return !f(left);
  61. }
  62. // There is no way to distinguish a failed generator from a
  63. // generator to be skipped. We assume the user takes responsibility
  64. // for ending the loop if no attribute is specified.
  65. template <typename F>
  66. bool generate_left(F f, unused_type, mpl::false_) const
  67. {
  68. return !f(left);
  69. }
  70. public:
  71. typedef Left left_type;
  72. typedef Right right_type;
  73. typedef mpl::int_<
  74. left_type::properties::value
  75. | right_type::properties::value
  76. | generator_properties::buffering
  77. | generator_properties::counting
  78. > properties;
  79. // Build a std::vector from the LHS's attribute. Note
  80. // that build_std_vector may return unused_type if the
  81. // subject's attribute is an unused_type.
  82. template <typename Context, typename Iterator>
  83. struct attribute
  84. : traits::build_std_vector<
  85. typename traits::attribute_of<Left, Context, Iterator>::type>
  86. {};
  87. base_list(Left const& left, Right const& right)
  88. : left(left), right(right)
  89. {}
  90. template <
  91. typename OutputIterator, typename Context, typename Delimiter
  92. , typename Attribute>
  93. bool generate(OutputIterator& sink, Context& ctx
  94. , Delimiter const& d, Attribute const& attr) const
  95. {
  96. typedef detail::fail_function<
  97. OutputIterator, Context, Delimiter
  98. > fail_function;
  99. typedef typename traits::container_iterator<
  100. typename add_const<Attribute>::type
  101. >::type iterator_type;
  102. typedef
  103. typename traits::make_indirect_iterator<iterator_type>::type
  104. indirect_iterator_type;
  105. typedef detail::pass_container<
  106. fail_function, Attribute, indirect_iterator_type, mpl::false_>
  107. pass_container;
  108. iterator_type it = traits::begin(attr);
  109. iterator_type end = traits::end(attr);
  110. pass_container pass(fail_function(sink, ctx, d),
  111. indirect_iterator_type(it), indirect_iterator_type(end));
  112. if (generate_left(pass, attr, Strict()))
  113. {
  114. while (!pass.is_at_end())
  115. {
  116. // wrap the given output iterator as generate_left might fail
  117. detail::enable_buffering<OutputIterator> buffering(sink);
  118. {
  119. detail::disable_counting<OutputIterator> nocounting(sink);
  120. if (!right.generate(sink, ctx, d, unused))
  121. return false; // shouldn't happen
  122. if (!generate_left(pass, attr, Strict()))
  123. break; // return true as one item succeeded
  124. }
  125. buffering.buffer_copy();
  126. }
  127. return detail::sink_is_good(sink);
  128. }
  129. return false;
  130. }
  131. template <typename Context>
  132. info what(Context& context) const
  133. {
  134. return info("list",
  135. std::make_pair(left.what(context), right.what(context)));
  136. }
  137. Left left;
  138. Right right;
  139. };
  140. template <typename Left, typename Right>
  141. struct list
  142. : base_list<Left, Right, mpl::false_, list<Left, Right> >
  143. {
  144. typedef base_list<Left, Right, mpl::false_, list> base_list_;
  145. list(Left const& left, Right const& right)
  146. : base_list_(left, right) {}
  147. };
  148. template <typename Left, typename Right>
  149. struct strict_list
  150. : base_list<Left, Right, mpl::true_, strict_list<Left, Right> >
  151. {
  152. typedef base_list<Left, Right, mpl::true_, strict_list> base_list_;
  153. strict_list (Left const& left, Right const& right)
  154. : base_list_(left, right) {}
  155. };
  156. ///////////////////////////////////////////////////////////////////////////
  157. // Generator generators: make_xxx function (objects)
  158. ///////////////////////////////////////////////////////////////////////////
  159. namespace detail
  160. {
  161. template <typename Subject, bool strict_mode = false>
  162. struct make_list
  163. : make_binary_composite<Subject, list>
  164. {};
  165. template <typename Subject>
  166. struct make_list<Subject, true>
  167. : make_binary_composite<Subject, strict_list>
  168. {};
  169. }
  170. template <typename Subject, typename Modifiers>
  171. struct make_composite<proto::tag::modulus, Subject, Modifiers>
  172. : detail::make_list<Subject, detail::get_stricttag<Modifiers>::value>
  173. {};
  174. }}}
  175. namespace boost { namespace spirit { namespace traits
  176. {
  177. ///////////////////////////////////////////////////////////////////////////
  178. template <typename Left, typename Right>
  179. struct has_semantic_action<karma::list<Left, Right> >
  180. : binary_has_semantic_action<Left, Right> {};
  181. template <typename Left, typename Right>
  182. struct has_semantic_action<karma::strict_list<Left, Right> >
  183. : binary_has_semantic_action<Left, Right> {};
  184. ///////////////////////////////////////////////////////////////////////////
  185. template <typename Left, typename Right, typename Attribute
  186. , typename Context, typename Iterator>
  187. struct handles_container<karma::list<Left, Right>, Attribute
  188. , Context, Iterator>
  189. : mpl::true_ {};
  190. template <typename Left, typename Right, typename Attribute
  191. , typename Context, typename Iterator>
  192. struct handles_container<karma::strict_list<Left, Right>, Attribute
  193. , Context, Iterator>
  194. : mpl::true_ {};
  195. }}}
  196. #endif