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