columns.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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_COLUMNS_DEC_03_2009_0736AM)
  6. #define BOOST_SPIRIT_KARMA_COLUMNS_DEC_03_2009_0736AM
  7. #if defined(_MSC_VER)
  8. #pragma once
  9. #endif
  10. #include <boost/spirit/home/karma/meta_compiler.hpp>
  11. #include <boost/spirit/home/karma/generator.hpp>
  12. #include <boost/spirit/home/karma/domain.hpp>
  13. #include <boost/spirit/home/karma/delimit_out.hpp>
  14. #include <boost/spirit/home/karma/detail/default_width.hpp>
  15. #include <boost/spirit/home/karma/auxiliary/eol.hpp>
  16. #include <boost/spirit/home/karma/auxiliary/lazy.hpp>
  17. #include <boost/spirit/home/support/unused.hpp>
  18. #include <boost/spirit/home/support/common_terminals.hpp>
  19. #include <boost/spirit/home/support/has_semantic_action.hpp>
  20. #include <boost/spirit/home/support/handles_container.hpp>
  21. #include <boost/spirit/home/karma/detail/attributes.hpp>
  22. #include <boost/spirit/home/support/info.hpp>
  23. #include <boost/fusion/include/at.hpp>
  24. #include <boost/fusion/include/vector.hpp>
  25. #include <boost/integer_traits.hpp>
  26. namespace boost { namespace spirit
  27. {
  28. ///////////////////////////////////////////////////////////////////////////
  29. // Enablers
  30. ///////////////////////////////////////////////////////////////////////////
  31. template <>
  32. struct use_directive<karma::domain, tag::columns> // enables columns[]
  33. : mpl::true_ {};
  34. // enables columns(c)[g], where c provides the number of require columns
  35. template <typename T>
  36. struct use_directive<karma::domain
  37. , terminal_ex<tag::columns, fusion::vector1<T> > >
  38. : mpl::true_ {};
  39. // enables *lazy* columns(c)[g]
  40. template <>
  41. struct use_lazy_directive<karma::domain, tag::columns, 1>
  42. : mpl::true_ {};
  43. // enables columns(c, d)[g], where c provides the number of require columns
  44. // and d is the custom column-delimiter (default is karma::endl)
  45. template <typename T1, typename T2>
  46. struct use_directive<karma::domain
  47. , terminal_ex<tag::columns, fusion::vector2<T1, T2> > >
  48. : boost::spirit::traits::matches<karma::domain, T2> {};
  49. // enables *lazy* columns(c, d)[g]
  50. template <>
  51. struct use_lazy_directive<karma::domain, tag::columns, 2>
  52. : mpl::true_ {};
  53. }}
  54. namespace boost { namespace spirit { namespace karma
  55. {
  56. #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
  57. using spirit::columns;
  58. #endif
  59. using spirit::columns_type;
  60. namespace detail
  61. {
  62. #ifdef _MSC_VER
  63. # pragma warning(push)
  64. # pragma warning(disable: 4512) // assignment operator could not be generated.
  65. #endif
  66. template <typename Delimiter, typename ColumnDelimiter>
  67. struct columns_delimiter
  68. {
  69. columns_delimiter(Delimiter const& delim
  70. , ColumnDelimiter const& cdelim, unsigned int const numcols)
  71. : delimiter(delim), column_delimiter(cdelim)
  72. , numcolumns(numcols), count(0) {}
  73. template <typename OutputIterator, typename Context
  74. , typename Delimiter_, typename Attribute>
  75. bool generate(OutputIterator& sink, Context&, Delimiter_ const&
  76. , Attribute const&) const
  77. {
  78. // first invoke the embedded delimiter
  79. if (!karma::delimit_out(sink, delimiter))
  80. return false;
  81. // now we count the number of invocations and emit the column
  82. // delimiter if needed
  83. if ((++count % numcolumns) == 0)
  84. return karma::delimit_out(sink, column_delimiter);
  85. return true;
  86. }
  87. // generate a final column delimiter if the last invocation didn't
  88. // emit one
  89. template <typename OutputIterator>
  90. bool delimit_out(OutputIterator& sink) const
  91. {
  92. if (count % numcolumns)
  93. return karma::delimit_out(sink, column_delimiter);
  94. return true;
  95. }
  96. Delimiter const& delimiter;
  97. ColumnDelimiter const& column_delimiter;
  98. unsigned int const numcolumns;
  99. mutable unsigned int count;
  100. };
  101. #ifdef _MSC_VER
  102. # pragma warning(pop)
  103. #endif
  104. }
  105. ///////////////////////////////////////////////////////////////////////////
  106. // The columns_generator is used for columns(c, d)[...] directives.
  107. ///////////////////////////////////////////////////////////////////////////
  108. template <typename Subject, typename NumColumns, typename ColumnsDelimiter>
  109. struct columns_generator
  110. : unary_generator<columns_generator<Subject, NumColumns, ColumnsDelimiter> >
  111. {
  112. typedef Subject subject_type;
  113. typedef ColumnsDelimiter delimiter_type;
  114. typedef mpl::int_<
  115. subject_type::properties::value | delimiter_type::properties::value
  116. > properties;
  117. template <typename Context, typename Iterator>
  118. struct attribute
  119. : traits::attribute_of<subject_type, Context, Iterator>
  120. {};
  121. columns_generator(Subject const& subject, NumColumns const& cols
  122. , ColumnsDelimiter const& cdelimiter)
  123. : subject(subject), numcolumns(cols), column_delimiter(cdelimiter)
  124. {
  125. // having zero number of columns doesn't make any sense
  126. BOOST_ASSERT(numcolumns > 0);
  127. }
  128. template <typename OutputIterator, typename Context
  129. , typename Delimiter, typename Attribute>
  130. bool generate(OutputIterator& sink, Context& ctx
  131. , Delimiter const& delimiter, Attribute const& attr) const
  132. {
  133. // The columns generator dispatches to the embedded generator
  134. // while supplying a new delimiter to use, wrapping the outer
  135. // delimiter.
  136. typedef detail::columns_delimiter<
  137. Delimiter, ColumnsDelimiter
  138. > columns_delimiter_type;
  139. columns_delimiter_type d(delimiter, column_delimiter, numcolumns);
  140. return subject.generate(sink, ctx, d, attr) && d.delimit_out(sink);
  141. }
  142. template <typename Context>
  143. info what(Context& context) const
  144. {
  145. return info("columns", subject.what(context));
  146. }
  147. Subject subject;
  148. NumColumns numcolumns;
  149. ColumnsDelimiter column_delimiter;
  150. };
  151. ///////////////////////////////////////////////////////////////////////////
  152. // Generator generators: make_xxx function (objects)
  153. ///////////////////////////////////////////////////////////////////////////
  154. // creates columns[] directive
  155. template <typename Subject, typename Modifiers>
  156. struct make_directive<tag::columns, Subject, Modifiers>
  157. {
  158. typedef typename
  159. result_of::compile<karma::domain, eol_type, Modifiers>::type
  160. columns_delimiter_type;
  161. typedef columns_generator<
  162. Subject, detail::default_columns, columns_delimiter_type>
  163. result_type;
  164. result_type operator()(unused_type, Subject const& subject
  165. , unused_type) const
  166. {
  167. #if defined(BOOST_SPIRIT_NO_PREDEFINED_TERMINALS)
  168. eol_type const eol = eol_type();
  169. #endif
  170. return result_type(subject, detail::default_columns()
  171. , compile<karma::domain>(eol));
  172. }
  173. };
  174. // creates columns(c)[] directive generator (c is the number of columns)
  175. template <typename T, typename Subject, typename Modifiers>
  176. struct make_directive<
  177. terminal_ex<tag::columns, fusion::vector1<T> >
  178. , Subject, Modifiers
  179. , typename enable_if_c<integer_traits<T>::is_integral>::type>
  180. {
  181. typedef typename
  182. result_of::compile<karma::domain, eol_type, Modifiers>::type
  183. columns_delimiter_type;
  184. typedef columns_generator<
  185. Subject, T, columns_delimiter_type
  186. > result_type;
  187. template <typename Terminal>
  188. result_type operator()(Terminal const& term, Subject const& subject
  189. , unused_type) const
  190. {
  191. #if defined(BOOST_SPIRIT_NO_PREDEFINED_TERMINALS)
  192. eol_type const eol = eol_type();
  193. #endif
  194. return result_type(subject, fusion::at_c<0>(term.args)
  195. , compile<karma::domain>(eol));
  196. }
  197. };
  198. // creates columns(d)[] directive generator (d is the column delimiter)
  199. template <typename T, typename Subject, typename Modifiers>
  200. struct make_directive<
  201. terminal_ex<tag::columns, fusion::vector1<T> >
  202. , Subject, Modifiers
  203. , typename enable_if<
  204. mpl::and_<
  205. spirit::traits::matches<karma::domain, T>,
  206. mpl::not_<mpl::bool_<integer_traits<T>::is_integral> >
  207. >
  208. >::type>
  209. {
  210. typedef typename
  211. result_of::compile<karma::domain, T, Modifiers>::type
  212. columns_delimiter_type;
  213. typedef columns_generator<
  214. Subject, detail::default_columns, columns_delimiter_type
  215. > result_type;
  216. template <typename Terminal>
  217. result_type operator()(Terminal const& term, Subject const& subject
  218. , unused_type) const
  219. {
  220. return result_type(subject, detail::default_columns()
  221. , compile<karma::domain>(fusion::at_c<0>(term.args)));
  222. }
  223. };
  224. // creates columns(c, d)[] directive generator (c is the number of columns
  225. // and d is the column delimiter)
  226. template <typename T1, typename T2, typename Subject, typename Modifiers>
  227. struct make_directive<
  228. terminal_ex<tag::columns, fusion::vector2<T1, T2> >
  229. , Subject, Modifiers>
  230. {
  231. typedef typename
  232. result_of::compile<karma::domain, T2, Modifiers>::type
  233. columns_delimiter_type;
  234. typedef columns_generator<
  235. Subject, T1, columns_delimiter_type
  236. > result_type;
  237. template <typename Terminal>
  238. result_type operator()(Terminal const& term, Subject const& subject
  239. , unused_type) const
  240. {
  241. return result_type (subject, fusion::at_c<0>(term.args)
  242. , compile<karma::domain>(fusion::at_c<1>(term.args)));
  243. }
  244. };
  245. }}}
  246. namespace boost { namespace spirit { namespace traits
  247. {
  248. ///////////////////////////////////////////////////////////////////////////
  249. template <typename Subject, typename T1, typename T2>
  250. struct has_semantic_action<karma::columns_generator<Subject, T1, T2> >
  251. : unary_has_semantic_action<Subject> {};
  252. ///////////////////////////////////////////////////////////////////////////
  253. template <typename Subject, typename T1, typename T2, typename Attribute
  254. , typename Context, typename Iterator>
  255. struct handles_container<
  256. karma::columns_generator<Subject, T1, T2>, Attribute
  257. , Context, Iterator>
  258. : unary_handles_container<Subject, Attribute, Context, Iterator> {};
  259. }}}
  260. #endif