binary.hpp 16 KB

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