]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/spirit/home/support/detail/endian/endian.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / spirit / home / support / detail / endian / endian.hpp
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/predef/other/endian.h>
38 #ifndef BOOST_MINIMAL_INTEGER_COVER_OPERATORS
39 #define BOOST_MINIMAL_INTEGER_COVER_OPERATORS
40 #endif
41 #ifndef BOOST_NO_IO_COVER_OPERATORS
42 #define BOOST_NO_IO_COVER_OPERATORS
43 #endif
44 #include <boost/spirit/home/support/detail/endian/cover_operators.hpp>
45 #undef BOOST_NO_IO_COVER_OPERATORS
46 #undef BOOST_MINIMAL_INTEGER_COVER_OPERATORS
47 #include <boost/type_traits/is_signed.hpp>
48 #include <boost/type_traits/make_unsigned.hpp>
49 #include <boost/cstdint.hpp>
50 #include <boost/static_assert.hpp>
51 #include <boost/spirit/home/support/detail/scoped_enum_emulation.hpp>
52 #include <iosfwd>
53 #include <climits>
54
55 # if CHAR_BIT != 8
56 # error Platforms with CHAR_BIT != 8 are not supported
57 # endif
58
59 # define BOOST_SPIRIT_ENDIAN_DEFAULT_CONSTRUCT {} // C++03
60
61 # if defined(BOOST_ENDIAN_NO_CTORS) || defined(BOOST_ENDIAN_FORCE_PODNESS)
62 # define BOOST_SPIRIT_ENDIAN_NO_CTORS
63 # endif
64
65
66 namespace boost { namespace spirit
67 {
68 namespace detail
69 {
70 // Unrolled loops for loading and storing streams of bytes.
71
72 template <typename T, std::size_t n_bytes,
73 bool sign=boost::is_signed<T>::value >
74 struct unrolled_byte_loops
75 {
76 typedef unrolled_byte_loops<T, n_bytes - 1, sign> next;
77
78 static typename boost::make_unsigned<T>::type load_big(const unsigned char* bytes)
79 { return *(bytes - 1) | (next::load_big(bytes - 1) << 8); }
80 static typename boost::make_unsigned<T>::type load_little(const unsigned char* bytes)
81 { return *bytes | (next::load_little(bytes + 1) << 8); }
82
83 static void store_big(char* bytes, T value)
84 {
85 *(bytes - 1) = static_cast<char>(value);
86 next::store_big(bytes - 1, value >> 8);
87 }
88 static void store_little(char* bytes, T value)
89 {
90 *bytes = static_cast<char>(value);
91 next::store_little(bytes + 1, value >> 8);
92 }
93 };
94
95 template <typename T>
96 struct unrolled_byte_loops<T, 1, false>
97 {
98 static T load_big(const unsigned char* bytes)
99 { return *(bytes - 1); }
100 static T load_little(const unsigned char* bytes)
101 { return *bytes; }
102 static void store_big(char* bytes, T value)
103 { *(bytes - 1) = static_cast<char>(value); }
104 static void store_little(char* bytes, T value)
105 { *bytes = static_cast<char>(value); }
106
107 };
108
109 template <typename T>
110 struct unrolled_byte_loops<T, 1, true>
111 {
112 static typename boost::make_unsigned<T>::type load_big(const unsigned char* bytes)
113 { return *(bytes - 1); }
114 static typename boost::make_unsigned<T>::type load_little(const unsigned char* bytes)
115 { return *bytes; }
116 static void store_big(char* bytes, T value)
117 { *(bytes - 1) = static_cast<char>(value); }
118 static void store_little(char* bytes, T value)
119 { *bytes = static_cast<char>(value); }
120 };
121
122 template <typename T, std::size_t n_bytes>
123 inline
124 T load_big_endian(const void* bytes)
125 {
126 return static_cast<T>(unrolled_byte_loops<T, n_bytes>::load_big
127 (static_cast<const unsigned char*>(bytes) + n_bytes));
128 }
129
130 template <>
131 inline
132 float load_big_endian<float, 4>(const void* bytes)
133 {
134 const unsigned char *b = reinterpret_cast<const unsigned char *>(
135 bytes);
136 b += 3;
137
138 float value;
139 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
140
141 for(std::size_t i = 0; i < 4; ++i)
142 {
143 *v++ = *b--;
144 }
145
146 return value;
147 }
148
149 template <>
150 inline
151 double load_big_endian<double, 8>(const void* bytes)
152 {
153 const unsigned char *b = reinterpret_cast<const unsigned char *>(
154 bytes);
155 b += 7;
156
157 double value;
158 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
159
160 for(std::size_t i = 0; i < 8; ++i)
161 {
162 *v++ = *b--;
163 }
164
165 return value;
166 }
167
168 template <typename T, std::size_t n_bytes>
169 inline
170 T load_little_endian(const void* bytes)
171 {
172 return static_cast<T>(unrolled_byte_loops<T, n_bytes>::load_little
173 (static_cast<const unsigned char*>(bytes)));
174 }
175
176 template <>
177 inline
178 float load_little_endian<float, 4>(const void* bytes)
179 {
180 const unsigned char *b = reinterpret_cast<const unsigned char *>(
181 bytes);
182
183 float value;
184 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
185
186 for(std::size_t i = 0; i < 4; ++i)
187 {
188 *v++ = *b++;
189 }
190
191 return value;
192 }
193
194 template <>
195 inline
196 double load_little_endian<double, 8>(const void* bytes)
197 {
198 const unsigned char *b = reinterpret_cast<const unsigned char *>(
199 bytes);
200
201 double value;
202 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
203
204 for(std::size_t i = 0; i < 8; ++i)
205 {
206 *v++ = *b++;
207 }
208
209 return value;
210 }
211
212 template <typename T, std::size_t n_bytes>
213 inline
214 void store_big_endian(void* bytes, T value)
215 {
216 unrolled_byte_loops<T, n_bytes>::store_big
217 (static_cast<char*>(bytes) + n_bytes, value);
218 }
219
220 template <>
221 inline
222 void store_big_endian<float, 4>(void* bytes, float value)
223 {
224 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
225 b += 3;
226
227 const unsigned char *v = reinterpret_cast<const unsigned char *>(
228 &value);
229
230 for(std::size_t i = 0; i < 4; ++i)
231 {
232 *b-- = *v++;
233 }
234 }
235
236 template <>
237 inline
238 void store_big_endian<double, 8>(void* bytes, double value)
239 {
240 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
241 b += 7;
242
243 const unsigned char *v = reinterpret_cast<const unsigned char *>(
244 &value);
245
246 for(std::size_t i = 0; i < 8; ++i)
247 {
248 *b-- = *v++;
249 }
250 }
251
252 template <typename T, std::size_t n_bytes>
253 inline
254 void store_little_endian(void* bytes, T value)
255 {
256 unrolled_byte_loops<T, n_bytes>::store_little
257 (static_cast<char*>(bytes), value);
258 }
259
260 template <>
261 inline
262 void store_little_endian<float, 4>(void* bytes, float value)
263 {
264 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
265
266 const unsigned char *v = reinterpret_cast<const unsigned char *>(
267 &value);
268
269 for(std::size_t i = 0; i < 4; ++i)
270 {
271 *b++ = *v++;
272 }
273 }
274
275 template <>
276 inline
277 void store_little_endian<double, 8>(void* bytes, double value)
278 {
279 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
280
281 const unsigned char *v = reinterpret_cast<const unsigned char *>(
282 &value);
283
284 for(std::size_t i = 0; i < 8; ++i)
285 {
286 *b++ = *v++;
287 }
288 }
289
290 } // namespace detail
291
292 namespace endian
293 {
294
295 # ifdef BOOST_ENDIAN_LOG
296 bool endian_log(true);
297 # endif
298
299
300 // endian class template and specializations ---------------------------------------//
301
302 BOOST_SCOPED_ENUM_START(endianness) { big, little, native }; BOOST_SCOPED_ENUM_END
303 BOOST_SCOPED_ENUM_START(alignment) { unaligned, aligned }; BOOST_SCOPED_ENUM_END
304
305 template <BOOST_SCOPED_ENUM(endianness) E, typename T, std::size_t n_bits,
306 BOOST_SCOPED_ENUM(alignment) A = alignment::unaligned>
307 class endian;
308
309 // Specializations that represent unaligned bytes.
310 // Taking an integer type as a parameter provides a nice way to pass both
311 // the size and signedness of the desired integer and get the appropriate
312 // corresponding integer type for the interface.
313
314 // unaligned big endian specialization
315 template <typename T, std::size_t n_bits>
316 class endian< endianness::big, T, n_bits, alignment::unaligned >
317 : cover_operators< endian< endianness::big, T, n_bits >, T >
318 {
319 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
320 public:
321 typedef T value_type;
322 # ifndef BOOST_SPIRIT_ENDIAN_NO_CTORS
323 endian() BOOST_SPIRIT_ENDIAN_DEFAULT_CONSTRUCT
324 explicit endian(T val)
325 {
326 # ifdef BOOST_ENDIAN_LOG
327 if ( endian_log )
328 std::clog << "big, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
329 # endif
330 detail::store_big_endian<T, n_bits/8>(m_value, val);
331 }
332 # endif
333 endian & operator=(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); return *this; }
334 operator T() const
335 {
336 # ifdef BOOST_ENDIAN_LOG
337 if ( endian_log )
338 std::clog << "big, unaligned, " << n_bits << "-bits, convert(" << detail::load_big_endian<T, n_bits/8>(m_value) << ")\n";
339 # endif
340 return detail::load_big_endian<T, n_bits/8>(m_value);
341 }
342 private:
343 char m_value[n_bits/8];
344 };
345
346 // unaligned little endian specialization
347 template <typename T, std::size_t n_bits>
348 class endian< endianness::little, T, n_bits, alignment::unaligned >
349 : cover_operators< endian< endianness::little, T, n_bits >, T >
350 {
351 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
352 public:
353 typedef T value_type;
354 # ifndef BOOST_SPIRIT_ENDIAN_NO_CTORS
355 endian() BOOST_SPIRIT_ENDIAN_DEFAULT_CONSTRUCT
356 explicit endian(T val)
357 {
358 # ifdef BOOST_ENDIAN_LOG
359 if ( endian_log )
360 std::clog << "little, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
361 # endif
362 detail::store_little_endian<T, n_bits/8>(m_value, val);
363 }
364 # endif
365 endian & operator=(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); return *this; }
366 operator T() const
367 {
368 # ifdef BOOST_ENDIAN_LOG
369 if ( endian_log )
370 std::clog << "little, unaligned, " << n_bits << "-bits, convert(" << detail::load_little_endian<T, n_bits/8>(m_value) << ")\n";
371 # endif
372 return detail::load_little_endian<T, n_bits/8>(m_value);
373 }
374 private:
375 char m_value[n_bits/8];
376 };
377
378 // unaligned native endian specialization
379 template <typename T, std::size_t n_bits>
380 class endian< endianness::native, T, n_bits, alignment::unaligned >
381 : cover_operators< endian< endianness::native, T, n_bits >, T >
382 {
383 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
384 public:
385 typedef T value_type;
386 # ifndef BOOST_SPIRIT_ENDIAN_NO_CTORS
387 endian() BOOST_SPIRIT_ENDIAN_DEFAULT_CONSTRUCT
388 # if BOOST_ENDIAN_BIG_BYTE
389 explicit endian(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); }
390 # else
391 explicit endian(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); }
392 # endif
393 # endif
394 # if BOOST_ENDIAN_BIG_BYTE
395 endian & operator=(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); return *this; }
396 operator T() const { return detail::load_big_endian<T, n_bits/8>(m_value); }
397 # else
398 endian & operator=(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); return *this; }
399 operator T() const { return detail::load_little_endian<T, n_bits/8>(m_value); }
400 # endif
401 private:
402 char m_value[n_bits/8];
403 };
404
405 // Specializations that mimic built-in integer types.
406 // These typically have the same alignment as the underlying types.
407
408 // aligned big endian specialization
409 template <typename T, std::size_t n_bits>
410 class endian< endianness::big, T, n_bits, alignment::aligned >
411 : cover_operators< endian< endianness::big, T, n_bits, alignment::aligned >, T >
412 {
413 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
414 BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 );
415 public:
416 typedef T value_type;
417 # ifndef BOOST_SPIRIT_ENDIAN_NO_CTORS
418 endian() BOOST_SPIRIT_ENDIAN_DEFAULT_CONSTRUCT
419 # if BOOST_ENDIAN_BIG_BYTE
420 endian(T val) : m_value(val) { }
421 # else
422 explicit endian(T val) { detail::store_big_endian<T, sizeof(T)>(&m_value, val); }
423 # endif
424 # endif
425 # if BOOST_ENDIAN_BIG_BYTE
426 endian & operator=(T val) { m_value = val; return *this; }
427 operator T() const { return m_value; }
428 # else
429 endian & operator=(T val) { detail::store_big_endian<T, sizeof(T)>(&m_value, val); return *this; }
430 operator T() const { return detail::load_big_endian<T, sizeof(T)>(&m_value); }
431 # endif
432 private:
433 T m_value;
434 };
435
436 // aligned little endian specialization
437 template <typename T, std::size_t n_bits>
438 class endian< endianness::little, T, n_bits, alignment::aligned >
439 : cover_operators< endian< endianness::little, T, n_bits, alignment::aligned >, T >
440 {
441 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
442 BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 );
443 public:
444 typedef T value_type;
445 # ifndef BOOST_SPIRIT_ENDIAN_NO_CTORS
446 endian() BOOST_SPIRIT_ENDIAN_DEFAULT_CONSTRUCT
447 # if BOOST_ENDIAN_LITTLE_BYTE
448 endian(T val) : m_value(val) { }
449 # else
450 explicit endian(T val) { detail::store_little_endian<T, sizeof(T)>(&m_value, val); }
451 # endif
452 # endif
453 # if BOOST_ENDIAN_LITTLE_BYTE
454 endian & operator=(T val) { m_value = val; return *this; }
455 operator T() const { return m_value; }
456 #else
457 endian & operator=(T val) { detail::store_little_endian<T, sizeof(T)>(&m_value, val); return *this; }
458 operator T() const { return detail::load_little_endian<T, sizeof(T)>(&m_value); }
459 #endif
460 private:
461 T m_value;
462 };
463
464 // naming convention typedefs ------------------------------------------------------//
465
466 // unaligned big endian signed integer types
467 typedef endian< endianness::big, int_least8_t, 8 > big8_t;
468 typedef endian< endianness::big, int_least16_t, 16 > big16_t;
469 typedef endian< endianness::big, int_least32_t, 24 > big24_t;
470 typedef endian< endianness::big, int_least32_t, 32 > big32_t;
471 typedef endian< endianness::big, int_least64_t, 40 > big40_t;
472 typedef endian< endianness::big, int_least64_t, 48 > big48_t;
473 typedef endian< endianness::big, int_least64_t, 56 > big56_t;
474 typedef endian< endianness::big, int_least64_t, 64 > big64_t;
475
476 // unaligned big endian unsigned integer types
477 typedef endian< endianness::big, uint_least8_t, 8 > ubig8_t;
478 typedef endian< endianness::big, uint_least16_t, 16 > ubig16_t;
479 typedef endian< endianness::big, uint_least32_t, 24 > ubig24_t;
480 typedef endian< endianness::big, uint_least32_t, 32 > ubig32_t;
481 typedef endian< endianness::big, uint_least64_t, 40 > ubig40_t;
482 typedef endian< endianness::big, uint_least64_t, 48 > ubig48_t;
483 typedef endian< endianness::big, uint_least64_t, 56 > ubig56_t;
484 typedef endian< endianness::big, uint_least64_t, 64 > ubig64_t;
485
486 // unaligned little endian signed integer types
487 typedef endian< endianness::little, int_least8_t, 8 > little8_t;
488 typedef endian< endianness::little, int_least16_t, 16 > little16_t;
489 typedef endian< endianness::little, int_least32_t, 24 > little24_t;
490 typedef endian< endianness::little, int_least32_t, 32 > little32_t;
491 typedef endian< endianness::little, int_least64_t, 40 > little40_t;
492 typedef endian< endianness::little, int_least64_t, 48 > little48_t;
493 typedef endian< endianness::little, int_least64_t, 56 > little56_t;
494 typedef endian< endianness::little, int_least64_t, 64 > little64_t;
495
496 // unaligned little endian unsigned integer types
497 typedef endian< endianness::little, uint_least8_t, 8 > ulittle8_t;
498 typedef endian< endianness::little, uint_least16_t, 16 > ulittle16_t;
499 typedef endian< endianness::little, uint_least32_t, 24 > ulittle24_t;
500 typedef endian< endianness::little, uint_least32_t, 32 > ulittle32_t;
501 typedef endian< endianness::little, uint_least64_t, 40 > ulittle40_t;
502 typedef endian< endianness::little, uint_least64_t, 48 > ulittle48_t;
503 typedef endian< endianness::little, uint_least64_t, 56 > ulittle56_t;
504 typedef endian< endianness::little, uint_least64_t, 64 > ulittle64_t;
505
506 // unaligned native endian signed integer types
507 typedef endian< endianness::native, int_least8_t, 8 > native8_t;
508 typedef endian< endianness::native, int_least16_t, 16 > native16_t;
509 typedef endian< endianness::native, int_least32_t, 24 > native24_t;
510 typedef endian< endianness::native, int_least32_t, 32 > native32_t;
511 typedef endian< endianness::native, int_least64_t, 40 > native40_t;
512 typedef endian< endianness::native, int_least64_t, 48 > native48_t;
513 typedef endian< endianness::native, int_least64_t, 56 > native56_t;
514 typedef endian< endianness::native, int_least64_t, 64 > native64_t;
515
516 // unaligned native endian unsigned integer types
517 typedef endian< endianness::native, uint_least8_t, 8 > unative8_t;
518 typedef endian< endianness::native, uint_least16_t, 16 > unative16_t;
519 typedef endian< endianness::native, uint_least32_t, 24 > unative24_t;
520 typedef endian< endianness::native, uint_least32_t, 32 > unative32_t;
521 typedef endian< endianness::native, uint_least64_t, 40 > unative40_t;
522 typedef endian< endianness::native, uint_least64_t, 48 > unative48_t;
523 typedef endian< endianness::native, uint_least64_t, 56 > unative56_t;
524 typedef endian< endianness::native, uint_least64_t, 64 > unative64_t;
525
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
531
532 // aligned native endian typedefs are not provided because
533 // <cstdint> types are superior for this use case
534
535 #ifdef INT16_MAX
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;
540 #endif
541
542 #ifdef INT32_MAX
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;
547 #endif
548
549 #ifdef INT64_MAX
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;
554 #endif
555
556 } // namespace endian
557 }} // namespace boost::spirit
558
559 #undef BOOST_SPIRIT_ENDIAN_DEFAULT_CONSTRUCT
560 #undef BOOST_SPIRIT_ENDIAN_NO_CTORS
561
562 #if defined(__BORLANDC__) || defined( __CODEGEARC__)
563 # pragma pack(pop)
564 #endif
565
566 #endif // BOOST_SPIRIT_ENDIAN_HPP