Line data Source code
1 : /**
2 : * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 : * All rights reserved.
4 : *
5 : * This source code is licensed under the BSD-style license found in the
6 : * LICENSE file in the root directory of this source tree. An additional grant
7 : * of patent rights can be found in the PATENTS file in the same directory.
8 : */
9 :
10 : #ifndef MEM_H_MODULE
11 : #define MEM_H_MODULE
12 :
13 : #if defined (__cplusplus)
14 : extern "C" {
15 : #endif
16 :
17 : /*-****************************************
18 : * Dependencies
19 : ******************************************/
20 : #include <stddef.h> /* size_t, ptrdiff_t */
21 : #include <string.h> /* memcpy */
22 :
23 :
24 : /*-****************************************
25 : * Compiler specifics
26 : ******************************************/
27 : #if defined(_MSC_VER) /* Visual Studio */
28 : # include <stdlib.h> /* _byteswap_ulong */
29 : # include <intrin.h> /* _byteswap_* */
30 : #endif
31 : #if defined(__GNUC__)
32 : # define MEM_STATIC static __inline __attribute__((unused))
33 : #elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
34 : # define MEM_STATIC static inline
35 : #elif defined(_MSC_VER)
36 : # define MEM_STATIC static __inline
37 : #else
38 : # define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
39 : #endif
40 :
41 : /* code only tested on 32 and 64 bits systems */
42 : #define MEM_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; }
43 : MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
44 :
45 :
46 : /*-**************************************************************
47 : * Basic Types
48 : *****************************************************************/
49 : #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
50 : # include <stdint.h>
51 : typedef uint8_t BYTE;
52 : typedef uint16_t U16;
53 : typedef int16_t S16;
54 : typedef uint32_t U32;
55 : typedef int32_t S32;
56 : typedef uint64_t U64;
57 : typedef int64_t S64;
58 : #else
59 : typedef unsigned char BYTE;
60 : typedef unsigned short U16;
61 : typedef signed short S16;
62 : typedef unsigned int U32;
63 : typedef signed int S32;
64 : typedef unsigned long long U64;
65 : typedef signed long long S64;
66 : #endif
67 :
68 :
69 : /*-**************************************************************
70 : * Memory I/O
71 : *****************************************************************/
72 : /* MEM_FORCE_MEMORY_ACCESS :
73 : * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
74 : * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
75 : * The below switch allow to select different access method for improved performance.
76 : * Method 0 (default) : use `memcpy()`. Safe and portable.
77 : * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
78 : * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
79 : * Method 2 : direct access. This method is portable but violate C standard.
80 : * It can generate buggy code on targets depending on alignment.
81 : * In some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
82 : * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
83 : * Prefer these methods in priority order (0 > 1 > 2)
84 : */
85 : #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
86 : # if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
87 : # define MEM_FORCE_MEMORY_ACCESS 2
88 : # elif defined(__INTEL_COMPILER) /*|| defined(_MSC_VER)*/ || \
89 : (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))
90 : # define MEM_FORCE_MEMORY_ACCESS 1
91 : # endif
92 : #endif
93 :
94 171323782 : MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
95 98300662 : MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
96 :
97 165732980 : MEM_STATIC unsigned MEM_isLittleEndian(void)
98 : {
99 165732980 : const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
100 165732980 : return one.c[0];
101 : }
102 :
103 : #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
104 :
105 : /* violates C standard, by lying on structure alignment.
106 : Only use if no other choice to achieve best performance on target platform */
107 : MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
108 : MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
109 : MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
110 : MEM_STATIC U64 MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }
111 :
112 : MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
113 : MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
114 : MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
115 :
116 : #elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
117 :
118 : /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
119 : /* currently only defined for gcc and icc */
120 : #if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))
121 : __pragma( pack(push, 1) )
122 : typedef union { U16 u16; U32 u32; U64 u64; size_t st; } unalign;
123 : __pragma( pack(pop) )
124 : #else
125 : typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign;
126 : #endif
127 :
128 : MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
129 : MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
130 : MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
131 : MEM_STATIC U64 MEM_readST(const void* ptr) { return ((const unalign*)ptr)->st; }
132 :
133 : MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
134 : MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
135 : MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; }
136 :
137 : #else
138 :
139 : /* default method, safe and standard.
140 : can sometimes prove slower */
141 :
142 18684 : MEM_STATIC U16 MEM_read16(const void* memPtr)
143 : {
144 18684 : U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
145 : }
146 :
147 262785080 : MEM_STATIC U32 MEM_read32(const void* memPtr)
148 : {
149 262785080 : U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
150 : }
151 :
152 108230878 : MEM_STATIC U64 MEM_read64(const void* memPtr)
153 : {
154 108230878 : U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
155 : }
156 :
157 33794404 : MEM_STATIC size_t MEM_readST(const void* memPtr)
158 : {
159 33794404 : size_t val; memcpy(&val, memPtr, sizeof(val)); return val;
160 : }
161 :
162 712244 : MEM_STATIC void MEM_write16(void* memPtr, U16 value)
163 : {
164 712244 : memcpy(memPtr, &value, sizeof(value));
165 712244 : }
166 :
167 4722 : MEM_STATIC void MEM_write32(void* memPtr, U32 value)
168 : {
169 4722 : memcpy(memPtr, &value, sizeof(value));
170 4722 : }
171 :
172 46148622 : MEM_STATIC void MEM_write64(void* memPtr, U64 value)
173 : {
174 46148622 : memcpy(memPtr, &value, sizeof(value));
175 46148622 : }
176 :
177 : #endif /* MEM_FORCE_MEMORY_ACCESS */
178 :
179 0 : MEM_STATIC U32 MEM_swap32(U32 in)
180 : {
181 : #if defined(_MSC_VER) /* Visual Studio */
182 : return _byteswap_ulong(in);
183 : #elif defined (__GNUC__)
184 0 : return __builtin_bswap32(in);
185 : #else
186 : return ((in << 24) & 0xff000000 ) |
187 : ((in << 8) & 0x00ff0000 ) |
188 : ((in >> 8) & 0x0000ff00 ) |
189 : ((in >> 24) & 0x000000ff );
190 : #endif
191 : }
192 :
193 0 : MEM_STATIC U64 MEM_swap64(U64 in)
194 : {
195 : #if defined(_MSC_VER) /* Visual Studio */
196 : return _byteswap_uint64(in);
197 : #elif defined (__GNUC__)
198 0 : return __builtin_bswap64(in);
199 : #else
200 : return ((in << 56) & 0xff00000000000000ULL) |
201 : ((in << 40) & 0x00ff000000000000ULL) |
202 : ((in << 24) & 0x0000ff0000000000ULL) |
203 : ((in << 8) & 0x000000ff00000000ULL) |
204 : ((in >> 8) & 0x00000000ff000000ULL) |
205 : ((in >> 24) & 0x0000000000ff0000ULL) |
206 : ((in >> 40) & 0x000000000000ff00ULL) |
207 : ((in >> 56) & 0x00000000000000ffULL);
208 : #endif
209 : }
210 :
211 : MEM_STATIC size_t MEM_swapST(size_t in)
212 : {
213 : if (MEM_32bits())
214 : return (size_t)MEM_swap32((U32)in);
215 : else
216 : return (size_t)MEM_swap64((U64)in);
217 : }
218 :
219 : /*=== Little endian r/w ===*/
220 :
221 9376 : MEM_STATIC U16 MEM_readLE16(const void* memPtr)
222 : {
223 9376 : if (MEM_isLittleEndian())
224 9376 : return MEM_read16(memPtr);
225 : else {
226 0 : const BYTE* p = (const BYTE*)memPtr;
227 0 : return (U16)(p[0] + (p[1]<<8));
228 : }
229 : }
230 :
231 712244 : MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
232 : {
233 712244 : if (MEM_isLittleEndian()) {
234 712244 : MEM_write16(memPtr, val);
235 : } else {
236 0 : BYTE* p = (BYTE*)memPtr;
237 0 : p[0] = (BYTE)val;
238 0 : p[1] = (BYTE)(val>>8);
239 : }
240 712244 : }
241 :
242 3362 : MEM_STATIC U32 MEM_readLE24(const void* memPtr)
243 : {
244 3362 : return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
245 : }
246 :
247 2064 : MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
248 : {
249 2064 : MEM_writeLE16(memPtr, (U16)val);
250 2064 : ((BYTE*)memPtr)[2] = (BYTE)(val>>16);
251 2064 : }
252 :
253 131530 : MEM_STATIC U32 MEM_readLE32(const void* memPtr)
254 : {
255 131530 : if (MEM_isLittleEndian())
256 131530 : return MEM_read32(memPtr);
257 : else
258 0 : return MEM_swap32(MEM_read32(memPtr));
259 : }
260 :
261 4722 : MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
262 : {
263 4722 : if (MEM_isLittleEndian())
264 4722 : MEM_write32(memPtr, val32);
265 : else
266 0 : MEM_write32(memPtr, MEM_swap32(val32));
267 4722 : }
268 :
269 107611486 : MEM_STATIC U64 MEM_readLE64(const void* memPtr)
270 : {
271 107611486 : if (MEM_isLittleEndian())
272 107611486 : return MEM_read64(memPtr);
273 : else
274 0 : return MEM_swap64(MEM_read64(memPtr));
275 : }
276 :
277 46148622 : MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
278 : {
279 46148622 : if (MEM_isLittleEndian())
280 46148622 : MEM_write64(memPtr, val64);
281 : else
282 0 : MEM_write64(memPtr, MEM_swap64(val64));
283 46148622 : }
284 :
285 40295114 : MEM_STATIC size_t MEM_readLEST(const void* memPtr)
286 : {
287 40295114 : if (MEM_32bits())
288 0 : return (size_t)MEM_readLE32(memPtr);
289 : else
290 40295114 : return (size_t)MEM_readLE64(memPtr);
291 : }
292 :
293 46148622 : MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
294 : {
295 46148622 : if (MEM_32bits())
296 0 : MEM_writeLE32(memPtr, (U32)val);
297 : else
298 46148622 : MEM_writeLE64(memPtr, (U64)val);
299 46148622 : }
300 :
301 : /*=== Big endian r/w ===*/
302 :
303 : MEM_STATIC U32 MEM_readBE32(const void* memPtr)
304 : {
305 : if (MEM_isLittleEndian())
306 : return MEM_swap32(MEM_read32(memPtr));
307 : else
308 : return MEM_read32(memPtr);
309 : }
310 :
311 : MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
312 : {
313 : if (MEM_isLittleEndian())
314 : MEM_write32(memPtr, MEM_swap32(val32));
315 : else
316 : MEM_write32(memPtr, val32);
317 : }
318 :
319 : MEM_STATIC U64 MEM_readBE64(const void* memPtr)
320 : {
321 : if (MEM_isLittleEndian())
322 : return MEM_swap64(MEM_read64(memPtr));
323 : else
324 : return MEM_read64(memPtr);
325 : }
326 :
327 : MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
328 : {
329 : if (MEM_isLittleEndian())
330 : MEM_write64(memPtr, MEM_swap64(val64));
331 : else
332 : MEM_write64(memPtr, val64);
333 : }
334 :
335 : MEM_STATIC size_t MEM_readBEST(const void* memPtr)
336 : {
337 : if (MEM_32bits())
338 : return (size_t)MEM_readBE32(memPtr);
339 : else
340 : return (size_t)MEM_readBE64(memPtr);
341 : }
342 :
343 : MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
344 : {
345 : if (MEM_32bits())
346 : MEM_writeBE32(memPtr, (U32)val);
347 : else
348 : MEM_writeBE64(memPtr, (U64)val);
349 : }
350 :
351 :
352 : /* function safe only for comparisons */
353 0 : MEM_STATIC U32 MEM_readMINMATCH(const void* memPtr, U32 length)
354 : {
355 0 : switch (length)
356 : {
357 : default :
358 0 : case 4 : return MEM_read32(memPtr);
359 0 : case 3 : if (MEM_isLittleEndian())
360 0 : return MEM_read32(memPtr)<<8;
361 : else
362 0 : return MEM_read32(memPtr)>>8;
363 : }
364 : }
365 :
366 : #if defined (__cplusplus)
367 : }
368 : #endif
369 :
370 : #endif /* MEM_H_MODULE */
|