left_alignment.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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_LEFT_ALIGNMENT_FEB_27_2007_1216PM)
  6. #define BOOST_SPIRIT_KARMA_LEFT_ALIGNMENT_FEB_27_2007_1216PM
  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/detail/output_iterator.hpp>
  14. #include <boost/spirit/home/karma/detail/default_width.hpp>
  15. #include <boost/spirit/home/karma/delimit_out.hpp>
  16. #include <boost/spirit/home/karma/auxiliary/lazy.hpp>
  17. #include <boost/spirit/home/karma/char/char.hpp>
  18. #include <boost/spirit/home/support/unused.hpp>
  19. #include <boost/spirit/home/support/common_terminals.hpp>
  20. #include <boost/spirit/home/karma/detail/attributes.hpp>
  21. #include <boost/spirit/home/support/info.hpp>
  22. #include <boost/spirit/home/support/unused.hpp>
  23. #include <boost/spirit/home/support/has_semantic_action.hpp>
  24. #include <boost/spirit/home/support/handles_container.hpp>
  25. #include <boost/fusion/include/at.hpp>
  26. #include <boost/fusion/include/vector.hpp>
  27. #include <boost/integer_traits.hpp>
  28. #include <boost/mpl/bool.hpp>
  29. #include <boost/utility/enable_if.hpp>
  30. #include <boost/detail/workaround.hpp>
  31. ///////////////////////////////////////////////////////////////////////////////
  32. namespace boost { namespace spirit
  33. {
  34. ///////////////////////////////////////////////////////////////////////////
  35. // Enablers
  36. ///////////////////////////////////////////////////////////////////////////
  37. // enables left_align[]
  38. template <>
  39. struct use_directive<karma::domain, tag::left_align>
  40. : mpl::true_ {};
  41. // enables left_align(d)[g] and left_align(w)[g], where d is a generator
  42. // and w is a maximum width
  43. template <typename T>
  44. struct use_directive<karma::domain
  45. , terminal_ex<tag::left_align, fusion::vector1<T> > >
  46. : mpl::true_ {};
  47. // enables *lazy* left_align(d)[g], where d provides a generator
  48. template <>
  49. struct use_lazy_directive<karma::domain, tag::left_align, 1>
  50. : mpl::true_ {};
  51. // enables left_align(w, d)[g], where d is a generator and w is a maximum
  52. // width
  53. template <typename Width, typename Padding>
  54. struct use_directive<karma::domain
  55. , terminal_ex<tag::left_align, fusion::vector2<Width, Padding> > >
  56. : spirit::traits::matches<karma::domain, Padding> {};
  57. // enables *lazy* left_align(w, d)[g], where d provides a generator and w
  58. // is a maximum width
  59. template <>
  60. struct use_lazy_directive<karma::domain, tag::left_align, 2>
  61. : mpl::true_ {};
  62. }}
  63. ///////////////////////////////////////////////////////////////////////////////
  64. namespace boost { namespace spirit { namespace karma
  65. {
  66. #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
  67. using spirit::left_align;
  68. #endif
  69. using spirit::left_align_type;
  70. namespace detail
  71. {
  72. ///////////////////////////////////////////////////////////////////////
  73. // The left_align_generate template function is used for all the
  74. // different flavors of the left_align[] directive.
  75. ///////////////////////////////////////////////////////////////////////
  76. template <typename OutputIterator, typename Context, typename Delimiter,
  77. typename Attribute, typename Embedded, typename Padding>
  78. inline static bool
  79. left_align_generate(OutputIterator& sink, Context& ctx,
  80. Delimiter const& d, Attribute const& attr, Embedded const& e,
  81. unsigned int const width, Padding const& p)
  82. {
  83. #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
  84. (void)e; // suppresses warning: C4100: 'e' : unreferenced formal parameter
  85. #endif
  86. // wrap the given output iterator to allow counting
  87. detail::enable_counting<OutputIterator> counting(sink);
  88. // first generate the underlying output
  89. bool r = e.generate(sink, ctx, d, attr);
  90. // pad the output until the max width is reached
  91. while(r && counting.count() < width)
  92. r = p.generate(sink, ctx, unused, unused);
  93. return r;
  94. }
  95. }
  96. ///////////////////////////////////////////////////////////////////////////
  97. // The simple left alignment directive is used for left_align[...]
  98. // generators. It uses default values for the generated width (defined via
  99. // the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant) and for the padding
  100. // generator (always spaces).
  101. ///////////////////////////////////////////////////////////////////////////
  102. template <typename Subject, typename Width = detail::default_width>
  103. struct simple_left_alignment
  104. : unary_generator<simple_left_alignment<Subject, Width> >
  105. {
  106. typedef Subject subject_type;
  107. typedef mpl::int_<
  108. generator_properties::counting | subject_type::properties::value
  109. > properties;
  110. template <typename Context, typename Iterator>
  111. struct attribute
  112. : traits::attribute_of<subject_type, Context, Iterator>
  113. {};
  114. simple_left_alignment(Subject const& subject, Width width = Width())
  115. : subject(subject), width(width) {}
  116. template <typename OutputIterator, typename Context, typename Delimiter
  117. , typename Attribute>
  118. bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d
  119. , Attribute const& attr) const
  120. {
  121. return detail::left_align_generate(sink, ctx, d, attr,
  122. subject, width, compile<karma::domain>(' '));
  123. }
  124. template <typename Context>
  125. info what(Context& context) const
  126. {
  127. return info("left_align", subject.what(context));
  128. }
  129. Subject subject;
  130. Width width;
  131. };
  132. ///////////////////////////////////////////////////////////////////////////
  133. // The left alignment directive with padding, is used for generators like
  134. // left_align(padding)[...], where padding is a arbitrary generator
  135. // expression. It uses a default value for the generated width (defined
  136. // via the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant).
  137. ///////////////////////////////////////////////////////////////////////////
  138. template <typename Subject, typename Padding
  139. , typename Width = detail::default_width>
  140. struct padding_left_alignment
  141. : unary_generator<padding_left_alignment<Subject, Padding, Width> >
  142. {
  143. typedef Subject subject_type;
  144. typedef Padding padding_type;
  145. typedef mpl::int_<
  146. generator_properties::counting |
  147. subject_type::properties::value | padding_type::properties::value
  148. > properties;
  149. template <typename Context, typename Iterator>
  150. struct attribute
  151. : traits::attribute_of<subject_type, Context, Iterator>
  152. {};
  153. padding_left_alignment(Subject const& subject, Padding const& padding
  154. , Width width = Width())
  155. : subject(subject), padding(padding), width(width) {}
  156. template <typename OutputIterator, typename Context, typename Delimiter
  157. , typename Attribute>
  158. bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d
  159. , Attribute const& attr) const
  160. {
  161. return detail::left_align_generate(sink, ctx, d, attr,
  162. subject, width, padding);
  163. }
  164. template <typename Context>
  165. info what(Context& context) const
  166. {
  167. return info("left_align", subject.what(context));
  168. }
  169. Subject subject;
  170. Padding padding;
  171. Width width;
  172. };
  173. ///////////////////////////////////////////////////////////////////////////
  174. // Generator generators: make_xxx function (objects)
  175. ///////////////////////////////////////////////////////////////////////////
  176. // creates left_align[] directive generator
  177. template <typename Subject, typename Modifiers>
  178. struct make_directive<tag::left_align, Subject, Modifiers>
  179. {
  180. typedef simple_left_alignment<Subject> result_type;
  181. result_type operator()(unused_type, Subject const& subject
  182. , unused_type) const
  183. {
  184. return result_type(subject);
  185. }
  186. };
  187. // creates left_align(width)[] directive generator
  188. template <typename Width, typename Subject, typename Modifiers>
  189. struct make_directive<
  190. terminal_ex<tag::left_align, fusion::vector1<Width> >
  191. , Subject, Modifiers
  192. , typename enable_if_c< integer_traits<Width>::is_integral >::type>
  193. {
  194. typedef simple_left_alignment<Subject, Width> result_type;
  195. template <typename Terminal>
  196. result_type operator()(Terminal const& term, Subject const& subject
  197. , unused_type) const
  198. {
  199. return result_type(subject, fusion::at_c<0>(term.args));
  200. }
  201. };
  202. // creates left_align(pad)[] directive generator
  203. template <typename Padding, typename Subject, typename Modifiers>
  204. struct make_directive<
  205. terminal_ex<tag::left_align, fusion::vector1<Padding> >
  206. , Subject, Modifiers
  207. , typename enable_if<
  208. mpl::and_<
  209. spirit::traits::matches<karma::domain, Padding>,
  210. mpl::not_<mpl::bool_<integer_traits<Padding>::is_integral> >
  211. >
  212. >::type>
  213. {
  214. typedef typename
  215. result_of::compile<karma::domain, Padding, Modifiers>::type
  216. padding_type;
  217. typedef padding_left_alignment<Subject, padding_type> result_type;
  218. template <typename Terminal>
  219. result_type operator()(Terminal const& term, Subject const& subject
  220. , Modifiers const& modifiers) const
  221. {
  222. return result_type(subject
  223. , compile<karma::domain>(fusion::at_c<0>(term.args), modifiers));
  224. }
  225. };
  226. // creates left_align(width, pad)[] directive generator
  227. template <typename Width, typename Padding, typename Subject
  228. , typename Modifiers>
  229. struct make_directive<
  230. terminal_ex<tag::left_align, fusion::vector2<Width, Padding> >
  231. , Subject, Modifiers>
  232. {
  233. typedef typename
  234. result_of::compile<karma::domain, Padding, Modifiers>::type
  235. padding_type;
  236. typedef padding_left_alignment<Subject, padding_type, Width> result_type;
  237. template <typename Terminal>
  238. result_type operator()(Terminal const& term, Subject const& subject
  239. , Modifiers const& modifiers) const
  240. {
  241. return result_type(subject
  242. , compile<karma::domain>(fusion::at_c<1>(term.args), modifiers)
  243. , fusion::at_c<0>(term.args));
  244. }
  245. };
  246. }}} // namespace boost::spirit::karma
  247. namespace boost { namespace spirit { namespace traits
  248. {
  249. ///////////////////////////////////////////////////////////////////////////
  250. template <typename Subject, typename Width>
  251. struct has_semantic_action<karma::simple_left_alignment<Subject, Width> >
  252. : unary_has_semantic_action<Subject> {};
  253. template <typename Subject, typename Padding, typename Width>
  254. struct has_semantic_action<
  255. karma::padding_left_alignment<Subject, Padding, Width> >
  256. : unary_has_semantic_action<Subject> {};
  257. ///////////////////////////////////////////////////////////////////////////
  258. template <typename Subject, typename Width, typename Attribute
  259. , typename Context, typename Iterator>
  260. struct handles_container<
  261. karma::simple_left_alignment<Subject, Width>, Attribute
  262. , Context, Iterator>
  263. : unary_handles_container<Subject, Attribute, Context, Iterator> {};
  264. template <typename Subject, typename Padding, typename Width
  265. , typename Attribute, typename Context, typename Iterator>
  266. struct handles_container<
  267. karma::padding_left_alignment<Subject, Padding, Width>
  268. , Attribute, Context, Iterator>
  269. : unary_handles_container<Subject, Attribute, Context, Iterator> {};
  270. }}}
  271. #endif