// Copyright (c) 2001-2010 Hartmut Kaiser // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #if !defined(BOOST_SPIRIT_KARMA_COLUMNS_DEC_03_2009_0736AM) #define BOOST_SPIRIT_KARMA_COLUMNS_DEC_03_2009_0736AM #if defined(_MSC_VER) #pragma once #endif #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace spirit { /////////////////////////////////////////////////////////////////////////// // Enablers /////////////////////////////////////////////////////////////////////////// template <> struct use_directive // enables columns[] : mpl::true_ {}; // enables columns(c)[g], where c provides the number of require columns template struct use_directive > > : mpl::true_ {}; // enables *lazy* columns(c)[g] template <> struct use_lazy_directive : mpl::true_ {}; // enables columns(c, d)[g], where c provides the number of require columns // and d is the custom column-delimiter (default is karma::endl) template struct use_directive > > : boost::spirit::traits::matches {}; // enables *lazy* columns(c, d)[g] template <> struct use_lazy_directive : mpl::true_ {}; }} namespace boost { namespace spirit { namespace karma { using spirit::columns; using spirit::columns_type; namespace detail { template struct columns_delimiter { columns_delimiter(Delimiter const& delim , ColumnDelimiter const& cdelim, unsigned int const numcols) : delimiter(delim), column_delimiter(cdelim) , numcolumns(numcols), count(0) {} template bool generate(OutputIterator& sink, Context&, Delimiter_ const& , Attribute const&) const { // first invoke the embedded delimiter if (!karma::delimit_out(sink, delimiter)) return false; // now we count the number of invocations and emit the column // delimiter if needed if ((++count % numcolumns) == 0) return karma::delimit_out(sink, column_delimiter); return true; } // generate a final column delimiter if the last invocation didn't // emit one template bool delimit_out(OutputIterator& sink) const { if (count % numcolumns) return karma::delimit_out(sink, column_delimiter); return true; } Delimiter const& delimiter; ColumnDelimiter const& column_delimiter; unsigned int const numcolumns; mutable unsigned int count; private: // silence MSVC warning C4512: assignment operator could not be generated columns_delimiter& operator= (columns_delimiter const&); }; } /////////////////////////////////////////////////////////////////////////// // The columns_generator is used for columns(c, d)[...] directives. /////////////////////////////////////////////////////////////////////////// template struct columns_generator : unary_generator > { typedef Subject subject_type; typedef ColumnsDelimiter delimiter_type; typedef mpl::int_< subject_type::properties::value | delimiter_type::properties::value > properties; template struct attribute : traits::attribute_of {}; columns_generator(Subject const& subject, NumColumns const& cols , ColumnsDelimiter const& cdelimiter) : subject(subject), numcolumns(cols), column_delimiter(cdelimiter) { // having zero number of columns doesn't make any sense BOOST_ASSERT(numcolumns > 0); } template bool generate(OutputIterator& sink, Context& ctx , Delimiter const& delimiter, Attribute const& attr) const { // The columns generator dispatches to the embedded generator // while supplying a new delimiter to use, wrapping the outer // delimiter. typedef detail::columns_delimiter< Delimiter, ColumnsDelimiter > columns_delimiter_type; columns_delimiter_type d(delimiter, column_delimiter, numcolumns); return subject.generate(sink, ctx, d, attr) && d.delimit_out(sink); } template info what(Context& context) const { return info("columns", subject.what(context)); } Subject subject; NumColumns numcolumns; ColumnsDelimiter column_delimiter; }; /////////////////////////////////////////////////////////////////////////// // Generator generators: make_xxx function (objects) /////////////////////////////////////////////////////////////////////////// // creates columns[] directive template struct make_directive { typedef typename result_of::compile::type columns_delimiter_type; typedef columns_generator< Subject, detail::default_columns, columns_delimiter_type> result_type; result_type operator()(unused_type, Subject const& subject , unused_type) const { return result_type(subject, detail::default_columns() , compile(eol)); } }; // creates columns(c)[] directive generator (c is the number of columns) template struct make_directive< terminal_ex > , Subject, Modifiers , typename enable_if_c::is_integral>::type> { typedef typename result_of::compile::type columns_delimiter_type; typedef columns_generator< Subject, T, columns_delimiter_type > result_type; template result_type operator()(Terminal const& term, Subject const& subject , unused_type) const { return result_type(subject, fusion::at_c<0>(term.args) , compile(eol)); } }; // creates columns(d)[] directive generator (d is the column delimiter) template struct make_directive< terminal_ex > , Subject, Modifiers , typename enable_if< mpl::and_< spirit::traits::matches, mpl::not_::is_integral> > > >::type> { typedef typename result_of::compile::type columns_delimiter_type; typedef columns_generator< Subject, detail::default_columns, columns_delimiter_type > result_type; template result_type operator()(Terminal const& term, Subject const& subject , unused_type) const { return result_type(subject, detail::default_columns() , compile(fusion::at_c<0>(term.args))); } }; // creates columns(c, d)[] directive generator (c is the number of columns // and d is the column delimiter) template struct make_directive< terminal_ex > , Subject, Modifiers> { typedef typename result_of::compile::type columns_delimiter_type; typedef columns_generator< Subject, T1, columns_delimiter_type > result_type; template result_type operator()(Terminal const& term, Subject const& subject , unused_type) const { return result_type (subject, fusion::at_c<0>(term.args) , compile(fusion::at_c<1>(term.args))); } }; }}} namespace boost { namespace spirit { namespace traits { template struct has_semantic_action > : unary_has_semantic_action {}; }}} #endif