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_REAL_FEB_26_2007_0512PM) 7 #define BOOST_SPIRIT_KARMA_REAL_FEB_26_2007_0512PM 8 9 #if defined(_MSC_VER) 10 #pragma once 11 #endif 12 13 #include <boost/config/no_tr1/cmath.hpp> 14 #include <boost/config.hpp> 15 #include <boost/mpl/bool.hpp> 16 #include <boost/utility/enable_if.hpp> 17 #include <boost/spirit/home/support/common_terminals.hpp> 18 #include <boost/spirit/home/support/string_traits.hpp> 19 #include <boost/spirit/home/support/numeric_traits.hpp> 20 #include <boost/spirit/home/support/info.hpp> 21 #include <boost/spirit/home/support/char_class.hpp> 22 #include <boost/spirit/home/support/container.hpp> 23 #include <boost/spirit/home/support/detail/get_encoding.hpp> 24 #include <boost/spirit/home/karma/meta_compiler.hpp> 25 #include <boost/spirit/home/karma/char.hpp> 26 #include <boost/spirit/home/karma/delimit_out.hpp> 27 #include <boost/spirit/home/karma/auxiliary/lazy.hpp> 28 #include <boost/spirit/home/karma/detail/get_casetag.hpp> 29 #include <boost/spirit/home/karma/detail/extract_from.hpp> 30 #include <boost/spirit/home/karma/detail/enable_lit.hpp> 31 #include <boost/spirit/home/karma/domain.hpp> 32 #include <boost/spirit/home/karma/numeric/real_policies.hpp> 33 #include <boost/spirit/home/karma/numeric/detail/real_utils.hpp> 34 #include <boost/fusion/include/at.hpp> 35 #include <boost/fusion/include/value_at.hpp> 36 #include <boost/fusion/include/vector.hpp> 37 38 namespace boost { namespace spirit 39 { 40 namespace karma 41 { 42 /////////////////////////////////////////////////////////////////////// 43 // forward declaration only 44 template <typename T> 45 struct real_policies; 46 47 /////////////////////////////////////////////////////////////////////// 48 // This is the class that the user can instantiate directly in 49 // order to create a customized real generator 50 template <typename T = double, typename Policies = real_policies<T> > 51 struct real_generator 52 : spirit::terminal<tag::stateful_tag<Policies, tag::double_, T> > 53 { 54 typedef tag::stateful_tag<Policies, tag::double_, T> tag_type; 55 real_generatorboost::spirit::karma::real_generator56 real_generator() {} real_generatorboost::spirit::karma::real_generator57 real_generator(Policies const& p) 58 : spirit::terminal<tag_type>(p) {} 59 }; 60 } 61 62 /////////////////////////////////////////////////////////////////////////// 63 // Enablers 64 /////////////////////////////////////////////////////////////////////////// 65 template <> 66 struct use_terminal<karma::domain, tag::float_> // enables float_ 67 : mpl::true_ {}; 68 69 template <> 70 struct use_terminal<karma::domain, tag::double_> // enables double_ 71 : mpl::true_ {}; 72 73 template <> 74 struct use_terminal<karma::domain, tag::long_double> // enables long_double 75 : mpl::true_ {}; 76 77 /////////////////////////////////////////////////////////////////////////// 78 template <> 79 struct use_terminal<karma::domain, float> // enables lit(1.0f) 80 : mpl::true_ {}; 81 82 template <> 83 struct use_terminal<karma::domain, double> // enables lit(1.0) 84 : mpl::true_ {}; 85 86 template <> 87 struct use_terminal<karma::domain, long double> // enables lit(1.0l) 88 : mpl::true_ {}; 89 90 /////////////////////////////////////////////////////////////////////////// 91 template <typename A0> 92 struct use_terminal<karma::domain // enables float_(...) 93 , terminal_ex<tag::float_, fusion::vector1<A0> > 94 > : mpl::true_ {}; 95 96 template <typename A0> 97 struct use_terminal<karma::domain // enables double_(...) 98 , terminal_ex<tag::double_, fusion::vector1<A0> > 99 > : mpl::true_ {}; 100 101 template <typename A0> 102 struct use_terminal<karma::domain // enables long_double(...) 103 , terminal_ex<tag::long_double, fusion::vector1<A0> > 104 > : mpl::true_ {}; 105 106 // lazy float_(...), double_(...), long_double(...) 107 template <> 108 struct use_lazy_terminal<karma::domain, tag::float_, 1> 109 : mpl::true_ {}; 110 111 template <> 112 struct use_lazy_terminal<karma::domain, tag::double_, 1> 113 : mpl::true_ {}; 114 115 template <> 116 struct use_lazy_terminal<karma::domain, tag::long_double, 1> 117 : mpl::true_ {}; 118 119 /////////////////////////////////////////////////////////////////////////// 120 // enables custom real generator 121 template <typename T, typename Policies> 122 struct use_terminal<karma::domain 123 , tag::stateful_tag<Policies, tag::double_, T> > 124 : mpl::true_ {}; 125 126 template <typename T, typename Policies, typename A0> 127 struct use_terminal<karma::domain 128 , terminal_ex<tag::stateful_tag<Policies, tag::double_, T> 129 , fusion::vector1<A0> > > 130 : mpl::true_ {}; 131 132 // enables *lazy* custom real generator 133 template <typename T, typename Policies> 134 struct use_lazy_terminal< 135 karma::domain 136 , tag::stateful_tag<Policies, tag::double_, T> 137 , 1 // arity 138 > : mpl::true_ {}; 139 140 // enables lit(double) 141 template <typename A0> 142 struct use_terminal<karma::domain 143 , terminal_ex<tag::lit, fusion::vector1<A0> > 144 , typename enable_if<traits::is_real<A0> >::type> 145 : mpl::true_ {}; 146 }} 147 148 /////////////////////////////////////////////////////////////////////////////// 149 namespace boost { namespace spirit { namespace karma 150 { 151 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 152 using spirit::float_; 153 using spirit::double_; 154 using spirit::long_double; 155 #endif 156 157 using spirit::float_type; 158 using spirit::double_type; 159 using spirit::long_double_type; 160 161 /////////////////////////////////////////////////////////////////////////// 162 // This specialization is used for real generators not having a direct 163 // initializer: float_, double_ etc. These generators must be used in 164 // conjunction with an attribute. 165 /////////////////////////////////////////////////////////////////////////// 166 template < 167 typename T, typename Policies, typename CharEncoding, typename Tag> 168 struct any_real_generator 169 : primitive_generator<any_real_generator<T, Policies, CharEncoding, Tag> > 170 { 171 typedef typename Policies::properties properties; 172 173 template <typename Context, typename Unused> 174 struct attribute 175 { 176 typedef T type; 177 }; 178 any_real_generatorboost::spirit::karma::any_real_generator179 any_real_generator(Policies const& policies = Policies()) 180 : p_(policies) {} 181 182 // double_/float_/etc. has an attached attribute 183 template <typename OutputIterator, typename Context, typename Delimiter 184 , typename Attribute> generateboost::spirit::karma::any_real_generator185 bool generate(OutputIterator& sink, Context& context 186 , Delimiter const& d, Attribute const& attr) const 187 { 188 if (!traits::has_optional_value(attr)) 189 return false; // fail if it's an uninitialized optional 190 191 typedef real_inserter<T, Policies, CharEncoding, Tag> inserter_type; 192 return inserter_type::call(sink, traits::extract_from<T>(attr, context), p_) && 193 karma::delimit_out(sink, d); // always do post-delimiting 194 } 195 196 // this double_/float_/etc. has no attribute attached, it needs to have 197 // been initialized from a direct literal 198 template <typename OutputIterator, typename Context, typename Delimiter> generateboost::spirit::karma::any_real_generator199 static bool generate(OutputIterator&, Context&, Delimiter const& 200 , unused_type) 201 { 202 // It is not possible (doesn't make sense) to use numeric generators 203 // without providing any attribute, as the generator doesn't 'know' 204 // what to output. The following assertion fires if this situation 205 // is detected in your code. 206 BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, real_not_usable_without_attribute, ()); 207 return false; 208 } 209 210 template <typename Context> whatboost::spirit::karma::any_real_generator211 static info what(Context const& /*context*/) 212 { 213 return info("real"); 214 } 215 216 Policies p_; 217 }; 218 219 /////////////////////////////////////////////////////////////////////////// 220 // This specialization is used for real generators having a direct 221 // initializer: float_(10.), double_(20.) etc. 222 /////////////////////////////////////////////////////////////////////////// 223 template < 224 typename T, typename Policies, typename CharEncoding, typename Tag 225 , bool no_attribute> 226 struct literal_real_generator 227 : primitive_generator<literal_real_generator<T, Policies, CharEncoding 228 , Tag, no_attribute> > 229 { 230 typedef typename Policies::properties properties; 231 232 template <typename Context, typename Unused = unused_type> 233 struct attribute 234 : mpl::if_c<no_attribute, unused_type, T> 235 {}; 236 literal_real_generatorboost::spirit::karma::literal_real_generator237 literal_real_generator(typename add_const<T>::type n 238 , Policies const& policies = Policies()) 239 : n_(n), p_(policies) {} 240 241 // A double_(1.0) which additionally has an associated attribute emits 242 // its immediate literal only if it matches the attribute, otherwise 243 // it fails. 244 template <typename OutputIterator, typename Context, typename Delimiter 245 , typename Attribute> generateboost::spirit::karma::literal_real_generator246 bool generate(OutputIterator& sink, Context& context 247 , Delimiter const& d, Attribute const& attr) const 248 { 249 typedef typename attribute<Context>::type attribute_type; 250 if (!traits::has_optional_value(attr) || 251 n_ != traits::extract_from<attribute_type>(attr, context)) 252 { 253 return false; 254 } 255 256 typedef real_inserter<T, Policies, CharEncoding, Tag> inserter_type; 257 return inserter_type::call(sink, n_, p_) && 258 karma::delimit_out(sink, d); // always do post-delimiting 259 } 260 261 // A double_(1.0) without any associated attribute just emits its 262 // immediate literal 263 template <typename OutputIterator, typename Context, typename Delimiter> generateboost::spirit::karma::literal_real_generator264 bool generate(OutputIterator& sink, Context&, Delimiter const& d 265 , unused_type) const 266 { 267 typedef real_inserter<T, Policies, CharEncoding, Tag> inserter_type; 268 return inserter_type::call(sink, n_, p_) && 269 karma::delimit_out(sink, d); // always do post-delimiting 270 } 271 272 template <typename Context> whatboost::spirit::karma::literal_real_generator273 static info what(Context const& /*context*/) 274 { 275 return info("real"); 276 } 277 278 T n_; 279 Policies p_; 280 }; 281 282 /////////////////////////////////////////////////////////////////////////// 283 // Generator generators: make_xxx function (objects) 284 /////////////////////////////////////////////////////////////////////////// 285 namespace detail 286 { 287 template <typename T, typename Modifiers 288 , typename Policies = real_policies<T> > 289 struct make_real 290 { 291 static bool const lower = 292 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; 293 static bool const upper = 294 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; 295 296 typedef any_real_generator< 297 T, Policies 298 , typename spirit::detail::get_encoding_with_case< 299 Modifiers, unused_type, lower || upper>::type 300 , typename detail::get_casetag<Modifiers, lower || upper>::type 301 > result_type; 302 303 template <typename Terminal> operator ()boost::spirit::karma::detail::make_real304 result_type operator()(Terminal const& term, unused_type) const 305 { 306 typedef tag::stateful_tag<Policies, tag::double_, T> tag_type; 307 using spirit::detail::get_stateful_data; 308 return result_type(get_stateful_data<tag_type>::call(term)); 309 } 310 }; 311 } 312 313 template <typename Modifiers> 314 struct make_primitive<tag::float_, Modifiers> 315 : detail::make_real<float, Modifiers> {}; 316 317 template <typename Modifiers> 318 struct make_primitive<tag::double_, Modifiers> 319 : detail::make_real<double, Modifiers> {}; 320 321 template <typename Modifiers> 322 struct make_primitive<tag::long_double, Modifiers> 323 : detail::make_real<long double, Modifiers> {}; 324 325 /////////////////////////////////////////////////////////////////////////// 326 template <typename T, typename Policies, typename Modifiers> 327 struct make_primitive< 328 tag::stateful_tag<Policies, tag::double_, T>, Modifiers> 329 : detail::make_real<typename remove_const<T>::type 330 , Modifiers, Policies> {}; 331 332 /////////////////////////////////////////////////////////////////////////// 333 namespace detail 334 { 335 template <typename T, typename Modifiers 336 , typename Policies = real_policies<T> > 337 struct make_real_direct 338 { 339 static bool const lower = 340 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; 341 static bool const upper = 342 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; 343 344 typedef literal_real_generator< 345 T, Policies 346 , typename spirit::detail::get_encoding_with_case< 347 Modifiers, unused_type, lower || upper>::type 348 , typename detail::get_casetag<Modifiers, lower || upper>::type 349 , false 350 > result_type; 351 352 template <typename Terminal> operator ()boost::spirit::karma::detail::make_real_direct353 result_type operator()(Terminal const& term, unused_type) const 354 { 355 typedef tag::stateful_tag<Policies, tag::double_, T> tag_type; 356 using spirit::detail::get_stateful_data; 357 return result_type(T(fusion::at_c<0>(term.args)) 358 , get_stateful_data<tag_type>::call(term.term)); 359 } 360 }; 361 } 362 363 template <typename Modifiers, typename A0> 364 struct make_primitive< 365 terminal_ex<tag::float_, fusion::vector1<A0> >, Modifiers> 366 : detail::make_real_direct<float, Modifiers> {}; 367 368 template <typename Modifiers, typename A0> 369 struct make_primitive< 370 terminal_ex<tag::double_, fusion::vector1<A0> >, Modifiers> 371 : detail::make_real_direct<double, Modifiers> {}; 372 373 template <typename Modifiers, typename A0> 374 struct make_primitive< 375 terminal_ex<tag::long_double, fusion::vector1<A0> >, Modifiers> 376 : detail::make_real_direct<long double, Modifiers> {}; 377 378 /////////////////////////////////////////////////////////////////////////// 379 template <typename T, typename Policies, typename A0, typename Modifiers> 380 struct make_primitive< 381 terminal_ex<tag::stateful_tag<Policies, tag::double_, T> 382 , fusion::vector1<A0> > 383 , Modifiers> 384 : detail::make_real_direct<typename remove_const<T>::type 385 , Modifiers, Policies> {}; 386 387 /////////////////////////////////////////////////////////////////////////// 388 namespace detail 389 { 390 template <typename T, typename Modifiers> 391 struct basic_real_literal 392 { 393 static bool const lower = 394 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; 395 static bool const upper = 396 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; 397 398 typedef literal_real_generator< 399 T, real_policies<T> 400 , typename spirit::detail::get_encoding_with_case< 401 Modifiers, unused_type, lower || upper>::type 402 , typename detail::get_casetag<Modifiers, lower || upper>::type 403 , true 404 > result_type; 405 406 template <typename T_> operator ()boost::spirit::karma::detail::basic_real_literal407 result_type operator()(T_ i, unused_type) const 408 { 409 return result_type(T(i)); 410 } 411 }; 412 } 413 414 template <typename Modifiers> 415 struct make_primitive<float, Modifiers> 416 : detail::basic_real_literal<float, Modifiers> {}; 417 418 template <typename Modifiers> 419 struct make_primitive<double, Modifiers> 420 : detail::basic_real_literal<double, Modifiers> {}; 421 422 template <typename Modifiers> 423 struct make_primitive<long double, Modifiers> 424 : detail::basic_real_literal<long double, Modifiers> {}; 425 426 // lit(double) 427 template <typename Modifiers, typename A0> 428 struct make_primitive< 429 terminal_ex<tag::lit, fusion::vector1<A0> > 430 , Modifiers 431 , typename enable_if<traits::is_real<A0> >::type> 432 { 433 static bool const lower = 434 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; 435 static bool const upper = 436 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; 437 438 typedef literal_real_generator< 439 typename remove_const<A0>::type, real_policies<A0> 440 , typename spirit::detail::get_encoding_with_case< 441 Modifiers, unused_type, lower || upper>::type 442 , typename detail::get_casetag<Modifiers, lower || upper>::type 443 , true 444 > result_type; 445 446 template <typename Terminal> operator ()boost::spirit::karma::make_primitive447 result_type operator()(Terminal const& term, unused_type) const 448 { 449 return result_type(fusion::at_c<0>(term.args)); 450 } 451 }; 452 }}} 453 454 #endif // defined(BOOST_SPIRIT_KARMA_REAL_FEB_26_2007_0512PM) 455