1 // boost/endian/buffers.hpp ----------------------------------------------------------// 2 3 // (C) Copyright Darin Adler 2000 4 // (C) Copyright Beman Dawes 2006, 2009, 2014 5 // (C) Copyright Peter Dimov 2019 6 7 // Distributed under the Boost Software License, Version 1.0. 8 // See http://www.boost.org/LICENSE_1_0.txt 9 10 // See library home page at http://www.boost.org/libs/endian 11 12 //--------------------------------------------------------------------------------------// 13 14 // Original design developed by Darin Adler based on classes developed by Mark 15 // Borgerding. Four original class templates were combined into a single endian 16 // class template by Beman Dawes, who also added the unrolled_byte_loops sign 17 // partial specialization to correctly extend the sign when cover integer size 18 // differs from endian representation size. 19 20 // TODO: When a compiler supporting constexpr becomes available, try possible uses. 21 22 #ifndef BOOST_ENDIAN_BUFFERS_HPP 23 #define BOOST_ENDIAN_BUFFERS_HPP 24 25 #if defined(_MSC_VER) 26 # pragma warning(push) 27 # pragma warning(disable: 4127) // conditional expression is constant 28 #endif 29 30 #include <boost/endian/detail/endian_store.hpp> 31 #include <boost/endian/detail/endian_load.hpp> 32 #include <boost/core/scoped_enum.hpp> 33 #include <boost/static_assert.hpp> 34 #include <boost/cstdint.hpp> 35 #include <boost/config.hpp> 36 #include <boost/config/workaround.hpp> 37 #include <iosfwd> 38 #include <climits> 39 #include <cstring> 40 41 #if defined(BOOST_BORLANDC) || defined(BOOST_CODEGEARC) 42 # pragma pack(push, 1) 43 #endif 44 45 # if CHAR_BIT != 8 46 # error Platforms with CHAR_BIT != 8 are not supported 47 # endif 48 49 # ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS 50 # define BOOST_ENDIAN_DEFAULT_CONSTRUCT {} // C++03 51 # else 52 # define BOOST_ENDIAN_DEFAULT_CONSTRUCT = default; // C++0x 53 # endif 54 55 // g++ pre-4.6 does not support unrestricted unions, but we have no Config macro for that 56 # if (defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || BOOST_WORKAROUND(BOOST_GCC, < 40600)) && defined(BOOST_ENDIAN_FORCE_PODNESS) 57 # define BOOST_ENDIAN_NO_CTORS 58 # endif 59 60 //---------------------------------- synopsis ----------------------------------------// 61 62 namespace boost 63 { 64 namespace endian 65 { 66 BOOST_SCOPED_ENUM_START(align)67 BOOST_SCOPED_ENUM_START(align) 68 {no, yes 69 # ifdef BOOST_ENDIAN_DEPRECATED_NAMES 70 , unaligned = no, aligned = yes 71 # endif 72 }; BOOST_SCOPED_ENUM_END 73 74 template <BOOST_SCOPED_ENUM(order) Order, class T, std::size_t n_bits, 75 BOOST_SCOPED_ENUM(align) A = align::no> 76 class endian_buffer; 77 78 // aligned big endian signed integer buffers 79 typedef endian_buffer<order::big, int8_t, 8, align::yes> big_int8_buf_at; 80 typedef endian_buffer<order::big, int16_t, 16, align::yes> big_int16_buf_at; 81 typedef endian_buffer<order::big, int32_t, 32, align::yes> big_int32_buf_at; 82 typedef endian_buffer<order::big, int64_t, 64, align::yes> big_int64_buf_at; 83 84 // aligned big endian unsigned integer buffers 85 typedef endian_buffer<order::big, uint8_t, 8, align::yes> big_uint8_buf_at; 86 typedef endian_buffer<order::big, uint16_t, 16, align::yes> big_uint16_buf_at; 87 typedef endian_buffer<order::big, uint32_t, 32, align::yes> big_uint32_buf_at; 88 typedef endian_buffer<order::big, uint64_t, 64, align::yes> big_uint64_buf_at; 89 90 // aligned little endian signed integer buffers 91 typedef endian_buffer<order::little, int8_t, 8, align::yes> little_int8_buf_at; 92 typedef endian_buffer<order::little, int16_t, 16, align::yes> little_int16_buf_at; 93 typedef endian_buffer<order::little, int32_t, 32, align::yes> little_int32_buf_at; 94 typedef endian_buffer<order::little, int64_t, 64, align::yes> little_int64_buf_at; 95 96 // aligned little endian unsigned integer buffers 97 typedef endian_buffer<order::little, uint8_t, 8, align::yes> little_uint8_buf_at; 98 typedef endian_buffer<order::little, uint16_t, 16, align::yes> little_uint16_buf_at; 99 typedef endian_buffer<order::little, uint32_t, 32, align::yes> little_uint32_buf_at; 100 typedef endian_buffer<order::little, uint64_t, 64, align::yes> little_uint64_buf_at; 101 102 // aligned floating point buffers 103 typedef endian_buffer<order::big, float, 32, align::yes> big_float32_buf_at; 104 typedef endian_buffer<order::big, double, 64, align::yes> big_float64_buf_at; 105 typedef endian_buffer<order::little, float, 32, align::yes> little_float32_buf_at; 106 typedef endian_buffer<order::little, double, 64, align::yes> little_float64_buf_at; 107 108 // aligned native endian typedefs are not provided because 109 // <cstdint> types are superior for this use case 110 111 // unaligned big endian signed integer buffers 112 typedef endian_buffer<order::big, int_least8_t, 8> big_int8_buf_t; 113 typedef endian_buffer<order::big, int_least16_t, 16> big_int16_buf_t; 114 typedef endian_buffer<order::big, int_least32_t, 24> big_int24_buf_t; 115 typedef endian_buffer<order::big, int_least32_t, 32> big_int32_buf_t; 116 typedef endian_buffer<order::big, int_least64_t, 40> big_int40_buf_t; 117 typedef endian_buffer<order::big, int_least64_t, 48> big_int48_buf_t; 118 typedef endian_buffer<order::big, int_least64_t, 56> big_int56_buf_t; 119 typedef endian_buffer<order::big, int_least64_t, 64> big_int64_buf_t; 120 121 // unaligned big endian unsigned integer buffers 122 typedef endian_buffer<order::big, uint_least8_t, 8> big_uint8_buf_t; 123 typedef endian_buffer<order::big, uint_least16_t, 16> big_uint16_buf_t; 124 typedef endian_buffer<order::big, uint_least32_t, 24> big_uint24_buf_t; 125 typedef endian_buffer<order::big, uint_least32_t, 32> big_uint32_buf_t; 126 typedef endian_buffer<order::big, uint_least64_t, 40> big_uint40_buf_t; 127 typedef endian_buffer<order::big, uint_least64_t, 48> big_uint48_buf_t; 128 typedef endian_buffer<order::big, uint_least64_t, 56> big_uint56_buf_t; 129 typedef endian_buffer<order::big, uint_least64_t, 64> big_uint64_buf_t; 130 131 // unaligned little endian signed integer buffers 132 typedef endian_buffer<order::little, int_least8_t, 8> little_int8_buf_t; 133 typedef endian_buffer<order::little, int_least16_t, 16> little_int16_buf_t; 134 typedef endian_buffer<order::little, int_least32_t, 24> little_int24_buf_t; 135 typedef endian_buffer<order::little, int_least32_t, 32> little_int32_buf_t; 136 typedef endian_buffer<order::little, int_least64_t, 40> little_int40_buf_t; 137 typedef endian_buffer<order::little, int_least64_t, 48> little_int48_buf_t; 138 typedef endian_buffer<order::little, int_least64_t, 56> little_int56_buf_t; 139 typedef endian_buffer<order::little, int_least64_t, 64> little_int64_buf_t; 140 141 // unaligned little endian unsigned integer buffers 142 typedef endian_buffer<order::little, uint_least8_t, 8> little_uint8_buf_t; 143 typedef endian_buffer<order::little, uint_least16_t, 16> little_uint16_buf_t; 144 typedef endian_buffer<order::little, uint_least32_t, 24> little_uint24_buf_t; 145 typedef endian_buffer<order::little, uint_least32_t, 32> little_uint32_buf_t; 146 typedef endian_buffer<order::little, uint_least64_t, 40> little_uint40_buf_t; 147 typedef endian_buffer<order::little, uint_least64_t, 48> little_uint48_buf_t; 148 typedef endian_buffer<order::little, uint_least64_t, 56> little_uint56_buf_t; 149 typedef endian_buffer<order::little, uint_least64_t, 64> little_uint64_buf_t; 150 151 // unaligned native endian signed integer buffers 152 typedef endian_buffer<order::native, int_least8_t, 8> native_int8_buf_t; 153 typedef endian_buffer<order::native, int_least16_t, 16> native_int16_buf_t; 154 typedef endian_buffer<order::native, int_least32_t, 24> native_int24_buf_t; 155 typedef endian_buffer<order::native, int_least32_t, 32> native_int32_buf_t; 156 typedef endian_buffer<order::native, int_least64_t, 40> native_int40_buf_t; 157 typedef endian_buffer<order::native, int_least64_t, 48> native_int48_buf_t; 158 typedef endian_buffer<order::native, int_least64_t, 56> native_int56_buf_t; 159 typedef endian_buffer<order::native, int_least64_t, 64> native_int64_buf_t; 160 161 // unaligned native endian unsigned integer buffers 162 typedef endian_buffer<order::native, uint_least8_t, 8> native_uint8_buf_t; 163 typedef endian_buffer<order::native, uint_least16_t, 16> native_uint16_buf_t; 164 typedef endian_buffer<order::native, uint_least32_t, 24> native_uint24_buf_t; 165 typedef endian_buffer<order::native, uint_least32_t, 32> native_uint32_buf_t; 166 typedef endian_buffer<order::native, uint_least64_t, 40> native_uint40_buf_t; 167 typedef endian_buffer<order::native, uint_least64_t, 48> native_uint48_buf_t; 168 typedef endian_buffer<order::native, uint_least64_t, 56> native_uint56_buf_t; 169 typedef endian_buffer<order::native, uint_least64_t, 64> native_uint64_buf_t; 170 171 // unaligned floating point buffers 172 typedef endian_buffer<order::big, float, 32, align::no> big_float32_buf_t; 173 typedef endian_buffer<order::big, double, 64, align::no> big_float64_buf_t; 174 typedef endian_buffer<order::little, float, 32, align::no> little_float32_buf_t; 175 typedef endian_buffer<order::little, double, 64, align::no> little_float64_buf_t; 176 typedef endian_buffer<order::native, float, 32, align::no> native_float32_buf_t; 177 typedef endian_buffer<order::native, double, 64, align::no> native_float64_buf_t; 178 179 // Stream inserter 180 template <class charT, class traits, BOOST_SCOPED_ENUM(order) Order, class T, 181 std::size_t n_bits, BOOST_SCOPED_ENUM(align) A> 182 std::basic_ostream<charT, traits>& operator <<(std::basic_ostream<charT,traits> & os,const endian_buffer<Order,T,n_bits,A> & x)183 operator<<(std::basic_ostream<charT, traits>& os, 184 const endian_buffer<Order, T, n_bits, A>& x) 185 { 186 return os << x.value(); 187 } 188 189 // Stream extractor 190 template <class charT, class traits, BOOST_SCOPED_ENUM(order) Order, class T, 191 std::size_t n_bits, BOOST_SCOPED_ENUM(align) A> 192 std::basic_istream<charT, traits>& operator >>(std::basic_istream<charT,traits> & is,endian_buffer<Order,T,n_bits,A> & x)193 operator>>(std::basic_istream<charT, traits>& is, 194 endian_buffer<Order, T, n_bits, A>& x) 195 { 196 T i; 197 if (is >> i) 198 x = i; 199 return is; 200 } 201 202 //---------------------------------- end synopsis ------------------------------------// 203 204 // endian_buffer class template specializations --------------------------------------// 205 206 // Specializations that represent unaligned bytes. 207 // Taking an integer type as a parameter provides a nice way to pass both 208 // the size and signedness of the desired integer and get the appropriate 209 // corresponding integer type for the interface. 210 211 // Q: Should endian_buffer supply "value_type operator value_type() const noexcept"? 212 // A: No. The rationale for endian_buffers is to prevent high-cost hidden 213 // conversions. If an implicit conversion operator is supplied, hidden conversions 214 // can occur. 215 216 // unaligned endian_buffer specialization 217 218 template< BOOST_SCOPED_ENUM(order) Order, class T, std::size_t n_bits > 219 class endian_buffer<Order, T, n_bits, align::no> 220 { 221 private: 222 223 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits ); 224 225 unsigned char value_[ n_bits / 8 ]; 226 227 public: 228 229 typedef T value_type; 230 231 #ifndef BOOST_ENDIAN_NO_CTORS 232 endian_buffer()233 endian_buffer() BOOST_ENDIAN_DEFAULT_CONSTRUCT 234 235 explicit endian_buffer( T val ) BOOST_NOEXCEPT 236 { 237 boost::endian::endian_store<T, n_bits / 8, Order>( value_, val ); 238 } 239 240 #endif 241 operator =(T val)242 endian_buffer& operator=( T val ) BOOST_NOEXCEPT 243 { 244 boost::endian::endian_store<T, n_bits / 8, Order>( value_, val ); 245 return *this; 246 } 247 value() const248 value_type value() const BOOST_NOEXCEPT 249 { 250 return boost::endian::endian_load<T, n_bits / 8, Order>( value_ ); 251 } 252 data() const253 unsigned char const * data() const BOOST_NOEXCEPT 254 { 255 return value_; 256 } 257 data()258 unsigned char * data() BOOST_NOEXCEPT 259 { 260 return value_; 261 } 262 }; 263 264 // aligned specializations; only n_bits == 16/32/64 supported 265 266 // aligned endian_buffer specialization 267 268 template< BOOST_SCOPED_ENUM(order) Order, class T, std::size_t n_bits > 269 class endian_buffer<Order, T, n_bits, align::yes> 270 { 271 private: 272 273 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits ); 274 BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 ); 275 276 union 277 { 278 unsigned char value_[ n_bits / 8 ]; 279 T align_; 280 }; 281 282 public: 283 284 typedef T value_type; 285 286 #ifndef BOOST_ENDIAN_NO_CTORS 287 endian_buffer()288 endian_buffer() BOOST_ENDIAN_DEFAULT_CONSTRUCT 289 290 explicit endian_buffer( T val ) BOOST_NOEXCEPT 291 { 292 boost::endian::endian_store<T, n_bits / 8, Order>( value_, val ); 293 } 294 295 #endif 296 operator =(T val)297 endian_buffer& operator=( T val ) BOOST_NOEXCEPT 298 { 299 boost::endian::endian_store<T, n_bits / 8, Order>( value_, val ); 300 return *this; 301 } 302 value() const303 value_type value() const BOOST_NOEXCEPT 304 { 305 return boost::endian::endian_load<T, n_bits / 8, Order>( value_ ); 306 } 307 data() const308 unsigned char const * data() const BOOST_NOEXCEPT 309 { 310 return value_; 311 } 312 data()313 unsigned char * data() BOOST_NOEXCEPT 314 { 315 return value_; 316 } 317 }; 318 319 // aligned native endian_buffer specialization 320 321 template< class T, std::size_t n_bits > 322 class endian_buffer<order::native, T, n_bits, align::yes> 323 { 324 private: 325 326 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits ); 327 BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 ); 328 329 T value_; 330 331 public: 332 333 typedef T value_type; 334 335 #ifndef BOOST_ENDIAN_NO_CTORS 336 endian_buffer()337 endian_buffer() BOOST_ENDIAN_DEFAULT_CONSTRUCT 338 339 explicit endian_buffer( T val ) BOOST_NOEXCEPT: value_( val ) 340 { 341 } 342 343 #endif 344 operator =(T val)345 endian_buffer& operator=( T val ) BOOST_NOEXCEPT 346 { 347 value_ = val; 348 return *this; 349 } 350 value() const351 value_type value() const BOOST_NOEXCEPT 352 { 353 return value_; 354 } 355 data() const356 unsigned char const * data() const BOOST_NOEXCEPT 357 { 358 return reinterpret_cast< unsigned char const* >( &value_ ); 359 } 360 data()361 unsigned char * data() BOOST_NOEXCEPT 362 { 363 return reinterpret_cast< unsigned char* >( &value_ ); 364 } 365 }; 366 367 } // namespace endian 368 } // namespace boost 369 370 #if defined(BOOST_BORLANDC) || defined(BOOST_CODEGEARC) 371 # pragma pack(pop) 372 #endif 373 374 #if defined(_MSC_VER) 375 # pragma warning(pop) 376 #endif 377 378 #endif // BOOST_ENDIAN_BUFFERS_HPP 379