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_CENTER_ALIGNMENT_FEB_27_2007_1216PM) 7 #define BOOST_SPIRIT_KARMA_CENTER_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 center[] 42 template <> 43 struct use_directive<karma::domain, tag::center> 44 : mpl::true_ {}; 45 46 // enables center(d)[g] and center(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::center, fusion::vector1<T> > > 51 : mpl::true_ {}; 52 53 // enables *lazy* center(d)[g], where d provides a generator 54 template <> 55 struct use_lazy_directive<karma::domain, tag::center, 1> 56 : mpl::true_ {}; 57 58 // enables center(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::center, fusion::vector2<Width, Padding> > > 63 : spirit::traits::matches<karma::domain, Padding> {}; 64 65 // enables *lazy* center(w, d)[g], where d provides a generator and w is 66 // a maximum width 67 template <> 68 struct use_lazy_directive<karma::domain, tag::center, 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::center; 78 #endif 79 using spirit::center_type; 80 81 namespace detail 82 { 83 /////////////////////////////////////////////////////////////////////// 84 // The center_generate template function is used for all the 85 // different flavors of the center[] directive. 86 /////////////////////////////////////////////////////////////////////// 87 template <typename OutputIterator, typename Context, typename Delimiter, 88 typename Attribute, typename Embedded, typename Padding> 89 inline static bool center_generate(OutputIterator & sink,Context & ctx,Delimiter const & d,Attribute const & attr,Embedded const & e,unsigned int const width,Padding const & p)90 center_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); 111 112 std::size_t const pre = width - (buffering.buffer_size() + width)/2; 113 while (r && counting.count() < pre) 114 r = p.generate(sink, ctx, unused, unused); 115 116 if (r) { 117 // copy the embedded output to the target output iterator 118 buffering.buffer_copy(); 119 120 // generate the right padding 121 while (r && counting.count() < width) 122 r = p.generate(sink, ctx, unused, unused); 123 } 124 return r; 125 } 126 } 127 128 /////////////////////////////////////////////////////////////////////////// 129 // The simple left alignment directive is used for center[...] 130 // generators. It uses default values for the generated width (defined via 131 // the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant) and for the padding 132 // generator (always spaces). 133 /////////////////////////////////////////////////////////////////////////// 134 template <typename Subject, typename Width = detail::default_width> 135 struct simple_center_alignment 136 : unary_generator<simple_center_alignment<Subject, Width> > 137 { 138 typedef Subject subject_type; 139 140 typedef mpl::int_< 141 generator_properties::countingbuffer | subject_type::properties::value 142 > properties; 143 144 template <typename Context, typename Iterator> 145 struct attribute 146 : traits::attribute_of<subject_type, Context, Iterator> 147 {}; 148 simple_center_alignmentboost::spirit::karma::simple_center_alignment149 simple_center_alignment(Subject const& subject, Width width = Width()) 150 : subject(subject), width(width) {} 151 152 template <typename OutputIterator, typename Context, typename Delimiter 153 , typename Attribute> generateboost::spirit::karma::simple_center_alignment154 bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d 155 , Attribute const& attr) const 156 { 157 return detail::center_generate(sink, ctx, d, attr, 158 subject, width, compile<karma::domain>(' ')); 159 } 160 161 template <typename Context> whatboost::spirit::karma::simple_center_alignment162 info what(Context& context) const 163 { 164 return info("center", subject.what(context)); 165 } 166 167 Subject subject; 168 Width width; 169 }; 170 171 /////////////////////////////////////////////////////////////////////////// 172 // The left alignment directive with padding, is used for generators like 173 // center(padding)[...], where padding is a arbitrary generator 174 // expression. It uses a default value for the generated width (defined 175 // via the BOOST_KARMA_DEFAULT_FIELD_LENGTH constant). 176 /////////////////////////////////////////////////////////////////////////// 177 template <typename Subject, typename Padding 178 , typename Width = detail::default_width> 179 struct padding_center_alignment 180 : unary_generator<padding_center_alignment<Subject, Padding, Width> > 181 { 182 typedef Subject subject_type; 183 typedef Padding padding_type; 184 185 typedef mpl::int_< 186 generator_properties::countingbuffer | 187 subject_type::properties::value | padding_type::properties::value 188 > properties; 189 190 template <typename Context, typename Iterator> 191 struct attribute 192 : traits::attribute_of<Subject, Context, Iterator> 193 {}; 194 padding_center_alignmentboost::spirit::karma::padding_center_alignment195 padding_center_alignment(Subject const& subject, Padding const& padding 196 , Width width = Width()) 197 : subject(subject), padding(padding), width(width) {} 198 199 template <typename OutputIterator, typename Context, typename Delimiter 200 , typename Attribute> generateboost::spirit::karma::padding_center_alignment201 bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d 202 , Attribute const& attr) const 203 { 204 return detail::center_generate(sink, ctx, d, attr, 205 subject, width, padding); 206 } 207 208 template <typename Context> whatboost::spirit::karma::padding_center_alignment209 info what(Context& context) const 210 { 211 return info("center", subject.what(context)); 212 } 213 214 Subject subject; 215 Padding padding; 216 Width width; 217 }; 218 219 /////////////////////////////////////////////////////////////////////////// 220 // Generator generators: make_xxx function (objects) 221 /////////////////////////////////////////////////////////////////////////// 222 223 // creates center[] directive generator 224 template <typename Subject, typename Modifiers> 225 struct make_directive<tag::center, Subject, Modifiers> 226 { 227 typedef simple_center_alignment<Subject> result_type; operator ()boost::spirit::karma::make_directive228 result_type operator()(unused_type, Subject const& subject 229 , unused_type) const 230 { 231 return result_type(subject); 232 } 233 }; 234 235 // creates center(width)[] directive generator 236 template <typename Width, typename Subject, typename Modifiers> 237 struct make_directive< 238 terminal_ex<tag::center, fusion::vector1<Width> > 239 , Subject, Modifiers 240 , typename enable_if_c< integer_traits<Width>::is_integral >::type> 241 { 242 typedef simple_center_alignment<Subject, Width> result_type; 243 244 template <typename Terminal> operator ()boost::spirit::karma::make_directive245 result_type operator()(Terminal const& term, Subject const& subject 246 , unused_type) const 247 { 248 return result_type(subject, fusion::at_c<0>(term.args)); 249 } 250 }; 251 252 // creates center(pad)[] directive generator 253 template <typename Padding, typename Subject, typename Modifiers> 254 struct make_directive< 255 terminal_ex<tag::center, fusion::vector1<Padding> > 256 , Subject, Modifiers 257 , typename enable_if< 258 mpl::and_< 259 spirit::traits::matches<karma::domain, Padding>, 260 mpl::not_<mpl::bool_<integer_traits<Padding>::is_integral> > 261 > 262 >::type> 263 { 264 typedef typename 265 result_of::compile<karma::domain, Padding, Modifiers>::type 266 padding_type; 267 268 typedef padding_center_alignment<Subject, padding_type> result_type; 269 270 template <typename Terminal> operator ()boost::spirit::karma::make_directive271 result_type operator()(Terminal const& term, Subject const& subject 272 , Modifiers const& modifiers) const 273 { 274 return result_type(subject 275 , compile<karma::domain>(fusion::at_c<0>(term.args), modifiers)); 276 } 277 }; 278 279 // creates center(width, pad)[] directive generator 280 template <typename Width, typename Padding, typename Subject 281 , typename Modifiers> 282 struct make_directive< 283 terminal_ex<tag::center, fusion::vector2<Width, Padding> > 284 , Subject, Modifiers> 285 { 286 typedef typename 287 result_of::compile<karma::domain, Padding, Modifiers>::type 288 padding_type; 289 290 typedef padding_center_alignment<Subject, padding_type, Width> result_type; 291 292 template <typename Terminal> operator ()boost::spirit::karma::make_directive293 result_type operator()(Terminal const& term, Subject const& subject 294 , Modifiers const& modifiers) const 295 { 296 return result_type(subject 297 , compile<karma::domain>(fusion::at_c<1>(term.args), modifiers) 298 , fusion::at_c<0>(term.args)); 299 } 300 }; 301 302 }}} // namespace boost::spirit::karma 303 304 namespace boost { namespace spirit { namespace traits 305 { 306 /////////////////////////////////////////////////////////////////////////// 307 template <typename Subject, typename Width> 308 struct has_semantic_action<karma::simple_center_alignment<Subject, Width> > 309 : unary_has_semantic_action<Subject> {}; 310 311 template <typename Subject, typename Padding, typename Width> 312 struct has_semantic_action< 313 karma::padding_center_alignment<Subject, Padding, Width> > 314 : unary_has_semantic_action<Subject> {}; 315 316 /////////////////////////////////////////////////////////////////////////// 317 template <typename Subject, typename Width, typename Attribute 318 , typename Context, typename Iterator> 319 struct handles_container< 320 karma::simple_center_alignment<Subject, Width>, Attribute 321 , Context, Iterator> 322 : unary_handles_container<Subject, Attribute, Context, Iterator> {}; 323 324 template <typename Subject, typename Padding, typename Width 325 , typename Attribute, typename Context, typename Iterator> 326 struct handles_container< 327 karma::padding_center_alignment<Subject, Padding, Width> 328 , Attribute, Context, Iterator> 329 : unary_handles_container<Subject, Attribute, Context, Iterator> {}; 330 }}} 331 332 #endif 333 334 335