1 //  Boost endian.hpp header file -------------------------------------------------------//
2 
3 //  (C) Copyright Darin Adler 2000
4 //  (C) Copyright Beman Dawes 2006, 2009
5 
6 //  Distributed under the Boost Software License, Version 1.0.
7 //  See http://www.boost.org/LICENSE_1_0.txt
8 
9 //  See library home page at http://www.boost.org/libs/endian
10 
11 //--------------------------------------------------------------------------------------//
12 
13 //  Original design developed by Darin Adler based on classes developed by Mark
14 //  Borgerding. Four original class templates were combined into a single endian
15 //  class template by Beman Dawes, who also added the unrolled_byte_loops sign
16 //  partial specialization to correctly extend the sign when cover integer size
17 //  differs from endian representation size.
18 
19 // TODO: When a compiler supporting constexpr becomes available, try possible uses.
20 
21 #ifndef BOOST_SPIRIT_ENDIAN_HPP
22 #define BOOST_SPIRIT_ENDIAN_HPP
23 
24 #if defined(_MSC_VER)
25 #pragma once
26 #endif
27 
28 #ifdef BOOST_ENDIAN_LOG
29 # include <iostream>
30 #endif
31 
32 #if defined(__BORLANDC__) || defined( __CODEGEARC__)
33 # pragma pack(push, 1)
34 #endif
35 
36 #include <boost/config.hpp>
37 #include <boost/detail/endian.hpp>
38 #define BOOST_MINIMAL_INTEGER_COVER_OPERATORS
39 #define BOOST_NO_IO_COVER_OPERATORS
40 #include <boost/spirit/home/support/detail/integer/cover_operators.hpp>
41 #undef  BOOST_NO_IO_COVER_OPERATORS
42 #undef  BOOST_MINIMAL_INTEGER_COVER_OPERATORS
43 #include <boost/type_traits/is_signed.hpp>
44 #include <boost/cstdint.hpp>
45 #include <boost/static_assert.hpp>
46 #include <boost/spirit/home/support/detail/scoped_enum_emulation.hpp>
47 #include <iosfwd>
48 #include <climits>
49 
50 # if CHAR_BIT != 8
51 #   error Platforms with CHAR_BIT != 8 are not supported
52 # endif
53 
54 # define BOOST_ENDIAN_DEFAULT_CONSTRUCT {}          // C++03
55 
56 # if defined(BOOST_ENDIAN_FORCE_PODNESS)
57 #   define BOOST_ENDIAN_NO_CTORS
58 # endif
59 
60 
61 namespace boost
62 {
63   namespace detail
64   {
65     // Unrolled loops for loading and storing streams of bytes.
66 
67     template <typename T, std::size_t n_bytes,
68       bool sign=boost::is_signed<T>::value >
69     struct unrolled_byte_loops
70     {
71       typedef unrolled_byte_loops<T, n_bytes - 1, sign> next;
72 
load_bigboost::detail::unrolled_byte_loops73       static T load_big(const unsigned char* bytes)
74         { return *(bytes - 1) | (next::load_big(bytes - 1) << 8); }
load_littleboost::detail::unrolled_byte_loops75       static T load_little(const unsigned char* bytes)
76         { return *bytes | (next::load_little(bytes + 1) << 8); }
77 
store_bigboost::detail::unrolled_byte_loops78       static void store_big(char* bytes, T value)
79         {
80           *(bytes - 1) = static_cast<char>(value);
81           next::store_big(bytes - 1, value >> 8);
82         }
store_littleboost::detail::unrolled_byte_loops83       static void store_little(char* bytes, T value)
84         {
85           *bytes = static_cast<char>(value);
86           next::store_little(bytes + 1, value >> 8);
87         }
88     };
89 
90     template <typename T>
91     struct unrolled_byte_loops<T, 1, false>
92     {
load_bigboost::detail::unrolled_byte_loops93       static T load_big(const unsigned char* bytes)
94         { return *(bytes - 1); }
load_littleboost::detail::unrolled_byte_loops95       static T load_little(const unsigned char* bytes)
96         { return *bytes; }
store_bigboost::detail::unrolled_byte_loops97       static void store_big(char* bytes, T value)
98         { *(bytes - 1) = static_cast<char>(value); }
store_littleboost::detail::unrolled_byte_loops99       static void store_little(char* bytes, T value)
100         { *bytes = static_cast<char>(value); }
101 
102     };
103 
104     template <typename T>
105     struct unrolled_byte_loops<T, 1, true>
106     {
load_bigboost::detail::unrolled_byte_loops107       static T load_big(const unsigned char* bytes)
108         { return *reinterpret_cast<const signed char*>(bytes - 1); }
load_littleboost::detail::unrolled_byte_loops109       static T load_little(const unsigned char* bytes)
110         { return *reinterpret_cast<const signed char*>(bytes); }
store_bigboost::detail::unrolled_byte_loops111       static void store_big(char* bytes, T value)
112         { *(bytes - 1) = static_cast<char>(value); }
store_littleboost::detail::unrolled_byte_loops113       static void store_little(char* bytes, T value)
114         { *bytes = static_cast<char>(value); }
115     };
116 
117     template <typename T, std::size_t n_bytes>
118     inline
load_big_endian(const void * bytes)119     T load_big_endian(const void* bytes)
120     {
121       return unrolled_byte_loops<T, n_bytes>::load_big
122         (static_cast<const unsigned char*>(bytes) + n_bytes);
123     }
124 
125     template <typename T, std::size_t n_bytes>
126     inline
load_little_endian(const void * bytes)127     T load_little_endian(const void* bytes)
128     {
129       return unrolled_byte_loops<T, n_bytes>::load_little
130         (static_cast<const unsigned char*>(bytes));
131     }
132 
133     template <typename T, std::size_t n_bytes>
134     inline
store_big_endian(void * bytes,T value)135     void store_big_endian(void* bytes, T value)
136     {
137       unrolled_byte_loops<T, n_bytes>::store_big
138         (static_cast<char*>(bytes) + n_bytes, value);
139     }
140 
141     template <typename T, std::size_t n_bytes>
142     inline
store_little_endian(void * bytes,T value)143     void store_little_endian(void* bytes, T value)
144     {
145       unrolled_byte_loops<T, n_bytes>::store_little
146         (static_cast<char*>(bytes), value);
147     }
148 
149   } // namespace detail
150 
151   namespace integer
152   {
153 
154 # ifdef BOOST_ENDIAN_LOG
155     bool endian_log(true);
156 # endif
157 
158 
159   //  endian class template and specializations  ---------------------------------------//
160 
BOOST_SCOPED_ENUM_START(endianness)161   BOOST_SCOPED_ENUM_START(endianness) { big, little, native }; BOOST_SCOPED_ENUM_END
BOOST_SCOPED_ENUM_START(alignment)162   BOOST_SCOPED_ENUM_START(alignment) { unaligned, aligned }; BOOST_SCOPED_ENUM_END
163 
164   template <BOOST_SCOPED_ENUM(endianness) E, typename T, std::size_t n_bits,
165     BOOST_SCOPED_ENUM(alignment) A = alignment::unaligned>
166     class endian;
167 
168     //  Specializations that represent unaligned bytes.
169     //  Taking an integer type as a parameter provides a nice way to pass both
170     //  the size and signedness of the desired integer and get the appropriate
171     //  corresponding integer type for the interface.
172 
173     //  unaligned big endian specialization
174     template <typename T, std::size_t n_bits>
175     class endian< endianness::big, T, n_bits, alignment::unaligned >
176       : cover_operators< endian< endianness::big, T, n_bits >, T >
177     {
178         BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
179       public:
180         typedef T value_type;
181 #     ifndef BOOST_ENDIAN_NO_CTORS
endian()182         endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
183         explicit endian(T val)
184         {
185 #       ifdef BOOST_ENDIAN_LOG
186           if ( endian_log )
187             std::clog << "big, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
188 #       endif
189           detail::store_big_endian<T, n_bits/8>(m_value, val);
190         }
191 #     endif
operator =(T val)192         endian & operator=(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const193         operator T() const
194         {
195 #       ifdef BOOST_ENDIAN_LOG
196           if ( endian_log )
197             std::clog << "big, unaligned, " << n_bits << "-bits, convert(" << detail::load_big_endian<T, n_bits/8>(m_value) << ")\n";
198 #       endif
199           return detail::load_big_endian<T, n_bits/8>(m_value);
200         }
201       private:
202         char m_value[n_bits/8];
203     };
204 
205     //  unaligned little endian specialization
206     template <typename T, std::size_t n_bits>
207     class endian< endianness::little, T, n_bits, alignment::unaligned >
208       : cover_operators< endian< endianness::little, T, n_bits >, T >
209     {
210         BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
211       public:
212         typedef T value_type;
213 #     ifndef BOOST_ENDIAN_NO_CTORS
endian()214         endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
215         explicit endian(T val)
216         {
217 #       ifdef BOOST_ENDIAN_LOG
218           if ( endian_log )
219             std::clog << "little, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
220 #       endif
221           detail::store_little_endian<T, n_bits/8>(m_value, val);
222         }
223 #     endif
operator =(T val)224         endian & operator=(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const225         operator T() const
226         {
227 #       ifdef BOOST_ENDIAN_LOG
228           if ( endian_log )
229             std::clog << "little, unaligned, " << n_bits << "-bits, convert(" << detail::load_little_endian<T, n_bits/8>(m_value) << ")\n";
230 #       endif
231           return detail::load_little_endian<T, n_bits/8>(m_value);
232         }
233       private:
234         char m_value[n_bits/8];
235     };
236 
237     //  unaligned native endian specialization
238     template <typename T, std::size_t n_bits>
239     class endian< endianness::native, T, n_bits, alignment::unaligned >
240       : cover_operators< endian< endianness::native, T, n_bits >, T >
241     {
242         BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
243       public:
244         typedef T value_type;
245 #   ifndef BOOST_ENDIAN_NO_CTORS
endian()246         endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
247 #     ifdef BOOST_BIG_ENDIAN
248         explicit endian(T val)    { detail::store_big_endian<T, n_bits/8>(m_value, val); }
249 #     else
250         explicit endian(T val)    { detail::store_little_endian<T, n_bits/8>(m_value, val); }
251 #     endif
252 #   endif
253 #   ifdef BOOST_BIG_ENDIAN
operator =(T val)254         endian & operator=(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const255         operator T() const        { return detail::load_big_endian<T, n_bits/8>(m_value); }
256 #   else
operator =(T val)257         endian & operator=(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const258         operator T() const        { return detail::load_little_endian<T, n_bits/8>(m_value); }
259 #   endif
260       private:
261         char m_value[n_bits/8];
262     };
263 
264     //  Specializations that mimic built-in integer types.
265     //  These typically have the same alignment as the underlying types.
266 
267     //  aligned big endian specialization
268     template <typename T, std::size_t n_bits>
269     class endian< endianness::big, T, n_bits, alignment::aligned  >
270       : cover_operators< endian< endianness::big, T, n_bits, alignment::aligned >, T >
271     {
272         BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
273         BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 );
274       public:
275         typedef T value_type;
276 #   ifndef BOOST_ENDIAN_NO_CTORS
endian()277         endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
278 #     ifdef BOOST_BIG_ENDIAN
279         endian(T val) : m_value(val) { }
280 #     else
281         explicit endian(T val)    { detail::store_big_endian<T, sizeof(T)>(&m_value, val); }
282 #     endif
283 #   endif
284 #   ifdef BOOST_BIG_ENDIAN
operator =(T val)285         endian & operator=(T val) { m_value = val; return *this; }
operator T() const286         operator T() const        { return m_value; }
287 #   else
operator =(T val)288         endian & operator=(T val) { detail::store_big_endian<T, sizeof(T)>(&m_value, val); return *this; }
operator T() const289         operator T() const        { return detail::load_big_endian<T, sizeof(T)>(&m_value); }
290 #   endif
291       private:
292         T m_value;
293     };
294 
295     //  aligned little endian specialization
296     template <typename T, std::size_t n_bits>
297     class endian< endianness::little, T, n_bits, alignment::aligned  >
298       : cover_operators< endian< endianness::little, T, n_bits, alignment::aligned >, T >
299     {
300         BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
301         BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 );
302       public:
303         typedef T value_type;
304 #   ifndef BOOST_ENDIAN_NO_CTORS
endian()305         endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
306 #     ifdef BOOST_LITTLE_ENDIAN
307         endian(T val) : m_value(val) { }
308 #     else
309         explicit endian(T val)    { detail::store_little_endian<T, sizeof(T)>(&m_value, val); }
310 #     endif
311 #   endif
312 #   ifdef BOOST_LITTLE_ENDIAN
operator =(T val)313         endian & operator=(T val) { m_value = val; return *this; }
operator T() const314         operator T() const        { return m_value; }
315     #else
operator =(T val)316         endian & operator=(T val) { detail::store_little_endian<T, sizeof(T)>(&m_value, val); return *this; }
operator T() const317         operator T() const        { return detail::load_little_endian<T, sizeof(T)>(&m_value); }
318     #endif
319       private:
320         T m_value;
321     };
322 
323   //  naming convention typedefs  ------------------------------------------------------//
324 
325     // unaligned big endian signed integer types
326     typedef endian< endianness::big, int_least8_t, 8 >           big8_t;
327     typedef endian< endianness::big, int_least16_t, 16 >         big16_t;
328     typedef endian< endianness::big, int_least32_t, 24 >         big24_t;
329     typedef endian< endianness::big, int_least32_t, 32 >         big32_t;
330     typedef endian< endianness::big, int_least64_t, 40 >         big40_t;
331     typedef endian< endianness::big, int_least64_t, 48 >         big48_t;
332     typedef endian< endianness::big, int_least64_t, 56 >         big56_t;
333     typedef endian< endianness::big, int_least64_t, 64 >         big64_t;
334 
335     // unaligned big endian unsigned integer types
336     typedef endian< endianness::big, uint_least8_t, 8 >          ubig8_t;
337     typedef endian< endianness::big, uint_least16_t, 16 >        ubig16_t;
338     typedef endian< endianness::big, uint_least32_t, 24 >        ubig24_t;
339     typedef endian< endianness::big, uint_least32_t, 32 >        ubig32_t;
340     typedef endian< endianness::big, uint_least64_t, 40 >        ubig40_t;
341     typedef endian< endianness::big, uint_least64_t, 48 >        ubig48_t;
342     typedef endian< endianness::big, uint_least64_t, 56 >        ubig56_t;
343     typedef endian< endianness::big, uint_least64_t, 64 >        ubig64_t;
344 
345     // unaligned little endian signed integer types
346     typedef endian< endianness::little, int_least8_t, 8 >        little8_t;
347     typedef endian< endianness::little, int_least16_t, 16 >      little16_t;
348     typedef endian< endianness::little, int_least32_t, 24 >      little24_t;
349     typedef endian< endianness::little, int_least32_t, 32 >      little32_t;
350     typedef endian< endianness::little, int_least64_t, 40 >      little40_t;
351     typedef endian< endianness::little, int_least64_t, 48 >      little48_t;
352     typedef endian< endianness::little, int_least64_t, 56 >      little56_t;
353     typedef endian< endianness::little, int_least64_t, 64 >      little64_t;
354 
355     // unaligned little endian unsigned integer types
356     typedef endian< endianness::little, uint_least8_t, 8 >       ulittle8_t;
357     typedef endian< endianness::little, uint_least16_t, 16 >     ulittle16_t;
358     typedef endian< endianness::little, uint_least32_t, 24 >     ulittle24_t;
359     typedef endian< endianness::little, uint_least32_t, 32 >     ulittle32_t;
360     typedef endian< endianness::little, uint_least64_t, 40 >     ulittle40_t;
361     typedef endian< endianness::little, uint_least64_t, 48 >     ulittle48_t;
362     typedef endian< endianness::little, uint_least64_t, 56 >     ulittle56_t;
363     typedef endian< endianness::little, uint_least64_t, 64 >     ulittle64_t;
364 
365     // unaligned native endian signed integer types
366     typedef endian< endianness::native, int_least8_t, 8 >        native8_t;
367     typedef endian< endianness::native, int_least16_t, 16 >      native16_t;
368     typedef endian< endianness::native, int_least32_t, 24 >      native24_t;
369     typedef endian< endianness::native, int_least32_t, 32 >      native32_t;
370     typedef endian< endianness::native, int_least64_t, 40 >      native40_t;
371     typedef endian< endianness::native, int_least64_t, 48 >      native48_t;
372     typedef endian< endianness::native, int_least64_t, 56 >      native56_t;
373     typedef endian< endianness::native, int_least64_t, 64 >      native64_t;
374 
375     // unaligned native endian unsigned integer types
376     typedef endian< endianness::native, uint_least8_t, 8 >       unative8_t;
377     typedef endian< endianness::native, uint_least16_t, 16 >     unative16_t;
378     typedef endian< endianness::native, uint_least32_t, 24 >     unative24_t;
379     typedef endian< endianness::native, uint_least32_t, 32 >     unative32_t;
380     typedef endian< endianness::native, uint_least64_t, 40 >     unative40_t;
381     typedef endian< endianness::native, uint_least64_t, 48 >     unative48_t;
382     typedef endian< endianness::native, uint_least64_t, 56 >     unative56_t;
383     typedef endian< endianness::native, uint_least64_t, 64 >     unative64_t;
384 
385 #define BOOST_HAS_INT16_T
386 #define BOOST_HAS_INT32_T
387 #define BOOST_HAS_INT64_T
388 
389   //  These types only present if platform has exact size integers:
390   //     aligned big endian signed integer types
391   //     aligned big endian unsigned integer types
392   //     aligned little endian signed integer types
393   //     aligned little endian unsigned integer types
394 
395   //     aligned native endian typedefs are not provided because
396   //     <cstdint> types are superior for this use case
397 
398 # if defined(BOOST_HAS_INT16_T)
399     typedef endian< endianness::big, int16_t, 16, alignment::aligned >      aligned_big16_t;
400     typedef endian< endianness::big, uint16_t, 16, alignment::aligned >     aligned_ubig16_t;
401     typedef endian< endianness::little, int16_t, 16, alignment::aligned >   aligned_little16_t;
402     typedef endian< endianness::little, uint16_t, 16, alignment::aligned >  aligned_ulittle16_t;
403 # endif
404 
405 # if defined(BOOST_HAS_INT32_T)
406     typedef endian< endianness::big, int32_t, 32, alignment::aligned >      aligned_big32_t;
407     typedef endian< endianness::big, uint32_t, 32, alignment::aligned >     aligned_ubig32_t;
408     typedef endian< endianness::little, int32_t, 32, alignment::aligned >   aligned_little32_t;
409     typedef endian< endianness::little, uint32_t, 32, alignment::aligned >  aligned_ulittle32_t;
410 # endif
411 
412 # if defined(BOOST_HAS_INT64_T)
413     typedef endian< endianness::big, int64_t, 64, alignment::aligned >      aligned_big64_t;
414     typedef endian< endianness::big, uint64_t, 64, alignment::aligned >     aligned_ubig64_t;
415     typedef endian< endianness::little, int64_t, 64, alignment::aligned >   aligned_little64_t;
416     typedef endian< endianness::little, uint64_t, 64, alignment::aligned >  aligned_ulittle64_t;
417 # endif
418 
419   } // namespace integer
420 } // namespace boost
421 
422 #if defined(__BORLANDC__) || defined( __CODEGEARC__)
423 # pragma pack(pop)
424 #endif
425 
426 #endif // BOOST_SPIRIT_ENDIAN_HPP
427