• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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