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