1 // Copyright (c) 2001-2011 Hartmut Kaiser
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)
6 #if !defined(BOOST_SPIRIT_KARMA_UINT_FEB_23_2007_0840PM)
7 #define BOOST_SPIRIT_KARMA_UINT_FEB_23_2007_0840PM
13 #include <boost/limits.hpp>
14 #include <boost/config.hpp>
15 #include <boost/mpl/bool.hpp>
16 #include <boost/utility/enable_if.hpp>
18 #include <boost/spirit/home/support/common_terminals.hpp>
19 #include <boost/spirit/home/support/string_traits.hpp>
20 #include <boost/spirit/home/support/numeric_traits.hpp>
21 #include <boost/spirit/home/support/info.hpp>
22 #include <boost/spirit/home/support/char_class.hpp>
23 #include <boost/spirit/home/support/container.hpp>
24 #include <boost/spirit/home/support/detail/get_encoding.hpp>
25 #include <boost/spirit/home/support/detail/is_spirit_tag.hpp>
26 #include <boost/spirit/home/karma/meta_compiler.hpp>
27 #include <boost/spirit/home/karma/delimit_out.hpp>
28 #include <boost/spirit/home/karma/auxiliary/lazy.hpp>
29 #include <boost/spirit/home/karma/detail/get_casetag.hpp>
30 #include <boost/spirit/home/karma/detail/extract_from.hpp>
31 #include <boost/spirit/home/karma/detail/enable_lit.hpp>
32 #include <boost/spirit/home/karma/domain.hpp>
33 #include <boost/spirit/home/karma/numeric/detail/numeric_utils.hpp>
34 #include <boost/fusion/include/at.hpp>
35 #include <boost/fusion/include/value_at.hpp>
36 #include <boost/fusion/include/vector.hpp>
38 namespace boost { namespace spirit
42 template <typename T, unsigned Radix>
51 ///////////////////////////////////////////////////////////////////////
52 // This one is the class that the user can instantiate directly in
53 // order to create a customized int generator
54 template <typename T = unsigned int, unsigned Radix = 10>
56 : spirit::terminal<tag::uint_generator<T, Radix> >
60 ///////////////////////////////////////////////////////////////////////////
62 ///////////////////////////////////////////////////////////////////////////
64 struct use_terminal<karma::domain, tag::ushort_> // enables ushort_
68 struct use_terminal<karma::domain, tag::uint_> // enables uint_
72 struct use_terminal<karma::domain, tag::ulong_> // enables ulong_
76 struct use_terminal<karma::domain, tag::bin> // enables bin
80 struct use_terminal<karma::domain, tag::oct> // enables oct
84 struct use_terminal<karma::domain, tag::hex> // enables hex
87 #ifdef BOOST_HAS_LONG_LONG
89 struct use_terminal<karma::domain, tag::ulong_long> // enables ulong_long
93 ///////////////////////////////////////////////////////////////////////////
94 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
95 template <> // enables lit(unsigned short(0))
96 struct use_terminal<karma::domain, unsigned short>
100 template <> // enables lit(0U)
101 struct use_terminal<karma::domain, unsigned int>
104 template <> // enables lit(0UL)
105 struct use_terminal<karma::domain, unsigned long>
108 #ifdef BOOST_HAS_LONG_LONG
109 template <> // enables lit(0ULL)
110 struct use_terminal<karma::domain, boost::ulong_long_type>
114 ///////////////////////////////////////////////////////////////////////////
115 template <typename A0>
116 struct use_terminal<karma::domain // enables ushort_(...)
117 , terminal_ex<tag::ushort_, fusion::vector1<A0> >
120 template <typename A0>
121 struct use_terminal<karma::domain // enables uint_(...)
122 , terminal_ex<tag::uint_, fusion::vector1<A0> >
125 template <typename A0>
126 struct use_terminal<karma::domain // enables ulong_(...)
127 , terminal_ex<tag::ulong_, fusion::vector1<A0> >
130 template <typename A0>
131 struct use_terminal<karma::domain // enables bin(...)
132 , terminal_ex<tag::bin, fusion::vector1<A0> >
135 template <typename A0>
136 struct use_terminal<karma::domain // enables oct(...)
137 , terminal_ex<tag::oct, fusion::vector1<A0> >
140 template <typename A0>
141 struct use_terminal<karma::domain // enables hex(...)
142 , terminal_ex<tag::hex, fusion::vector1<A0> >
145 #ifdef BOOST_HAS_LONG_LONG
146 template <typename A0>
147 struct use_terminal<karma::domain // enables ulong_long(...)
148 , terminal_ex<tag::ulong_long, fusion::vector1<A0> >
152 ///////////////////////////////////////////////////////////////////////////
153 template <> // enables *lazy* ushort_(...)
154 struct use_lazy_terminal<karma::domain, tag::ushort_, 1>
157 template <> // enables *lazy* uint_(...)
158 struct use_lazy_terminal<karma::domain, tag::uint_, 1>
161 template <> // enables *lazy* ulong_(...)
162 struct use_lazy_terminal<karma::domain, tag::ulong_, 1>
165 template <> // enables *lazy* bin(...)
166 struct use_lazy_terminal<karma::domain, tag::bin, 1>
169 template <> // enables *lazy* oct(...)
170 struct use_lazy_terminal<karma::domain, tag::oct, 1>
173 template <> // enables *lazy* hex(...)
174 struct use_lazy_terminal<karma::domain, tag::hex, 1>
177 #ifdef BOOST_HAS_LONG_LONG
178 template <> // enables *lazy* ulong_long(...)
179 struct use_lazy_terminal<karma::domain, tag::ulong_long, 1>
183 ///////////////////////////////////////////////////////////////////////////
184 // enables any custom uint_generator
185 template <typename T, unsigned Radix>
186 struct use_terminal<karma::domain, tag::uint_generator<T, Radix> >
189 // enables any custom uint_generator(...)
190 template <typename T, unsigned Radix, typename A0>
191 struct use_terminal<karma::domain
192 , terminal_ex<tag::uint_generator<T, Radix>, fusion::vector1<A0> >
195 // enables *lazy* custom uint_generator
196 template <typename T, unsigned Radix>
197 struct use_lazy_terminal<
199 , tag::uint_generator<T, Radix>
204 template <typename A0>
205 struct use_terminal<karma::domain
206 , terminal_ex<tag::lit, fusion::vector1<A0> >
207 , typename enable_if<traits::is_uint<A0> >::type>
211 ///////////////////////////////////////////////////////////////////////////////
212 namespace boost { namespace spirit { namespace karma
214 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
215 using spirit::ushort_;
217 using spirit::ulong_;
218 #ifdef BOOST_HAS_LONG_LONG
219 using spirit::ulong_long;
225 using spirit::lit; // lit(1U) is equivalent to 1U
228 using spirit::ushort_type;
229 using spirit::uint_type;
230 using spirit::ulong_type;
231 #ifdef BOOST_HAS_LONG_LONG
232 using spirit::ulong_long_type;
234 using spirit::bin_type;
235 using spirit::oct_type;
236 using spirit::hex_type;
238 using spirit::lit_type;
240 ///////////////////////////////////////////////////////////////////////////
241 // This specialization is used for unsigned int generators not having a
242 // direct initializer: uint_, ulong_ etc. These generators must be used in
243 // conjunction with an Attribute.
244 ///////////////////////////////////////////////////////////////////////////
245 template <typename T, typename CharEncoding, typename Tag, unsigned Radix>
246 struct any_uint_generator
247 : primitive_generator<any_uint_generator<T, CharEncoding, Tag, Radix> >
249 template <typename Context, typename Unused>
255 // check template Attribute 'Radix' for validity
256 BOOST_SPIRIT_ASSERT_MSG(
257 Radix >= 2 && Radix <= 36, not_supported_radix, ());
259 BOOST_SPIRIT_ASSERT_MSG(
260 // the following is a workaround for STLPort, where the simpler
261 // `!std::numeric_limits<T>::is_signed` wouldn't compile
262 mpl::not_<mpl::bool_<std::numeric_limits<T>::is_signed> >::value,
263 signed_unsigned_mismatch, ());
265 // int has a Attribute attached
266 template <typename OutputIterator, typename Context, typename Delimiter
267 , typename Attribute>
269 generate(OutputIterator& sink, Context& context, Delimiter const& d
270 , Attribute const& attr)
272 if (!traits::has_optional_value(attr))
273 return false; // fail if it's an uninitialized optional
275 return uint_inserter<Radix, CharEncoding, Tag>::
276 call(sink, traits::extract_from<T>(attr, context)) &&
277 delimit_out(sink, d); // always do post-delimiting
280 // this int has no Attribute attached, it needs to have been
281 // initialized from a direct literal
282 template <typename OutputIterator, typename Context, typename Delimiter>
284 generate(OutputIterator&, Context&, Delimiter const&, unused_type)
286 // It is not possible (doesn't make sense) to use numeric generators
287 // without providing any attribute, as the generator doesn't 'know'
288 // what to output. The following assertion fires if this situation
289 // is detected in your code.
290 BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, uint_not_usable_without_attribute, ());
294 template <typename Context>
295 static info what(Context const& /*context*/)
297 return info("unsigned-integer");
301 ///////////////////////////////////////////////////////////////////////////
302 // This specialization is used for unsigned int generators having a direct
303 // initializer: uint_(10), ulong_(20) etc.
304 ///////////////////////////////////////////////////////////////////////////
306 typename T, typename CharEncoding, typename Tag, unsigned Radix
308 struct literal_uint_generator
309 : primitive_generator<literal_uint_generator<T, CharEncoding, Tag, Radix
312 template <typename Context, typename Unused = unused_type>
314 : mpl::if_c<no_attribute, unused_type, T>
317 literal_uint_generator(typename add_const<T>::type n)
320 // check template Attribute 'Radix' for validity
321 BOOST_SPIRIT_ASSERT_MSG(
322 Radix >= 2 && Radix <= 36, not_supported_radix, ());
324 BOOST_SPIRIT_ASSERT_MSG(
325 // the following is a workaround for STLPort, where the simpler
326 // `!std::numeric_limits<T>::is_signed wouldn't` compile
327 mpl::not_<mpl::bool_<std::numeric_limits<T>::is_signed> >::value,
328 signed_unsigned_mismatch, ());
330 // A uint(1U) which additionally has an associated attribute emits
331 // its immediate literal only if it matches the attribute, otherwise
333 template <typename OutputIterator, typename Context, typename Delimiter
334 , typename Attribute>
335 bool generate(OutputIterator& sink, Context& context
336 , Delimiter const& d, Attribute const& attr) const
338 typedef typename attribute<Context>::type attribute_type;
339 if (!traits::has_optional_value(attr) ||
340 n_ != traits::extract_from<attribute_type>(attr, context))
344 return uint_inserter<Radix, CharEncoding, Tag>::call(sink, n_) &&
345 delimit_out(sink, d); // always do post-delimiting
348 // A uint(1U) without any associated attribute just emits its
350 template <typename OutputIterator, typename Context, typename Delimiter>
351 bool generate(OutputIterator& sink, Context&, Delimiter const& d
354 return uint_inserter<Radix, CharEncoding, Tag>::call(sink, n_) &&
355 delimit_out(sink, d); // always do post-delimiting
358 template <typename Context>
359 static info what(Context const& /*context*/)
361 return info("unsigned-integer");
367 ///////////////////////////////////////////////////////////////////////////
368 // Generator generators: make_xxx function (objects)
369 ///////////////////////////////////////////////////////////////////////////
372 template <typename T, typename Modifiers, unsigned Radix = 10>
375 static bool const lower =
376 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
377 static bool const upper =
378 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
380 typedef any_uint_generator<
382 , typename spirit::detail::get_encoding_with_case<
383 Modifiers, unused_type, lower || upper>::type
384 , typename detail::get_casetag<Modifiers, lower || upper>::type
388 result_type operator()(unused_type, unused_type) const
390 return result_type();
395 ///////////////////////////////////////////////////////////////////////////
396 template <typename Modifiers>
397 struct make_primitive<tag::ushort_, Modifiers>
398 : detail::make_uint<unsigned short, Modifiers> {};
400 template <typename Modifiers>
401 struct make_primitive<tag::uint_, Modifiers>
402 : detail::make_uint<unsigned int, Modifiers> {};
404 template <typename Modifiers>
405 struct make_primitive<tag::ulong_, Modifiers>
406 : detail::make_uint<unsigned long, Modifiers> {};
408 template <typename Modifiers>
409 struct make_primitive<tag::bin, Modifiers>
410 : detail::make_uint<unsigned, Modifiers, 2> {};
412 template <typename Modifiers>
413 struct make_primitive<tag::oct, Modifiers>
414 : detail::make_uint<unsigned, Modifiers, 8> {};
416 template <typename Modifiers>
417 struct make_primitive<tag::hex, Modifiers>
418 : detail::make_uint<unsigned, Modifiers, 16> {};
420 #ifdef BOOST_HAS_LONG_LONG
421 template <typename Modifiers>
422 struct make_primitive<tag::ulong_long, Modifiers>
423 : detail::make_uint<boost::ulong_long_type, Modifiers> {};
426 template <typename T, unsigned Radix, typename Modifiers>
427 struct make_primitive<tag::uint_generator<T, Radix>, Modifiers>
428 : detail::make_uint<typename remove_const<T>::type, Modifiers, Radix> {};
430 ///////////////////////////////////////////////////////////////////////////
433 template <typename T, typename Modifiers, unsigned Radix = 10>
434 struct make_uint_direct
436 static bool const lower =
437 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
438 static bool const upper =
439 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
441 typedef literal_uint_generator<
443 , typename spirit::detail::get_encoding_with_case<
444 Modifiers, unused_type, lower || upper>::type
445 , typename detail::get_casetag<Modifiers, lower || upper>::type
449 template <typename Terminal>
450 result_type operator()(Terminal const& term, unused_type) const
452 return result_type(fusion::at_c<0>(term.args));
457 template <typename Modifiers, typename A0>
458 struct make_primitive<
459 terminal_ex<tag::ushort_, fusion::vector1<A0> >, Modifiers>
460 : detail::make_uint_direct<unsigned short, Modifiers> {};
462 template <typename Modifiers, typename A0>
463 struct make_primitive<
464 terminal_ex<tag::uint_, fusion::vector1<A0> >, Modifiers>
465 : detail::make_uint_direct<unsigned int, Modifiers> {};
467 template <typename Modifiers, typename A0>
468 struct make_primitive<
469 terminal_ex<tag::ulong_, fusion::vector1<A0> >, Modifiers>
470 : detail::make_uint_direct<unsigned long, Modifiers> {};
472 template <typename Modifiers, typename A0>
473 struct make_primitive<
474 terminal_ex<tag::bin, fusion::vector1<A0> >, Modifiers>
475 : detail::make_uint_direct<unsigned, Modifiers, 2> {};
477 template <typename Modifiers, typename A0>
478 struct make_primitive<
479 terminal_ex<tag::oct, fusion::vector1<A0> >, Modifiers>
480 : detail::make_uint_direct<unsigned, Modifiers, 8> {};
482 template <typename Modifiers, typename A0>
483 struct make_primitive<
484 terminal_ex<tag::hex, fusion::vector1<A0> >, Modifiers>
485 : detail::make_uint_direct<unsigned, Modifiers, 16> {};
487 #ifdef BOOST_HAS_LONG_LONG
488 template <typename Modifiers, typename A0>
489 struct make_primitive<
490 terminal_ex<tag::ulong_long, fusion::vector1<A0> >, Modifiers>
491 : detail::make_uint_direct<boost::ulong_long_type, Modifiers> {};
494 template <typename T, unsigned Radix, typename A0, typename Modifiers>
495 struct make_primitive<
496 terminal_ex<tag::uint_generator<T, Radix>, fusion::vector1<A0> >
498 : detail::make_uint_direct<typename remove_const<T>::type, Modifiers, Radix>
501 ///////////////////////////////////////////////////////////////////////////
504 template <typename T, typename Modifiers>
505 struct basic_uint_literal
507 static bool const lower =
508 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
509 static bool const upper =
510 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
512 typedef literal_uint_generator<
514 , typename spirit::detail::get_encoding_with_case<
515 Modifiers, unused_type, lower || upper>::type
516 , typename detail::get_casetag<Modifiers, lower || upper>::type
520 template <typename T_>
521 result_type operator()(T_ i, unused_type) const
523 return result_type(i);
528 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
529 template <typename Modifiers>
530 struct make_primitive<unsigned short, Modifiers>
531 : detail::basic_uint_literal<unsigned short, Modifiers> {};
534 template <typename Modifiers>
535 struct make_primitive<unsigned int, Modifiers>
536 : detail::basic_uint_literal<unsigned int, Modifiers> {};
538 template <typename Modifiers>
539 struct make_primitive<unsigned long, Modifiers>
540 : detail::basic_uint_literal<unsigned long, Modifiers> {};
542 #ifdef BOOST_HAS_LONG_LONG
543 template <typename Modifiers>
544 struct make_primitive<boost::ulong_long_type, Modifiers>
545 : detail::basic_uint_literal<boost::ulong_long_type, Modifiers> {};
549 template <typename Modifiers, typename A0>
550 struct make_primitive<
551 terminal_ex<tag::lit, fusion::vector1<A0> >
553 , typename enable_if<traits::is_uint<A0> >::type>
555 static bool const lower =
556 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
557 static bool const upper =
558 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
560 typedef literal_uint_generator<
561 typename remove_const<A0>::type
562 , typename spirit::detail::get_encoding_with_case<
563 Modifiers, unused_type, lower || upper>::type
564 , typename detail::get_casetag<Modifiers, lower || upper>::type
568 template <typename Terminal>
569 result_type operator()(Terminal const& term, unused_type) const
571 return result_type(fusion::at_c<0>(term.args));