1 // Boost endian.hpp header file -------------------------------------------------------//
3 // (C) Copyright Darin Adler 2000
4 // (C) Copyright Beman Dawes 2006, 2009
6 // Distributed under the Boost Software License, Version 1.0.
7 // See http://www.boost.org/LICENSE_1_0.txt
9 // See library home page at http://www.boost.org/libs/endian
11 //--------------------------------------------------------------------------------------//
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.
19 // TODO: When a compiler supporting constexpr becomes available, try possible uses.
21 #ifndef BOOST_SPIRIT_ENDIAN_HPP
22 #define BOOST_SPIRIT_ENDIAN_HPP
28 #ifdef BOOST_ENDIAN_LOG
32 #if defined(__BORLANDC__) || defined( __CODEGEARC__)
33 # pragma pack(push, 1)
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/endian/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/type_traits/make_unsigned.hpp>
45 #include <boost/cstdint.hpp>
46 #include <boost/static_assert.hpp>
47 #include <boost/spirit/home/support/detail/scoped_enum_emulation.hpp>
52 # error Platforms with CHAR_BIT != 8 are not supported
55 # define BOOST_ENDIAN_DEFAULT_CONSTRUCT {} // C++03
57 # if defined(BOOST_ENDIAN_FORCE_PODNESS)
58 # define BOOST_ENDIAN_NO_CTORS
62 namespace boost { namespace spirit
66 // Unrolled loops for loading and storing streams of bytes.
68 template <typename T, std::size_t n_bytes,
69 bool sign=boost::is_signed<T>::value >
70 struct unrolled_byte_loops
72 typedef unrolled_byte_loops<T, n_bytes - 1, sign> next;
74 static typename boost::make_unsigned<T>::type load_big(const unsigned char* bytes)
75 { return *(bytes - 1) | (next::load_big(bytes - 1) << 8); }
76 static typename boost::make_unsigned<T>::type load_little(const unsigned char* bytes)
77 { return *bytes | (next::load_little(bytes + 1) << 8); }
79 static void store_big(char* bytes, T value)
81 *(bytes - 1) = static_cast<char>(value);
82 next::store_big(bytes - 1, value >> 8);
84 static void store_little(char* bytes, T value)
86 *bytes = static_cast<char>(value);
87 next::store_little(bytes + 1, value >> 8);
92 struct unrolled_byte_loops<T, 1, false>
94 static T load_big(const unsigned char* bytes)
95 { return *(bytes - 1); }
96 static T load_little(const unsigned char* bytes)
98 static void store_big(char* bytes, T value)
99 { *(bytes - 1) = static_cast<char>(value); }
100 static void store_little(char* bytes, T value)
101 { *bytes = static_cast<char>(value); }
105 template <typename T>
106 struct unrolled_byte_loops<T, 1, true>
108 static typename boost::make_unsigned<T>::type load_big(const unsigned char* bytes)
109 { return *(bytes - 1); }
110 static typename boost::make_unsigned<T>::type load_little(const unsigned char* bytes)
112 static void store_big(char* bytes, T value)
113 { *(bytes - 1) = static_cast<char>(value); }
114 static void store_little(char* bytes, T value)
115 { *bytes = static_cast<char>(value); }
118 template <typename T, std::size_t n_bytes>
120 T load_big_endian(const void* bytes)
122 return static_cast<T>(unrolled_byte_loops<T, n_bytes>::load_big
123 (static_cast<const unsigned char*>(bytes) + n_bytes));
128 float load_big_endian<float, 4>(const void* bytes)
130 const unsigned char *b = reinterpret_cast<const unsigned char *>(
135 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
137 for(std::size_t i = 0; i < 4; ++i)
147 double load_big_endian<double, 8>(const void* bytes)
149 const unsigned char *b = reinterpret_cast<const unsigned char *>(
154 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
156 for(std::size_t i = 0; i < 8; ++i)
164 template <typename T, std::size_t n_bytes>
166 T load_little_endian(const void* bytes)
168 return static_cast<T>(unrolled_byte_loops<T, n_bytes>::load_little
169 (static_cast<const unsigned char*>(bytes)));
174 float load_little_endian<float, 4>(const void* bytes)
176 const unsigned char *b = reinterpret_cast<const unsigned char *>(
180 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
182 for(std::size_t i = 0; i < 4; ++i)
192 double load_little_endian<double, 8>(const void* bytes)
194 const unsigned char *b = reinterpret_cast<const unsigned char *>(
198 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
200 for(std::size_t i = 0; i < 8; ++i)
208 template <typename T, std::size_t n_bytes>
210 void store_big_endian(void* bytes, T value)
212 unrolled_byte_loops<T, n_bytes>::store_big
213 (static_cast<char*>(bytes) + n_bytes, value);
218 void store_big_endian<float, 4>(void* bytes, float value)
220 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
223 const unsigned char *v = reinterpret_cast<const unsigned char *>(
226 for(std::size_t i = 0; i < 4; ++i)
234 void store_big_endian<double, 8>(void* bytes, double value)
236 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
239 const unsigned char *v = reinterpret_cast<const unsigned char *>(
242 for(std::size_t i = 0; i < 8; ++i)
248 template <typename T, std::size_t n_bytes>
250 void store_little_endian(void* bytes, T value)
252 unrolled_byte_loops<T, n_bytes>::store_little
253 (static_cast<char*>(bytes), value);
258 void store_little_endian<float, 4>(void* bytes, float value)
260 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
262 const unsigned char *v = reinterpret_cast<const unsigned char *>(
265 for(std::size_t i = 0; i < 4; ++i)
273 void store_little_endian<double, 8>(void* bytes, double value)
275 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
277 const unsigned char *v = reinterpret_cast<const unsigned char *>(
280 for(std::size_t i = 0; i < 8; ++i)
286 } // namespace detail
291 # ifdef BOOST_ENDIAN_LOG
292 bool endian_log(true);
296 // endian class template and specializations ---------------------------------------//
298 BOOST_SCOPED_ENUM_START(endianness) { big, little, native }; BOOST_SCOPED_ENUM_END
299 BOOST_SCOPED_ENUM_START(alignment) { unaligned, aligned }; BOOST_SCOPED_ENUM_END
301 template <BOOST_SCOPED_ENUM(endianness) E, typename T, std::size_t n_bits,
302 BOOST_SCOPED_ENUM(alignment) A = alignment::unaligned>
305 // Specializations that represent unaligned bytes.
306 // Taking an integer type as a parameter provides a nice way to pass both
307 // the size and signedness of the desired integer and get the appropriate
308 // corresponding integer type for the interface.
310 // unaligned big endian specialization
311 template <typename T, std::size_t n_bits>
312 class endian< endianness::big, T, n_bits, alignment::unaligned >
313 : cover_operators< endian< endianness::big, T, n_bits >, T >
315 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
317 typedef T value_type;
318 # ifndef BOOST_ENDIAN_NO_CTORS
319 endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
320 explicit endian(T val)
322 # ifdef BOOST_ENDIAN_LOG
324 std::clog << "big, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
326 detail::store_big_endian<T, n_bits/8>(m_value, val);
329 endian & operator=(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); return *this; }
332 # ifdef BOOST_ENDIAN_LOG
334 std::clog << "big, unaligned, " << n_bits << "-bits, convert(" << detail::load_big_endian<T, n_bits/8>(m_value) << ")\n";
336 return detail::load_big_endian<T, n_bits/8>(m_value);
339 char m_value[n_bits/8];
342 // unaligned little endian specialization
343 template <typename T, std::size_t n_bits>
344 class endian< endianness::little, T, n_bits, alignment::unaligned >
345 : cover_operators< endian< endianness::little, T, n_bits >, T >
347 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
349 typedef T value_type;
350 # ifndef BOOST_ENDIAN_NO_CTORS
351 endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
352 explicit endian(T val)
354 # ifdef BOOST_ENDIAN_LOG
356 std::clog << "little, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
358 detail::store_little_endian<T, n_bits/8>(m_value, val);
361 endian & operator=(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); return *this; }
364 # ifdef BOOST_ENDIAN_LOG
366 std::clog << "little, unaligned, " << n_bits << "-bits, convert(" << detail::load_little_endian<T, n_bits/8>(m_value) << ")\n";
368 return detail::load_little_endian<T, n_bits/8>(m_value);
371 char m_value[n_bits/8];
374 // unaligned native endian specialization
375 template <typename T, std::size_t n_bits>
376 class endian< endianness::native, T, n_bits, alignment::unaligned >
377 : cover_operators< endian< endianness::native, T, n_bits >, T >
379 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
381 typedef T value_type;
382 # ifndef BOOST_ENDIAN_NO_CTORS
383 endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
384 # ifdef BOOST_BIG_ENDIAN
385 explicit endian(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); }
387 explicit endian(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); }
390 # ifdef BOOST_BIG_ENDIAN
391 endian & operator=(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); return *this; }
392 operator T() const { return detail::load_big_endian<T, n_bits/8>(m_value); }
394 endian & operator=(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); return *this; }
395 operator T() const { return detail::load_little_endian<T, n_bits/8>(m_value); }
398 char m_value[n_bits/8];
401 // Specializations that mimic built-in integer types.
402 // These typically have the same alignment as the underlying types.
404 // aligned big endian specialization
405 template <typename T, std::size_t n_bits>
406 class endian< endianness::big, T, n_bits, alignment::aligned >
407 : cover_operators< endian< endianness::big, T, n_bits, alignment::aligned >, T >
409 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
410 BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 );
412 typedef T value_type;
413 # ifndef BOOST_ENDIAN_NO_CTORS
414 endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
415 # ifdef BOOST_BIG_ENDIAN
416 endian(T val) : m_value(val) { }
418 explicit endian(T val) { detail::store_big_endian<T, sizeof(T)>(&m_value, val); }
421 # ifdef BOOST_BIG_ENDIAN
422 endian & operator=(T val) { m_value = val; return *this; }
423 operator T() const { return m_value; }
425 endian & operator=(T val) { detail::store_big_endian<T, sizeof(T)>(&m_value, val); return *this; }
426 operator T() const { return detail::load_big_endian<T, sizeof(T)>(&m_value); }
432 // aligned little endian specialization
433 template <typename T, std::size_t n_bits>
434 class endian< endianness::little, T, n_bits, alignment::aligned >
435 : cover_operators< endian< endianness::little, T, n_bits, alignment::aligned >, T >
437 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
438 BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 );
440 typedef T value_type;
441 # ifndef BOOST_ENDIAN_NO_CTORS
442 endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
443 # ifdef BOOST_LITTLE_ENDIAN
444 endian(T val) : m_value(val) { }
446 explicit endian(T val) { detail::store_little_endian<T, sizeof(T)>(&m_value, val); }
449 # ifdef BOOST_LITTLE_ENDIAN
450 endian & operator=(T val) { m_value = val; return *this; }
451 operator T() const { return m_value; }
453 endian & operator=(T val) { detail::store_little_endian<T, sizeof(T)>(&m_value, val); return *this; }
454 operator T() const { return detail::load_little_endian<T, sizeof(T)>(&m_value); }
460 // naming convention typedefs ------------------------------------------------------//
462 // unaligned big endian signed integer types
463 typedef endian< endianness::big, int_least8_t, 8 > big8_t;
464 typedef endian< endianness::big, int_least16_t, 16 > big16_t;
465 typedef endian< endianness::big, int_least32_t, 24 > big24_t;
466 typedef endian< endianness::big, int_least32_t, 32 > big32_t;
467 typedef endian< endianness::big, int_least64_t, 40 > big40_t;
468 typedef endian< endianness::big, int_least64_t, 48 > big48_t;
469 typedef endian< endianness::big, int_least64_t, 56 > big56_t;
470 typedef endian< endianness::big, int_least64_t, 64 > big64_t;
472 // unaligned big endian unsigned integer types
473 typedef endian< endianness::big, uint_least8_t, 8 > ubig8_t;
474 typedef endian< endianness::big, uint_least16_t, 16 > ubig16_t;
475 typedef endian< endianness::big, uint_least32_t, 24 > ubig24_t;
476 typedef endian< endianness::big, uint_least32_t, 32 > ubig32_t;
477 typedef endian< endianness::big, uint_least64_t, 40 > ubig40_t;
478 typedef endian< endianness::big, uint_least64_t, 48 > ubig48_t;
479 typedef endian< endianness::big, uint_least64_t, 56 > ubig56_t;
480 typedef endian< endianness::big, uint_least64_t, 64 > ubig64_t;
482 // unaligned little endian signed integer types
483 typedef endian< endianness::little, int_least8_t, 8 > little8_t;
484 typedef endian< endianness::little, int_least16_t, 16 > little16_t;
485 typedef endian< endianness::little, int_least32_t, 24 > little24_t;
486 typedef endian< endianness::little, int_least32_t, 32 > little32_t;
487 typedef endian< endianness::little, int_least64_t, 40 > little40_t;
488 typedef endian< endianness::little, int_least64_t, 48 > little48_t;
489 typedef endian< endianness::little, int_least64_t, 56 > little56_t;
490 typedef endian< endianness::little, int_least64_t, 64 > little64_t;
492 // unaligned little endian unsigned integer types
493 typedef endian< endianness::little, uint_least8_t, 8 > ulittle8_t;
494 typedef endian< endianness::little, uint_least16_t, 16 > ulittle16_t;
495 typedef endian< endianness::little, uint_least32_t, 24 > ulittle24_t;
496 typedef endian< endianness::little, uint_least32_t, 32 > ulittle32_t;
497 typedef endian< endianness::little, uint_least64_t, 40 > ulittle40_t;
498 typedef endian< endianness::little, uint_least64_t, 48 > ulittle48_t;
499 typedef endian< endianness::little, uint_least64_t, 56 > ulittle56_t;
500 typedef endian< endianness::little, uint_least64_t, 64 > ulittle64_t;
502 // unaligned native endian signed integer types
503 typedef endian< endianness::native, int_least8_t, 8 > native8_t;
504 typedef endian< endianness::native, int_least16_t, 16 > native16_t;
505 typedef endian< endianness::native, int_least32_t, 24 > native24_t;
506 typedef endian< endianness::native, int_least32_t, 32 > native32_t;
507 typedef endian< endianness::native, int_least64_t, 40 > native40_t;
508 typedef endian< endianness::native, int_least64_t, 48 > native48_t;
509 typedef endian< endianness::native, int_least64_t, 56 > native56_t;
510 typedef endian< endianness::native, int_least64_t, 64 > native64_t;
512 // unaligned native endian unsigned integer types
513 typedef endian< endianness::native, uint_least8_t, 8 > unative8_t;
514 typedef endian< endianness::native, uint_least16_t, 16 > unative16_t;
515 typedef endian< endianness::native, uint_least32_t, 24 > unative24_t;
516 typedef endian< endianness::native, uint_least32_t, 32 > unative32_t;
517 typedef endian< endianness::native, uint_least64_t, 40 > unative40_t;
518 typedef endian< endianness::native, uint_least64_t, 48 > unative48_t;
519 typedef endian< endianness::native, uint_least64_t, 56 > unative56_t;
520 typedef endian< endianness::native, uint_least64_t, 64 > unative64_t;
522 #define BOOST_HAS_INT16_T
523 #define BOOST_HAS_INT32_T
524 #define BOOST_HAS_INT64_T
526 // These types only present if platform has exact size integers:
527 // aligned big endian signed integer types
528 // aligned big endian unsigned integer types
529 // aligned little endian signed integer types
530 // aligned little endian unsigned integer types
532 // aligned native endian typedefs are not provided because
533 // <cstdint> types are superior for this use case
535 # if defined(BOOST_HAS_INT16_T)
536 typedef endian< endianness::big, int16_t, 16, alignment::aligned > aligned_big16_t;
537 typedef endian< endianness::big, uint16_t, 16, alignment::aligned > aligned_ubig16_t;
538 typedef endian< endianness::little, int16_t, 16, alignment::aligned > aligned_little16_t;
539 typedef endian< endianness::little, uint16_t, 16, alignment::aligned > aligned_ulittle16_t;
542 # if defined(BOOST_HAS_INT32_T)
543 typedef endian< endianness::big, int32_t, 32, alignment::aligned > aligned_big32_t;
544 typedef endian< endianness::big, uint32_t, 32, alignment::aligned > aligned_ubig32_t;
545 typedef endian< endianness::little, int32_t, 32, alignment::aligned > aligned_little32_t;
546 typedef endian< endianness::little, uint32_t, 32, alignment::aligned > aligned_ulittle32_t;
549 # if defined(BOOST_HAS_INT64_T)
550 typedef endian< endianness::big, int64_t, 64, alignment::aligned > aligned_big64_t;
551 typedef endian< endianness::big, uint64_t, 64, alignment::aligned > aligned_ubig64_t;
552 typedef endian< endianness::little, int64_t, 64, alignment::aligned > aligned_little64_t;
553 typedef endian< endianness::little, uint64_t, 64, alignment::aligned > aligned_ulittle64_t;
556 } // namespace endian
557 }} // namespace boost::spirit
559 // import the namespace above into boost::endian
560 namespace boost { namespace endian
562 using namespace boost::spirit::endian;
565 #if defined(__BORLANDC__) || defined( __CODEGEARC__)
569 #endif // BOOST_SPIRIT_ENDIAN_HPP