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