Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "mozilla/Assertions.h"
6 #include "mozilla/Endian.h"
8 #include <stddef.h>
10 using mozilla::BigEndian;
11 using mozilla::LittleEndian;
12 using mozilla::NativeEndian;
14 template<typename T>
15 void
16 TestSingleSwap(T value, T swappedValue)
17 {
18 #if MOZ_LITTLE_ENDIAN
19 MOZ_RELEASE_ASSERT(NativeEndian::swapToBigEndian(value) == swappedValue);
20 MOZ_RELEASE_ASSERT(NativeEndian::swapFromBigEndian(value) == swappedValue);
21 MOZ_RELEASE_ASSERT(NativeEndian::swapToNetworkOrder(value) == swappedValue);
22 MOZ_RELEASE_ASSERT(NativeEndian::swapFromNetworkOrder(value) == swappedValue);
23 #else
24 MOZ_RELEASE_ASSERT(NativeEndian::swapToLittleEndian(value) == swappedValue);
25 MOZ_RELEASE_ASSERT(NativeEndian::swapFromLittleEndian(value) == swappedValue);
26 #endif
27 }
29 template<typename T>
30 void
31 TestSingleNoSwap(T value, T notSwappedValue)
32 {
33 #if MOZ_LITTLE_ENDIAN
34 MOZ_RELEASE_ASSERT(NativeEndian::swapToLittleEndian(value) == notSwappedValue);
35 MOZ_RELEASE_ASSERT(NativeEndian::swapFromLittleEndian(value) == notSwappedValue);
36 #else
37 MOZ_RELEASE_ASSERT(NativeEndian::swapToBigEndian(value) == notSwappedValue);
38 MOZ_RELEASE_ASSERT(NativeEndian::swapFromBigEndian(value) == notSwappedValue);
39 MOZ_RELEASE_ASSERT(NativeEndian::swapToNetworkOrder(value) == notSwappedValue);
40 MOZ_RELEASE_ASSERT(NativeEndian::swapFromNetworkOrder(value) == notSwappedValue);
41 #endif
42 }
44 // Endian.h functions are declared as protected in an base class and
45 // then re-exported as public in public derived classes. The
46 // standardese around explicit instantiation of templates is not clear
47 // in such cases. Provide these wrappers to make things more explicit.
48 // For your own enlightenment, you may wish to peruse:
49 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56152 and subsequently
50 // http://j.mp/XosS6S .
51 #define WRAP_COPYTO(NAME) \
52 template<typename T> \
53 void \
54 NAME(void* dst, const T* src, size_t count) \
55 { \
56 NativeEndian::NAME<T>(dst, src, count); \
57 }
59 WRAP_COPYTO(copyAndSwapToLittleEndian)
60 WRAP_COPYTO(copyAndSwapToBigEndian)
61 WRAP_COPYTO(copyAndSwapToNetworkOrder)
63 #define WRAP_COPYFROM(NAME) \
64 template<typename T> \
65 void \
66 NAME(T* dst, const void* src, size_t count) \
67 { \
68 NativeEndian::NAME<T>(dst, src, count); \
69 }
71 WRAP_COPYFROM(copyAndSwapFromLittleEndian)
72 WRAP_COPYFROM(copyAndSwapFromBigEndian)
73 WRAP_COPYFROM(copyAndSwapFromNetworkOrder)
75 #define WRAP_IN_PLACE(NAME) \
76 template<typename T> \
77 void \
78 NAME(T* p, size_t count) \
79 { \
80 NativeEndian::NAME<T>(p, count); \
81 }
82 WRAP_IN_PLACE(swapToLittleEndianInPlace)
83 WRAP_IN_PLACE(swapFromLittleEndianInPlace)
84 WRAP_IN_PLACE(swapToBigEndianInPlace)
85 WRAP_IN_PLACE(swapFromBigEndianInPlace)
86 WRAP_IN_PLACE(swapToNetworkOrderInPlace)
87 WRAP_IN_PLACE(swapFromNetworkOrderInPlace)
89 enum SwapExpectation {
90 Swap,
91 NoSwap
92 };
94 template<typename T, size_t Count>
95 void
96 TestBulkSwapToSub(enum SwapExpectation expectSwap,
97 const T (&values)[Count],
98 void (*swapperFunc)(void*, const T*, size_t),
99 T (*readerFunc)(const void*))
100 {
101 const size_t arraySize = 2 * Count;
102 const size_t bufferSize = arraySize * sizeof(T);
103 static uint8_t buffer[bufferSize];
104 const uint8_t fillValue = 0xa5;
105 static uint8_t checkBuffer[bufferSize];
107 MOZ_RELEASE_ASSERT(bufferSize > 2 * sizeof(T));
109 memset(checkBuffer, fillValue, bufferSize);
111 for (size_t startPosition = 0; startPosition < sizeof(T); ++startPosition) {
112 for (size_t nValues = 0; nValues < Count; ++nValues) {
113 memset(buffer, fillValue, bufferSize);
114 swapperFunc(buffer + startPosition, values, nValues);
116 MOZ_RELEASE_ASSERT(memcmp(buffer, checkBuffer, startPosition) == 0);
117 size_t valuesEndPosition = startPosition + sizeof(T) * nValues;
118 MOZ_RELEASE_ASSERT(memcmp(buffer + valuesEndPosition,
119 checkBuffer + valuesEndPosition,
120 bufferSize - valuesEndPosition) == 0);
121 if (expectSwap == NoSwap) {
122 MOZ_RELEASE_ASSERT(memcmp(buffer + startPosition, values,
123 nValues * sizeof(T)) == 0);
124 }
125 for (size_t i = 0; i < nValues; ++i) {
126 MOZ_RELEASE_ASSERT(readerFunc(buffer + startPosition + sizeof(T) * i) ==
127 values[i]);
128 }
129 }
130 }
131 }
133 template<typename T, size_t Count>
134 void
135 TestBulkSwapFromSub(enum SwapExpectation expectSwap,
136 const T (&values)[Count],
137 void (*swapperFunc)(T*, const void*, size_t),
138 T (*readerFunc)(const void*))
139 {
140 const size_t arraySize = 2 * Count;
141 const size_t bufferSize = arraySize * sizeof(T);
142 static T buffer[arraySize];
143 const uint8_t fillValue = 0xa5;
144 static T checkBuffer[arraySize];
146 memset(checkBuffer, fillValue, bufferSize);
148 for (size_t startPosition = 0; startPosition < Count; ++startPosition) {
149 for (size_t nValues = 0; nValues < (Count - startPosition); ++nValues) {
150 memset(buffer, fillValue, bufferSize);
151 swapperFunc(buffer + startPosition, values, nValues);
153 MOZ_RELEASE_ASSERT(memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0);
154 size_t valuesEndPosition = startPosition + nValues;
155 MOZ_RELEASE_ASSERT(memcmp(buffer + valuesEndPosition,
156 checkBuffer + valuesEndPosition,
157 (arraySize - valuesEndPosition) * sizeof(T)) == 0);
158 if (expectSwap == NoSwap) {
159 MOZ_RELEASE_ASSERT(memcmp(buffer + startPosition, values,
160 nValues * sizeof(T)) == 0);
161 }
162 for (size_t i = 0; i < nValues; ++i)
163 MOZ_RELEASE_ASSERT(readerFunc(buffer + startPosition + i) == values[i]);
164 }
165 }
166 }
169 template<typename T, size_t Count>
170 void
171 TestBulkInPlaceSub(enum SwapExpectation expectSwap,
172 const T (&values)[Count],
173 void (*swapperFunc)(T* p, size_t),
174 T (*readerFunc)(const void*))
175 {
176 const size_t bufferCount = 4 * Count;
177 const size_t bufferSize = bufferCount * sizeof(T);
178 static T buffer[bufferCount];
179 const T fillValue = 0xa5;
180 static T checkBuffer[bufferCount];
182 MOZ_RELEASE_ASSERT(bufferSize > 2 * sizeof(T));
184 memset(checkBuffer, fillValue, bufferSize);
186 for (size_t startPosition = 0; startPosition < Count; ++startPosition) {
187 for (size_t nValues = 0; nValues < Count; ++nValues) {
188 memset(buffer, fillValue, bufferSize);
189 memcpy(buffer + startPosition, values, nValues * sizeof(T));
190 swapperFunc(buffer + startPosition, nValues);
192 MOZ_RELEASE_ASSERT(memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0);
193 size_t valuesEndPosition = startPosition + nValues;
194 MOZ_RELEASE_ASSERT(memcmp(buffer + valuesEndPosition,
195 checkBuffer + valuesEndPosition,
196 bufferSize - valuesEndPosition * sizeof(T)) == 0);
197 if (expectSwap == NoSwap) {
198 MOZ_RELEASE_ASSERT(memcmp(buffer + startPosition, values,
199 nValues * sizeof(T)) == 0);
200 }
201 for (size_t i = 0; i < nValues; ++i)
202 MOZ_RELEASE_ASSERT(readerFunc(buffer + startPosition + i) == values[i]);
203 }
204 }
205 }
207 template<typename T>
208 struct Reader
209 {
210 };
212 #define SPECIALIZE_READER(TYPE, READ_FUNC) \
213 template<> \
214 struct Reader<TYPE> \
215 { \
216 static TYPE readLE(const void* p) { return LittleEndian::READ_FUNC(p); } \
217 static TYPE readBE(const void* p) { return BigEndian::READ_FUNC(p); } \
218 };
220 SPECIALIZE_READER(uint16_t, readUint16)
221 SPECIALIZE_READER(uint32_t, readUint32)
222 SPECIALIZE_READER(uint64_t, readUint64)
223 SPECIALIZE_READER(int16_t, readInt16)
224 SPECIALIZE_READER(int32_t, readInt32)
225 SPECIALIZE_READER(int64_t, readInt64)
227 template<typename T, size_t Count>
228 void
229 TestBulkSwap(const T (&bytes)[Count])
230 {
231 #if MOZ_LITTLE_ENDIAN
232 TestBulkSwapToSub(Swap, bytes, copyAndSwapToBigEndian<T>, Reader<T>::readBE);
233 TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromBigEndian<T>, Reader<T>::readBE);
234 TestBulkSwapToSub(Swap, bytes, copyAndSwapToNetworkOrder<T>, Reader<T>::readBE);
235 TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromNetworkOrder<T>, Reader<T>::readBE);
236 #else
237 TestBulkSwapToSub(Swap, bytes, copyAndSwapToLittleEndian<T>, Reader<T>::readLE);
238 TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromLittleEndian<T>, Reader<T>::readLE);
239 #endif
240 }
242 template<typename T, size_t Count>
243 void
244 TestBulkNoSwap(const T (&bytes)[Count])
245 {
246 #if MOZ_LITTLE_ENDIAN
247 TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToLittleEndian<T>, Reader<T>::readLE);
248 TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromLittleEndian<T>, Reader<T>::readLE);
249 #else
250 TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToBigEndian<T>, Reader<T>::readBE);
251 TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromBigEndian<T>, Reader<T>::readBE);
252 TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToNetworkOrder<T>, Reader<T>::readBE);
253 TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromNetworkOrder<T>, Reader<T>::readBE);
254 #endif
255 }
257 template<typename T, size_t Count>
258 void
259 TestBulkInPlaceSwap(const T (&bytes)[Count])
260 {
261 #if MOZ_LITTLE_ENDIAN
262 TestBulkInPlaceSub(Swap, bytes, swapToBigEndianInPlace<T>, Reader<T>::readBE);
263 TestBulkInPlaceSub(Swap, bytes, swapFromBigEndianInPlace<T>, Reader<T>::readBE);
264 TestBulkInPlaceSub(Swap, bytes, swapToNetworkOrderInPlace<T>, Reader<T>::readBE);
265 TestBulkInPlaceSub(Swap, bytes, swapFromNetworkOrderInPlace<T>, Reader<T>::readBE);
266 #else
267 TestBulkInPlaceSub(Swap, bytes, swapToLittleEndianInPlace<T>, Reader<T>::readLE);
268 TestBulkInPlaceSub(Swap, bytes, swapFromLittleEndianInPlace<T>, Reader<T>::readLE);
269 #endif
270 }
272 template<typename T, size_t Count>
273 void
274 TestBulkInPlaceNoSwap(const T (&bytes)[Count])
275 {
276 #if MOZ_LITTLE_ENDIAN
277 TestBulkInPlaceSub(NoSwap, bytes, swapToLittleEndianInPlace<T>, Reader<T>::readLE);
278 TestBulkInPlaceSub(NoSwap, bytes, swapFromLittleEndianInPlace<T>, Reader<T>::readLE);
279 #else
280 TestBulkInPlaceSub(NoSwap, bytes, swapToBigEndianInPlace<T>, Reader<T>::readBE);
281 TestBulkInPlaceSub(NoSwap, bytes, swapFromBigEndianInPlace<T>, Reader<T>::readBE);
282 TestBulkInPlaceSub(NoSwap, bytes, swapToNetworkOrderInPlace<T>, Reader<T>::readBE);
283 TestBulkInPlaceSub(NoSwap, bytes, swapFromNetworkOrderInPlace<T>, Reader<T>::readBE);
284 #endif
285 }
287 int
288 main()
289 {
290 static const uint8_t unsigned_bytes[16] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
291 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 };
292 static const int8_t signed_bytes[16] = { -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08,
293 -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08 };
294 static const uint16_t uint16_values[8] = { 0x102, 0x304, 0x506, 0x708, 0x102, 0x304, 0x506, 0x708 };
295 static const int16_t int16_values[8] = { int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8),
296 int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8) };
297 static const uint32_t uint32_values[4] = { 0x1020304, 0x5060708, 0x1020304, 0x5060708 };
298 static const int32_t int32_values[4] = { int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8),
299 int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8) };
300 static const uint64_t uint64_values[2] = { 0x102030405060708, 0x102030405060708 };
301 static const int64_t int64_values[2] = { int64_t(0xf1f2f3f4f5f6f7f8),
302 int64_t(0xf1f2f3f4f5f6f7f8) };
303 uint8_t buffer[8];
305 MOZ_RELEASE_ASSERT(LittleEndian::readUint16(&unsigned_bytes[0]) == 0x201);
306 MOZ_RELEASE_ASSERT(BigEndian::readUint16(&unsigned_bytes[0]) == 0x102);
308 MOZ_RELEASE_ASSERT(LittleEndian::readUint32(&unsigned_bytes[0]) == 0x4030201U);
309 MOZ_RELEASE_ASSERT(BigEndian::readUint32(&unsigned_bytes[0]) == 0x1020304U);
311 MOZ_RELEASE_ASSERT(LittleEndian::readUint64(&unsigned_bytes[0]) == 0x807060504030201ULL);
312 MOZ_RELEASE_ASSERT(BigEndian::readUint64(&unsigned_bytes[0]) == 0x102030405060708ULL);
314 LittleEndian::writeUint16(&buffer[0], 0x201);
315 MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0);
316 BigEndian::writeUint16(&buffer[0], 0x102);
317 MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0);
319 LittleEndian::writeUint32(&buffer[0], 0x4030201U);
320 MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0);
321 BigEndian::writeUint32(&buffer[0], 0x1020304U);
322 MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0);
324 LittleEndian::writeUint64(&buffer[0], 0x807060504030201ULL);
325 MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0);
326 BigEndian::writeUint64(&buffer[0], 0x102030405060708ULL);
327 MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0);
329 MOZ_RELEASE_ASSERT(LittleEndian::readInt16(&signed_bytes[0]) == int16_t(0xf2f1));
330 MOZ_RELEASE_ASSERT(BigEndian::readInt16(&signed_bytes[0]) == int16_t(0xf1f2));
332 MOZ_RELEASE_ASSERT(LittleEndian::readInt32(&signed_bytes[0]) == int32_t(0xf4f3f2f1));
333 MOZ_RELEASE_ASSERT(BigEndian::readInt32(&signed_bytes[0]) == int32_t(0xf1f2f3f4));
335 MOZ_RELEASE_ASSERT(LittleEndian::readInt64(&signed_bytes[0]) == int64_t(0xf8f7f6f5f4f3f2f1LL));
336 MOZ_RELEASE_ASSERT(BigEndian::readInt64(&signed_bytes[0]) == int64_t(0xf1f2f3f4f5f6f7f8LL));
338 LittleEndian::writeInt16(&buffer[0], 0xf2f1);
339 MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0);
340 BigEndian::writeInt16(&buffer[0], 0xf1f2);
341 MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0);
343 LittleEndian::writeInt32(&buffer[0], 0xf4f3f2f1);
344 MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0);
345 BigEndian::writeInt32(&buffer[0], 0xf1f2f3f4);
346 MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0);
348 LittleEndian::writeInt64(&buffer[0], 0xf8f7f6f5f4f3f2f1LL);
349 MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0);
350 BigEndian::writeInt64(&buffer[0], 0xf1f2f3f4f5f6f7f8LL);
351 MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0);
353 TestSingleSwap(uint16_t(0xf2f1), uint16_t(0xf1f2));
354 TestSingleSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf1f2f3f4));
355 TestSingleSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf1f2f3f4f5f6f7f8));
357 TestSingleSwap(int16_t(0xf2f1), int16_t(0xf1f2));
358 TestSingleSwap(int32_t(0xf4f3f2f1), int32_t(0xf1f2f3f4));
359 TestSingleSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf1f2f3f4f5f6f7f8));
361 TestSingleNoSwap(uint16_t(0xf2f1), uint16_t(0xf2f1));
362 TestSingleNoSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf4f3f2f1));
363 TestSingleNoSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf8f7f6f5f4f3f2f1));
365 TestSingleNoSwap(int16_t(0xf2f1), int16_t(0xf2f1));
366 TestSingleNoSwap(int32_t(0xf4f3f2f1), int32_t(0xf4f3f2f1));
367 TestSingleNoSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf8f7f6f5f4f3f2f1));
369 TestBulkSwap(uint16_values);
370 TestBulkSwap(int16_values);
371 TestBulkSwap(uint32_values);
372 TestBulkSwap(int32_values);
373 TestBulkSwap(uint64_values);
374 TestBulkSwap(int64_values);
376 TestBulkNoSwap(uint16_values);
377 TestBulkNoSwap(int16_values);
378 TestBulkNoSwap(uint32_values);
379 TestBulkNoSwap(int32_values);
380 TestBulkNoSwap(uint64_values);
381 TestBulkNoSwap(int64_values);
383 TestBulkInPlaceSwap(uint16_values);
384 TestBulkInPlaceSwap(int16_values);
385 TestBulkInPlaceSwap(uint32_values);
386 TestBulkInPlaceSwap(int32_values);
387 TestBulkInPlaceSwap(uint64_values);
388 TestBulkInPlaceSwap(int64_values);
390 TestBulkInPlaceNoSwap(uint16_values);
391 TestBulkInPlaceNoSwap(int16_values);
392 TestBulkInPlaceNoSwap(uint32_values);
393 TestBulkInPlaceNoSwap(int32_values);
394 TestBulkInPlaceNoSwap(uint64_values);
395 TestBulkInPlaceNoSwap(int64_values);
397 return 0;
398 }