/** * Copyright (c) 2011 Ubimet * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) **/ #include "endian.hpp" #include "float.hpp" #include #include #include namespace boost { namespace spirit { #define BOOST_SPIRIT_ENABLE_BINARY(name) \ template<> \ struct use_terminal: mpl::true_ {}; \ \ template \ struct use_terminal > >: is_floating_point {}; \ \ template<> \ struct use_lazy_terminal : mpl::true_ {}; \ \ /***/ BOOST_SPIRIT_ENABLE_BINARY(bin_float) BOOST_SPIRIT_ENABLE_BINARY(big_bin_float) BOOST_SPIRIT_ENABLE_BINARY(little_bin_float) BOOST_SPIRIT_ENABLE_BINARY(bin_double) BOOST_SPIRIT_ENABLE_BINARY(big_bin_double) BOOST_SPIRIT_ENABLE_BINARY(little_bin_double) #undef BOOST_SPIRIT_ENABLE_BINARY }} namespace boost { namespace spirit { namespace karma { namespace detail { template struct floating_point { BOOST_SPIRIT_ASSERT_MSG(bits == 32 || bits == 64, not_supported_binary_size, ()); }; template<> struct floating_point<32> { typedef float type; }; template<> struct floating_point<64> { typedef double type; }; } template struct bin_float_generator: primitive_generator > { template struct attribute: detail::floating_point {}; template static bool generate(OutputIterator& sink, Context& context, Delimiter const& d, Attribute const& attr) { if(!traits::has_optional_value(attr)) return false; typename detail::floating_point::type p; typedef typename detail::floating_point::type attribute_type; p = traits::extract_from(attr, context); endian bytes(p); for (unsigned int i = 0; i < sizeof(p); ++i) { if(!detail::generate_to(sink, bytes.current)) { return false; } bytes.next(); } return karma::delimit_out(sink, d); // always do post-delimiting } template static bool generate(OutputIterator& sink, Context&, Delimiter const& d, unused_type) { // It is not possible (doesn't make sense) to use binary generators // without providing any attribute, as the generator doesn't 'know' // what to output. The following assertion fires if this situation // is detected in your code. BOOST_SPIRIT_ASSERT_MSG(false, binary_generator_not_usable_without_attribute, ()); return false; } template static info what(Context const& /*context*/) { return info("bin_float"); } }; template struct literal_bin_float_generator: primitive_generator > { template struct attribute { typedef unused_type type; }; template literal_bin_float_generator(T const& t) { data_ = t; } template bool generate(OutputIterator& sink, Context&, Delimiter const& d, Attribute const&) const { endian bytes(data_); for (unsigned int i = 0; i < sizeof(data_type); ++i) { if(!detail::generate_to(sink, *bytes.current)) { return false; } bytes.next(); } return karma::delimit_out(sink, d); // always do post-delimiting } template static info what(Context const& /*context*/) { return info("bin_float"); } typedef typename detail::floating_point::type data_type; data_type data_; }; namespace detail { template struct basic_bin_float { typedef bin_float_generator result_type; result_type operator()(unused_type, unused_type) const { return result_type(); } }; template struct basic_bin_float_literal { typedef literal_bin_float_generator result_type; template result_type operator()(Terminal const& term, unused_type) const { return result_type(fusion::at_c<0>(term.args)); } }; } #define BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(name, endian, bits) \ template \ struct make_primitive \ : detail::basic_bin_float< ::detail::endianness::endian, bits> {}; \ \ template \ struct make_primitive >, \ Modifiers>: detail::basic_bin_float_literal {}; \ \ /***/ BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(bin_float, native, 32) BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_bin_float, big, 32) BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_bin_float, little, 32) BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(bin_double, native, 64) BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_bin_double, big, 64) BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_bin_double, little, 64) #undef BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE }}}