int.hpp 19 KB

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