1 //  Copyright (c) 2001-2010 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 
6 #if !defined(COLUMNS_DEC_05_2009_0716PM)
7 #define COLUMNS_DEC_05_2009_0716PM
8 
9 #include <boost/spirit/include/karma_generate.hpp>
10 
11 ///////////////////////////////////////////////////////////////////////////////
12 // definition the place holder
13 namespace custom_generator
14 {
15     BOOST_SPIRIT_TERMINAL(columns);
16 }
17 
18 ///////////////////////////////////////////////////////////////////////////////
19 // implementation the enabler
20 namespace boost { namespace spirit
21 {
22     // We want custom_generator::columns to be usable as a directive only,
23     // and only for generator expressions (karma::domain).
24     template <>
25     struct use_directive<karma::domain, custom_generator::tag::columns>
26       : mpl::true_ {};
27 }}
28 
29 ///////////////////////////////////////////////////////////////////////////////
30 // implementation of the generator
31 namespace custom_generator
32 {
33     // special delimiter wrapping the original one while additionally emitting
34     // the column delimiter after each 5th invocation
35     template <typename Delimiter>
36     struct columns_delimiter
37     {
columns_delimitercustom_generator::columns_delimiter38         columns_delimiter(Delimiter const& delim)
39           : delimiter(delim), count(0) {}
40 
41         // This function is called during the actual delimiter output
42         template <typename OutputIterator, typename Context
43           , typename Delimiter_, typename Attribute>
generatecustom_generator::columns_delimiter44         bool generate(OutputIterator& sink, Context&, Delimiter_ const&
45           , Attribute const&) const
46         {
47             // first invoke the wrapped delimiter
48             if (!karma::delimit_out(sink, delimiter))
49                 return false;
50 
51             // now we count the number of invocations and emit the column
52             // delimiter after each 5th column
53             if ((++count % 5) == 0)
54                 *sink++ = '\n';
55             return true;
56         }
57 
58         // Generate a final column delimiter if the last invocation didn't
59         // emit one
60         template <typename OutputIterator>
final_delimit_outcustom_generator::columns_delimiter61         bool final_delimit_out(OutputIterator& sink) const
62         {
63             if (count % 5)
64                 *sink++ = '\n';
65             return true;
66         }
67 
68         Delimiter const& delimiter;   // wrapped delimiter
69         mutable unsigned int count;   // invocation counter
70     };
71 
72     // That's the actual columns generator
73     template <typename Subject>
74     struct simple_columns_generator
75       : boost::spirit::karma::unary_generator<
76             simple_columns_generator<Subject> >
77     {
78         // Define required output iterator properties
79         typedef typename Subject::properties properties;
80 
81         // Define the attribute type exposed by this parser component
82         template <typename Context, typename Iterator>
83         struct attribute
84           : boost::spirit::traits::attribute_of<Subject, Context, Iterator>
85         {};
86 
simple_columns_generatorcustom_generator::simple_columns_generator87         simple_columns_generator(Subject const& s)
88           : subject(s)
89         {}
90 
91         // This function is called during the actual output generation process.
92         // It dispatches to the embedded generator while supplying a new
93         // delimiter to use, wrapping the outer delimiter.
94         template <typename OutputIterator, typename Context
95           , typename Delimiter, typename Attribute>
generatecustom_generator::simple_columns_generator96         bool generate(OutputIterator& sink, Context& ctx
97           , Delimiter const& delimiter, Attribute const& attr) const
98         {
99             columns_delimiter<Delimiter> d(delimiter);
100             return subject.generate(sink, ctx, d, attr) && d.final_delimit_out(sink);
101         }
102 
103         // This function is called during error handling to create
104         // a human readable string for the error context.
105         template <typename Context>
whatcustom_generator::simple_columns_generator106         boost::spirit::info what(Context& ctx) const
107         {
108             return boost::spirit::info("columns", subject.what(ctx));
109         }
110 
111         Subject subject;
112     };
113 }
114 
115 ///////////////////////////////////////////////////////////////////////////////
116 // instantiation of the generator
117 namespace boost { namespace spirit { namespace karma
118 {
119     // This is the factory function object invoked in order to create
120     // an instance of our simple_columns_generator.
121     template <typename Subject, typename Modifiers>
122     struct make_directive<custom_generator::tag::columns, Subject, Modifiers>
123     {
124         typedef custom_generator::simple_columns_generator<Subject> result_type;
125 
operator ()boost::spirit::karma::make_directive126         result_type operator()(unused_type, Subject const& s, unused_type) const
127         {
128             return result_type(s);
129         }
130     };
131 }}}
132 
133 #endif
134