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