right_alignment.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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_RIGHT_ALIGNMENT_FEB_27_2007_1216PM)
  6. #define BOOST_SPIRIT_KARMA_RIGHT_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/support/has_semantic_action.hpp>
  21. #include <boost/spirit/home/support/handles_container.hpp>
  22. #include <boost/spirit/home/karma/detail/attributes.hpp>
  23. #include <boost/spirit/home/support/info.hpp>
  24. #include <boost/spirit/home/support/unused.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 right_align[]
  38. template <>
  39. struct use_directive<karma::domain, tag::right_align>
  40. : mpl::true_ {};
  41. // enables right_align(d)[g] and right_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::right_align, fusion::vector1<T> > >
  46. : mpl::true_ {};
  47. // enables *lazy* right_align(d)[g], where d provides a generator
  48. template <>
  49. struct use_lazy_directive<karma::domain, tag::right_align, 1>
  50. : mpl::true_ {};
  51. // enables right_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::right_align, fusion::vector2<Width, Padding> > >
  56. : spirit::traits::matches<karma::domain, Padding> {};
  57. // enables *lazy* right_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::right_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::right_align;
  68. #endif
  69. using spirit::right_align_type;
  70. namespace detail
  71. {
  72. ///////////////////////////////////////////////////////////////////////
  73. // The right_align_generate template function is used for all the
  74. // different flavors of the right_align[] directive.
  75. ///////////////////////////////////////////////////////////////////////
  76. template <typename OutputIterator, typename Context, typename Delimiter,
  77. typename Attribute, typename Embedded, typename Padding>
  78. inline static bool
  79. right_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 left padding
  87. detail::enable_buffering<OutputIterator> buffering(sink, width);
  88. bool r = false;
  89. // first generate the embedded output
  90. {
  91. detail::disable_counting<OutputIterator> nocounting(sink);
  92. r = e.generate(sink, ctx, d, attr);
  93. } // re-enable counting
  94. buffering.disable(); // do not perform buffering any more
  95. // generate the left padding
  96. detail::enable_counting<OutputIterator> counting(sink, buffering.buffer_size());
  97. while(r && counting.count() < width)
  98. r = p.generate(sink, ctx, unused, unused);
  99. // copy the buffered output to the target output iterator
  100. if (r)
  101. buffering.buffer_copy();
  102. return r;
  103. }
  104. }
  105. ///////////////////////////////////////////////////////////////////////////
  106. // The simple left alignment directive is used for right_align[...]
  107. // generators. It uses default values for the generated width (defined via
  108. // the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant) and for the padding
  109. // generator (always spaces).
  110. ///////////////////////////////////////////////////////////////////////////
  111. template <typename Subject, typename Width = detail::default_width>
  112. struct simple_right_alignment
  113. : unary_generator<simple_right_alignment<Subject, Width> >
  114. {
  115. typedef Subject subject_type;
  116. typedef mpl::int_<
  117. generator_properties::countingbuffer | subject_type::properties::value
  118. > properties;
  119. template <typename Context, typename Iterator>
  120. struct attribute
  121. : traits::attribute_of<subject_type, Context, Iterator>
  122. {};
  123. simple_right_alignment(Subject const& subject, Width width = Width())
  124. : subject(subject), width(width) {}
  125. template <typename OutputIterator, typename Context, typename Delimiter
  126. , typename Attribute>
  127. bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d
  128. , Attribute const& attr) const
  129. {
  130. return detail::right_align_generate(sink, ctx, d, attr,
  131. subject, width, compile<karma::domain>(' '));
  132. }
  133. template <typename Context>
  134. info what(Context& context) const
  135. {
  136. return info("right_align", subject.what(context));
  137. }
  138. Subject subject;
  139. Width width;
  140. };
  141. ///////////////////////////////////////////////////////////////////////////
  142. // The left alignment directive with padding, is used for generators like
  143. // right_align(padding)[...], where padding is a arbitrary generator
  144. // expression. It uses a default value for the generated width (defined
  145. // via the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant).
  146. ///////////////////////////////////////////////////////////////////////////
  147. template <typename Subject, typename Padding
  148. , typename Width = detail::default_width>
  149. struct padding_right_alignment
  150. : unary_generator<padding_right_alignment<Subject, Padding, Width> >
  151. {
  152. typedef Subject subject_type;
  153. typedef Padding padding_type;
  154. typedef mpl::int_<
  155. generator_properties::countingbuffer |
  156. subject_type::properties::value | padding_type::properties::value
  157. > properties;
  158. template <typename Context, typename Iterator>
  159. struct attribute
  160. : traits::attribute_of<subject_type, Context, Iterator>
  161. {};
  162. padding_right_alignment(Subject const& subject, Padding const& padding
  163. , Width width = Width())
  164. : subject(subject), padding(padding), width(width) {}
  165. template <typename OutputIterator, typename Context, typename Delimiter
  166. , typename Attribute>
  167. bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d
  168. , Attribute const& attr) const
  169. {
  170. return detail::right_align_generate(sink, ctx, d, attr,
  171. subject, width, padding);
  172. }
  173. template <typename Context>
  174. info what(Context& context) const
  175. {
  176. return info("right_align", subject.what(context));
  177. }
  178. Subject subject;
  179. Padding padding;
  180. Width width;
  181. };
  182. ///////////////////////////////////////////////////////////////////////////
  183. // Generator generators: make_xxx function (objects)
  184. ///////////////////////////////////////////////////////////////////////////
  185. // creates right_align[] directive generator
  186. template <typename Subject, typename Modifiers>
  187. struct make_directive<tag::right_align, Subject, Modifiers>
  188. {
  189. typedef simple_right_alignment<Subject> result_type;
  190. result_type operator()(unused_type, Subject const& subject
  191. , unused_type) const
  192. {
  193. return result_type(subject);
  194. }
  195. };
  196. // creates right_align(width)[] directive generator
  197. template <typename Width, typename Subject, typename Modifiers>
  198. struct make_directive<
  199. terminal_ex<tag::right_align, fusion::vector1<Width> >
  200. , Subject, Modifiers
  201. , typename enable_if_c< integer_traits<Width>::is_integral >::type>
  202. {
  203. typedef simple_right_alignment<Subject, Width> result_type;
  204. template <typename Terminal>
  205. result_type operator()(Terminal const& term, Subject const& subject
  206. , unused_type) const
  207. {
  208. return result_type(subject, fusion::at_c<0>(term.args));
  209. }
  210. };
  211. // creates right_align(pad)[] directive generator
  212. template <typename Padding, typename Subject, typename Modifiers>
  213. struct make_directive<
  214. terminal_ex<tag::right_align, fusion::vector1<Padding> >
  215. , Subject, Modifiers
  216. , typename enable_if<
  217. mpl::and_<
  218. spirit::traits::matches<karma::domain, Padding>,
  219. mpl::not_<mpl::bool_<integer_traits<Padding>::is_integral> >
  220. >
  221. >::type>
  222. {
  223. typedef typename
  224. result_of::compile<karma::domain, Padding, Modifiers>::type
  225. padding_type;
  226. typedef padding_right_alignment<Subject, padding_type> result_type;
  227. template <typename Terminal>
  228. result_type operator()(Terminal const& term, Subject const& subject
  229. , Modifiers const& modifiers) const
  230. {
  231. return result_type(subject
  232. , compile<karma::domain>(fusion::at_c<0>(term.args), modifiers));
  233. }
  234. };
  235. // creates right_align(width, pad)[] directive generator
  236. template <typename Width, typename Padding, typename Subject
  237. , typename Modifiers>
  238. struct make_directive<
  239. terminal_ex<tag::right_align, fusion::vector2<Width, Padding> >
  240. , Subject, Modifiers>
  241. {
  242. typedef typename
  243. result_of::compile<karma::domain, Padding, Modifiers>::type
  244. padding_type;
  245. typedef padding_right_alignment<Subject, padding_type, Width> result_type;
  246. template <typename Terminal>
  247. result_type operator()(Terminal const& term, Subject const& subject
  248. , Modifiers const& modifiers) const
  249. {
  250. return result_type(subject
  251. , compile<karma::domain>(fusion::at_c<1>(term.args), modifiers)
  252. , fusion::at_c<0>(term.args));
  253. }
  254. };
  255. }}} // namespace boost::spirit::karma
  256. namespace boost { namespace spirit { namespace traits
  257. {
  258. ///////////////////////////////////////////////////////////////////////////
  259. template <typename Subject, typename Width>
  260. struct has_semantic_action<karma::simple_right_alignment<Subject, Width> >
  261. : unary_has_semantic_action<Subject> {};
  262. template <typename Subject, typename Padding, typename Width>
  263. struct has_semantic_action<
  264. karma::padding_right_alignment<Subject, Padding, Width> >
  265. : unary_has_semantic_action<Subject> {};
  266. ///////////////////////////////////////////////////////////////////////////
  267. template <typename Subject, typename Width, typename Attribute
  268. , typename Context, typename Iterator>
  269. struct handles_container<
  270. karma::simple_right_alignment<Subject, Width>
  271. , Attribute, Context, Iterator>
  272. : unary_handles_container<Subject, Attribute, Context, Iterator> {};
  273. template <typename Subject, typename Padding, typename Width
  274. , typename Attribute, typename Context, typename Iterator>
  275. struct handles_container<
  276. karma::padding_right_alignment<Subject, Padding, Width>
  277. , Attribute, Context, Iterator>
  278. : unary_handles_container<Subject, Attribute, Context, Iterator> {};
  279. }}}
  280. #endif