1 // Copyright (c) 2001-2011 Hartmut Kaiser 2 // Copyright (c) 2001-2011 Joel de Guzman 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 7 #ifndef BOOST_SPIRIT_KARMA_DIRECTIVE_REPEAT_HPP 8 #define BOOST_SPIRIT_KARMA_DIRECTIVE_REPEAT_HPP 9 10 #if defined(_MSC_VER) 11 #pragma once 12 #endif 13 14 #include <boost/spirit/home/karma/meta_compiler.hpp> 15 #include <boost/spirit/home/karma/detail/output_iterator.hpp> 16 #include <boost/spirit/home/karma/detail/get_stricttag.hpp> 17 #include <boost/spirit/home/karma/generator.hpp> 18 #include <boost/spirit/home/karma/auxiliary/lazy.hpp> 19 #include <boost/spirit/home/karma/operator/kleene.hpp> 20 #include <boost/spirit/home/support/container.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 28 namespace boost { namespace spirit 29 { 30 /////////////////////////////////////////////////////////////////////////// 31 // Enablers 32 /////////////////////////////////////////////////////////////////////////// 33 template <> 34 struct use_directive<karma::domain, tag::repeat> // enables repeat[p] 35 : mpl::true_ {}; 36 37 template <typename T> 38 struct use_directive<karma::domain 39 , terminal_ex<tag::repeat // enables repeat(exact)[p] 40 , fusion::vector1<T> > 41 > : mpl::true_ {}; 42 43 template <typename T> 44 struct use_directive<karma::domain 45 , terminal_ex<tag::repeat // enables repeat(min, max)[p] 46 , fusion::vector2<T, T> > 47 > : mpl::true_ {}; 48 49 template <typename T> 50 struct use_directive<karma::domain 51 , terminal_ex<tag::repeat // enables repeat(min, inf)[p] 52 , fusion::vector2<T, inf_type> > 53 > : mpl::true_ {}; 54 55 template <> // enables *lazy* repeat(exact)[p] 56 struct use_lazy_directive< 57 karma::domain 58 , tag::repeat 59 , 1 // arity 60 > : mpl::true_ {}; 61 62 template <> // enables *lazy* repeat(min, max)[p] 63 struct use_lazy_directive< // and repeat(min, inf)[p] 64 karma::domain 65 , tag::repeat 66 , 2 // arity 67 > : mpl::true_ {}; 68 }} 69 70 namespace boost { namespace spirit { namespace karma 71 { 72 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 73 using spirit::repeat; 74 using spirit::inf; 75 #endif 76 using spirit::repeat_type; 77 using spirit::inf_type; 78 79 /////////////////////////////////////////////////////////////////////////// 80 // handles repeat(exact)[p] 81 template <typename T> 82 struct exact_iterator 83 { exact_iteratorboost::spirit::karma::exact_iterator84 exact_iterator(T const exact) 85 : exact(exact) {} 86 87 typedef T type; startboost::spirit::karma::exact_iterator88 T start() const { return 0; } got_maxboost::spirit::karma::exact_iterator89 bool got_max(T i) const { return i >= exact; } got_minboost::spirit::karma::exact_iterator90 bool got_min(T i) const { return i >= exact; } 91 92 T const exact; 93 94 // silence MSVC warning C4512: assignment operator could not be generated 95 BOOST_DELETED_FUNCTION(exact_iterator& operator= (exact_iterator const&)) 96 }; 97 98 // handles repeat(min, max)[p] 99 template <typename T> 100 struct finite_iterator 101 { finite_iteratorboost::spirit::karma::finite_iterator102 finite_iterator(T const min, T const max) 103 : min BOOST_PREVENT_MACRO_SUBSTITUTION (min) 104 , max BOOST_PREVENT_MACRO_SUBSTITUTION (max) {} 105 106 typedef T type; startboost::spirit::karma::finite_iterator107 T start() const { return 0; } got_maxboost::spirit::karma::finite_iterator108 bool got_max(T i) const { return i >= max; } got_minboost::spirit::karma::finite_iterator109 bool got_min(T i) const { return i >= min; } 110 111 T const min; 112 T const max; 113 114 // silence MSVC warning C4512: assignment operator could not be generated 115 BOOST_DELETED_FUNCTION(finite_iterator& operator= (finite_iterator const&)) 116 }; 117 118 // handles repeat(min, inf)[p] 119 template <typename T> 120 struct infinite_iterator 121 { infinite_iteratorboost::spirit::karma::infinite_iterator122 infinite_iterator(T const min) 123 : min BOOST_PREVENT_MACRO_SUBSTITUTION (min) {} 124 125 typedef T type; startboost::spirit::karma::infinite_iterator126 T start() const { return 0; } got_maxboost::spirit::karma::infinite_iterator127 bool got_max(T /*i*/) const { return false; } got_minboost::spirit::karma::infinite_iterator128 bool got_min(T i) const { return i >= min; } 129 130 T const min; 131 132 // silence MSVC warning C4512: assignment operator could not be generated 133 BOOST_DELETED_FUNCTION(infinite_iterator& operator= (infinite_iterator const&)) 134 }; 135 136 /////////////////////////////////////////////////////////////////////////// 137 template <typename Subject, typename LoopIter, typename Strict 138 , typename Derived> 139 struct base_repeat_generator : unary_generator<Derived> 140 { 141 private: 142 // iterate over the given container until its exhausted or the embedded 143 // generator succeeds 144 template <typename F, typename Attribute> generate_subjectboost::spirit::karma::base_repeat_generator145 bool generate_subject(F f, Attribute const&, mpl::false_) const 146 { 147 // Failing subject generators are just skipped. This allows to 148 // selectively generate items in the provided attribute. 149 while (!f.is_at_end()) 150 { 151 bool r = !f(subject); 152 if (r) 153 return true; 154 if (!f.is_at_end()) 155 f.next(); 156 } 157 return false; 158 } 159 160 template <typename F, typename Attribute> generate_subjectboost::spirit::karma::base_repeat_generator161 bool generate_subject(F f, Attribute const&, mpl::true_) const 162 { 163 return !f(subject); 164 } 165 166 // There is no way to distinguish a failed generator from a 167 // generator to be skipped. We assume the user takes responsibility 168 // for ending the loop if no attribute is specified. 169 template <typename F> generate_subjectboost::spirit::karma::base_repeat_generator170 bool generate_subject(F f, unused_type, mpl::false_) const 171 { 172 return !f(subject); 173 } 174 175 public: 176 typedef Subject subject_type; 177 178 typedef mpl::int_<subject_type::properties::value> properties; 179 180 // Build a std::vector from the subject's attribute. Note 181 // that build_std_vector may return unused_type if the 182 // subject's attribute is an unused_type. 183 template <typename Context, typename Iterator> 184 struct attribute 185 : traits::build_std_vector< 186 typename traits::attribute_of<Subject, Context, Iterator>::type 187 > 188 {}; 189 base_repeat_generatorboost::spirit::karma::base_repeat_generator190 base_repeat_generator(Subject const& subject, LoopIter const& iter) 191 : subject(subject), iter(iter) {} 192 193 template <typename OutputIterator, typename Context, typename Delimiter 194 , typename Attribute> generateboost::spirit::karma::base_repeat_generator195 bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d 196 , Attribute const& attr) const 197 { 198 typedef detail::fail_function< 199 OutputIterator, Context, Delimiter 200 > fail_function; 201 202 typedef typename traits::container_iterator< 203 typename add_const<Attribute>::type 204 >::type iterator_type; 205 206 typedef 207 typename traits::make_indirect_iterator<iterator_type>::type 208 indirect_iterator_type; 209 210 typedef detail::pass_container< 211 fail_function, Attribute, indirect_iterator_type, mpl::false_> 212 pass_container; 213 214 iterator_type it = traits::begin(attr); 215 iterator_type end = traits::end(attr); 216 217 pass_container pass(fail_function(sink, ctx, d), 218 indirect_iterator_type(it), indirect_iterator_type(end)); 219 220 // generate the minimal required amount of output 221 typename LoopIter::type i = iter.start(); 222 for (/**/; !pass.is_at_end() && !iter.got_min(i); ++i) 223 { 224 if (!generate_subject(pass, attr, Strict())) 225 { 226 // if we fail before reaching the minimum iteration 227 // required, do not output anything and return false 228 return false; 229 } 230 } 231 232 if (pass.is_at_end() && !iter.got_min(i)) 233 return false; // insufficient attribute elements 234 235 // generate some more up to the maximum specified 236 for (/**/; !pass.is_at_end() && !iter.got_max(i); ++i) 237 { 238 if (!generate_subject(pass, attr, Strict())) 239 break; 240 } 241 return detail::sink_is_good(sink); 242 } 243 244 template <typename Context> whatboost::spirit::karma::base_repeat_generator245 info what(Context& context) const 246 { 247 return info("repeat", subject.what(context)); 248 } 249 250 Subject subject; 251 LoopIter iter; 252 }; 253 254 template <typename Subject, typename LoopIter> 255 struct repeat_generator 256 : base_repeat_generator< 257 Subject, LoopIter, mpl::false_ 258 , repeat_generator<Subject, LoopIter> > 259 { 260 typedef base_repeat_generator< 261 Subject, LoopIter, mpl::false_, repeat_generator 262 > base_repeat_generator_; 263 repeat_generatorboost::spirit::karma::repeat_generator264 repeat_generator(Subject const& subject, LoopIter const& iter) 265 : base_repeat_generator_(subject, iter) {} 266 }; 267 268 template <typename Subject, typename LoopIter> 269 struct strict_repeat_generator 270 : base_repeat_generator< 271 Subject, LoopIter, mpl::true_ 272 , strict_repeat_generator<Subject, LoopIter> > 273 { 274 typedef base_repeat_generator< 275 Subject, LoopIter, mpl::true_, strict_repeat_generator 276 > base_repeat_generator_; 277 strict_repeat_generatorboost::spirit::karma::strict_repeat_generator278 strict_repeat_generator(Subject const& subject, LoopIter const& iter) 279 : base_repeat_generator_(subject, iter) {} 280 }; 281 282 /////////////////////////////////////////////////////////////////////////// 283 // Generator generators: make_xxx function (objects) 284 /////////////////////////////////////////////////////////////////////////// 285 template <typename Subject, typename Modifiers> 286 struct make_directive<tag::repeat, Subject, Modifiers> 287 { 288 typedef typename mpl::if_< 289 detail::get_stricttag<Modifiers> 290 , strict_kleene<Subject>, kleene<Subject> 291 >::type result_type; 292 operator ()boost::spirit::karma::make_directive293 result_type operator()(unused_type, Subject const& subject 294 , unused_type) const 295 { 296 return result_type(subject); 297 } 298 }; 299 300 template <typename T, typename Subject, typename Modifiers> 301 struct make_directive< 302 terminal_ex<tag::repeat, fusion::vector1<T> >, Subject, Modifiers> 303 { 304 typedef exact_iterator<T> iterator_type; 305 306 typedef typename mpl::if_< 307 detail::get_stricttag<Modifiers> 308 , strict_repeat_generator<Subject, iterator_type> 309 , repeat_generator<Subject, iterator_type> 310 >::type result_type; 311 312 template <typename Terminal> operator ()boost::spirit::karma::make_directive313 result_type operator()( 314 Terminal const& term, Subject const& subject, unused_type) const 315 { 316 return result_type(subject, fusion::at_c<0>(term.args)); 317 } 318 }; 319 320 template <typename T, typename Subject, typename Modifiers> 321 struct make_directive< 322 terminal_ex<tag::repeat, fusion::vector2<T, T> >, Subject, Modifiers> 323 { 324 typedef finite_iterator<T> iterator_type; 325 326 typedef typename mpl::if_< 327 detail::get_stricttag<Modifiers> 328 , strict_repeat_generator<Subject, iterator_type> 329 , repeat_generator<Subject, iterator_type> 330 >::type result_type; 331 332 template <typename Terminal> operator ()boost::spirit::karma::make_directive333 result_type operator()( 334 Terminal const& term, Subject const& subject, unused_type) const 335 { 336 return result_type(subject, 337 iterator_type( 338 fusion::at_c<0>(term.args) 339 , fusion::at_c<1>(term.args) 340 ) 341 ); 342 } 343 }; 344 345 template <typename T, typename Subject, typename Modifiers> 346 struct make_directive< 347 terminal_ex<tag::repeat 348 , fusion::vector2<T, inf_type> >, Subject, Modifiers> 349 { 350 typedef infinite_iterator<T> iterator_type; 351 352 typedef typename mpl::if_< 353 detail::get_stricttag<Modifiers> 354 , strict_repeat_generator<Subject, iterator_type> 355 , repeat_generator<Subject, iterator_type> 356 >::type result_type; 357 358 template <typename Terminal> operator ()boost::spirit::karma::make_directive359 result_type operator()( 360 Terminal const& term, Subject const& subject, unused_type) const 361 { 362 return result_type(subject, fusion::at_c<0>(term.args)); 363 } 364 }; 365 }}} 366 367 namespace boost { namespace spirit { namespace traits 368 { 369 /////////////////////////////////////////////////////////////////////////// 370 template <typename Subject, typename LoopIter> 371 struct has_semantic_action<karma::repeat_generator<Subject, LoopIter> > 372 : unary_has_semantic_action<Subject> {}; 373 374 template <typename Subject, typename LoopIter> 375 struct has_semantic_action<karma::strict_repeat_generator<Subject, LoopIter> > 376 : unary_has_semantic_action<Subject> {}; 377 378 /////////////////////////////////////////////////////////////////////////// 379 template <typename Subject, typename LoopIter, typename Attribute 380 , typename Context, typename Iterator> 381 struct handles_container< 382 karma::repeat_generator<Subject, LoopIter>, Attribute 383 , Context, Iterator> 384 : mpl::true_ {}; 385 386 template <typename Subject, typename LoopIter, typename Attribute 387 , typename Context, typename Iterator> 388 struct handles_container< 389 karma::strict_repeat_generator<Subject, LoopIter>, Attribute 390 , Context, Iterator> 391 : mpl::true_ {}; 392 }}} 393 394 #endif 395