1 #ifndef BOOST_ENDIAN_DETAIL_ENDIAN_LOAD_HPP_INCLUDED
2 #define BOOST_ENDIAN_DETAIL_ENDIAN_LOAD_HPP_INCLUDED
3
4 // Copyright 2019 Peter Dimov
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // http://www.boost.org/LICENSE_1_0.txt
8
9 #include <boost/endian/detail/endian_reverse.hpp>
10 #include <boost/endian/detail/order.hpp>
11 #include <boost/endian/detail/integral_by_size.hpp>
12 #include <boost/endian/detail/is_trivially_copyable.hpp>
13 #include <boost/type_traits/is_signed.hpp>
14 #include <boost/type_traits/is_integral.hpp>
15 #include <boost/type_traits/is_enum.hpp>
16 #include <boost/static_assert.hpp>
17 #include <cstddef>
18 #include <cstring>
19
20 namespace boost
21 {
22 namespace endian
23 {
24
25 namespace detail
26 {
27
28 template<class T, std::size_t N1, BOOST_SCOPED_ENUM(order) O1, std::size_t N2, BOOST_SCOPED_ENUM(order) O2> struct endian_load_impl
29 {
30 };
31
32 } // namespace detail
33
34 // Requires:
35 //
36 // sizeof(T) must be 1, 2, 4, or 8
37 // 1 <= N <= sizeof(T)
38 // T is TriviallyCopyable
39 // if N < sizeof(T), T is integral or enum
40
41 template<class T, std::size_t N, BOOST_SCOPED_ENUM(order) Order>
endian_load(unsigned char const * p)42 inline T endian_load( unsigned char const * p ) BOOST_NOEXCEPT
43 {
44 BOOST_STATIC_ASSERT( sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8 );
45 BOOST_STATIC_ASSERT( N >= 1 && N <= sizeof(T) );
46
47 return detail::endian_load_impl<T, sizeof(T), order::native, N, Order>()( p );
48 }
49
50 namespace detail
51 {
52
53 // same endianness, same size
54
55 template<class T, std::size_t N, BOOST_SCOPED_ENUM(order) O> struct endian_load_impl<T, N, O, N, O>
56 {
operator ()boost::endian::detail::endian_load_impl57 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
58 {
59 BOOST_STATIC_ASSERT( is_trivially_copyable<T>::value );
60
61 T t;
62 std::memcpy( &t, p, N );
63 return t;
64 }
65 };
66
67 // same size, reverse endianness
68
69 template<class T, std::size_t N, BOOST_SCOPED_ENUM(order) O1, BOOST_SCOPED_ENUM(order) O2> struct endian_load_impl<T, N, O1, N, O2>
70 {
operator ()boost::endian::detail::endian_load_impl71 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
72 {
73 BOOST_STATIC_ASSERT( is_trivially_copyable<T>::value );
74
75 typename integral_by_size<N>::type tmp;
76 std::memcpy( &tmp, p, N );
77
78 endian_reverse_inplace( tmp );
79
80 T t;
81 std::memcpy( &t, &tmp, N );
82 return t;
83 }
84 };
85
86 // expanding load 1 -> 2
87
88 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 2, Order, 1, order::little>
89 {
operator ()boost::endian::detail::endian_load_impl90 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
91 {
92 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
93
94 unsigned char tmp[ 2 ];
95
96 tmp[0] = p[0];
97 tmp[1] = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
98
99 return boost::endian::endian_load<T, 2, order::little>( tmp );
100 }
101 };
102
103 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 2, Order, 1, order::big>
104 {
operator ()boost::endian::detail::endian_load_impl105 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
106 {
107 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
108
109 unsigned char tmp[ 2 ];
110
111 tmp[0] = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
112 tmp[1] = p[0];
113
114 return boost::endian::endian_load<T, 2, order::big>( tmp );
115 }
116 };
117
118 // expanding load 1 -> 4
119
120 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 4, Order, 1, order::little>
121 {
operator ()boost::endian::detail::endian_load_impl122 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
123 {
124 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
125
126 unsigned char tmp[ 4 ];
127
128 unsigned char fill = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
129
130 tmp[0] = p[0];
131 tmp[1] = fill;
132 tmp[2] = fill;
133 tmp[3] = fill;
134
135 return boost::endian::endian_load<T, 4, order::little>( tmp );
136 }
137 };
138
139 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 4, Order, 1, order::big>
140 {
operator ()boost::endian::detail::endian_load_impl141 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
142 {
143 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
144
145 unsigned char tmp[ 4 ];
146
147 unsigned char fill = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
148
149 tmp[0] = fill;
150 tmp[1] = fill;
151 tmp[2] = fill;
152 tmp[3] = p[0];
153
154 return boost::endian::endian_load<T, 4, order::big>( tmp );
155 }
156 };
157
158 // expanding load 2 -> 4
159
160 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 4, Order, 2, order::little>
161 {
operator ()boost::endian::detail::endian_load_impl162 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
163 {
164 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
165
166 unsigned char tmp[ 4 ];
167
168 unsigned char fill = boost::is_signed<T>::value && ( p[1] & 0x80 )? 0xFF: 0x00;
169
170 tmp[0] = p[0];
171 tmp[1] = p[1];
172 tmp[2] = fill;
173 tmp[3] = fill;
174
175 return boost::endian::endian_load<T, 4, order::little>( tmp );
176 }
177 };
178
179 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 4, Order, 2, order::big>
180 {
operator ()boost::endian::detail::endian_load_impl181 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
182 {
183 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
184
185 unsigned char tmp[ 4 ];
186
187 unsigned char fill = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
188
189 tmp[0] = fill;
190 tmp[1] = fill;
191 tmp[2] = p[0];
192 tmp[3] = p[1];
193
194 return boost::endian::endian_load<T, 4, order::big>( tmp );
195 }
196 };
197
198 // expanding load 3 -> 4
199
200 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 4, Order, 3, order::little>
201 {
operator ()boost::endian::detail::endian_load_impl202 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
203 {
204 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
205
206 unsigned char tmp[ 4 ];
207
208 tmp[0] = p[0];
209 tmp[1] = p[1];
210 tmp[2] = p[2];
211 tmp[3] = boost::is_signed<T>::value && ( p[2] & 0x80 )? 0xFF: 0x00;
212
213 return boost::endian::endian_load<T, 4, order::little>( tmp );
214 }
215 };
216
217 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 4, Order, 3, order::big>
218 {
operator ()boost::endian::detail::endian_load_impl219 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
220 {
221 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
222
223 unsigned char tmp[ 4 ];
224
225 tmp[0] = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
226 tmp[1] = p[0];
227 tmp[2] = p[1];
228 tmp[3] = p[2];
229
230 return boost::endian::endian_load<T, 4, order::big>( tmp );
231 }
232 };
233
234 // expanding load 1 -> 8
235
236 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 1, order::little>
237 {
operator ()boost::endian::detail::endian_load_impl238 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
239 {
240 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
241
242 unsigned char tmp[ 8 ];
243
244 unsigned char fill = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
245
246 tmp[0] = p[0];
247
248 tmp[1] = fill;
249 tmp[2] = fill;
250 tmp[3] = fill;
251 tmp[4] = fill;
252 tmp[5] = fill;
253 tmp[6] = fill;
254 tmp[7] = fill;
255
256 return boost::endian::endian_load<T, 8, order::little>( tmp );
257 }
258 };
259
260 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 1, order::big>
261 {
operator ()boost::endian::detail::endian_load_impl262 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
263 {
264 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
265
266 unsigned char tmp[ 8 ];
267
268 unsigned char fill = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
269
270 tmp[0] = fill;
271 tmp[1] = fill;
272 tmp[2] = fill;
273 tmp[3] = fill;
274 tmp[4] = fill;
275 tmp[5] = fill;
276 tmp[6] = fill;
277
278 tmp[7] = p[0];
279
280 return boost::endian::endian_load<T, 8, order::big>( tmp );
281 }
282 };
283
284 // expanding load 2 -> 8
285
286 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 2, order::little>
287 {
operator ()boost::endian::detail::endian_load_impl288 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
289 {
290 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
291
292 unsigned char tmp[ 8 ];
293
294 unsigned char fill = boost::is_signed<T>::value && ( p[1] & 0x80 )? 0xFF: 0x00;
295
296 tmp[0] = p[0];
297 tmp[1] = p[1];
298
299 tmp[2] = fill;
300 tmp[3] = fill;
301 tmp[4] = fill;
302 tmp[5] = fill;
303 tmp[6] = fill;
304 tmp[7] = fill;
305
306 return boost::endian::endian_load<T, 8, order::little>( tmp );
307 }
308 };
309
310 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 2, order::big>
311 {
operator ()boost::endian::detail::endian_load_impl312 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
313 {
314 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
315
316 unsigned char tmp[ 8 ];
317
318 unsigned char fill = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
319
320 tmp[0] = fill;
321 tmp[1] = fill;
322 tmp[2] = fill;
323 tmp[3] = fill;
324 tmp[4] = fill;
325 tmp[5] = fill;
326
327 tmp[6] = p[0];
328 tmp[7] = p[1];
329
330 return boost::endian::endian_load<T, 8, order::big>( tmp );
331 }
332 };
333
334 // expanding load 3 -> 8
335
336 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 3, order::little>
337 {
operator ()boost::endian::detail::endian_load_impl338 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
339 {
340 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
341
342 unsigned char tmp[ 8 ];
343
344 unsigned char fill = boost::is_signed<T>::value && ( p[2] & 0x80 )? 0xFF: 0x00;
345
346 tmp[0] = p[0];
347 tmp[1] = p[1];
348 tmp[2] = p[2];
349
350 tmp[3] = fill;
351 tmp[4] = fill;
352 tmp[5] = fill;
353 tmp[6] = fill;
354 tmp[7] = fill;
355
356 return boost::endian::endian_load<T, 8, order::little>( tmp );
357 }
358 };
359
360 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 3, order::big>
361 {
operator ()boost::endian::detail::endian_load_impl362 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
363 {
364 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
365
366 unsigned char tmp[ 8 ];
367
368 unsigned char fill = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
369
370 tmp[0] = fill;
371 tmp[1] = fill;
372 tmp[2] = fill;
373 tmp[3] = fill;
374 tmp[4] = fill;
375
376 tmp[5] = p[0];
377 tmp[6] = p[1];
378 tmp[7] = p[2];
379
380 return boost::endian::endian_load<T, 8, order::big>( tmp );
381 }
382 };
383
384 // expanding load 4 -> 8
385
386 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 4, order::little>
387 {
operator ()boost::endian::detail::endian_load_impl388 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
389 {
390 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
391
392 unsigned char tmp[ 8 ];
393
394 unsigned char fill = boost::is_signed<T>::value && ( p[3] & 0x80 )? 0xFF: 0x00;
395
396 tmp[0] = p[0];
397 tmp[1] = p[1];
398 tmp[2] = p[2];
399 tmp[3] = p[3];
400
401 tmp[4] = fill;
402 tmp[5] = fill;
403 tmp[6] = fill;
404 tmp[7] = fill;
405
406 return boost::endian::endian_load<T, 8, order::little>( tmp );
407 }
408 };
409
410 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 4, order::big>
411 {
operator ()boost::endian::detail::endian_load_impl412 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
413 {
414 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
415
416 unsigned char tmp[ 8 ];
417
418 unsigned char fill = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
419
420 tmp[0] = fill;
421 tmp[1] = fill;
422 tmp[2] = fill;
423 tmp[3] = fill;
424
425 tmp[4] = p[0];
426 tmp[5] = p[1];
427 tmp[6] = p[2];
428 tmp[7] = p[3];
429
430 return boost::endian::endian_load<T, 8, order::big>( tmp );
431 }
432 };
433
434 // expanding load 5 -> 8
435
436 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 5, order::little>
437 {
operator ()boost::endian::detail::endian_load_impl438 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
439 {
440 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
441
442 unsigned char tmp[ 8 ];
443
444 unsigned char fill = boost::is_signed<T>::value && ( p[4] & 0x80 )? 0xFF: 0x00;
445
446 tmp[0] = p[0];
447 tmp[1] = p[1];
448 tmp[2] = p[2];
449 tmp[3] = p[3];
450 tmp[4] = p[4];
451
452 tmp[5] = fill;
453 tmp[6] = fill;
454 tmp[7] = fill;
455
456 return boost::endian::endian_load<T, 8, order::little>( tmp );
457 }
458 };
459
460 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 5, order::big>
461 {
operator ()boost::endian::detail::endian_load_impl462 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
463 {
464 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
465
466 unsigned char tmp[ 8 ];
467
468 unsigned char fill = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
469
470 tmp[0] = fill;
471 tmp[1] = fill;
472 tmp[2] = fill;
473
474 tmp[3] = p[0];
475 tmp[4] = p[1];
476 tmp[5] = p[2];
477 tmp[6] = p[3];
478 tmp[7] = p[4];
479
480 return boost::endian::endian_load<T, 8, order::big>( tmp );
481 }
482 };
483
484 // expanding load 6 -> 8
485
486 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 6, order::little>
487 {
operator ()boost::endian::detail::endian_load_impl488 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
489 {
490 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
491
492 unsigned char tmp[ 8 ];
493
494 unsigned char fill = boost::is_signed<T>::value && ( p[5] & 0x80 )? 0xFF: 0x00;
495
496 tmp[0] = p[0];
497 tmp[1] = p[1];
498 tmp[2] = p[2];
499 tmp[3] = p[3];
500 tmp[4] = p[4];
501 tmp[5] = p[5];
502
503 tmp[6] = fill;
504 tmp[7] = fill;
505
506 return boost::endian::endian_load<T, 8, order::little>( tmp );
507 }
508 };
509
510 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 6, order::big>
511 {
operator ()boost::endian::detail::endian_load_impl512 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
513 {
514 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
515
516 unsigned char tmp[ 8 ];
517
518 unsigned char fill = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
519
520 tmp[0] = fill;
521 tmp[1] = fill;
522
523 tmp[2] = p[0];
524 tmp[3] = p[1];
525 tmp[4] = p[2];
526 tmp[5] = p[3];
527 tmp[6] = p[4];
528 tmp[7] = p[5];
529
530 return boost::endian::endian_load<T, 8, order::big>( tmp );
531 }
532 };
533
534 // expanding load 7 -> 8
535
536 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 7, order::little>
537 {
operator ()boost::endian::detail::endian_load_impl538 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
539 {
540 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
541
542 unsigned char tmp[ 8 ];
543
544 unsigned char fill = boost::is_signed<T>::value && ( p[6] & 0x80 )? 0xFF: 0x00;
545
546 tmp[0] = p[0];
547 tmp[1] = p[1];
548 tmp[2] = p[2];
549 tmp[3] = p[3];
550 tmp[4] = p[4];
551 tmp[5] = p[5];
552 tmp[6] = p[6];
553
554 tmp[7] = fill;
555
556 return boost::endian::endian_load<T, 8, order::little>( tmp );
557 }
558 };
559
560 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_load_impl<T, 8, Order, 7, order::big>
561 {
operator ()boost::endian::detail::endian_load_impl562 inline T operator()( unsigned char const * p ) const BOOST_NOEXCEPT
563 {
564 BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
565
566 unsigned char tmp[ 8 ];
567
568 unsigned char fill = boost::is_signed<T>::value && ( p[0] & 0x80 )? 0xFF: 0x00;
569
570 tmp[0] = fill;
571
572 tmp[1] = p[0];
573 tmp[2] = p[1];
574 tmp[3] = p[2];
575 tmp[4] = p[3];
576 tmp[5] = p[4];
577 tmp[6] = p[5];
578 tmp[7] = p[6];
579
580 return boost::endian::endian_load<T, 8, order::big>( tmp );
581 }
582 };
583
584 } // namespace detail
585
586 } // namespace endian
587 } // namespace boost
588
589 #endif // BOOST_ENDIAN_DETAIL_ENDIAN_LOAD_HPP_INCLUDED
590