1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #pragma once
32 
33 #include <climits>
34 #include <cstdint>
35 #include <cstring>
36 #include <type_traits>
37 
38 #include "mongo/base/static_assert.h"
39 #include "mongo/config.h"
40 #include "mongo/platform/decimal128.h"
41 
42 #pragma push_macro("MONGO_UINT16_SWAB")
43 #pragma push_macro("MONGO_UINT32_SWAB")
44 #pragma push_macro("MONGO_UINT64_SWAB")
45 #pragma push_macro("htobe16")
46 #pragma push_macro("htobe32")
47 #pragma push_macro("htobe64")
48 #pragma push_macro("htole16")
49 #pragma push_macro("htole32")
50 #pragma push_macro("htole64")
51 #pragma push_macro("be16toh")
52 #pragma push_macro("be32toh")
53 #pragma push_macro("be64toh")
54 #pragma push_macro("le16toh")
55 #pragma push_macro("le32toh")
56 #pragma push_macro("le64toh")
57 
58 #undef MONGO_UINT16_SWAB
59 #undef MONGO_UINT32_SWAB
60 #undef MONGO_UINT64_SWAB
61 #undef htobe16
62 #undef htobe32
63 #undef htobe64
64 #undef htole16
65 #undef htole32
66 #undef htole64
67 #undef be16toh
68 #undef be32toh
69 #undef be64toh
70 #undef le16toh
71 #undef le32toh
72 #undef le64toh
73 
74 #define MONGO_LITTLE_ENDIAN 1234
75 #define MONGO_BIG_ENDIAN 4321
76 
77 #if defined(_MSC_VER)
78 #include <cstdlib>
79 #define MONGO_UINT16_SWAB(v) _byteswap_ushort(v)
80 #define MONGO_UINT32_SWAB(v) _byteswap_ulong(v)
81 #define MONGO_UINT64_SWAB(v) _byteswap_uint64(v)
82 #elif defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) && \
83     (__clang_major__ >= 3) && (__clang_minor__ >= 1)
84 #if __has_builtin(__builtin_bswap16)
85 #define MONGO_UINT16_SWAB(v) __builtin_bswap16(v)
86 #endif
87 #if __has_builtin(__builtin_bswap32)
88 #define MONGO_UINT32_SWAB(v) __builtin_bswap32(v)
89 #endif
90 #if __has_builtin(__builtin_bswap64)
91 #define MONGO_UINT64_SWAB(v) __builtin_bswap64(v)
92 #endif
93 #elif defined(__GNUC__) && (__GNUC__ >= 4)
94 #if __GNUC__ >= 4 && defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 3
95 #define MONGO_UINT32_SWAB(v) __builtin_bswap32(v)
96 #define MONGO_UINT64_SWAB(v) __builtin_bswap64(v)
97 #endif
98 #if __GNUC__ >= 4 && defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 8
99 #define MONGO_UINT16_SWAB(v) __builtin_bswap16(v)
100 #endif
101 #elif defined(__sun)
102 #include <sys/byteorder.h>
103 #define MONGO_UINT16_SWAB(v) BSWAP_16(v)
104 #define MONGO_UINT32_SWAB(v) BSWAP_32(v)
105 #define MONGO_UINT64_SWAB(v) BSWAP_64(v)
106 #endif
107 
108 #ifndef MONGO_UINT16_SWAB
109 #define MONGO_UINT16_SWAB(v) endian::bswap_slow16(v)
110 #endif
111 
112 #ifndef MONGO_UINT32_SWAB
113 #define MONGO_UINT32_SWAB(v) endian::bswap_slow32(v)
114 #endif
115 
116 #ifndef MONGO_UINT64_SWAB
117 #define MONGO_UINT64_SWAB(v) endian::bswap_slow64(v)
118 #endif
119 
120 #if MONGO_CONFIG_BYTE_ORDER == MONGO_LITTLE_ENDIAN
121 #define htobe16(v) MONGO_UINT16_SWAB(v)
122 #define htobe32(v) MONGO_UINT32_SWAB(v)
123 #define htobe64(v) MONGO_UINT64_SWAB(v)
124 #define htole16(v) (v)
125 #define htole32(v) (v)
126 #define htole64(v) (v)
127 #define be16toh(v) MONGO_UINT16_SWAB(v)
128 #define be32toh(v) MONGO_UINT32_SWAB(v)
129 #define be64toh(v) MONGO_UINT64_SWAB(v)
130 #define le16toh(v) (v)
131 #define le32toh(v) (v)
132 #define le64toh(v) (v)
133 #elif MONGO_CONFIG_BYTE_ORDER == MONGO_BIG_ENDIAN
134 #define htobe16(v) (v)
135 #define htobe32(v) (v)
136 #define htobe64(v) (v)
137 #define htole16(v) MONGO_UINT16_SWAB(v)
138 #define htole32(v) MONGO_UINT32_SWAB(v)
139 #define htole64(v) MONGO_UINT64_SWAB(v)
140 #define be16toh(v) (v)
141 #define be32toh(v) (v)
142 #define be64toh(v) (v)
143 #define le16toh(v) MONGO_UINT16_SWAB(v)
144 #define le32toh(v) MONGO_UINT32_SWAB(v)
145 #define le64toh(v) MONGO_UINT64_SWAB(v)
146 #else
147 #error \
148     "The endianness of target architecture is unknown. " \
149         "Please define MONGO_CONFIG_BYTE_ORDER"
150 #endif
151 
152 namespace mongo {
153 namespace endian {
154 
bswap_slow16(uint16_t v)155 static inline uint16_t bswap_slow16(uint16_t v) {
156     return ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8);
157 }
158 
bswap_slow32(uint32_t v)159 static inline uint32_t bswap_slow32(uint32_t v) {
160     return ((v & 0x000000FFUL) << 24) | ((v & 0x0000FF00UL) << 8) | ((v & 0x00FF0000UL) >> 8) |
161         ((v & 0xFF000000UL) >> 24);
162 }
163 
bswap_slow64(uint64_t v)164 static inline uint64_t bswap_slow64(uint64_t v) {
165     return ((v & 0x00000000000000FFULL) << 56) | ((v & 0x000000000000FF00ULL) << 40) |
166         ((v & 0x0000000000FF0000ULL) << 24) | ((v & 0x00000000FF000000ULL) << 8) |
167         ((v & 0x000000FF00000000ULL) >> 8) | ((v & 0x0000FF0000000000ULL) >> 24) |
168         ((v & 0x00FF000000000000ULL) >> 40) | ((v & 0xFF00000000000000ULL) >> 56);
169 }
170 
171 template <typename T>
172 struct ByteOrderConverter;
173 
174 template <>
175 struct ByteOrderConverter<uint8_t> {
176     typedef uint8_t T;
177 
178     inline static T nativeToBig(T t) {
179         return t;
180     }
181 
182     inline static T bigToNative(T t) {
183         return t;
184     }
185 
186     inline static T nativeToLittle(T t) {
187         return t;
188     }
189 
190     inline static T littleToNative(T t) {
191         return t;
192     }
193 };
194 
195 template <>
196 struct ByteOrderConverter<uint16_t> {
197     typedef uint16_t T;
198 
199     inline static T nativeToBig(T t) {
200         return htobe16(t);
201     }
202 
203     inline static T bigToNative(T t) {
204         return be16toh(t);
205     }
206 
207     inline static T nativeToLittle(T t) {
208         return htole16(t);
209     }
210 
211     inline static T littleToNative(T t) {
212         return le16toh(t);
213     }
214 };
215 
216 template <>
217 struct ByteOrderConverter<uint32_t> {
218     typedef uint32_t T;
219 
220     inline static T nativeToBig(T t) {
221         return htobe32(t);
222     }
223 
224     inline static T bigToNative(T t) {
225         return be32toh(t);
226     }
227 
228     inline static T nativeToLittle(T t) {
229         return htole32(t);
230     }
231 
232     inline static T littleToNative(T t) {
233         return le32toh(t);
234     }
235 };
236 
237 template <>
238 struct ByteOrderConverter<uint64_t> {
239     typedef uint64_t T;
240 
241     inline static T nativeToBig(T t) {
242         return htobe64(t);
243     }
244 
245     inline static T bigToNative(T t) {
246         return be64toh(t);
247     }
248 
249     inline static T nativeToLittle(T t) {
250         return htole64(t);
251     }
252 
253     inline static T littleToNative(T t) {
254         return le64toh(t);
255     }
256 };
257 
258 template <>
259 struct ByteOrderConverter<int8_t> {
260     typedef int8_t T;
261 
262     inline static T nativeToBig(T t) {
263         return t;
264     }
265 
266     inline static T bigToNative(T t) {
267         return t;
268     }
269 
270     inline static T nativeToLittle(T t) {
271         return t;
272     }
273 
274     inline static T littleToNative(T t) {
275         return t;
276     }
277 };
278 
279 template <>
280 struct ByteOrderConverter<int16_t> {
281     typedef int16_t T;
282 
283     inline static T nativeToBig(T t) {
284         return htobe16(static_cast<uint16_t>(t));
285     }
286 
287     inline static T bigToNative(T t) {
288         return be16toh(static_cast<uint16_t>(t));
289     }
290 
291     inline static T nativeToLittle(T t) {
292         return htole16(static_cast<uint16_t>(t));
293     }
294 
295     inline static T littleToNative(T t) {
296         return le16toh(static_cast<uint16_t>(t));
297     }
298 };
299 
300 template <>
301 struct ByteOrderConverter<int32_t> {
302     typedef int32_t T;
303 
304     inline static T nativeToBig(T t) {
305         return htobe32(static_cast<uint32_t>(t));
306     }
307 
308     inline static T bigToNative(T t) {
309         return be32toh(static_cast<uint32_t>(t));
310     }
311 
312     inline static T nativeToLittle(T t) {
313         return htole32(static_cast<uint32_t>(t));
314     }
315 
316     inline static T littleToNative(T t) {
317         return le32toh(static_cast<uint32_t>(t));
318     }
319 };
320 
321 template <>
322 struct ByteOrderConverter<int64_t> {
323     typedef int64_t T;
324 
325     inline static T nativeToBig(T t) {
326         return htobe64(static_cast<uint64_t>(t));
327     }
328 
329     inline static T bigToNative(T t) {
330         return be64toh(static_cast<uint64_t>(t));
331     }
332 
333     inline static T nativeToLittle(T t) {
334         return htole64(static_cast<uint64_t>(t));
335     }
336 
337     inline static T littleToNative(T t) {
338         return le64toh(static_cast<uint64_t>(t));
339     }
340 };
341 
342 template <>
343 struct ByteOrderConverter<float> {
344     typedef float T;
345 
346     inline static T nativeToBig(T t) {
347         MONGO_STATIC_ASSERT(sizeof(T) == sizeof(uint32_t));
348 
349         uint32_t temp;
350         std::memcpy(&temp, &t, sizeof(t));
351         temp = htobe32(temp);
352         std::memcpy(&t, &temp, sizeof(t));
353         return t;
354     }
355 
356     inline static T bigToNative(T t) {
357         uint32_t temp;
358         std::memcpy(&temp, &t, sizeof(t));
359         temp = be32toh(temp);
360         std::memcpy(&t, &temp, sizeof(t));
361         return t;
362     }
363 
364     inline static T nativeToLittle(T t) {
365         uint32_t temp;
366         std::memcpy(&temp, &t, sizeof(t));
367         temp = htole32(temp);
368         std::memcpy(&t, &temp, sizeof(t));
369         return t;
370     }
371 
372     inline static T littleToNative(T t) {
373         uint32_t temp;
374         std::memcpy(&temp, &t, sizeof(t));
375         temp = le32toh(temp);
376         std::memcpy(&t, &temp, sizeof(t));
377         return t;
378     }
379 };
380 
381 template <>
382 struct ByteOrderConverter<double> {
383     typedef double T;
384 
385     inline static T nativeToBig(T t) {
386         MONGO_STATIC_ASSERT(sizeof(T) == sizeof(uint64_t));
387 
388         uint64_t temp;
389         std::memcpy(&temp, &t, sizeof(t));
390         temp = htobe64(temp);
391         std::memcpy(&t, &temp, sizeof(t));
392         return t;
393     }
394 
395     inline static T bigToNative(T t) {
396         uint64_t temp;
397         std::memcpy(&temp, &t, sizeof(t));
398         temp = be64toh(temp);
399         std::memcpy(&t, &temp, sizeof(t));
400         return t;
401     }
402 
403     inline static T nativeToLittle(T t) {
404         uint64_t temp;
405         std::memcpy(&temp, &t, sizeof(t));
406         temp = htole64(temp);
407         std::memcpy(&t, &temp, sizeof(t));
408         return t;
409     }
410 
411     inline static T littleToNative(T t) {
412         uint64_t temp;
413         std::memcpy(&temp, &t, sizeof(t));
414         temp = le64toh(temp);
415         std::memcpy(&t, &temp, sizeof(t));
416         return t;
417     }
418 };
419 
420 template <>
421 struct ByteOrderConverter<Decimal128::Value> {
422     typedef Decimal128::Value T;
423 
424     inline static T nativeToBig(T t) {
425         ByteOrderConverter<uint64_t>::nativeToBig(t.low64);
426         ByteOrderConverter<uint64_t>::nativeToBig(t.high64);
427         return t;
428     }
429 
430     inline static T bigToNative(T t) {
431         ByteOrderConverter<uint64_t>::bigToNative(t.low64);
432         ByteOrderConverter<uint64_t>::bigToNative(t.high64);
433         return t;
434     }
435 
436     inline static T nativeToLittle(T t) {
437         ByteOrderConverter<uint64_t>::nativeToLittle(t.low64);
438         ByteOrderConverter<uint64_t>::nativeToLittle(t.high64);
439         return t;
440     }
441 
442     inline static T littleToNative(T t) {
443         ByteOrderConverter<uint64_t>::littleToNative(t.low64);
444         ByteOrderConverter<uint64_t>::littleToNative(t.high64);
445         return t;
446     }
447 };
448 
449 // Use a typemape to normalize non-fixed-width integral types to the associated fixed width
450 // types.
451 
452 template <typename T>
453 struct IntegralTypeMap {
454     typedef T type;
455 };
456 
457 template <>
458 struct IntegralTypeMap<signed char> {
459     MONGO_STATIC_ASSERT(CHAR_BIT == 8);
460     typedef int8_t type;
461 };
462 
463 template <>
464 struct IntegralTypeMap<unsigned char> {
465     MONGO_STATIC_ASSERT(CHAR_BIT == 8);
466     typedef uint8_t type;
467 };
468 
469 template <>
470 struct IntegralTypeMap<char> {
471     MONGO_STATIC_ASSERT(CHAR_BIT == 8);
472     typedef std::conditional<std::is_signed<char>::value, int8_t, uint8_t>::type type;
473 };
474 
475 template <>
476 struct IntegralTypeMap<long long> {
477     MONGO_STATIC_ASSERT(sizeof(long long) == sizeof(int64_t));
478     typedef int64_t type;
479 };
480 
481 template <>
482 struct IntegralTypeMap<unsigned long long> {
483     MONGO_STATIC_ASSERT(sizeof(unsigned long long) == sizeof(uint64_t));
484     typedef uint64_t type;
485 };
486 
487 template <typename T>
488 inline T nativeToBig(T t) {
489     return ByteOrderConverter<typename IntegralTypeMap<T>::type>::nativeToBig(t);
490 }
491 
492 template <typename T>
493 inline T bigToNative(T t) {
494     return ByteOrderConverter<typename IntegralTypeMap<T>::type>::bigToNative(t);
495 }
496 
497 template <typename T>
498 inline T nativeToLittle(T t) {
499     return ByteOrderConverter<typename IntegralTypeMap<T>::type>::nativeToLittle(t);
500 }
501 
502 template <typename T>
503 inline T littleToNative(T t) {
504     return ByteOrderConverter<typename IntegralTypeMap<T>::type>::littleToNative(t);
505 }
506 
507 }  // namespace endian
508 }  // namespace mongo
509 
510 #undef MONGO_UINT16_SWAB
511 #undef MONGO_UINT32_SWAB
512 #undef MONGO_UINT64_SWAB
513 #undef htobe16
514 #undef htobe32
515 #undef htobe64
516 #undef htole16
517 #undef htole32
518 #undef htole64
519 #undef be16toh
520 #undef be32toh
521 #undef be64toh
522 #undef le16toh
523 #undef le32toh
524 #undef le64toh
525 
526 #pragma pop_macro("MONGO_UINT16_SWAB")
527 #pragma pop_macro("MONGO_UINT32_SWAB")
528 #pragma pop_macro("MONGO_UINT64_SWAB")
529 #pragma pop_macro("htobe16")
530 #pragma pop_macro("htobe32")
531 #pragma pop_macro("htobe64")
532 #pragma pop_macro("htole16")
533 #pragma pop_macro("htole32")
534 #pragma pop_macro("htole64")
535 #pragma pop_macro("be16toh")
536 #pragma pop_macro("be32toh")
537 #pragma pop_macro("be64toh")
538 #pragma pop_macro("le16toh")
539 #pragma pop_macro("le32toh")
540 #pragma pop_macro("le64toh")
541