1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef LIBTEXTCLASSIFIER_UTILS_BASE_ENDIAN_H_
18 #define LIBTEXTCLASSIFIER_UTILS_BASE_ENDIAN_H_
19 
20 #include "utils/base/integral_types.h"
21 
22 namespace libtextclassifier3 {
23 
24 #if defined OS_LINUX || defined OS_CYGWIN || defined OS_ANDROID || \
25     defined(__ANDROID__)
26 #include <endian.h>
27 #elif defined(__APPLE__)
28 #include <machine/endian.h>
29 // Add linux style defines.
30 #ifndef __BYTE_ORDER
31 #define __BYTE_ORDER BYTE_ORDER
32 #endif  // __BYTE_ORDER
33 #ifndef __LITTLE_ENDIAN
34 #define __LITTLE_ENDIAN LITTLE_ENDIAN
35 #endif  // __LITTLE_ENDIAN
36 #ifndef __BIG_ENDIAN
37 #define __BIG_ENDIAN BIG_ENDIAN
38 #endif  // __BIG_ENDIAN
39 #endif
40 
41 // The following guarantees declaration of the byte swap functions, and
42 // defines __BYTE_ORDER for MSVC
43 #if defined(__GLIBC__) || defined(__BIONIC__) || defined(__CYGWIN__)
44 #include <byteswap.h>  // IWYU pragma: export
45 // The following section defines the byte swap functions for OS X / iOS,
46 // which does not ship with byteswap.h.
47 #elif defined(__APPLE__)
48 // Make sure that byte swap functions are not already defined.
49 #if !defined(bswap_16)
50 #include <libkern/OSByteOrder.h>
51 #define bswap_16(x) OSSwapInt16(x)
52 #define bswap_32(x) OSSwapInt32(x)
53 #define bswap_64(x) OSSwapInt64(x)
54 #endif  // !defined(bswap_16)
55 #else
56 #define int64_t {x} x##LL
57 #define uint64_t {x} x##ULL
58 static inline uint16 bswap_16(uint16 x) {
59   return (uint16)(((x & 0xFF) << 8) | ((x & 0xFF00) >> 8));  // NOLINT
60 }
61 #define bswap_16(x) bswap_16(x)
62 static inline uint32 bswap_32(uint32 x) {
63   return (((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) |
64           ((x & 0xFF000000) >> 24));
65 }
66 #define bswap_32(x) bswap_32(x)
67 static inline uint64 bswap_64(uint64 x) {
68   return (((x & uint64_t{0xFF}) << 56) | ((x & uint64_t{0xFF00}) << 40) |
69           ((x & uint64_t{0xFF0000}) << 24) | ((x & uint64_t{0xFF000000}) << 8) |
70           ((x & uint64_t{0xFF00000000}) >> 8) |
71           ((x & uint64_t{0xFF0000000000}) >> 24) |
72           ((x & uint64_t{0xFF000000000000}) >> 40) |
73           ((x & uint64_t{0xFF00000000000000}) >> 56));
74 }
75 #define bswap_64(x) bswap_64(x)
76 #endif
77 
78 // define the macros IS_LITTLE_ENDIAN or IS_BIG_ENDIAN
79 // using the above endian definitions from endian.h if
80 // endian.h was included
81 #ifdef __BYTE_ORDER
82 #if __BYTE_ORDER == __LITTLE_ENDIAN
83 #define IS_LITTLE_ENDIAN
84 #endif
85 
86 #if __BYTE_ORDER == __BIG_ENDIAN
87 #define IS_BIG_ENDIAN
88 #endif
89 
90 #else
91 
92 #if defined(__LITTLE_ENDIAN__)
93 #define IS_LITTLE_ENDIAN
94 #elif defined(__BIG_ENDIAN__)
95 #define IS_BIG_ENDIAN
96 #endif
97 
98 // there is also PDP endian ...
99 
100 #endif  // __BYTE_ORDER
101 
102 class LittleEndian {
103  public:
104 // Conversion functions.
105 #ifdef IS_LITTLE_ENDIAN
106 
FromHost16(uint16 x)107   static uint16 FromHost16(uint16 x) { return x; }
ToHost16(uint16 x)108   static uint16 ToHost16(uint16 x) { return x; }
109 
FromHost32(uint32 x)110   static uint32 FromHost32(uint32 x) { return x; }
ToHost32(uint32 x)111   static uint32 ToHost32(uint32 x) { return x; }
112 
FromHost64(uint64 x)113   static uint64 FromHost64(uint64 x) { return x; }
ToHost64(uint64 x)114   static uint64 ToHost64(uint64 x) { return x; }
115 
IsLittleEndian()116   static bool IsLittleEndian() { return true; }
117 
118 #elif defined IS_BIG_ENDIAN
119 
120   static uint16 FromHost16(uint16 x) { return gbswap_16(x); }
121   static uint16 ToHost16(uint16 x) { return gbswap_16(x); }
122 
123   static uint32 FromHost32(uint32 x) { return gbswap_32(x); }
124   static uint32 ToHost32(uint32 x) { return gbswap_32(x); }
125 
126   static uint64 FromHost64(uint64 x) { return gbswap_64(x); }
127   static uint64 ToHost64(uint64 x) { return gbswap_64(x); }
128 
129   static bool IsLittleEndian() { return false; }
130 
131 #endif /* ENDIAN */
132 };
133 
134 }  // namespace libtextclassifier3
135 
136 #endif  // LIBTEXTCLASSIFIER_UTILS_BASE_ENDIAN_H_
137