binary.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  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. #if !defined(BOOST_SPIRIT_KARMA_BINARY_MAY_04_2007_0904AM)
  6. #define BOOST_SPIRIT_KARMA_BINARY_MAY_04_2007_0904AM
  7. #if defined(_MSC_VER)
  8. #pragma once
  9. #endif
  10. #include <boost/spirit/home/support/common_terminals.hpp>
  11. #include <boost/spirit/home/support/info.hpp>
  12. #include <boost/spirit/home/support/detail/endian.hpp>
  13. #include <boost/spirit/home/karma/domain.hpp>
  14. #include <boost/spirit/home/karma/meta_compiler.hpp>
  15. #include <boost/spirit/home/karma/delimit_out.hpp>
  16. #include <boost/spirit/home/karma/auxiliary/lazy.hpp>
  17. #include <boost/spirit/home/karma/detail/generate_to.hpp>
  18. #include <boost/spirit/home/karma/detail/extract_from.hpp>
  19. #include <boost/spirit/home/support/unused.hpp>
  20. #include <boost/spirit/home/support/container.hpp>
  21. #include <boost/fusion/include/vector.hpp>
  22. #include <boost/fusion/include/at.hpp>
  23. #include <boost/mpl/or.hpp>
  24. #include <boost/type_traits/is_integral.hpp>
  25. #include <boost/type_traits/is_enum.hpp>
  26. #include <boost/type_traits/is_floating_point.hpp>
  27. #include <boost/config.hpp>
  28. ///////////////////////////////////////////////////////////////////////////////
  29. #define BOOST_SPIRIT_ENABLE_BINARY(name) \
  30. template <> \
  31. struct use_terminal<karma::domain, tag::name> \
  32. : mpl::true_ {}; \
  33. \
  34. template <typename A0> \
  35. struct use_terminal<karma::domain \
  36. , terminal_ex<tag::name, fusion::vector1<A0> > > \
  37. : mpl::or_<is_integral<A0>, is_enum<A0> > {}; \
  38. \
  39. template <> \
  40. struct use_lazy_terminal<karma::domain, tag::name, 1> : mpl::true_ {}; \
  41. \
  42. /***/
  43. #define BOOST_SPIRIT_ENABLE_BINARY_IEEE754(name) \
  44. template<> \
  45. struct use_terminal<karma::domain, tag::name>: mpl::true_ {}; \
  46. \
  47. template<typename A0> \
  48. struct use_terminal<karma::domain, terminal_ex<tag::name, \
  49. fusion::vector1<A0> > >: is_floating_point<A0> {}; \
  50. \
  51. template<> \
  52. struct use_lazy_terminal<karma::domain, tag::name, 1> : mpl::true_ {}; \
  53. \
  54. /***/
  55. namespace boost { namespace spirit
  56. {
  57. ///////////////////////////////////////////////////////////////////////////
  58. // Enablers
  59. ///////////////////////////////////////////////////////////////////////////
  60. BOOST_SPIRIT_ENABLE_BINARY(byte_) // enables byte_
  61. BOOST_SPIRIT_ENABLE_BINARY(word) // enables word
  62. BOOST_SPIRIT_ENABLE_BINARY(big_word) // enables big_word
  63. BOOST_SPIRIT_ENABLE_BINARY(little_word) // enables little_word
  64. BOOST_SPIRIT_ENABLE_BINARY(dword) // enables dword
  65. BOOST_SPIRIT_ENABLE_BINARY(big_dword) // enables big_dword
  66. BOOST_SPIRIT_ENABLE_BINARY(little_dword) // enables little_dword
  67. #ifdef BOOST_HAS_LONG_LONG
  68. BOOST_SPIRIT_ENABLE_BINARY(qword) // enables qword
  69. BOOST_SPIRIT_ENABLE_BINARY(big_qword) // enables big_qword
  70. BOOST_SPIRIT_ENABLE_BINARY(little_qword) // enables little_qword
  71. #endif
  72. BOOST_SPIRIT_ENABLE_BINARY_IEEE754(bin_float)
  73. BOOST_SPIRIT_ENABLE_BINARY_IEEE754(big_bin_float)
  74. BOOST_SPIRIT_ENABLE_BINARY_IEEE754(little_bin_float)
  75. BOOST_SPIRIT_ENABLE_BINARY_IEEE754(bin_double)
  76. BOOST_SPIRIT_ENABLE_BINARY_IEEE754(big_bin_double)
  77. BOOST_SPIRIT_ENABLE_BINARY_IEEE754(little_bin_double)
  78. }}
  79. #undef BOOST_SPIRIT_ENABLE_BINARY
  80. #undef BOOST_SPIRIT_ENABLE_BINARY_IEEE754
  81. ///////////////////////////////////////////////////////////////////////////////
  82. namespace boost { namespace spirit { namespace karma
  83. {
  84. #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
  85. using boost::spirit::byte_;
  86. using boost::spirit::word;
  87. using boost::spirit::big_word;
  88. using boost::spirit::little_word;
  89. using boost::spirit::dword;
  90. using boost::spirit::big_dword;
  91. using boost::spirit::little_dword;
  92. #ifdef BOOST_HAS_LONG_LONG
  93. using boost::spirit::qword;
  94. using boost::spirit::big_qword;
  95. using boost::spirit::little_qword;
  96. #endif
  97. using boost::spirit::bin_float;
  98. using boost::spirit::big_bin_float;
  99. using boost::spirit::little_bin_float;
  100. using boost::spirit::bin_double;
  101. using boost::spirit::big_bin_double;
  102. using boost::spirit::little_bin_double;
  103. #endif
  104. using boost::spirit::byte_type;
  105. using boost::spirit::word_type;
  106. using boost::spirit::big_word_type;
  107. using boost::spirit::little_word_type;
  108. using boost::spirit::dword_type;
  109. using boost::spirit::big_dword_type;
  110. using boost::spirit::little_dword_type;
  111. #ifdef BOOST_HAS_LONG_LONG
  112. using boost::spirit::qword_type;
  113. using boost::spirit::big_qword_type;
  114. using boost::spirit::little_qword_type;
  115. #endif
  116. using boost::spirit::bin_float_type;
  117. using boost::spirit::big_bin_float_type;
  118. using boost::spirit::little_bin_float_type;
  119. using boost::spirit::bin_double_type;
  120. using boost::spirit::big_bin_double_type;
  121. using boost::spirit::little_bin_double_type;
  122. namespace detail
  123. {
  124. template <int bits>
  125. struct integer
  126. {
  127. #ifdef BOOST_HAS_LONG_LONG
  128. BOOST_SPIRIT_ASSERT_MSG(
  129. bits == 8 || bits == 16 || bits == 32 || bits == 64,
  130. not_supported_binary_size, ());
  131. #else
  132. BOOST_SPIRIT_ASSERT_MSG(
  133. bits == 8 || bits == 16 || bits == 32,
  134. not_supported_binary_size, ());
  135. #endif
  136. };
  137. template <>
  138. struct integer<8>
  139. {
  140. typedef uint_least8_t type;
  141. };
  142. template <>
  143. struct integer<16>
  144. {
  145. typedef uint_least16_t type;
  146. };
  147. template <>
  148. struct integer<32>
  149. {
  150. typedef uint_least32_t type;
  151. };
  152. #ifdef BOOST_HAS_LONG_LONG
  153. template <>
  154. struct integer<64>
  155. {
  156. typedef uint_least64_t type;
  157. };
  158. #endif
  159. template <int bits>
  160. struct floating_point
  161. {
  162. BOOST_SPIRIT_ASSERT_MSG(
  163. bits == 32 || bits == 64,
  164. not_supported_binary_size, ());
  165. };
  166. template <>
  167. struct floating_point<32>
  168. {
  169. typedef float type;
  170. };
  171. template <>
  172. struct floating_point<64>
  173. {
  174. typedef double type;
  175. };
  176. ///////////////////////////////////////////////////////////////////////
  177. template <BOOST_SCOPED_ENUM(boost::spirit::endian::endianness) bits>
  178. struct what;
  179. template <>
  180. struct what<boost::spirit::endian::endianness::native>
  181. {
  182. static info is()
  183. {
  184. return info("native-endian binary");
  185. }
  186. };
  187. template <>
  188. struct what<boost::spirit::endian::endianness::little>
  189. {
  190. static info is()
  191. {
  192. return info("little-endian binary");
  193. }
  194. };
  195. template <>
  196. struct what<boost::spirit::endian::endianness::big>
  197. {
  198. static info is()
  199. {
  200. return info("big-endian binary");
  201. }
  202. };
  203. }
  204. ///////////////////////////////////////////////////////////////////////////
  205. template <typename T, BOOST_SCOPED_ENUM(boost::spirit::endian::endianness) endian, int bits>
  206. struct any_binary_generator
  207. : primitive_generator<any_binary_generator<T, endian, bits> >
  208. {
  209. template <typename Context, typename Unused = unused_type>
  210. struct attribute: T {};
  211. template <
  212. typename OutputIterator, typename Context, typename Delimiter
  213. , typename Attribute>
  214. static bool generate(OutputIterator& sink, Context& context
  215. , Delimiter const& d, Attribute const& attr)
  216. {
  217. if (!traits::has_optional_value(attr))
  218. return false;
  219. // Even if the endian types are not pod's (at least not in the
  220. // definition of C++03) it seems to be safe to assume they are.
  221. // This allows us to treat them as a sequence of consecutive bytes.
  222. boost::spirit::endian::endian<endian, typename T::type, bits> p;
  223. #if defined(BOOST_MSVC)
  224. // warning C4244: 'argument' : conversion from 'const int' to 'foo', possible loss of data
  225. #pragma warning(push)
  226. #pragma warning(disable: 4244)
  227. #endif
  228. typedef typename T::type attribute_type;
  229. p = traits::extract_from<attribute_type>(attr, context);
  230. #if defined(BOOST_MSVC)
  231. #pragma warning(pop)
  232. #endif
  233. unsigned char const* bytes =
  234. reinterpret_cast<unsigned char const*>(&p);
  235. for (unsigned int i = 0; i < sizeof(p); ++i)
  236. {
  237. if (!detail::generate_to(sink, *bytes++))
  238. return false;
  239. }
  240. return karma::delimit_out(sink, d); // always do post-delimiting
  241. }
  242. // this any_byte_director has no parameter attached, it needs to have
  243. // been initialized from a direct literal
  244. template <
  245. typename OutputIterator, typename Context, typename Delimiter>
  246. static bool generate(OutputIterator&, Context&, Delimiter const&
  247. , unused_type)
  248. {
  249. // It is not possible (doesn't make sense) to use binary generators
  250. // without providing any attribute, as the generator doesn't 'know'
  251. // what to output. The following assertion fires if this situation
  252. // is detected in your code.
  253. BOOST_SPIRIT_ASSERT_FAIL(OutputIterator,
  254. binary_generator_not_usable_without_attribute, ());
  255. return false;
  256. }
  257. template <typename Context>
  258. static info what(Context const& /*context*/)
  259. {
  260. return karma::detail::what<endian>::is();
  261. }
  262. };
  263. ///////////////////////////////////////////////////////////////////////////
  264. template <typename T, BOOST_SCOPED_ENUM(boost::spirit::endian::endianness) endian, int bits>
  265. struct literal_binary_generator
  266. : primitive_generator<literal_binary_generator<T, endian, bits> >
  267. {
  268. template <typename Context, typename Unused>
  269. struct attribute
  270. {
  271. typedef unused_type type;
  272. };
  273. template <typename V>
  274. literal_binary_generator(V const& v)
  275. {
  276. #if defined(BOOST_MSVC)
  277. // warning C4244: 'argument' : conversion from 'const int' to 'foo', possible loss of data
  278. #pragma warning(push)
  279. #pragma warning(disable: 4244)
  280. #endif
  281. data_ = v;
  282. #if defined(BOOST_MSVC)
  283. #pragma warning(pop)
  284. #endif
  285. }
  286. template <
  287. typename OutputIterator, typename Context, typename Delimiter
  288. , typename Attribute>
  289. bool generate(OutputIterator& sink, Context&, Delimiter const& d
  290. , Attribute const&) const
  291. {
  292. // Even if the endian types are not pod's (at least not in the
  293. // definition of C++03) it seems to be safe to assume they are
  294. // (but in C++0x the endian types _are_ PODs).
  295. // This allows us to treat them as a sequence of consecutive bytes.
  296. unsigned char const* bytes =
  297. reinterpret_cast<unsigned char const*>(&data_);
  298. for (unsigned int i = 0; i < sizeof(data_type); ++i)
  299. {
  300. if (!detail::generate_to(sink, *bytes++))
  301. return false;
  302. }
  303. return karma::delimit_out(sink, d); // always do post-delimiting
  304. }
  305. template <typename Context>
  306. static info what(Context const& /*context*/)
  307. {
  308. return karma::detail::what<endian>::is();
  309. }
  310. typedef boost::spirit::endian::endian<endian, typename T::type,
  311. bits> data_type;
  312. data_type data_;
  313. };
  314. ///////////////////////////////////////////////////////////////////////////
  315. // Generator generators: make_xxx function (objects)
  316. ///////////////////////////////////////////////////////////////////////////
  317. namespace detail
  318. {
  319. template <typename T, BOOST_SCOPED_ENUM(boost::spirit::endian::endianness) endian
  320. , int bits>
  321. struct basic_binary
  322. {
  323. typedef any_binary_generator<T, endian, bits> result_type;
  324. result_type operator()(unused_type, unused_type) const
  325. {
  326. return result_type();
  327. }
  328. };
  329. template <typename Modifiers, typename T
  330. , BOOST_SCOPED_ENUM(boost::spirit::endian::endianness) endian, int bits>
  331. struct basic_binary_literal
  332. {
  333. typedef literal_binary_generator<T, endian, bits> result_type;
  334. template <typename Terminal>
  335. result_type operator()(Terminal const& term, unused_type) const
  336. {
  337. return result_type(fusion::at_c<0>(term.args));
  338. }
  339. };
  340. }
  341. #define BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(name, endiantype, bits) \
  342. template <typename Modifiers> \
  343. struct make_primitive<tag::name, Modifiers> \
  344. : detail::basic_binary<detail::integer<bits>, \
  345. boost::spirit::endian::endianness::endiantype, bits> {}; \
  346. \
  347. template <typename Modifiers, typename A0> \
  348. struct make_primitive<terminal_ex<tag::name, fusion::vector1<A0> > \
  349. , Modifiers> \
  350. : detail::basic_binary_literal<Modifiers, detail::integer<bits> \
  351. , boost::spirit::endian::endianness::endiantype, bits> {}; \
  352. \
  353. /***/
  354. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(byte_, native, 8)
  355. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(word, native, 16)
  356. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_word, big, 16)
  357. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_word, little, 16)
  358. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(dword, native, 32)
  359. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_dword, big, 32)
  360. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_dword, little, 32)
  361. #ifdef BOOST_HAS_LONG_LONG
  362. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(qword, native, 64)
  363. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_qword, big, 64)
  364. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_qword, little, 64)
  365. #endif
  366. #undef BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE
  367. #define BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(name, endiantype, bits) \
  368. template <typename Modifiers> \
  369. struct make_primitive<tag::name, Modifiers> \
  370. : detail::basic_binary<detail::floating_point<bits>, \
  371. boost::spirit::endian::endianness::endiantype, bits> {}; \
  372. \
  373. template <typename Modifiers, typename A0> \
  374. struct make_primitive<terminal_ex<tag::name, fusion::vector1<A0> > \
  375. , Modifiers> \
  376. : detail::basic_binary_literal<Modifiers, detail::floating_point<bits> \
  377. , boost::spirit::endian::endianness::endiantype, bits> {}; \
  378. \
  379. /***/
  380. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_float, native, 32)
  381. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_float, big, 32)
  382. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_float, little, 32)
  383. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_double, native, 64)
  384. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_double, big, 64)
  385. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_double, little, 64)
  386. #undef BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE
  387. }}}
  388. #endif