center_alignment.hpp 13 KB

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