Chris@16: // Copyright (c) 2001-2011 Hartmut Kaiser Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #if !defined(BOOST_SPIRIT_KARMA_BINARY_MAY_04_2007_0904AM) Chris@16: #define BOOST_SPIRIT_KARMA_BINARY_MAY_04_2007_0904AM Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: #define BOOST_SPIRIT_ENABLE_BINARY(name) \ Chris@16: template <> \ Chris@16: struct use_terminal \ Chris@16: : mpl::true_ {}; \ Chris@16: \ Chris@16: template \ Chris@16: struct use_terminal > > \ Chris@16: : mpl::or_, is_enum > {}; \ Chris@16: \ Chris@16: template <> \ Chris@16: struct use_lazy_terminal : mpl::true_ {}; \ Chris@16: \ Chris@16: /***/ Chris@16: Chris@16: #define BOOST_SPIRIT_ENABLE_BINARY_IEEE754(name) \ Chris@16: template<> \ Chris@16: struct use_terminal: mpl::true_ {}; \ Chris@16: \ Chris@16: template \ Chris@16: struct use_terminal > >: is_floating_point {}; \ Chris@16: \ Chris@16: template<> \ Chris@16: struct use_lazy_terminal : mpl::true_ {}; \ Chris@16: \ Chris@16: /***/ Chris@16: Chris@16: namespace boost { namespace spirit Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Enablers Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: BOOST_SPIRIT_ENABLE_BINARY(byte_) // enables byte_ Chris@16: BOOST_SPIRIT_ENABLE_BINARY(word) // enables word Chris@16: BOOST_SPIRIT_ENABLE_BINARY(big_word) // enables big_word Chris@16: BOOST_SPIRIT_ENABLE_BINARY(little_word) // enables little_word Chris@16: BOOST_SPIRIT_ENABLE_BINARY(dword) // enables dword Chris@16: BOOST_SPIRIT_ENABLE_BINARY(big_dword) // enables big_dword Chris@16: BOOST_SPIRIT_ENABLE_BINARY(little_dword) // enables little_dword Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: BOOST_SPIRIT_ENABLE_BINARY(qword) // enables qword Chris@16: BOOST_SPIRIT_ENABLE_BINARY(big_qword) // enables big_qword Chris@16: BOOST_SPIRIT_ENABLE_BINARY(little_qword) // enables little_qword Chris@16: #endif Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(bin_float) Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(big_bin_float) Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(little_bin_float) Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(bin_double) Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(big_bin_double) Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(little_bin_double) Chris@16: }} Chris@16: Chris@16: #undef BOOST_SPIRIT_ENABLE_BINARY Chris@16: #undef BOOST_SPIRIT_ENABLE_BINARY_IEEE754 Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace boost { namespace spirit { namespace karma Chris@16: { Chris@16: #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS Chris@16: using boost::spirit::byte_; Chris@16: using boost::spirit::word; Chris@16: using boost::spirit::big_word; Chris@16: using boost::spirit::little_word; Chris@16: using boost::spirit::dword; Chris@16: using boost::spirit::big_dword; Chris@16: using boost::spirit::little_dword; Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: using boost::spirit::qword; Chris@16: using boost::spirit::big_qword; Chris@16: using boost::spirit::little_qword; Chris@16: #endif Chris@16: using boost::spirit::bin_float; Chris@16: using boost::spirit::big_bin_float; Chris@16: using boost::spirit::little_bin_float; Chris@16: using boost::spirit::bin_double; Chris@16: using boost::spirit::big_bin_double; Chris@16: using boost::spirit::little_bin_double; Chris@16: #endif Chris@16: Chris@16: using boost::spirit::byte_type; Chris@16: using boost::spirit::word_type; Chris@16: using boost::spirit::big_word_type; Chris@16: using boost::spirit::little_word_type; Chris@16: using boost::spirit::dword_type; Chris@16: using boost::spirit::big_dword_type; Chris@16: using boost::spirit::little_dword_type; Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: using boost::spirit::qword_type; Chris@16: using boost::spirit::big_qword_type; Chris@16: using boost::spirit::little_qword_type; Chris@16: #endif Chris@16: using boost::spirit::bin_float_type; Chris@16: using boost::spirit::big_bin_float_type; Chris@16: using boost::spirit::little_bin_float_type; Chris@16: using boost::spirit::bin_double_type; Chris@16: using boost::spirit::big_bin_double_type; Chris@16: using boost::spirit::little_bin_double_type; Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct integer Chris@16: { Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: BOOST_SPIRIT_ASSERT_MSG( Chris@16: bits == 8 || bits == 16 || bits == 32 || bits == 64, Chris@16: not_supported_binary_size, ()); Chris@16: #else Chris@16: BOOST_SPIRIT_ASSERT_MSG( Chris@16: bits == 8 || bits == 16 || bits == 32, Chris@16: not_supported_binary_size, ()); Chris@16: #endif Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct integer<8> Chris@16: { Chris@16: typedef uint_least8_t type; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct integer<16> Chris@16: { Chris@16: typedef uint_least16_t type; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct integer<32> Chris@16: { Chris@16: typedef uint_least32_t type; Chris@16: }; Chris@16: Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: template <> Chris@16: struct integer<64> Chris@16: { Chris@16: typedef uint_least64_t type; Chris@16: }; Chris@16: #endif Chris@16: Chris@16: template Chris@16: struct floating_point Chris@16: { Chris@16: BOOST_SPIRIT_ASSERT_MSG( Chris@16: bits == 32 || bits == 64, Chris@16: not_supported_binary_size, ()); Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct floating_point<32> Chris@16: { Chris@16: typedef float type; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct floating_point<64> Chris@16: { Chris@16: typedef double type; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct what; Chris@16: Chris@16: template <> Chris@16: struct what Chris@16: { Chris@16: static info is() Chris@16: { Chris@16: return info("native-endian binary"); Chris@16: } Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct what Chris@16: { Chris@16: static info is() Chris@16: { Chris@16: return info("little-endian binary"); Chris@16: } Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct what Chris@16: { Chris@16: static info is() Chris@16: { Chris@16: return info("big-endian binary"); Chris@16: } Chris@16: }; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct any_binary_generator Chris@16: : primitive_generator > Chris@16: { Chris@16: template Chris@16: struct attribute: T {}; Chris@16: Chris@16: template < Chris@16: typename OutputIterator, typename Context, typename Delimiter Chris@16: , typename Attribute> Chris@16: static bool generate(OutputIterator& sink, Context& context Chris@16: , Delimiter const& d, Attribute const& attr) Chris@16: { Chris@16: if (!traits::has_optional_value(attr)) Chris@16: return false; Chris@16: Chris@16: // Even if the endian types are not pod's (at least not in the Chris@16: // definition of C++03) it seems to be safe to assume they are. Chris@16: // This allows us to treat them as a sequence of consecutive bytes. Chris@16: boost::endian::endian p; Chris@16: Chris@16: #if defined(BOOST_MSVC) Chris@16: // warning C4244: 'argument' : conversion from 'const int' to 'foo', possible loss of data Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable: 4244) Chris@16: #endif Chris@16: typedef typename T::type attribute_type; Chris@16: p = traits::extract_from(attr, context); Chris@16: #if defined(BOOST_MSVC) Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: unsigned char const* bytes = Chris@16: reinterpret_cast(&p); Chris@16: Chris@16: for (unsigned int i = 0; i < sizeof(p); ++i) Chris@16: { Chris@16: if (!detail::generate_to(sink, *bytes++)) Chris@16: return false; Chris@16: } Chris@16: return karma::delimit_out(sink, d); // always do post-delimiting Chris@16: } Chris@16: Chris@16: // this any_byte_director has no parameter attached, it needs to have Chris@16: // been initialized from a direct literal Chris@16: template < Chris@16: typename OutputIterator, typename Context, typename Delimiter> Chris@16: static bool generate(OutputIterator&, Context&, Delimiter const& Chris@16: , unused_type) Chris@16: { Chris@16: // It is not possible (doesn't make sense) to use binary generators Chris@16: // without providing any attribute, as the generator doesn't 'know' Chris@16: // what to output. The following assertion fires if this situation Chris@16: // is detected in your code. Chris@16: BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, Chris@16: binary_generator_not_usable_without_attribute, ()); Chris@16: return false; Chris@16: } Chris@16: Chris@16: template Chris@16: static info what(Context const& /*context*/) Chris@16: { Chris@16: return karma::detail::what::is(); Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct literal_binary_generator Chris@16: : primitive_generator > Chris@16: { Chris@16: template Chris@16: struct attribute Chris@16: { Chris@16: typedef unused_type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: literal_binary_generator(V const& v) Chris@16: { Chris@16: #if defined(BOOST_MSVC) Chris@16: // warning C4244: 'argument' : conversion from 'const int' to 'foo', possible loss of data Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable: 4244) Chris@16: #endif Chris@16: data_ = v; Chris@16: #if defined(BOOST_MSVC) Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: } Chris@16: Chris@16: template < Chris@16: typename OutputIterator, typename Context, typename Delimiter Chris@16: , typename Attribute> Chris@16: bool generate(OutputIterator& sink, Context&, Delimiter const& d Chris@16: , Attribute const&) const Chris@16: { Chris@16: // Even if the endian types are not pod's (at least not in the Chris@16: // definition of C++03) it seems to be safe to assume they are Chris@16: // (but in C++0x the endian types _are_ PODs). Chris@16: // This allows us to treat them as a sequence of consecutive bytes. Chris@16: unsigned char const* bytes = Chris@16: reinterpret_cast(&data_); Chris@16: Chris@16: for (unsigned int i = 0; i < sizeof(data_type); ++i) Chris@16: { Chris@16: if (!detail::generate_to(sink, *bytes++)) Chris@16: return false; Chris@16: } Chris@16: return karma::delimit_out(sink, d); // always do post-delimiting Chris@16: } Chris@16: Chris@16: template Chris@16: static info what(Context const& /*context*/) Chris@16: { Chris@16: return karma::detail::what::is(); Chris@16: } Chris@16: Chris@16: typedef boost::endian::endian data_type; Chris@16: Chris@16: data_type data_; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Generator generators: make_xxx function (objects) Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct basic_binary Chris@16: { Chris@16: typedef any_binary_generator result_type; Chris@16: Chris@16: result_type operator()(unused_type, unused_type) const Chris@16: { Chris@16: return result_type(); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct basic_binary_literal Chris@16: { Chris@16: typedef literal_binary_generator result_type; Chris@16: Chris@16: template Chris@16: result_type operator()(Terminal const& term, unused_type) const Chris@16: { Chris@16: return result_type(fusion::at_c<0>(term.args)); Chris@16: } Chris@16: }; Chris@16: } Chris@16: Chris@16: #define BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(name, endiantype, bits) \ Chris@16: template \ Chris@16: struct make_primitive \ Chris@16: : detail::basic_binary, \ Chris@16: boost::endian::endianness::endiantype, bits> {}; \ Chris@16: \ Chris@16: template \ Chris@16: struct make_primitive > \ Chris@16: , Modifiers> \ Chris@16: : detail::basic_binary_literal \ Chris@16: , boost::endian::endianness::endiantype, bits> {}; \ Chris@16: \ Chris@16: /***/ Chris@16: Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(byte_, native, 8) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(word, native, 16) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_word, big, 16) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_word, little, 16) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(dword, native, 32) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_dword, big, 32) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_dword, little, 32) Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(qword, native, 64) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_qword, big, 64) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_qword, little, 64) Chris@16: #endif Chris@16: Chris@16: #undef BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE Chris@16: Chris@16: #define BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(name, endiantype, bits) \ Chris@16: template \ Chris@16: struct make_primitive \ Chris@16: : detail::basic_binary, \ Chris@16: boost::endian::endianness::endiantype, bits> {}; \ Chris@16: \ Chris@16: template \ Chris@16: struct make_primitive > \ Chris@16: , Modifiers> \ Chris@16: : detail::basic_binary_literal \ Chris@16: , boost::endian::endianness::endiantype, bits> {}; \ Chris@16: \ Chris@16: /***/ Chris@16: Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_float, native, 32) Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_float, big, 32) Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_float, little, 32) Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_double, native, 64) Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_double, big, 64) Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_double, little, 64) Chris@16: Chris@16: #undef BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE Chris@16: Chris@16: }}} Chris@16: Chris@16: #endif