]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
208 | 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 | |
235 | 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 | |
249 | 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> | |
260 | 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> | |
279 | 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 | ||
293 | 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> | |
309 | 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> | |
324 | 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> | |
331 | 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 | ||
362 | 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> | |
414 | 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_> | |
472 | 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> | |
518 | 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 |