]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/include/boost/spirit/home/support/detail/endian/endian.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / spirit / include / 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/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>
48 #include <iosfwd>
49 #include <climits>
50
51 # if CHAR_BIT != 8
52 # error Platforms with CHAR_BIT != 8 are not supported
53 # endif
54
55 # define BOOST_ENDIAN_DEFAULT_CONSTRUCT {} // C++03
56
57 # if defined(BOOST_ENDIAN_FORCE_PODNESS)
58 # define BOOST_ENDIAN_NO_CTORS
59 # endif
60
61
62 namespace boost { namespace spirit
63 {
64 namespace detail
65 {
66 // Unrolled loops for loading and storing streams of bytes.
67
68 template <typename T, std::size_t n_bytes,
69 bool sign=boost::is_signed<T>::value >
70 struct unrolled_byte_loops
71 {
72 typedef unrolled_byte_loops<T, n_bytes - 1, sign> next;
73
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); }
78
79 static void store_big(char* bytes, T value)
80 {
81 *(bytes - 1) = static_cast<char>(value);
82 next::store_big(bytes - 1, value >> 8);
83 }
84 static void store_little(char* bytes, T value)
85 {
86 *bytes = static_cast<char>(value);
87 next::store_little(bytes + 1, value >> 8);
88 }
89 };
90
91 template <typename T>
92 struct unrolled_byte_loops<T, 1, false>
93 {
94 static T load_big(const unsigned char* bytes)
95 { return *(bytes - 1); }
96 static T load_little(const unsigned char* bytes)
97 { return *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); }
102
103 };
104
105 template <typename T>
106 struct unrolled_byte_loops<T, 1, true>
107 {
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)
111 { return *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); }
116 };
117
118 template <typename T, std::size_t n_bytes>
119 inline
120 T load_big_endian(const void* bytes)
121 {
122 return static_cast<T>(unrolled_byte_loops<T, n_bytes>::load_big
123 (static_cast<const unsigned char*>(bytes) + n_bytes));
124 }
125
126 template <>
127 inline
128 float load_big_endian<float, 4>(const void* bytes)
129 {
130 const unsigned char *b = reinterpret_cast<const unsigned char *>(
131 bytes);
132 b += 3;
133
134 float value;
135 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
136
137 for(std::size_t i = 0; i < 4; ++i)
138 {
139 *v++ = *b--;
140 }
141
142 return value;
143 }
144
145 template <>
146 inline
147 double load_big_endian<double, 8>(const void* bytes)
148 {
149 const unsigned char *b = reinterpret_cast<const unsigned char *>(
150 bytes);
151 b += 7;
152
153 double value;
154 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
155
156 for(std::size_t i = 0; i < 8; ++i)
157 {
158 *v++ = *b--;
159 }
160
161 return value;
162 }
163
164 template <typename T, std::size_t n_bytes>
165 inline
166 T load_little_endian(const void* bytes)
167 {
168 return static_cast<T>(unrolled_byte_loops<T, n_bytes>::load_little
169 (static_cast<const unsigned char*>(bytes)));
170 }
171
172 template <>
173 inline
174 float load_little_endian<float, 4>(const void* bytes)
175 {
176 const unsigned char *b = reinterpret_cast<const unsigned char *>(
177 bytes);
178
179 float value;
180 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
181
182 for(std::size_t i = 0; i < 4; ++i)
183 {
184 *v++ = *b++;
185 }
186
187 return value;
188 }
189
190 template <>
191 inline
192 double load_little_endian<double, 8>(const void* bytes)
193 {
194 const unsigned char *b = reinterpret_cast<const unsigned char *>(
195 bytes);
196
197 double value;
198 unsigned char *v = reinterpret_cast<unsigned char *>(&value);
199
200 for(std::size_t i = 0; i < 8; ++i)
201 {
202 *v++ = *b++;
203 }
204
205 return value;
206 }
207
208 template <typename T, std::size_t n_bytes>
209 inline
210 void store_big_endian(void* bytes, T value)
211 {
212 unrolled_byte_loops<T, n_bytes>::store_big
213 (static_cast<char*>(bytes) + n_bytes, value);
214 }
215
216 template <>
217 inline
218 void store_big_endian<float, 4>(void* bytes, float value)
219 {
220 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
221 b += 3;
222
223 const unsigned char *v = reinterpret_cast<const unsigned char *>(
224 &value);
225
226 for(std::size_t i = 0; i < 4; ++i)
227 {
228 *b-- = *v++;
229 }
230 }
231
232 template <>
233 inline
234 void store_big_endian<double, 8>(void* bytes, double value)
235 {
236 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
237 b += 7;
238
239 const unsigned char *v = reinterpret_cast<const unsigned char *>(
240 &value);
241
242 for(std::size_t i = 0; i < 8; ++i)
243 {
244 *b-- = *v++;
245 }
246 }
247
248 template <typename T, std::size_t n_bytes>
249 inline
250 void store_little_endian(void* bytes, T value)
251 {
252 unrolled_byte_loops<T, n_bytes>::store_little
253 (static_cast<char*>(bytes), value);
254 }
255
256 template <>
257 inline
258 void store_little_endian<float, 4>(void* bytes, float value)
259 {
260 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
261
262 const unsigned char *v = reinterpret_cast<const unsigned char *>(
263 &value);
264
265 for(std::size_t i = 0; i < 4; ++i)
266 {
267 *b++ = *v++;
268 }
269 }
270
271 template <>
272 inline
273 void store_little_endian<double, 8>(void* bytes, double value)
274 {
275 unsigned char *b = reinterpret_cast<unsigned char *>(bytes);
276
277 const unsigned char *v = reinterpret_cast<const unsigned char *>(
278 &value);
279
280 for(std::size_t i = 0; i < 8; ++i)
281 {
282 *b++ = *v++;
283 }
284 }
285
286 } // namespace detail
287
288 namespace endian
289 {
290
291 # ifdef BOOST_ENDIAN_LOG
292 bool endian_log(true);
293 # endif
294
295
296 // endian class template and specializations ---------------------------------------//
297
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
300
301 template <BOOST_SCOPED_ENUM(endianness) E, typename T, std::size_t n_bits,
302 BOOST_SCOPED_ENUM(alignment) A = alignment::unaligned>
303 class endian;
304
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.
309
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 >
314 {
315 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
316 public:
317 typedef T value_type;
318 # ifndef BOOST_ENDIAN_NO_CTORS
319 endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
320 explicit endian(T val)
321 {
322 # ifdef BOOST_ENDIAN_LOG
323 if ( endian_log )
324 std::clog << "big, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
325 # endif
326 detail::store_big_endian<T, n_bits/8>(m_value, val);
327 }
328 # endif
329 endian & operator=(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); return *this; }
330 operator T() const
331 {
332 # ifdef BOOST_ENDIAN_LOG
333 if ( endian_log )
334 std::clog << "big, unaligned, " << n_bits << "-bits, convert(" << detail::load_big_endian<T, n_bits/8>(m_value) << ")\n";
335 # endif
336 return detail::load_big_endian<T, n_bits/8>(m_value);
337 }
338 private:
339 char m_value[n_bits/8];
340 };
341
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 >
346 {
347 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
348 public:
349 typedef T value_type;
350 # ifndef BOOST_ENDIAN_NO_CTORS
351 endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
352 explicit endian(T val)
353 {
354 # ifdef BOOST_ENDIAN_LOG
355 if ( endian_log )
356 std::clog << "little, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
357 # endif
358 detail::store_little_endian<T, n_bits/8>(m_value, val);
359 }
360 # endif
361 endian & operator=(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); return *this; }
362 operator T() const
363 {
364 # ifdef BOOST_ENDIAN_LOG
365 if ( endian_log )
366 std::clog << "little, unaligned, " << n_bits << "-bits, convert(" << detail::load_little_endian<T, n_bits/8>(m_value) << ")\n";
367 # endif
368 return detail::load_little_endian<T, n_bits/8>(m_value);
369 }
370 private:
371 char m_value[n_bits/8];
372 };
373
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 >
378 {
379 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
380 public:
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); }
386 # else
387 explicit endian(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); }
388 # endif
389 # endif
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); }
393 # else
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); }
396 # endif
397 private:
398 char m_value[n_bits/8];
399 };
400
401 // Specializations that mimic built-in integer types.
402 // These typically have the same alignment as the underlying types.
403
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 >
408 {
409 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
410 BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 );
411 public:
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) { }
417 # else
418 explicit endian(T val) { detail::store_big_endian<T, sizeof(T)>(&m_value, val); }
419 # endif
420 # endif
421 # ifdef BOOST_BIG_ENDIAN
422 endian & operator=(T val) { m_value = val; return *this; }
423 operator T() const { return m_value; }
424 # else
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); }
427 # endif
428 private:
429 T m_value;
430 };
431
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 >
436 {
437 BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
438 BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 );
439 public:
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) { }
445 # else
446 explicit endian(T val) { detail::store_little_endian<T, sizeof(T)>(&m_value, val); }
447 # endif
448 # endif
449 # ifdef BOOST_LITTLE_ENDIAN
450 endian & operator=(T val) { m_value = val; return *this; }
451 operator T() const { return m_value; }
452 #else
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); }
455 #endif
456 private:
457 T m_value;
458 };
459
460 // naming convention typedefs ------------------------------------------------------//
461
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;
471
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;
481
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;
491
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;
501
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;
511
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;
521
522 #define BOOST_HAS_INT16_T
523 #define BOOST_HAS_INT32_T
524 #define BOOST_HAS_INT64_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 # 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;
540 # endif
541
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;
547 # endif
548
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;
554 # endif
555
556 } // namespace endian
557 }} // namespace boost::spirit
558
559 // import the namespace above into boost::endian
560 namespace boost { namespace endian
561 {
562 using namespace boost::spirit::endian;
563 }}
564
565 #if defined(__BORLANDC__) || defined( __CODEGEARC__)
566 # pragma pack(pop)
567 #endif
568
569 #endif // BOOST_SPIRIT_ENDIAN_HPP