1
// Copyright (c) 2001-2011 Hartmut Kaiser
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)
6
#if !defined(BOOST_SPIRIT_KARMA_CENTER_ALIGNMENT_FEB_27_2007_1216PM)
7
#define BOOST_SPIRIT_KARMA_CENTER_ALIGNMENT_FEB_27_2007_1216PM
13
#include <boost/spirit/home/karma/meta_compiler.hpp>
14
#include <boost/spirit/home/karma/generator.hpp>
15
#include <boost/spirit/home/karma/domain.hpp>
16
#include <boost/spirit/home/karma/detail/output_iterator.hpp>
17
#include <boost/spirit/home/karma/detail/default_width.hpp>
18
#include <boost/spirit/home/karma/delimit_out.hpp>
19
#include <boost/spirit/home/karma/auxiliary/lazy.hpp>
20
#include <boost/spirit/home/support/unused.hpp>
21
#include <boost/spirit/home/support/common_terminals.hpp>
22
#include <boost/spirit/home/support/has_semantic_action.hpp>
23
#include <boost/spirit/home/support/handles_container.hpp>
24
#include <boost/spirit/home/karma/detail/attributes.hpp>
25
#include <boost/spirit/home/support/info.hpp>
26
#include <boost/spirit/home/support/unused.hpp>
27
#include <boost/fusion/include/at.hpp>
28
#include <boost/fusion/include/vector.hpp>
29
#include <boost/lexical_cast.hpp>
30
#include <boost/integer_traits.hpp>
31
#include <boost/mpl/bool.hpp>
32
#include <boost/utility/enable_if.hpp>
33
#include <boost/detail/workaround.hpp>
35
///////////////////////////////////////////////////////////////////////////////
36
namespace boost { namespace spirit
38
///////////////////////////////////////////////////////////////////////////
40
///////////////////////////////////////////////////////////////////////////
44
struct use_directive<karma::domain, tag::center>
47
// enables center(d)[g] and center(w)[g], where d is a generator
48
// and w is a maximum width
50
struct use_directive<karma::domain
51
, terminal_ex<tag::center, fusion::vector1<T> > >
54
// enables *lazy* delimit(d)[g], where d provides a generator
56
struct use_lazy_directive<karma::domain, tag::center, 1>
59
// enables center(w, d)[g], where d is a generator and w is a maximum
61
template <typename Width, typename Padding>
62
struct use_directive<karma::domain
63
, terminal_ex<tag::center, fusion::vector2<Width, Padding> > >
64
: spirit::traits::matches<karma::domain, Padding> {};
66
// enables *lazy* delimit(w, d)[g], where d provides a generator and w is
69
struct use_lazy_directive<karma::domain, tag::center, 2>
74
///////////////////////////////////////////////////////////////////////////////
75
namespace boost { namespace spirit { namespace karma
78
using spirit::center_type;
82
///////////////////////////////////////////////////////////////////////
83
// The center_generate template function is used for all the
84
// different flavors of the center[] directive.
85
///////////////////////////////////////////////////////////////////////
86
template <typename OutputIterator, typename Context, typename Delimiter,
87
typename Attribute, typename Embedded, typename Padding>
89
center_generate(OutputIterator& sink, Context& ctx,
90
Delimiter const& d, Attribute const& attr, Embedded const& e,
91
unsigned int const width, Padding const& p)
93
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
94
e; // suppresses warning: C4100: 'e' : unreferenced formal parameter
96
// wrap the given output iterator to allow left padding
97
detail::enable_buffering<OutputIterator> buffering(sink, width);
100
// first generate the embedded output
102
detail::disable_counting<OutputIterator> nocounting(sink);
103
r = e.generate(sink, ctx, d, attr);
104
} // re-enable counting
106
buffering.disable(); // do not perform buffering any more
108
// generate the left padding
109
detail::enable_counting<OutputIterator> counting(sink);
111
std::size_t const pre = width - (buffering.buffer_size() + width)/2;
112
while (r && counting.count() < pre)
113
r = p.generate(sink, ctx, unused, unused);
116
// copy the embedded output to the target output iterator
117
buffering.buffer_copy();
119
// generate the right padding
120
while (r && counting.count() < width)
121
r = p.generate(sink, ctx, unused, unused);
127
///////////////////////////////////////////////////////////////////////////
128
// The simple left alignment directive is used for center[...]
129
// generators. It uses default values for the generated width (defined via
130
// the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant) and for the padding
131
// generator (always spaces).
132
///////////////////////////////////////////////////////////////////////////
133
template <typename Subject, typename Width = detail::default_width>
134
struct simple_center_alignment
135
: unary_generator<simple_center_alignment<Subject, Width> >
137
typedef Subject subject_type;
140
generator_properties::countingbuffer | subject_type::properties::value
143
template <typename Context, typename Iterator>
145
: traits::attribute_of<subject_type, Context, Iterator>
148
simple_center_alignment(Subject const& subject, Width width = Width())
149
: subject(subject), width(width) {}
151
template <typename OutputIterator, typename Context, typename Delimiter
152
, typename Attribute>
153
bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d
154
, Attribute const& attr) const
156
return detail::center_generate(sink, ctx, d, attr,
157
subject, width, compile<karma::domain>(' '));
160
template <typename Context>
161
info what(Context& context) const
163
return info("center", subject.what(context));
170
///////////////////////////////////////////////////////////////////////////
171
// The left alignment directive with padding, is used for generators like
172
// center(padding)[...], where padding is a arbitrary generator
173
// expression. It uses a default value for the generated width (defined
174
// via the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant).
175
///////////////////////////////////////////////////////////////////////////
176
template <typename Subject, typename Padding
177
, typename Width = detail::default_width>
178
struct padding_center_alignment
179
: unary_generator<padding_center_alignment<Subject, Padding, Width> >
181
typedef Subject subject_type;
182
typedef Padding padding_type;
185
generator_properties::countingbuffer |
186
subject_type::properties::value | padding_type::properties::value
189
template <typename Context, typename Iterator>
191
: traits::attribute_of<Subject, Context, Iterator>::type
194
padding_center_alignment(Subject const& subject, Padding const& padding
195
, Width width = Width())
196
: subject(subject), padding(padding), width(width) {}
198
template <typename OutputIterator, typename Context, typename Delimiter
199
, typename Attribute>
200
bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d
201
, Attribute const& attr) const
203
return detail::center_generate(sink, ctx, d, attr,
204
subject, width, padding);
207
template <typename Context>
208
info what(Context& context) const
210
return info("center", subject.what(context));
218
///////////////////////////////////////////////////////////////////////////
219
// Generator generators: make_xxx function (objects)
220
///////////////////////////////////////////////////////////////////////////
222
// creates center[] directive generator
223
template <typename Subject, typename Modifiers>
224
struct make_directive<tag::center, Subject, Modifiers>
226
typedef simple_center_alignment<Subject> result_type;
227
result_type operator()(unused_type, Subject const& subject
230
return result_type(subject);
234
// creates center(width)[] directive generator
235
template <typename Width, typename Subject, typename Modifiers>
236
struct make_directive<
237
terminal_ex<tag::center, fusion::vector1<Width> >
239
, typename enable_if_c< integer_traits<Width>::is_integral >::type>
241
typedef simple_center_alignment<Subject, Width> result_type;
243
template <typename Terminal>
244
result_type operator()(Terminal const& term, Subject const& subject
247
return result_type(subject, fusion::at_c<0>(term.args));
251
// creates center(pad)[] directive generator
252
template <typename Padding, typename Subject, typename Modifiers>
253
struct make_directive<
254
terminal_ex<tag::center, fusion::vector1<Padding> >
256
, typename enable_if<
258
spirit::traits::matches<karma::domain, Padding>,
259
mpl::not_<mpl::bool_<integer_traits<Padding>::is_integral> >
264
result_of::compile<karma::domain, Padding, Modifiers>::type
267
typedef padding_center_alignment<Subject, padding_type> result_type;
269
template <typename Terminal>
270
result_type operator()(Terminal const& term, Subject const& subject
271
, Modifiers const& modifiers) const
273
return result_type(subject
274
, compile<karma::domain>(fusion::at_c<0>(term.args), modifiers));
278
// creates center(width, pad)[] directive generator
279
template <typename Width, typename Padding, typename Subject
280
, typename Modifiers>
281
struct make_directive<
282
terminal_ex<tag::center, fusion::vector2<Width, Padding> >
283
, Subject, Modifiers>
286
result_of::compile<karma::domain, Padding, Modifiers>::type
289
typedef padding_center_alignment<Subject, padding_type, Width> result_type;
291
template <typename Terminal>
292
result_type operator()(Terminal const& term, Subject const& subject
293
, Modifiers const& modifiers) const
295
return result_type(subject
296
, compile<karma::domain>(fusion::at_c<1>(term.args), modifiers)
297
, fusion::at_c<0>(term.args));
301
}}} // namespace boost::spirit::karma
303
namespace boost { namespace spirit { namespace traits
305
///////////////////////////////////////////////////////////////////////////
306
template <typename Subject, typename Width>
307
struct has_semantic_action<karma::simple_center_alignment<Subject, Width> >
308
: unary_has_semantic_action<Subject> {};
310
template <typename Subject, typename Padding, typename Width>
311
struct has_semantic_action<
312
karma::padding_center_alignment<Subject, Padding, Width> >
313
: unary_has_semantic_action<Subject> {};
315
///////////////////////////////////////////////////////////////////////////
316
template <typename Subject, typename Width, typename Attribute
317
, typename Context, typename Iterator>
318
struct handles_container<
319
karma::simple_center_alignment<Subject, Width>, Attribute
321
: unary_handles_container<Subject, Attribute, Context, Iterator> {};
323
template <typename Subject, typename Padding, typename Width
324
, typename Attribute, typename Context, typename Iterator>
325
struct handles_container<
326
karma::padding_center_alignment<Subject, Padding, Width>
327
, Attribute, Context, Iterator>
328
: unary_handles_container<Subject, Attribute, Context, Iterator> {};