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_RIGHT_ALIGNMENT_FEB_27_2007_1216PM) 7 #define BOOST_SPIRIT_KARMA_RIGHT_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/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/spirit/home/support/unused.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 right_align[] 42 template <> 43 struct use_directive<karma::domain, tag::right_align> 44 : mpl::true_ {}; 45 46 // enables right_align(d)[g] and right_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::right_align, fusion::vector1<T> > > 51 : mpl::true_ {}; 52 53 // enables *lazy* right_align(d)[g], where d provides a generator 54 template <> 55 struct use_lazy_directive<karma::domain, tag::right_align, 1> 56 : mpl::true_ {}; 57 58 // enables right_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::right_align, fusion::vector2<Width, Padding> > > 63 : spirit::traits::matches<karma::domain, Padding> {}; 64 65 // enables *lazy* right_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::right_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::right_align; 78 #endif 79 using spirit::right_align_type; 80 81 namespace detail 82 { 83 /////////////////////////////////////////////////////////////////////// 84 // The right_align_generate template function is used for all the 85 // different flavors of the right_align[] directive. 86 /////////////////////////////////////////////////////////////////////// 87 template <typename OutputIterator, typename Context, typename Delimiter, 88 typename Attribute, typename Embedded, typename Padding> 89 inline static bool right_align_generate(OutputIterator & sink,Context & ctx,Delimiter const & d,Attribute const & attr,Embedded const & e,unsigned int const width,Padding const & p)90 right_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 left padding 98 detail::enable_buffering<OutputIterator> buffering(sink, width); 99 bool r = false; 100 101 // first generate the embedded output 102 { 103 detail::disable_counting<OutputIterator> nocounting(sink); 104 r = e.generate(sink, ctx, d, attr); 105 } // re-enable counting 106 107 buffering.disable(); // do not perform buffering any more 108 109 // generate the left padding 110 detail::enable_counting<OutputIterator> counting(sink, buffering.buffer_size()); 111 while(r && counting.count() < width) 112 r = p.generate(sink, ctx, unused, unused); 113 114 // copy the buffered output to the target output iterator 115 if (r) 116 buffering.buffer_copy(); 117 return r; 118 } 119 } 120 121 /////////////////////////////////////////////////////////////////////////// 122 // The simple left alignment directive is used for right_align[...] 123 // generators. It uses default values for the generated width (defined via 124 // the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant) and for the padding 125 // generator (always spaces). 126 /////////////////////////////////////////////////////////////////////////// 127 template <typename Subject, typename Width = detail::default_width> 128 struct simple_right_alignment 129 : unary_generator<simple_right_alignment<Subject, Width> > 130 { 131 typedef Subject subject_type; 132 133 typedef mpl::int_< 134 generator_properties::countingbuffer | subject_type::properties::value 135 > properties; 136 137 template <typename Context, typename Iterator> 138 struct attribute 139 : traits::attribute_of<subject_type, Context, Iterator> 140 {}; 141 simple_right_alignmentboost::spirit::karma::simple_right_alignment142 simple_right_alignment(Subject const& subject, Width width = Width()) 143 : subject(subject), width(width) {} 144 145 template <typename OutputIterator, typename Context, typename Delimiter 146 , typename Attribute> generateboost::spirit::karma::simple_right_alignment147 bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d 148 , Attribute const& attr) const 149 { 150 return detail::right_align_generate(sink, ctx, d, attr, 151 subject, width, compile<karma::domain>(' ')); 152 } 153 154 template <typename Context> whatboost::spirit::karma::simple_right_alignment155 info what(Context& context) const 156 { 157 return info("right_align", subject.what(context)); 158 } 159 160 Subject subject; 161 Width width; 162 }; 163 164 /////////////////////////////////////////////////////////////////////////// 165 // The left alignment directive with padding, is used for generators like 166 // right_align(padding)[...], where padding is a arbitrary generator 167 // expression. It uses a default value for the generated width (defined 168 // via the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant). 169 /////////////////////////////////////////////////////////////////////////// 170 template <typename Subject, typename Padding 171 , typename Width = detail::default_width> 172 struct padding_right_alignment 173 : unary_generator<padding_right_alignment<Subject, Padding, Width> > 174 { 175 typedef Subject subject_type; 176 typedef Padding padding_type; 177 178 typedef mpl::int_< 179 generator_properties::countingbuffer | 180 subject_type::properties::value | padding_type::properties::value 181 > properties; 182 183 template <typename Context, typename Iterator> 184 struct attribute 185 : traits::attribute_of<subject_type, Context, Iterator> 186 {}; 187 padding_right_alignmentboost::spirit::karma::padding_right_alignment188 padding_right_alignment(Subject const& subject, Padding const& padding 189 , Width width = Width()) 190 : subject(subject), padding(padding), width(width) {} 191 192 template <typename OutputIterator, typename Context, typename Delimiter 193 , typename Attribute> generateboost::spirit::karma::padding_right_alignment194 bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d 195 , Attribute const& attr) const 196 { 197 return detail::right_align_generate(sink, ctx, d, attr, 198 subject, width, padding); 199 } 200 201 template <typename Context> whatboost::spirit::karma::padding_right_alignment202 info what(Context& context) const 203 { 204 return info("right_align", subject.what(context)); 205 } 206 207 Subject subject; 208 Padding padding; 209 Width width; 210 }; 211 212 /////////////////////////////////////////////////////////////////////////// 213 // Generator generators: make_xxx function (objects) 214 /////////////////////////////////////////////////////////////////////////// 215 216 // creates right_align[] directive generator 217 template <typename Subject, typename Modifiers> 218 struct make_directive<tag::right_align, Subject, Modifiers> 219 { 220 typedef simple_right_alignment<Subject> result_type; operator ()boost::spirit::karma::make_directive221 result_type operator()(unused_type, Subject const& subject 222 , unused_type) const 223 { 224 return result_type(subject); 225 } 226 }; 227 228 // creates right_align(width)[] directive generator 229 template <typename Width, typename Subject, typename Modifiers> 230 struct make_directive< 231 terminal_ex<tag::right_align, fusion::vector1<Width> > 232 , Subject, Modifiers 233 , typename enable_if_c< integer_traits<Width>::is_integral >::type> 234 { 235 typedef simple_right_alignment<Subject, Width> result_type; 236 237 template <typename Terminal> operator ()boost::spirit::karma::make_directive238 result_type operator()(Terminal const& term, Subject const& subject 239 , unused_type) const 240 { 241 return result_type(subject, fusion::at_c<0>(term.args)); 242 } 243 }; 244 245 // creates right_align(pad)[] directive generator 246 template <typename Padding, typename Subject, typename Modifiers> 247 struct make_directive< 248 terminal_ex<tag::right_align, fusion::vector1<Padding> > 249 , Subject, Modifiers 250 , typename enable_if< 251 mpl::and_< 252 spirit::traits::matches<karma::domain, Padding>, 253 mpl::not_<mpl::bool_<integer_traits<Padding>::is_integral> > 254 > 255 >::type> 256 { 257 typedef typename 258 result_of::compile<karma::domain, Padding, Modifiers>::type 259 padding_type; 260 261 typedef padding_right_alignment<Subject, padding_type> result_type; 262 263 template <typename Terminal> operator ()boost::spirit::karma::make_directive264 result_type operator()(Terminal const& term, Subject const& subject 265 , Modifiers const& modifiers) const 266 { 267 return result_type(subject 268 , compile<karma::domain>(fusion::at_c<0>(term.args), modifiers)); 269 } 270 }; 271 272 // creates right_align(width, pad)[] directive generator 273 template <typename Width, typename Padding, typename Subject 274 , typename Modifiers> 275 struct make_directive< 276 terminal_ex<tag::right_align, fusion::vector2<Width, Padding> > 277 , Subject, Modifiers> 278 { 279 typedef typename 280 result_of::compile<karma::domain, Padding, Modifiers>::type 281 padding_type; 282 283 typedef padding_right_alignment<Subject, padding_type, Width> result_type; 284 285 template <typename Terminal> operator ()boost::spirit::karma::make_directive286 result_type operator()(Terminal const& term, Subject const& subject 287 , Modifiers const& modifiers) const 288 { 289 return result_type(subject 290 , compile<karma::domain>(fusion::at_c<1>(term.args), modifiers) 291 , fusion::at_c<0>(term.args)); 292 } 293 }; 294 295 }}} // namespace boost::spirit::karma 296 297 namespace boost { namespace spirit { namespace traits 298 { 299 /////////////////////////////////////////////////////////////////////////// 300 template <typename Subject, typename Width> 301 struct has_semantic_action<karma::simple_right_alignment<Subject, Width> > 302 : unary_has_semantic_action<Subject> {}; 303 304 template <typename Subject, typename Padding, typename Width> 305 struct has_semantic_action< 306 karma::padding_right_alignment<Subject, Padding, Width> > 307 : unary_has_semantic_action<Subject> {}; 308 309 /////////////////////////////////////////////////////////////////////////// 310 template <typename Subject, typename Width, typename Attribute 311 , typename Context, typename Iterator> 312 struct handles_container< 313 karma::simple_right_alignment<Subject, Width> 314 , Attribute, Context, Iterator> 315 : unary_handles_container<Subject, Attribute, Context, Iterator> {}; 316 317 template <typename Subject, typename Padding, typename Width 318 , typename Attribute, typename Context, typename Iterator> 319 struct handles_container< 320 karma::padding_right_alignment<Subject, Padding, Width> 321 , Attribute, Context, Iterator> 322 : unary_handles_container<Subject, Attribute, Context, Iterator> {}; 323 }}} 324 325 #endif 326 327