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 6 #if !defined(BOOST_SPIRIT_KARMA_COLUMNS_DEC_03_2009_0736AM) 7 #define BOOST_SPIRIT_KARMA_COLUMNS_DEC_03_2009_0736AM 8 9 #if defined(_MSC_VER) 10 #pragma once 11 #endif 12 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/delimit_out.hpp> 17 #include <boost/spirit/home/karma/detail/default_width.hpp> 18 #include <boost/spirit/home/karma/auxiliary/eol.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/fusion/include/at.hpp> 27 #include <boost/fusion/include/vector.hpp> 28 #include <boost/integer_traits.hpp> 29 30 namespace boost { namespace spirit 31 { 32 /////////////////////////////////////////////////////////////////////////// 33 // Enablers 34 /////////////////////////////////////////////////////////////////////////// 35 template <> 36 struct use_directive<karma::domain, tag::columns> // enables columns[] 37 : mpl::true_ {}; 38 39 // enables columns(c)[g], where c provides the number of require columns 40 template <typename T> 41 struct use_directive<karma::domain 42 , terminal_ex<tag::columns, fusion::vector1<T> > > 43 : mpl::true_ {}; 44 45 // enables *lazy* columns(c)[g] 46 template <> 47 struct use_lazy_directive<karma::domain, tag::columns, 1> 48 : mpl::true_ {}; 49 50 // enables columns(c, d)[g], where c provides the number of require columns 51 // and d is the custom column-delimiter (default is karma::endl) 52 template <typename T1, typename T2> 53 struct use_directive<karma::domain 54 , terminal_ex<tag::columns, fusion::vector2<T1, T2> > > 55 : boost::spirit::traits::matches<karma::domain, T2> {}; 56 57 // enables *lazy* columns(c, d)[g] 58 template <> 59 struct use_lazy_directive<karma::domain, tag::columns, 2> 60 : mpl::true_ {}; 61 62 }} 63 64 namespace boost { namespace spirit { namespace karma 65 { 66 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 67 using spirit::columns; 68 #endif 69 using spirit::columns_type; 70 71 namespace detail 72 { 73 template <typename Delimiter, typename ColumnDelimiter> 74 struct columns_delimiter 75 { columns_delimiterboost::spirit::karma::detail::columns_delimiter76 columns_delimiter(Delimiter const& delim 77 , ColumnDelimiter const& cdelim, unsigned int const numcols) 78 : delimiter(delim), column_delimiter(cdelim) 79 , numcolumns(numcols), count(0) {} 80 81 template <typename OutputIterator, typename Context 82 , typename Delimiter_, typename Attribute> generateboost::spirit::karma::detail::columns_delimiter83 bool generate(OutputIterator& sink, Context&, Delimiter_ const& 84 , Attribute const&) const 85 { 86 // first invoke the embedded delimiter 87 if (!karma::delimit_out(sink, delimiter)) 88 return false; 89 90 // now we count the number of invocations and emit the column 91 // delimiter if needed 92 if ((++count % numcolumns) == 0) 93 return karma::delimit_out(sink, column_delimiter); 94 return true; 95 } 96 97 // generate a final column delimiter if the last invocation didn't 98 // emit one 99 template <typename OutputIterator> delimit_outboost::spirit::karma::detail::columns_delimiter100 bool delimit_out(OutputIterator& sink) const 101 { 102 if (count % numcolumns) 103 return karma::delimit_out(sink, column_delimiter); 104 return true; 105 } 106 107 Delimiter const& delimiter; 108 ColumnDelimiter const& column_delimiter; 109 unsigned int const numcolumns; 110 mutable unsigned int count; 111 112 // silence MSVC warning C4512: assignment operator could not be generated 113 BOOST_DELETED_FUNCTION(columns_delimiter& operator= (columns_delimiter const&)) 114 }; 115 } 116 117 /////////////////////////////////////////////////////////////////////////// 118 // The columns_generator is used for columns(c, d)[...] directives. 119 /////////////////////////////////////////////////////////////////////////// 120 template <typename Subject, typename NumColumns, typename ColumnsDelimiter> 121 struct columns_generator 122 : unary_generator<columns_generator<Subject, NumColumns, ColumnsDelimiter> > 123 { 124 typedef Subject subject_type; 125 typedef ColumnsDelimiter delimiter_type; 126 127 typedef mpl::int_< 128 subject_type::properties::value | delimiter_type::properties::value 129 > properties; 130 131 template <typename Context, typename Iterator> 132 struct attribute 133 : traits::attribute_of<subject_type, Context, Iterator> 134 {}; 135 columns_generatorboost::spirit::karma::columns_generator136 columns_generator(Subject const& subject, NumColumns const& cols 137 , ColumnsDelimiter const& cdelimiter) 138 : subject(subject), numcolumns(cols), column_delimiter(cdelimiter) 139 { 140 // having zero number of columns doesn't make any sense 141 BOOST_ASSERT(numcolumns > 0); 142 } 143 144 template <typename OutputIterator, typename Context 145 , typename Delimiter, typename Attribute> generateboost::spirit::karma::columns_generator146 bool generate(OutputIterator& sink, Context& ctx 147 , Delimiter const& delimiter, Attribute const& attr) const 148 { 149 // The columns generator dispatches to the embedded generator 150 // while supplying a new delimiter to use, wrapping the outer 151 // delimiter. 152 typedef detail::columns_delimiter< 153 Delimiter, ColumnsDelimiter 154 > columns_delimiter_type; 155 156 columns_delimiter_type d(delimiter, column_delimiter, numcolumns); 157 return subject.generate(sink, ctx, d, attr) && d.delimit_out(sink); 158 } 159 160 template <typename Context> whatboost::spirit::karma::columns_generator161 info what(Context& context) const 162 { 163 return info("columns", subject.what(context)); 164 } 165 166 Subject subject; 167 NumColumns numcolumns; 168 ColumnsDelimiter column_delimiter; 169 }; 170 171 /////////////////////////////////////////////////////////////////////////// 172 // Generator generators: make_xxx function (objects) 173 /////////////////////////////////////////////////////////////////////////// 174 175 // creates columns[] directive 176 template <typename Subject, typename Modifiers> 177 struct make_directive<tag::columns, Subject, Modifiers> 178 { 179 typedef typename 180 result_of::compile<karma::domain, eol_type, Modifiers>::type 181 columns_delimiter_type; 182 typedef columns_generator< 183 Subject, detail::default_columns, columns_delimiter_type> 184 result_type; 185 operator ()boost::spirit::karma::make_directive186 result_type operator()(unused_type, Subject const& subject 187 , unused_type) const 188 { 189 #if defined(BOOST_SPIRIT_NO_PREDEFINED_TERMINALS) 190 eol_type const eol = eol_type(); 191 #endif 192 return result_type(subject, detail::default_columns() 193 , compile<karma::domain>(eol)); 194 } 195 }; 196 197 // creates columns(c)[] directive generator (c is the number of columns) 198 template <typename T, typename Subject, typename Modifiers> 199 struct make_directive< 200 terminal_ex<tag::columns, fusion::vector1<T> > 201 , Subject, Modifiers 202 , typename enable_if_c<integer_traits<T>::is_integral>::type> 203 { 204 typedef typename 205 result_of::compile<karma::domain, eol_type, Modifiers>::type 206 columns_delimiter_type; 207 typedef columns_generator< 208 Subject, T, columns_delimiter_type 209 > result_type; 210 211 template <typename Terminal> operator ()boost::spirit::karma::make_directive212 result_type operator()(Terminal const& term, Subject const& subject 213 , unused_type) const 214 { 215 #if defined(BOOST_SPIRIT_NO_PREDEFINED_TERMINALS) 216 eol_type const eol = eol_type(); 217 #endif 218 return result_type(subject, fusion::at_c<0>(term.args) 219 , compile<karma::domain>(eol)); 220 } 221 }; 222 223 // creates columns(d)[] directive generator (d is the column delimiter) 224 template <typename T, typename Subject, typename Modifiers> 225 struct make_directive< 226 terminal_ex<tag::columns, fusion::vector1<T> > 227 , Subject, Modifiers 228 , typename enable_if< 229 mpl::and_< 230 spirit::traits::matches<karma::domain, T>, 231 mpl::not_<mpl::bool_<integer_traits<T>::is_integral> > 232 > 233 >::type> 234 { 235 typedef typename 236 result_of::compile<karma::domain, T, Modifiers>::type 237 columns_delimiter_type; 238 typedef columns_generator< 239 Subject, detail::default_columns, columns_delimiter_type 240 > result_type; 241 242 template <typename Terminal> operator ()boost::spirit::karma::make_directive243 result_type operator()(Terminal const& term, Subject const& subject 244 , unused_type) const 245 { 246 return result_type(subject, detail::default_columns() 247 , compile<karma::domain>(fusion::at_c<0>(term.args))); 248 } 249 }; 250 251 // creates columns(c, d)[] directive generator (c is the number of columns 252 // and d is the column delimiter) 253 template <typename T1, typename T2, typename Subject, typename Modifiers> 254 struct make_directive< 255 terminal_ex<tag::columns, fusion::vector2<T1, T2> > 256 , Subject, Modifiers> 257 { 258 typedef typename 259 result_of::compile<karma::domain, T2, Modifiers>::type 260 columns_delimiter_type; 261 typedef columns_generator< 262 Subject, T1, columns_delimiter_type 263 > result_type; 264 265 template <typename Terminal> operator ()boost::spirit::karma::make_directive266 result_type operator()(Terminal const& term, Subject const& subject 267 , unused_type) const 268 { 269 return result_type (subject, fusion::at_c<0>(term.args) 270 , compile<karma::domain>(fusion::at_c<1>(term.args))); 271 } 272 }; 273 274 }}} 275 276 namespace boost { namespace spirit { namespace traits 277 { 278 /////////////////////////////////////////////////////////////////////////// 279 template <typename Subject, typename T1, typename T2> 280 struct has_semantic_action<karma::columns_generator<Subject, T1, T2> > 281 : unary_has_semantic_action<Subject> {}; 282 283 /////////////////////////////////////////////////////////////////////////// 284 template <typename Subject, typename T1, typename T2, typename Attribute 285 , typename Context, typename Iterator> 286 struct handles_container< 287 karma::columns_generator<Subject, T1, T2>, Attribute 288 , Context, Iterator> 289 : unary_handles_container<Subject, Attribute, Context, Iterator> {}; 290 }}} 291 292 #endif 293