1 #ifndef BOOST_ENDIAN_DETAIL_ENDIAN_STORE_HPP_INCLUDED
2 #define BOOST_ENDIAN_DETAIL_ENDIAN_STORE_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_integral.hpp>
14 #include <boost/type_traits/is_enum.hpp>
15 #include <boost/static_assert.hpp>
16 #include <cstddef>
17 #include <cstring>
18 
19 namespace boost
20 {
21 namespace endian
22 {
23 
24 namespace detail
25 {
26 
27 template<class T, std::size_t N1, BOOST_SCOPED_ENUM(order) O1, std::size_t N2, BOOST_SCOPED_ENUM(order) O2> struct endian_store_impl
28 {
29 };
30 
31 } // namespace detail
32 
33 // Requires:
34 //
35 //    sizeof(T) must be 1, 2, 4, or 8
36 //    1 <= N <= sizeof(T)
37 //    T is TriviallyCopyable
38 //    if N < sizeof(T), T is integral or enum
39 
40 template<class T, std::size_t N, BOOST_SCOPED_ENUM(order) Order>
endian_store(unsigned char * p,T const & v)41 inline void endian_store( unsigned char * p, T const & v ) BOOST_NOEXCEPT
42 {
43     BOOST_STATIC_ASSERT( sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8 );
44     BOOST_STATIC_ASSERT( N >= 1 && N <= sizeof(T) );
45 
46     return detail::endian_store_impl<T, sizeof(T), order::native, N, Order>()( p, v );
47 }
48 
49 namespace detail
50 {
51 
52 // same endianness, same size
53 
54 template<class T, std::size_t N, BOOST_SCOPED_ENUM(order) O> struct endian_store_impl<T, N, O, N, O>
55 {
operator ()boost::endian::detail::endian_store_impl56     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
57     {
58         BOOST_STATIC_ASSERT( is_trivially_copyable<T>::value );
59 
60         std::memcpy( p, &v, N );
61     }
62 };
63 
64 // same size, reverse endianness
65 
66 template<class T, std::size_t N, BOOST_SCOPED_ENUM(order) O1, BOOST_SCOPED_ENUM(order) O2> struct endian_store_impl<T, N, O1, N, O2>
67 {
operator ()boost::endian::detail::endian_store_impl68     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
69     {
70         BOOST_STATIC_ASSERT( is_trivially_copyable<T>::value );
71 
72         typename integral_by_size<N>::type tmp;
73         std::memcpy( &tmp, &v, N );
74 
75         endian_reverse_inplace( tmp );
76 
77         std::memcpy( p, &tmp, N );
78     }
79 };
80 
81 // truncating store 2 -> 1
82 
83 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 2, Order, 1, order::little>
84 {
operator ()boost::endian::detail::endian_store_impl85     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
86     {
87         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
88 
89         unsigned char tmp[ 2 ];
90         boost::endian::endian_store<T, 2, order::little>( tmp, v );
91 
92         p[0] = tmp[0];
93     }
94 };
95 
96 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 2, Order, 1, order::big>
97 {
operator ()boost::endian::detail::endian_store_impl98     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
99     {
100         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
101 
102         unsigned char tmp[ 2 ];
103         boost::endian::endian_store<T, 2, order::big>( tmp, v );
104 
105         p[0] = tmp[1];
106     }
107 };
108 
109 // truncating store 4 -> 1
110 
111 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 4, Order, 1, order::little>
112 {
operator ()boost::endian::detail::endian_store_impl113     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
114     {
115         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
116 
117         unsigned char tmp[ 4 ];
118         boost::endian::endian_store<T, 4, order::little>( tmp, v );
119 
120         p[0] = tmp[0];
121     }
122 };
123 
124 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 4, Order, 1, order::big>
125 {
operator ()boost::endian::detail::endian_store_impl126     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
127     {
128         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
129 
130         unsigned char tmp[ 4 ];
131         boost::endian::endian_store<T, 4, order::big>( tmp, v );
132 
133         p[0] = tmp[3];
134     }
135 };
136 
137 // truncating store 4 -> 2
138 
139 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 4, Order, 2, order::little>
140 {
operator ()boost::endian::detail::endian_store_impl141     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
142     {
143         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
144 
145         unsigned char tmp[ 4 ];
146         boost::endian::endian_store<T, 4, order::little>( tmp, v );
147 
148         p[0] = tmp[0];
149         p[1] = tmp[1];
150     }
151 };
152 
153 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 4, Order, 2, order::big>
154 {
operator ()boost::endian::detail::endian_store_impl155     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
156     {
157         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
158 
159         unsigned char tmp[ 4 ];
160         boost::endian::endian_store<T, 4, order::big>( tmp, v );
161 
162         p[0] = tmp[2];
163         p[1] = tmp[3];
164     }
165 };
166 
167 // truncating store 4 -> 3
168 
169 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 4, Order, 3, order::little>
170 {
operator ()boost::endian::detail::endian_store_impl171     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
172     {
173         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
174 
175         unsigned char tmp[ 4 ];
176         boost::endian::endian_store<T, 4, order::little>( tmp, v );
177 
178         p[0] = tmp[0];
179         p[1] = tmp[1];
180         p[2] = tmp[2];
181     }
182 };
183 
184 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 4, Order, 3, order::big>
185 {
operator ()boost::endian::detail::endian_store_impl186     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
187     {
188         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
189 
190         unsigned char tmp[ 4 ];
191         boost::endian::endian_store<T, 4, order::big>( tmp, v );
192 
193         p[0] = tmp[1];
194         p[1] = tmp[2];
195         p[2] = tmp[3];
196     }
197 };
198 
199 // truncating store 8 -> 1
200 
201 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 1, order::little>
202 {
operator ()boost::endian::detail::endian_store_impl203     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
204     {
205         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
206 
207         unsigned char tmp[ 8 ];
208         boost::endian::endian_store<T, 8, order::little>( tmp, v );
209 
210         p[0] = tmp[0];
211     }
212 };
213 
214 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 1, order::big>
215 {
operator ()boost::endian::detail::endian_store_impl216     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
217     {
218         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
219 
220         unsigned char tmp[ 8 ];
221         boost::endian::endian_store<T, 8, order::big>( tmp, v );
222 
223         p[0] = tmp[7];
224     }
225 };
226 
227 // truncating store 8 -> 2
228 
229 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 2, order::little>
230 {
operator ()boost::endian::detail::endian_store_impl231     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
232     {
233         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
234 
235         unsigned char tmp[ 8 ];
236         boost::endian::endian_store<T, 8, order::little>( tmp, v );
237 
238         p[0] = tmp[0];
239         p[1] = tmp[1];
240     }
241 };
242 
243 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 2, order::big>
244 {
operator ()boost::endian::detail::endian_store_impl245     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
246     {
247         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
248 
249         unsigned char tmp[ 8 ];
250         boost::endian::endian_store<T, 8, order::big>( tmp, v );
251 
252         p[0] = tmp[6];
253         p[1] = tmp[7];
254     }
255 };
256 
257 // truncating store 8 -> 3
258 
259 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 3, order::little>
260 {
operator ()boost::endian::detail::endian_store_impl261     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
262     {
263         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
264 
265         unsigned char tmp[ 8 ];
266         boost::endian::endian_store<T, 8, order::little>( tmp, v );
267 
268         p[0] = tmp[0];
269         p[1] = tmp[1];
270         p[2] = tmp[2];
271     }
272 };
273 
274 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 3, order::big>
275 {
operator ()boost::endian::detail::endian_store_impl276     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
277     {
278         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
279 
280         unsigned char tmp[ 8 ];
281         boost::endian::endian_store<T, 8, order::big>( tmp, v );
282 
283         p[0] = tmp[5];
284         p[1] = tmp[6];
285         p[2] = tmp[7];
286     }
287 };
288 
289 // truncating store 8 -> 4
290 
291 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 4, order::little>
292 {
operator ()boost::endian::detail::endian_store_impl293     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
294     {
295         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
296 
297         unsigned char tmp[ 8 ];
298         boost::endian::endian_store<T, 8, order::little>( tmp, v );
299 
300         p[0] = tmp[0];
301         p[1] = tmp[1];
302         p[2] = tmp[2];
303         p[3] = tmp[3];
304     }
305 };
306 
307 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 4, order::big>
308 {
operator ()boost::endian::detail::endian_store_impl309     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
310     {
311         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
312 
313         unsigned char tmp[ 8 ];
314         boost::endian::endian_store<T, 8, order::big>( tmp, v );
315 
316         p[0] = tmp[4];
317         p[1] = tmp[5];
318         p[2] = tmp[6];
319         p[3] = tmp[7];
320     }
321 };
322 
323 // truncating store 8 -> 5
324 
325 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 5, order::little>
326 {
operator ()boost::endian::detail::endian_store_impl327     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
328     {
329         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
330 
331         unsigned char tmp[ 8 ];
332         boost::endian::endian_store<T, 8, order::little>( tmp, v );
333 
334         p[0] = tmp[0];
335         p[1] = tmp[1];
336         p[2] = tmp[2];
337         p[3] = tmp[3];
338         p[4] = tmp[4];
339     }
340 };
341 
342 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 5, order::big>
343 {
operator ()boost::endian::detail::endian_store_impl344     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
345     {
346         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
347 
348         unsigned char tmp[ 8 ];
349         boost::endian::endian_store<T, 8, order::big>( tmp, v );
350 
351         p[0] = tmp[3];
352         p[1] = tmp[4];
353         p[2] = tmp[5];
354         p[3] = tmp[6];
355         p[4] = tmp[7];
356     }
357 };
358 
359 // truncating store 8 -> 6
360 
361 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 6, order::little>
362 {
operator ()boost::endian::detail::endian_store_impl363     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
364     {
365         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
366 
367         unsigned char tmp[ 8 ];
368         boost::endian::endian_store<T, 8, order::little>( tmp, v );
369 
370         p[0] = tmp[0];
371         p[1] = tmp[1];
372         p[2] = tmp[2];
373         p[3] = tmp[3];
374         p[4] = tmp[4];
375         p[5] = tmp[5];
376     }
377 };
378 
379 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 6, order::big>
380 {
operator ()boost::endian::detail::endian_store_impl381     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
382     {
383         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
384 
385         unsigned char tmp[ 8 ];
386         boost::endian::endian_store<T, 8, order::big>( tmp, v );
387 
388         p[0] = tmp[2];
389         p[1] = tmp[3];
390         p[2] = tmp[4];
391         p[3] = tmp[5];
392         p[4] = tmp[6];
393         p[5] = tmp[7];
394     }
395 };
396 
397 // truncating store 8 -> 7
398 
399 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 7, order::little>
400 {
operator ()boost::endian::detail::endian_store_impl401     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
402     {
403         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
404 
405         unsigned char tmp[ 8 ];
406         boost::endian::endian_store<T, 8, order::little>( tmp, v );
407 
408         p[0] = tmp[0];
409         p[1] = tmp[1];
410         p[2] = tmp[2];
411         p[3] = tmp[3];
412         p[4] = tmp[4];
413         p[5] = tmp[5];
414         p[6] = tmp[6];
415     }
416 };
417 
418 template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 7, order::big>
419 {
operator ()boost::endian::detail::endian_store_impl420     inline void operator()( unsigned char * p, T const & v ) const BOOST_NOEXCEPT
421     {
422         BOOST_STATIC_ASSERT( is_integral<T>::value || is_enum<T>::value );
423 
424         unsigned char tmp[ 8 ];
425         boost::endian::endian_store<T, 8, order::big>( tmp, v );
426 
427         p[0] = tmp[1];
428         p[1] = tmp[2];
429         p[2] = tmp[3];
430         p[3] = tmp[4];
431         p[4] = tmp[5];
432         p[5] = tmp[6];
433         p[6] = tmp[7];
434     }
435 };
436 
437 } // namespace detail
438 
439 } // namespace endian
440 } // namespace boost
441 
442 #endif  // BOOST_ENDIAN_DETAIL_ENDIAN_STORE_HPP_INCLUDED
443