MCKL
Monte Carlo Kernel Library
byte_order.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/internal/byte_order.hpp
3 //----------------------------------------------------------------------------
4 // MCKL: Monte Carlo Kernel Library
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2018, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef MCKL_INTERNAL_BYTE_ORDER_HPP
33 #define MCKL_INTERNAL_BYTE_ORDER_HPP
34 
35 #include <mckl/internal/config.h>
36 #include <mckl/math/constants.hpp>
37 #include <array>
38 #include <climits>
39 
40 namespace mckl {
41 
42 namespace internal {
43 
44 inline bool is_little_endian()
45 {
46  union {
47  char c[sizeof(int)];
48  int i;
49  } buf;
50 
51  buf.i = 0x01;
52 
53  return buf.c[0] == 0x01;
54 }
55 
56 inline bool is_big_endian()
57 {
58  union {
59  char c[sizeof(int)];
60  int i;
61  } buf;
62 
63  buf.i = 0x01 << (sizeof(int) * CHAR_BIT - CHAR_BIT);
64 
65  return buf.c[0] == 0x01;
66 }
67 
68 template <int, int, typename U>
69 inline U swap_bytes(U, std::false_type)
70 {
71  return 0;
72 }
73 
74 template <int Bytes, int N, typename U>
75 inline U swap_bytes(U u, std::true_type)
76 {
77  constexpr int bits = sizeof(U) * CHAR_BIT;
78  constexpr int p = Bytes * CHAR_BIT;
79  constexpr int q = p < bits ? p : 0;
80  constexpr int r = p * N;
81  constexpr int l = bits - r - p;
82  constexpr U mask = (~const_zero<U>()) >> (bits - p);
83 
84  return ((u & mask) << l) |
85  swap_bytes<Bytes, N + 1>(
86  u >> q, std::integral_constant<bool, (r + p < bits)>());
87 }
88 
89 template <int Bytes, typename T>
90 inline T swap_bytes(T x)
91 {
92  static_assert(sizeof(T) % Bytes == 0,
93  "**swap_bytes** sizeof(T) is not divisible by Bytes");
94 
95  using U = std::make_unsigned_t<T>;
96 
97  return static_cast<T>(swap_bytes<Bytes, 0>(static_cast<U>(x),
98  std::integral_constant<bool, Bytes <= sizeof(U)>()));
99 }
100 
101 #if MCKL_HAS_LITTLE_ENDIAN
102 
103 // Let in the following union
104 // union {
105 // U v[sizeof(T) * sizeof(K) / sizeof(U);
106 // T r[K]
107 // } buf;
108 // buf.v is given the exact value
109 // transform buf.r such that its value will be as if we are using little endian
110 template <typename, typename T>
111 inline void union_le(std::size_t, T *)
112 {
113 }
114 
115 template <typename, typename T>
116 inline void union_le(T &)
117 {
118 }
119 
120 #else // MCKL_HAS_LITTLE_ENDIAN
121 
122 template <typename, typename T>
123 inline void union_le(std::size_t, T *, std::false_type, std::false_type)
124 {
125 }
126 
127 template <typename U, typename T>
128 inline void union_le(std::size_t n, T *r, std::false_type, std::true_type)
129 {
130  const std::size_t m = sizeof(U) / sizeof(T);
131  const std::size_t l = n / m;
132 
133  for (std::size_t i = 0; i != l; ++i, r += m)
134  std::reverse(r, r + m);
135 }
136 
137 template <typename U, typename T>
138 inline void union_le(std::size_t n, T *r, std::true_type, std::false_type)
139 {
140  for (std::size_t i = 0; i != n; ++i)
141  r[i] = swap_bytes<sizeof(U)>(r[i]);
142 }
143 
144 template <typename U, typename T>
145 inline void union_le(std::size_t n, T *r)
146 {
147  static_assert(sizeof(U) % sizeof(T) == 0 || sizeof(T) % sizeof(U) == 0,
148  "**union_le** used with sizeof(U) and sizeof(T) with neither of them "
149  "a multiple of the other");
150 
151 #if MCKL_HAS_BIG_ENDIAN
152  union_le<U>(n, r, std::integral_constant<bool, (sizeof(U) < sizeof(T))>(),
153  std::integral_constant<bool, (sizeof(U) > sizeof(T))>());
154 #else
155  if (is_little_endian())
156  return;
157  union_le<U>(n, r, std::integral_constant<bool, (sizeof(U) < sizeof(T))>(),
158  std::integral_constant<bool, (sizeof(U) > sizeof(T))>());
159 #endif
160 }
161 
162 template <typename U, typename T>
163 class UnionLE
164 {
165  public:
166  static void eval(T &r) { union_le<U>(1, &r); }
167 }; // class UnionLE
168 
169 template <typename U, typename T, std::size_t K>
170 class UnionLE<U, std::array<T, K>>
171 {
172  public:
173  static void eval(std::array<T, K> &r) { union_le<U>(K, r.data()); }
174 }; // class UnionLE
175 
176 template <typename U, typename T>
177 inline void union_le(T &r)
178 {
179  UnionLE<U, T>::eval(r);
180 }
181 
182 #endif // MCKL_HAS_LITTLE_ENDIAN
183 
184 } // namespace internal
185 
186 } // namespace mckl
187 
188 #endif // MCKL_INTERNAL_BYTE_ORDER_HPP
void union_le(std::size_t, T *)
Definition: byte_order.hpp:111
bool is_little_endian()
Definition: byte_order.hpp:44
Definition: mcmc.hpp:40
U swap_bytes(U, std::false_type)
Definition: byte_order.hpp:69
bool is_big_endian()
Definition: byte_order.hpp:56