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_UINT_FEB_23_2007_0840PM)
7 #define BOOST_SPIRIT_KARMA_UINT_FEB_23_2007_0840PM
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/limits.hpp>
14 #include <boost/config.hpp>
15 #include <boost/mpl/bool.hpp>
16 #include <boost/utility/enable_if.hpp>
17 
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>
37 
38 namespace boost { namespace spirit
39 {
40     namespace tag
41     {
42         template <typename T, unsigned Radix>
43         struct uint_generator
44         {
45             BOOST_SPIRIT_IS_TAG()
46         };
47     }
48 
49     namespace karma
50     {
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>
55         struct uint_generator
56           : spirit::terminal<tag::uint_generator<T, Radix> >
57         {};
58     }
59 
60     ///////////////////////////////////////////////////////////////////////////
61     // Enablers
62     ///////////////////////////////////////////////////////////////////////////
63     template <>
64     struct use_terminal<karma::domain, tag::ushort_>   // enables ushort_
65       : mpl::true_ {};
66 
67     template <>
68     struct use_terminal<karma::domain, tag::uint_>     // enables uint_
69       : mpl::true_ {};
70 
71     template <>
72     struct use_terminal<karma::domain, tag::ulong_>    // enables ulong_
73       : mpl::true_ {};
74 
75     template <>
76     struct use_terminal<karma::domain, tag::bin>       // enables bin
77       : mpl::true_ {};
78 
79     template <>
80     struct use_terminal<karma::domain, tag::oct>       // enables oct
81       : mpl::true_ {};
82 
83     template <>
84     struct use_terminal<karma::domain, tag::hex>       // enables hex
85       : mpl::true_ {};
86 
87 #ifdef BOOST_HAS_LONG_LONG
88     template <>
89     struct use_terminal<karma::domain, tag::ulong_long> // enables ulong_long
90       : mpl::true_ {};
91 #endif
92 
93     ///////////////////////////////////////////////////////////////////////////
94 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
95     template <>           // enables lit(unsigned short(0))
96     struct use_terminal<karma::domain, unsigned short>
97       : mpl::true_ {};
98 #endif
99 
100     template <>           // enables lit(0U)
101     struct use_terminal<karma::domain, unsigned int>
102       : mpl::true_ {};
103 
104     template <>           // enables lit(0UL)
105     struct use_terminal<karma::domain, unsigned long>
106       : mpl::true_ {};
107 
108 #ifdef BOOST_HAS_LONG_LONG
109     template <>           // enables lit(0ULL)
110     struct use_terminal<karma::domain, boost::ulong_long_type>
111       : mpl::true_ {};
112 #endif
113 
114     ///////////////////////////////////////////////////////////////////////////
115     template <typename A0>
116     struct use_terminal<karma::domain         // enables ushort_(...)
117       , terminal_ex<tag::ushort_, fusion::vector1<A0> >
118     > : mpl::true_ {};
119 
120     template <typename A0>
121     struct use_terminal<karma::domain         // enables uint_(...)
122       , terminal_ex<tag::uint_, fusion::vector1<A0> >
123     > : mpl::true_ {};
124 
125     template <typename A0>
126     struct use_terminal<karma::domain         // enables ulong_(...)
127       , terminal_ex<tag::ulong_, fusion::vector1<A0> >
128     > : mpl::true_ {};
129 
130     template <typename A0>
131     struct use_terminal<karma::domain         // enables bin(...)
132       , terminal_ex<tag::bin, fusion::vector1<A0> >
133     > : mpl::true_ {};
134 
135     template <typename A0>
136     struct use_terminal<karma::domain         // enables oct(...)
137       , terminal_ex<tag::oct, fusion::vector1<A0> >
138     > : mpl::true_ {};
139 
140     template <typename A0>
141     struct use_terminal<karma::domain         // enables hex(...)
142       , terminal_ex<tag::hex, fusion::vector1<A0> >
143     > : mpl::true_ {};
144 
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> >
149     > : mpl::true_ {};
150 #endif
151 
152     ///////////////////////////////////////////////////////////////////////////
153     template <>                               // enables *lazy* ushort_(...)
154     struct use_lazy_terminal<karma::domain, tag::ushort_, 1>
155       : mpl::true_ {};
156 
157     template <>                               // enables *lazy* uint_(...)
158     struct use_lazy_terminal<karma::domain, tag::uint_, 1>
159       : mpl::true_ {};
160 
161     template <>                               // enables *lazy* ulong_(...)
162     struct use_lazy_terminal<karma::domain, tag::ulong_, 1>
163       : mpl::true_ {};
164 
165     template <>                               // enables *lazy* bin(...)
166     struct use_lazy_terminal<karma::domain, tag::bin, 1>
167       : mpl::true_ {};
168 
169     template <>                               // enables *lazy* oct(...)
170     struct use_lazy_terminal<karma::domain, tag::oct, 1>
171       : mpl::true_ {};
172 
173     template <>                               // enables *lazy* hex(...)
174     struct use_lazy_terminal<karma::domain, tag::hex, 1>
175       : mpl::true_ {};
176 
177 #ifdef BOOST_HAS_LONG_LONG
178     template <>                               // enables *lazy* ulong_long(...)
179     struct use_lazy_terminal<karma::domain, tag::ulong_long, 1>
180       : mpl::true_ {};
181 #endif
182 
183     ///////////////////////////////////////////////////////////////////////////
184     // enables any custom uint_generator
185     template <typename T, unsigned Radix>
186     struct use_terminal<karma::domain, tag::uint_generator<T, Radix> >
187       : mpl::true_ {};
188 
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> >
193     > : mpl::true_ {};
194 
195     // enables *lazy* custom uint_generator
196     template <typename T, unsigned Radix>
197     struct use_lazy_terminal<
198         karma::domain
199       , tag::uint_generator<T, Radix>
200       , 1 // arity
201     > : mpl::true_ {};
202 
203     // enables lit(uint)
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>
208       : mpl::true_ {};
209 }}
210 
211 ///////////////////////////////////////////////////////////////////////////////
212 namespace boost { namespace spirit { namespace karma
213 {
214 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
215     using spirit::ushort_;
216     using spirit::uint_;
217     using spirit::ulong_;
218 #ifdef BOOST_HAS_LONG_LONG
219     using spirit::ulong_long;
220 #endif
221     using spirit::bin;
222     using spirit::oct;
223     using spirit::hex;
224 
225     using spirit::lit;    // lit(1U) is equivalent to 1U
226 #endif
227 
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;
233 #endif
234     using spirit::bin_type;
235     using spirit::oct_type;
236     using spirit::hex_type;
237 
238     using spirit::lit_type;
239 
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> >
248     {
249         template <typename Context, typename Unused>
250         struct attribute
251         {
252             typedef T type;
253         };
254 
255         // check template Attribute 'Radix' for validity
256         BOOST_SPIRIT_ASSERT_MSG(
257             Radix >= 2 && Radix <= 36, not_supported_radix, ());
258 
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, ());
264 
265         // int has a Attribute attached
266         template <typename OutputIterator, typename Context, typename Delimiter
267           , typename Attribute>
268         static bool
generateboost::spirit::karma::any_uint_generator269         generate(OutputIterator& sink, Context& context, Delimiter const& d
270           , Attribute const& attr)
271         {
272             if (!traits::has_optional_value(attr))
273                 return false;       // fail if it's an uninitialized optional
274 
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
278         }
279 
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>
283         static bool
generateboost::spirit::karma::any_uint_generator284         generate(OutputIterator&, Context&, Delimiter const&, unused_type)
285         {
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, ());
291             return false;
292         }
293 
294         template <typename Context>
whatboost::spirit::karma::any_uint_generator295         static info what(Context const& /*context*/)
296         {
297             return info("unsigned-integer");
298         }
299     };
300 
301     ///////////////////////////////////////////////////////////////////////////
302     //  This specialization is used for unsigned int generators having a direct
303     //  initializer: uint_(10), ulong_(20) etc.
304     ///////////////////////////////////////////////////////////////////////////
305     template <
306         typename T, typename CharEncoding, typename Tag, unsigned Radix
307       , bool no_attribute>
308     struct literal_uint_generator
309       : primitive_generator<literal_uint_generator<T, CharEncoding, Tag, Radix
310           , no_attribute> >
311     {
312         template <typename Context, typename Unused = unused_type>
313         struct attribute
314           : mpl::if_c<no_attribute, unused_type, T>
315         {};
316 
literal_uint_generatorboost::spirit::karma::literal_uint_generator317         literal_uint_generator(typename add_const<T>::type n)
318           : n_(n) {}
319 
320         // check template Attribute 'Radix' for validity
321         BOOST_SPIRIT_ASSERT_MSG(
322             Radix >= 2 && Radix <= 36, not_supported_radix, ());
323 
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, ());
329 
330         // A uint(1U) which additionally has an associated attribute emits
331         // its immediate literal only if it matches the attribute, otherwise
332         // it fails.
333         template <typename OutputIterator, typename Context, typename Delimiter
334           , typename Attribute>
generateboost::spirit::karma::literal_uint_generator335         bool generate(OutputIterator& sink, Context& context
336           , Delimiter const& d, Attribute const& attr) const
337         {
338             typedef typename attribute<Context>::type attribute_type;
339             if (!traits::has_optional_value(attr) ||
340                 n_ != traits::extract_from<attribute_type>(attr, context))
341             {
342                 return false;
343             }
344             return uint_inserter<Radix, CharEncoding, Tag>::call(sink, n_) &&
345                    delimit_out(sink, d);      // always do post-delimiting
346         }
347 
348         // A uint(1U) without any associated attribute just emits its
349         // immediate literal
350         template <typename OutputIterator, typename Context, typename Delimiter>
generateboost::spirit::karma::literal_uint_generator351         bool generate(OutputIterator& sink, Context&, Delimiter const& d
352           , unused_type) const
353         {
354             return uint_inserter<Radix, CharEncoding, Tag>::call(sink, n_) &&
355                    delimit_out(sink, d);      // always do post-delimiting
356         }
357 
358         template <typename Context>
whatboost::spirit::karma::literal_uint_generator359         static info what(Context const& /*context*/)
360         {
361             return info("unsigned-integer");
362         }
363 
364         T n_;
365     };
366 
367     ///////////////////////////////////////////////////////////////////////////
368     // Generator generators: make_xxx function (objects)
369     ///////////////////////////////////////////////////////////////////////////
370     namespace detail
371     {
372         template <typename T, typename Modifiers, unsigned Radix = 10>
373         struct make_uint
374         {
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;
379 
380             typedef any_uint_generator<
381                 T
382               , typename spirit::detail::get_encoding_with_case<
383                     Modifiers, unused_type, lower || upper>::type
384               , typename detail::get_casetag<Modifiers, lower || upper>::type
385               , Radix
386             > result_type;
387 
operator ()boost::spirit::karma::detail::make_uint388             result_type operator()(unused_type, unused_type) const
389             {
390                 return result_type();
391             }
392         };
393     }
394 
395     ///////////////////////////////////////////////////////////////////////////
396     template <typename Modifiers>
397     struct make_primitive<tag::ushort_, Modifiers>
398       : detail::make_uint<unsigned short, Modifiers> {};
399 
400     template <typename Modifiers>
401     struct make_primitive<tag::uint_, Modifiers>
402       : detail::make_uint<unsigned int, Modifiers> {};
403 
404     template <typename Modifiers>
405     struct make_primitive<tag::ulong_, Modifiers>
406       : detail::make_uint<unsigned long, Modifiers> {};
407 
408     template <typename Modifiers>
409     struct make_primitive<tag::bin, Modifiers>
410       : detail::make_uint<unsigned, Modifiers, 2> {};
411 
412     template <typename Modifiers>
413     struct make_primitive<tag::oct, Modifiers>
414       : detail::make_uint<unsigned, Modifiers, 8> {};
415 
416     template <typename Modifiers>
417     struct make_primitive<tag::hex, Modifiers>
418       : detail::make_uint<unsigned, Modifiers, 16> {};
419 
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> {};
424 #endif
425 
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> {};
429 
430     ///////////////////////////////////////////////////////////////////////////
431     namespace detail
432     {
433         template <typename T, typename Modifiers, unsigned Radix = 10>
434         struct make_uint_direct
435         {
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;
440 
441             typedef literal_uint_generator<
442                 T
443               , typename spirit::detail::get_encoding_with_case<
444                     Modifiers, unused_type, lower || upper>::type
445               , typename detail::get_casetag<Modifiers, lower || upper>::type
446               , Radix, false
447             > result_type;
448 
449             template <typename Terminal>
operator ()boost::spirit::karma::detail::make_uint_direct450             result_type operator()(Terminal const& term, unused_type) const
451             {
452                 return result_type(fusion::at_c<0>(term.args));
453             }
454         };
455     }
456 
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> {};
461 
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> {};
466 
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> {};
471 
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> {};
476 
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> {};
481 
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> {};
486 
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> {};
492 #endif
493 
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> >
497           , Modifiers>
498       : detail::make_uint_direct<typename remove_const<T>::type, Modifiers, Radix>
499     {};
500 
501     ///////////////////////////////////////////////////////////////////////////
502     namespace detail
503     {
504         template <typename T, typename Modifiers>
505         struct basic_uint_literal
506         {
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;
511 
512             typedef literal_uint_generator<
513                 T
514               , typename spirit::detail::get_encoding_with_case<
515                     Modifiers, unused_type, lower || upper>::type
516               , typename detail::get_casetag<Modifiers, lower || upper>::type
517               , 10, true
518             > result_type;
519 
520             template <typename T_>
operator ()boost::spirit::karma::detail::basic_uint_literal521             result_type operator()(T_ i, unused_type) const
522             {
523                 return result_type(i);
524             }
525         };
526     }
527 
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> {};
532 #endif
533 
534     template <typename Modifiers>
535     struct make_primitive<unsigned int, Modifiers>
536       : detail::basic_uint_literal<unsigned int, Modifiers> {};
537 
538     template <typename Modifiers>
539     struct make_primitive<unsigned long, Modifiers>
540       : detail::basic_uint_literal<unsigned long, Modifiers> {};
541 
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> {};
546 #endif
547 
548     // lit(uint)
549     template <typename Modifiers, typename A0>
550     struct make_primitive<
551             terminal_ex<tag::lit, fusion::vector1<A0> >
552           , Modifiers
553           , typename enable_if<traits::is_uint<A0> >::type>
554     {
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;
559 
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
565           , 10, true
566         > result_type;
567 
568         template <typename Terminal>
operator ()boost::spirit::karma::make_primitive569         result_type operator()(Terminal const& term, unused_type) const
570         {
571             return result_type(fusion::at_c<0>(term.args));
572         }
573     };
574 }}}
575 
576 #endif
577