1 //  Copyright (c) 2001-2012 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_INT_FEB_23_2007_0840PM)
7 #define BOOST_SPIRIT_KARMA_INT_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 ///////////////////////////////////////////////////////////////////////////////
39 namespace boost { namespace spirit
40 {
41     namespace tag
42     {
43         template <typename T, unsigned Radix, bool force_sign>
44         struct int_generator
45         {
46             BOOST_SPIRIT_IS_TAG()
47         };
48     }
49 
50     namespace karma
51     {
52         ///////////////////////////////////////////////////////////////////////
53         // This one is the class that the user can instantiate directly in
54         // order to create a customized int generator
55         template <typename T = int, unsigned Radix = 10, bool force_sign = false>
56         struct int_generator
57           : spirit::terminal<tag::int_generator<T, Radix, force_sign> >
58         {};
59     }
60 
61     ///////////////////////////////////////////////////////////////////////////
62     // Enablers
63     ///////////////////////////////////////////////////////////////////////////
64     template <>
65     struct use_terminal<karma::domain, tag::short_>    // enables short_
66       : mpl::true_ {};
67 
68     template <>
69     struct use_terminal<karma::domain, tag::int_>      // enables int_
70       : mpl::true_ {};
71 
72     template <>
73     struct use_terminal<karma::domain, tag::long_>     // enables long_
74       : mpl::true_ {};
75 
76 #ifdef BOOST_HAS_LONG_LONG
77     template <>
78     struct use_terminal<karma::domain, tag::long_long> // enables long_long
79       : mpl::true_ {};
80 #endif
81 
82     ///////////////////////////////////////////////////////////////////////////
83     template <>
84     struct use_terminal<karma::domain, short>    // enables lit(short(0))
85       : mpl::true_ {};
86 
87     template <>
88     struct use_terminal<karma::domain, int>      // enables lit(0)
89       : mpl::true_ {};
90 
91     template <>
92     struct use_terminal<karma::domain, long>     // enables lit(0L)
93       : mpl::true_ {};
94 
95 #ifdef BOOST_HAS_LONG_LONG
96     template <>
97     struct use_terminal<karma::domain, boost::long_long_type> // enables lit(0LL)
98       : mpl::true_ {};
99 #endif
100 
101     ///////////////////////////////////////////////////////////////////////////
102     template <typename A0>
103     struct use_terminal<karma::domain         // enables short_(...)
104       , terminal_ex<tag::short_, fusion::vector1<A0> >
105     > : mpl::true_ {};
106 
107     template <typename A0>
108     struct use_terminal<karma::domain         // enables int_(...)
109       , terminal_ex<tag::int_, fusion::vector1<A0> >
110     > : mpl::true_ {};
111 
112     template <typename A0>
113     struct use_terminal<karma::domain         // enables long_(...)
114       , terminal_ex<tag::long_, fusion::vector1<A0> >
115     > : mpl::true_ {};
116 
117 #ifdef BOOST_HAS_LONG_LONG
118     template <typename A0>
119     struct use_terminal<karma::domain         // enables long_long(...)
120       , terminal_ex<tag::long_long, fusion::vector1<A0> >
121     > : mpl::true_ {};
122 #endif
123 
124     ///////////////////////////////////////////////////////////////////////////
125     template <>                               // enables *lazy* short_(...)
126     struct use_lazy_terminal<karma::domain, tag::short_, 1>
127       : mpl::true_ {};
128 
129     template <>                               // enables *lazy* int_(...)
130     struct use_lazy_terminal<karma::domain, tag::int_, 1>
131       : mpl::true_ {};
132 
133     template <>                               // enables *lazy* long_(...)
134     struct use_lazy_terminal<karma::domain, tag::long_, 1>
135       : mpl::true_ {};
136 
137 #ifdef BOOST_HAS_LONG_LONG
138     template <>                               // enables *lazy* long_long(...)
139     struct use_lazy_terminal<karma::domain, tag::long_long, 1>
140       : mpl::true_ {};
141 #endif
142 
143     ///////////////////////////////////////////////////////////////////////////
144     // enables any custom int_generator
145     template <typename T, unsigned Radix, bool force_sign>
146     struct use_terminal<karma::domain, tag::int_generator<T, Radix, force_sign> >
147       : mpl::true_ {};
148 
149     // enables any custom int_generator(...)
150     template <typename T, unsigned Radix, bool force_sign, typename A0>
151     struct use_terminal<karma::domain
152       , terminal_ex<tag::int_generator<T, Radix, force_sign>
153                   , fusion::vector1<A0> >
154     > : mpl::true_ {};
155 
156     // enables *lazy* custom int_generator
157     template <typename T, unsigned Radix, bool force_sign>
158     struct use_lazy_terminal<
159         karma::domain
160       , tag::int_generator<T, Radix, force_sign>
161       , 1 // arity
162     > : mpl::true_ {};
163 
164     // enables lit(int)
165     template <typename A0>
166     struct use_terminal<karma::domain
167           , terminal_ex<tag::lit, fusion::vector1<A0> >
168           , typename enable_if<traits::is_int<A0> >::type>
169       : mpl::true_ {};
170 }}
171 
172 ///////////////////////////////////////////////////////////////////////////////
173 namespace boost { namespace spirit { namespace karma
174 {
175 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
176     using spirit::short_;
177     using spirit::int_;
178     using spirit::long_;
179 #ifdef BOOST_HAS_LONG_LONG
180     using spirit::long_long;
181 #endif
182     using spirit::lit;    // lit(1) is equivalent to 1
183 #endif
184 
185     using spirit::short_type;
186     using spirit::int_type;
187     using spirit::long_type;
188 #ifdef BOOST_HAS_LONG_LONG
189     using spirit::long_long_type;
190 #endif
191 
192     using spirit::lit_type;
193 
194     ///////////////////////////////////////////////////////////////////////////
195     //  This specialization is used for int generators not having a direct
196     //  initializer: int_, long_ etc. These generators must be used in
197     //  conjunction with an Attribute.
198     ///////////////////////////////////////////////////////////////////////////
199     template <
200         typename T, typename CharEncoding, typename Tag, unsigned Radix
201       , bool force_sign>
202     struct any_int_generator
203       : primitive_generator<any_int_generator<T, CharEncoding, Tag, Radix
204           , force_sign> >
205     {
206     private:
207         template <typename OutputIterator, typename Attribute>
insert_intboost::spirit::karma::any_int_generator208         static bool insert_int(OutputIterator& sink, Attribute const& attr)
209         {
210             return sign_inserter::call(sink, traits::test_zero(attr)
211                       , traits::test_negative(attr), force_sign) &&
212                    int_inserter<Radix, CharEncoding, Tag>::call(sink
213                       , traits::get_absolute_value(attr));
214         }
215 
216     public:
217         template <typename Context, typename Unused>
218         struct attribute
219         {
220             typedef T type;
221         };
222 
223         // check template Attribute 'Radix' for validity
224         BOOST_SPIRIT_ASSERT_MSG(
225             Radix == 2 || Radix == 8 || Radix == 10 || Radix == 16,
226             not_supported_radix, ());
227 
228         BOOST_SPIRIT_ASSERT_MSG(std::numeric_limits<T>::is_signed,
229             signed_unsigned_mismatch, ());
230 
231         // int has a Attribute attached
232         template <typename OutputIterator, typename Context, typename Delimiter
233           , typename Attribute>
234         static bool
generateboost::spirit::karma::any_int_generator235         generate(OutputIterator& sink, Context& context, Delimiter const& d
236           , Attribute const& attr)
237         {
238             if (!traits::has_optional_value(attr))
239                 return false;       // fail if it's an uninitialized optional
240 
241             return insert_int(sink, traits::extract_from<T>(attr, context)) &&
242                    delimit_out(sink, d);      // always do post-delimiting
243         }
244 
245         // this int has no Attribute attached, it needs to have been
246         // initialized from a direct literal
247         template <typename OutputIterator, typename Context, typename Delimiter>
248         static bool
generateboost::spirit::karma::any_int_generator249         generate(OutputIterator&, Context&, Delimiter const&, unused_type)
250         {
251             // It is not possible (doesn't make sense) to use numeric generators
252             // without providing any attribute, as the generator doesn't 'know'
253             // what to output. The following assertion fires if this situation
254             // is detected in your code.
255             BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, int_not_usable_without_attribute, ());
256             return false;
257         }
258 
259         template <typename Context>
whatboost::spirit::karma::any_int_generator260         static info what(Context const& /*context*/)
261         {
262             return info("integer");
263         }
264     };
265 
266     ///////////////////////////////////////////////////////////////////////////
267     //  This specialization is used for int generators having a direct
268     //  initializer: int_(10), long_(20) etc.
269     ///////////////////////////////////////////////////////////////////////////
270     template <
271         typename T, typename CharEncoding, typename Tag, unsigned Radix
272       , bool force_sign, bool no_attribute>
273     struct literal_int_generator
274       : primitive_generator<literal_int_generator<T, CharEncoding, Tag, Radix
275           , force_sign, no_attribute> >
276     {
277     private:
278         template <typename OutputIterator, typename Attribute>
insert_intboost::spirit::karma::literal_int_generator279         static bool insert_int(OutputIterator& sink, Attribute const& attr)
280         {
281             return sign_inserter::call(sink, traits::test_zero(attr)
282                       , traits::test_negative(attr), force_sign) &&
283                    int_inserter<Radix, CharEncoding, Tag>::call(sink
284                       , traits::get_absolute_value(attr));
285         }
286 
287     public:
288         template <typename Context, typename Unused = unused_type>
289         struct attribute
290           : mpl::if_c<no_attribute, unused_type, T>
291         {};
292 
literal_int_generatorboost::spirit::karma::literal_int_generator293         literal_int_generator(typename add_const<T>::type n)
294           : n_(n) {}
295 
296         // check template Attribute 'Radix' for validity
297         BOOST_SPIRIT_ASSERT_MSG(
298             Radix == 2 || Radix == 8 || Radix == 10 || Radix == 16,
299             not_supported_radix, ());
300 
301         BOOST_SPIRIT_ASSERT_MSG(std::numeric_limits<T>::is_signed,
302             signed_unsigned_mismatch, ());
303 
304         // A int_(1) which additionally has an associated attribute emits
305         // its immediate literal only if it matches the attribute, otherwise
306         // it fails.
307         template <typename OutputIterator, typename Context, typename Delimiter
308           , typename Attribute>
generateboost::spirit::karma::literal_int_generator309         bool generate(OutputIterator& sink, Context& context
310           , Delimiter const& d, Attribute const& attr) const
311         {
312             typedef typename attribute<Context>::type attribute_type;
313             if (!traits::has_optional_value(attr) ||
314                 n_ != traits::extract_from<attribute_type>(attr, context))
315             {
316                 return false;
317             }
318             return insert_int(sink, n_) && delimit_out(sink, d);
319         }
320 
321         // A int_(1) without any associated attribute just emits its
322         // immediate literal
323         template <typename OutputIterator, typename Context, typename Delimiter>
generateboost::spirit::karma::literal_int_generator324         bool generate(OutputIterator& sink, Context&, Delimiter const& d
325           , unused_type) const
326         {
327             return insert_int(sink, n_) && delimit_out(sink, d);
328         }
329 
330         template <typename Context>
whatboost::spirit::karma::literal_int_generator331         static info what(Context const& /*context*/)
332         {
333             return info("integer");
334         }
335 
336         T n_;
337     };
338 
339     ///////////////////////////////////////////////////////////////////////////
340     // Generator generators: make_xxx function (objects)
341     ///////////////////////////////////////////////////////////////////////////
342     namespace detail
343     {
344         template <typename T, typename Modifiers, unsigned Radix = 10
345           , bool force_sign = false>
346         struct make_int
347         {
348             static bool const lower =
349                 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
350             static bool const upper =
351                 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
352 
353             typedef any_int_generator<
354                 T
355               , typename spirit::detail::get_encoding_with_case<
356                     Modifiers, unused_type, lower || upper>::type
357               , typename detail::get_casetag<Modifiers, lower || upper>::type
358               , Radix
359               , force_sign
360             > result_type;
361 
operator ()boost::spirit::karma::detail::make_int362             result_type operator()(unused_type, unused_type) const
363             {
364                 return result_type();
365             }
366         };
367     }
368 
369     ///////////////////////////////////////////////////////////////////////////
370     template <typename Modifiers>
371     struct make_primitive<tag::short_, Modifiers>
372       : detail::make_int<short, Modifiers> {};
373 
374     template <typename Modifiers>
375     struct make_primitive<tag::int_, Modifiers>
376       : detail::make_int<int, Modifiers> {};
377 
378     template <typename Modifiers>
379     struct make_primitive<tag::long_, Modifiers>
380       : detail::make_int<long, Modifiers> {};
381 
382 #ifdef BOOST_HAS_LONG_LONG
383     template <typename Modifiers>
384     struct make_primitive<tag::long_long, Modifiers>
385       : detail::make_int<boost::long_long_type, Modifiers> {};
386 #endif
387 
388     template <typename T, unsigned Radix, bool force_sign, typename Modifiers>
389     struct make_primitive<tag::int_generator<T, Radix, force_sign>, Modifiers>
390       : detail::make_int<typename remove_const<T>::type
391           , Modifiers, Radix, force_sign> {};
392 
393     ///////////////////////////////////////////////////////////////////////////
394     namespace detail
395     {
396         template <typename T, typename Modifiers, unsigned Radix = 10
397           , bool force_sign = false>
398         struct make_int_direct
399         {
400             static bool const lower =
401                 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
402             static bool const upper =
403                 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
404 
405             typedef literal_int_generator<
406                 T
407               , typename spirit::detail::get_encoding_with_case<
408                     Modifiers, unused_type, lower || upper>::type
409               , typename detail::get_casetag<Modifiers, lower || upper>::type
410               , Radix, force_sign, false
411             > result_type;
412 
413             template <typename Terminal>
operator ()boost::spirit::karma::detail::make_int_direct414             result_type operator()(Terminal const& term, unused_type) const
415             {
416                 return result_type(fusion::at_c<0>(term.args));
417             }
418         };
419     }
420 
421     ///////////////////////////////////////////////////////////////////////////
422     template <typename Modifiers, typename A0>
423     struct make_primitive<
424         terminal_ex<tag::short_, fusion::vector1<A0> >, Modifiers>
425       : detail::make_int_direct<short, Modifiers> {};
426 
427     template <typename Modifiers, typename A0>
428     struct make_primitive<
429         terminal_ex<tag::int_, fusion::vector1<A0> >, Modifiers>
430       : detail::make_int_direct<int, Modifiers> {};
431 
432     template <typename Modifiers, typename A0>
433     struct make_primitive<
434         terminal_ex<tag::long_, fusion::vector1<A0> >, Modifiers>
435       : detail::make_int_direct<long, Modifiers> {};
436 
437 #ifdef BOOST_HAS_LONG_LONG
438     template <typename Modifiers, typename A0>
439     struct make_primitive<
440         terminal_ex<tag::long_long, fusion::vector1<A0> >, Modifiers>
441       : detail::make_int_direct<boost::long_long_type, Modifiers> {};
442 #endif
443 
444     template <typename T, unsigned Radix, bool force_sign, typename A0
445       , typename Modifiers>
446     struct make_primitive<
447         terminal_ex<tag::int_generator<T, Radix, force_sign>
448           , fusion::vector1<A0> >, Modifiers>
449       : detail::make_int_direct<typename remove_const<T>::type
450           , Modifiers, Radix, force_sign> {};
451 
452     ///////////////////////////////////////////////////////////////////////////
453     namespace detail
454     {
455         template <typename T, typename Modifiers>
456         struct basic_int_literal
457         {
458             static bool const lower =
459                 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
460             static bool const upper =
461                 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
462 
463             typedef literal_int_generator<
464                 T
465               , typename spirit::detail::get_encoding_with_case<
466                     Modifiers, unused_type, lower || upper>::type
467               , typename detail::get_casetag<Modifiers, lower || upper>::type
468               , 10, false, true
469             > result_type;
470 
471             template <typename T_>
operator ()boost::spirit::karma::detail::basic_int_literal472             result_type operator()(T_ i, unused_type) const
473             {
474                 return result_type(i);
475             }
476         };
477     }
478 
479     template <typename Modifiers>
480     struct make_primitive<short, Modifiers>
481       : detail::basic_int_literal<short, Modifiers> {};
482 
483     template <typename Modifiers>
484     struct make_primitive<int, Modifiers>
485       : detail::basic_int_literal<int, Modifiers> {};
486 
487     template <typename Modifiers>
488     struct make_primitive<long, Modifiers>
489       : detail::basic_int_literal<long, Modifiers> {};
490 
491 #ifdef BOOST_HAS_LONG_LONG
492     template <typename Modifiers>
493     struct make_primitive<boost::long_long_type, Modifiers>
494       : detail::basic_int_literal<boost::long_long_type, Modifiers> {};
495 #endif
496 
497     // lit(int)
498     template <typename Modifiers, typename A0>
499     struct make_primitive<
500             terminal_ex<tag::lit, fusion::vector1<A0> >
501           , Modifiers
502           , typename enable_if<traits::is_int<A0> >::type>
503     {
504         static bool const lower =
505             has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
506         static bool const upper =
507             has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
508 
509         typedef literal_int_generator<
510             typename remove_const<A0>::type
511           , typename spirit::detail::get_encoding_with_case<
512                 Modifiers, unused_type, lower || upper>::type
513           , typename detail::get_casetag<Modifiers, lower || upper>::type
514           , 10, false, true
515         > result_type;
516 
517         template <typename Terminal>
operator ()boost::spirit::karma::make_primitive518         result_type operator()(Terminal const& term, unused_type) const
519         {
520             return result_type(fusion::at_c<0>(term.args));
521         }
522     };
523 }}}
524 
525 #endif
526