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_LEFT_ALIGNMENT_FEB_27_2007_1216PM) 7 #define BOOST_SPIRIT_KARMA_LEFT_ALIGNMENT_FEB_27_2007_1216PM 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/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/karma/detail/attributes.hpp> 23 #include <boost/spirit/home/support/info.hpp> 24 #include <boost/spirit/home/support/unused.hpp> 25 #include <boost/spirit/home/support/has_semantic_action.hpp> 26 #include <boost/spirit/home/support/handles_container.hpp> 27 #include <boost/fusion/include/at.hpp> 28 #include <boost/fusion/include/vector.hpp> 29 #include <boost/integer_traits.hpp> 30 #include <boost/mpl/bool.hpp> 31 #include <boost/utility/enable_if.hpp> 32 #include <boost/detail/workaround.hpp> 33 34 /////////////////////////////////////////////////////////////////////////////// 35 namespace boost { namespace spirit 36 { 37 /////////////////////////////////////////////////////////////////////////// 38 // Enablers 39 /////////////////////////////////////////////////////////////////////////// 40 41 // enables left_align[] 42 template <> 43 struct use_directive<karma::domain, tag::left_align> 44 : mpl::true_ {}; 45 46 // enables left_align(d)[g] and left_align(w)[g], where d is a generator 47 // and w is a maximum width 48 template <typename T> 49 struct use_directive<karma::domain 50 , terminal_ex<tag::left_align, fusion::vector1<T> > > 51 : mpl::true_ {}; 52 53 // enables *lazy* left_align(d)[g], where d provides a generator 54 template <> 55 struct use_lazy_directive<karma::domain, tag::left_align, 1> 56 : mpl::true_ {}; 57 58 // enables left_align(w, d)[g], where d is a generator and w is a maximum 59 // width 60 template <typename Width, typename Padding> 61 struct use_directive<karma::domain 62 , terminal_ex<tag::left_align, fusion::vector2<Width, Padding> > > 63 : spirit::traits::matches<karma::domain, Padding> {}; 64 65 // enables *lazy* left_align(w, d)[g], where d provides a generator and w 66 // is a maximum width 67 template <> 68 struct use_lazy_directive<karma::domain, tag::left_align, 2> 69 : mpl::true_ {}; 70 71 }} 72 73 /////////////////////////////////////////////////////////////////////////////// 74 namespace boost { namespace spirit { namespace karma 75 { 76 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 77 using spirit::left_align; 78 #endif 79 using spirit::left_align_type; 80 81 namespace detail 82 { 83 /////////////////////////////////////////////////////////////////////// 84 // The left_align_generate template function is used for all the 85 // different flavors of the left_align[] directive. 86 /////////////////////////////////////////////////////////////////////// 87 template <typename OutputIterator, typename Context, typename Delimiter, 88 typename Attribute, typename Embedded, typename Padding> 89 inline static bool left_align_generate(OutputIterator & sink,Context & ctx,Delimiter const & d,Attribute const & attr,Embedded const & e,unsigned int const width,Padding const & p)90 left_align_generate(OutputIterator& sink, Context& ctx, 91 Delimiter const& d, Attribute const& attr, Embedded const& e, 92 unsigned int const width, Padding const& p) 93 { 94 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) 95 e; // suppresses warning: C4100: 'e' : unreferenced formal parameter 96 #endif 97 // wrap the given output iterator to allow counting 98 detail::enable_counting<OutputIterator> counting(sink); 99 100 // first generate the underlying output 101 bool r = e.generate(sink, ctx, d, attr); 102 103 // pad the output until the max width is reached 104 while(r && counting.count() < width) 105 r = p.generate(sink, ctx, unused, unused); 106 107 return r; 108 } 109 } 110 111 /////////////////////////////////////////////////////////////////////////// 112 // The simple left alignment directive is used for left_align[...] 113 // generators. It uses default values for the generated width (defined via 114 // the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant) and for the padding 115 // generator (always spaces). 116 /////////////////////////////////////////////////////////////////////////// 117 template <typename Subject, typename Width = detail::default_width> 118 struct simple_left_alignment 119 : unary_generator<simple_left_alignment<Subject, Width> > 120 { 121 typedef Subject subject_type; 122 123 typedef mpl::int_< 124 generator_properties::counting | subject_type::properties::value 125 > properties; 126 127 template <typename Context, typename Iterator> 128 struct attribute 129 : traits::attribute_of<subject_type, Context, Iterator> 130 {}; 131 simple_left_alignmentboost::spirit::karma::simple_left_alignment132 simple_left_alignment(Subject const& subject, Width width = Width()) 133 : subject(subject), width(width) {} 134 135 template <typename OutputIterator, typename Context, typename Delimiter 136 , typename Attribute> generateboost::spirit::karma::simple_left_alignment137 bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d 138 , Attribute const& attr) const 139 { 140 return detail::left_align_generate(sink, ctx, d, attr, 141 subject, width, compile<karma::domain>(' ')); 142 } 143 144 template <typename Context> whatboost::spirit::karma::simple_left_alignment145 info what(Context& context) const 146 { 147 return info("left_align", subject.what(context)); 148 } 149 150 Subject subject; 151 Width width; 152 }; 153 154 /////////////////////////////////////////////////////////////////////////// 155 // The left alignment directive with padding, is used for generators like 156 // left_align(padding)[...], where padding is a arbitrary generator 157 // expression. It uses a default value for the generated width (defined 158 // via the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant). 159 /////////////////////////////////////////////////////////////////////////// 160 template <typename Subject, typename Padding 161 , typename Width = detail::default_width> 162 struct padding_left_alignment 163 : unary_generator<padding_left_alignment<Subject, Padding, Width> > 164 { 165 typedef Subject subject_type; 166 typedef Padding padding_type; 167 168 typedef mpl::int_< 169 generator_properties::counting | 170 subject_type::properties::value | padding_type::properties::value 171 > properties; 172 173 template <typename Context, typename Iterator> 174 struct attribute 175 : traits::attribute_of<subject_type, Context, Iterator> 176 {}; 177 padding_left_alignmentboost::spirit::karma::padding_left_alignment178 padding_left_alignment(Subject const& subject, Padding const& padding 179 , Width width = Width()) 180 : subject(subject), padding(padding), width(width) {} 181 182 template <typename OutputIterator, typename Context, typename Delimiter 183 , typename Attribute> generateboost::spirit::karma::padding_left_alignment184 bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d 185 , Attribute const& attr) const 186 { 187 return detail::left_align_generate(sink, ctx, d, attr, 188 subject, width, padding); 189 } 190 191 template <typename Context> whatboost::spirit::karma::padding_left_alignment192 info what(Context& context) const 193 { 194 return info("left_align", subject.what(context)); 195 } 196 197 Subject subject; 198 Padding padding; 199 Width width; 200 }; 201 202 /////////////////////////////////////////////////////////////////////////// 203 // Generator generators: make_xxx function (objects) 204 /////////////////////////////////////////////////////////////////////////// 205 206 // creates left_align[] directive generator 207 template <typename Subject, typename Modifiers> 208 struct make_directive<tag::left_align, Subject, Modifiers> 209 { 210 typedef simple_left_alignment<Subject> result_type; operator ()boost::spirit::karma::make_directive211 result_type operator()(unused_type, Subject const& subject 212 , unused_type) const 213 { 214 return result_type(subject); 215 } 216 }; 217 218 // creates left_align(width)[] directive generator 219 template <typename Width, typename Subject, typename Modifiers> 220 struct make_directive< 221 terminal_ex<tag::left_align, fusion::vector1<Width> > 222 , Subject, Modifiers 223 , typename enable_if_c< integer_traits<Width>::is_integral >::type> 224 { 225 typedef simple_left_alignment<Subject, Width> result_type; 226 227 template <typename Terminal> operator ()boost::spirit::karma::make_directive228 result_type operator()(Terminal const& term, Subject const& subject 229 , unused_type) const 230 { 231 return result_type(subject, fusion::at_c<0>(term.args)); 232 } 233 }; 234 235 // creates left_align(pad)[] directive generator 236 template <typename Padding, typename Subject, typename Modifiers> 237 struct make_directive< 238 terminal_ex<tag::left_align, fusion::vector1<Padding> > 239 , Subject, Modifiers 240 , typename enable_if< 241 mpl::and_< 242 spirit::traits::matches<karma::domain, Padding>, 243 mpl::not_<mpl::bool_<integer_traits<Padding>::is_integral> > 244 > 245 >::type> 246 { 247 typedef typename 248 result_of::compile<karma::domain, Padding, Modifiers>::type 249 padding_type; 250 251 typedef padding_left_alignment<Subject, padding_type> result_type; 252 253 template <typename Terminal> operator ()boost::spirit::karma::make_directive254 result_type operator()(Terminal const& term, Subject const& subject 255 , Modifiers const& modifiers) const 256 { 257 return result_type(subject 258 , compile<karma::domain>(fusion::at_c<0>(term.args), modifiers)); 259 } 260 }; 261 262 // creates left_align(width, pad)[] directive generator 263 template <typename Width, typename Padding, typename Subject 264 , typename Modifiers> 265 struct make_directive< 266 terminal_ex<tag::left_align, fusion::vector2<Width, Padding> > 267 , Subject, Modifiers> 268 { 269 typedef typename 270 result_of::compile<karma::domain, Padding, Modifiers>::type 271 padding_type; 272 273 typedef padding_left_alignment<Subject, padding_type, Width> result_type; 274 275 template <typename Terminal> operator ()boost::spirit::karma::make_directive276 result_type operator()(Terminal const& term, Subject const& subject 277 , Modifiers const& modifiers) const 278 { 279 return result_type(subject 280 , compile<karma::domain>(fusion::at_c<1>(term.args), modifiers) 281 , fusion::at_c<0>(term.args)); 282 } 283 }; 284 285 }}} // namespace boost::spirit::karma 286 287 namespace boost { namespace spirit { namespace traits 288 { 289 /////////////////////////////////////////////////////////////////////////// 290 template <typename Subject, typename Width> 291 struct has_semantic_action<karma::simple_left_alignment<Subject, Width> > 292 : unary_has_semantic_action<Subject> {}; 293 294 template <typename Subject, typename Padding, typename Width> 295 struct has_semantic_action< 296 karma::padding_left_alignment<Subject, Padding, Width> > 297 : unary_has_semantic_action<Subject> {}; 298 299 /////////////////////////////////////////////////////////////////////////// 300 template <typename Subject, typename Width, typename Attribute 301 , typename Context, typename Iterator> 302 struct handles_container< 303 karma::simple_left_alignment<Subject, Width>, Attribute 304 , Context, Iterator> 305 : unary_handles_container<Subject, Attribute, Context, Iterator> {}; 306 307 template <typename Subject, typename Padding, typename Width 308 , typename Attribute, typename Context, typename Iterator> 309 struct handles_container< 310 karma::padding_left_alignment<Subject, Padding, Width> 311 , Attribute, Context, Iterator> 312 : unary_handles_container<Subject, Attribute, Context, Iterator> {}; 313 }}} 314 315 #endif 316 317 318