2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
5 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * in the COPYING file in the root directory of this source tree).
13 #if defined (__cplusplus)
17 /*-****************************************
19 ******************************************/
20 #include <stddef.h> /* size_t, ptrdiff_t */
21 #include <string.h> /* memcpy */
24 /*-****************************************
26 ******************************************/
27 #if defined(_MSC_VER) /* Visual Studio */
28 # include <stdlib.h> /* _byteswap_ulong */
29 # include <intrin.h> /* _byteswap_* */
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
38 # define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
41 /* code only tested on 32 and 64 bits systems */
42 #define MEM_STATIC_ASSERT(c) { enum { MEM_static_assert = 1/(int)(!!(c)) }; }
43 MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
46 /*-**************************************************************
48 *****************************************************************/
49 #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
58 typedef intptr_t iPtrDiff;
59 typedef uintptr_t uPtrDiff;
61 typedef unsigned char BYTE;
62 typedef unsigned short U16;
63 typedef signed short S16;
64 typedef unsigned int U32;
65 typedef signed int S32;
66 typedef unsigned long long U64;
67 typedef signed long long S64;
68 typedef ptrdiff_t iPtrDiff;
69 typedef size_t uPtrDiff;
73 /*-**************************************************************
75 *****************************************************************/
76 /* MEM_FORCE_MEMORY_ACCESS :
77 * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
78 * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
79 * The below switch allow to select different access method for improved performance.
80 * Method 0 (default) : use `memcpy()`. Safe and portable.
81 * Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable).
82 * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
83 * Method 2 : direct access. This method is portable but violate C standard.
84 * It can generate buggy code on targets depending on alignment.
85 * In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6)
86 * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
87 * Prefer these methods in priority order (0 > 1 > 2)
89 #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
90 # 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__) )
91 # define MEM_FORCE_MEMORY_ACCESS 2
92 # elif defined(__INTEL_COMPILER) || defined(__GNUC__)
93 # define MEM_FORCE_MEMORY_ACCESS 1
97 MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
98 MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
100 MEM_STATIC unsigned MEM_isLittleEndian(void)
102 const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
106 #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
108 /* violates C standard, by lying on structure alignment.
109 Only use if no other choice to achieve best performance on target platform */
110 MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
111 MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
112 MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
113 MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }
115 MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
116 MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
117 MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
119 #elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
121 /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
122 /* currently only defined for gcc and icc */
123 #if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))
124 __pragma( pack(push, 1) )
125 typedef union { U16 u16; U32 u32; U64 u64; size_t st; } unalign;
126 __pragma( pack(pop) )
128 typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign;
131 MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
132 MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
133 MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
134 MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalign*)ptr)->st; }
136 MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
137 MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
138 MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; }
142 /* default method, safe and standard.
143 can sometimes prove slower */
145 MEM_STATIC U16 MEM_read16(const void* memPtr)
147 U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
150 MEM_STATIC U32 MEM_read32(const void* memPtr)
152 U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
155 MEM_STATIC U64 MEM_read64(const void* memPtr)
157 U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
160 MEM_STATIC size_t MEM_readST(const void* memPtr)
162 size_t val; memcpy(&val, memPtr, sizeof(val)); return val;
165 MEM_STATIC void MEM_write16(void* memPtr, U16 value)
167 memcpy(memPtr, &value, sizeof(value));
170 MEM_STATIC void MEM_write32(void* memPtr, U32 value)
172 memcpy(memPtr, &value, sizeof(value));
175 MEM_STATIC void MEM_write64(void* memPtr, U64 value)
177 memcpy(memPtr, &value, sizeof(value));
180 #endif /* MEM_FORCE_MEMORY_ACCESS */
182 MEM_STATIC U32 MEM_swap32(U32 in)
184 #if defined(_MSC_VER) /* Visual Studio */
185 return _byteswap_ulong(in);
186 #elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)
187 return __builtin_bswap32(in);
189 return ((in << 24) & 0xff000000 ) |
190 ((in << 8) & 0x00ff0000 ) |
191 ((in >> 8) & 0x0000ff00 ) |
192 ((in >> 24) & 0x000000ff );
196 MEM_STATIC U64 MEM_swap64(U64 in)
198 #if defined(_MSC_VER) /* Visual Studio */
199 return _byteswap_uint64(in);
200 #elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)
201 return __builtin_bswap64(in);
203 return ((in << 56) & 0xff00000000000000ULL) |
204 ((in << 40) & 0x00ff000000000000ULL) |
205 ((in << 24) & 0x0000ff0000000000ULL) |
206 ((in << 8) & 0x000000ff00000000ULL) |
207 ((in >> 8) & 0x00000000ff000000ULL) |
208 ((in >> 24) & 0x0000000000ff0000ULL) |
209 ((in >> 40) & 0x000000000000ff00ULL) |
210 ((in >> 56) & 0x00000000000000ffULL);
214 MEM_STATIC size_t MEM_swapST(size_t in)
217 return (size_t)MEM_swap32((U32)in);
219 return (size_t)MEM_swap64((U64)in);
222 /*=== Little endian r/w ===*/
224 MEM_STATIC U16 MEM_readLE16(const void* memPtr)
226 if (MEM_isLittleEndian())
227 return MEM_read16(memPtr);
229 const BYTE* p = (const BYTE*)memPtr;
230 return (U16)(p[0] + (p[1]<<8));
234 MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
236 if (MEM_isLittleEndian()) {
237 MEM_write16(memPtr, val);
239 BYTE* p = (BYTE*)memPtr;
241 p[1] = (BYTE)(val>>8);
245 MEM_STATIC U32 MEM_readLE24(const void* memPtr)
247 return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
250 MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
252 MEM_writeLE16(memPtr, (U16)val);
253 ((BYTE*)memPtr)[2] = (BYTE)(val>>16);
256 MEM_STATIC U32 MEM_readLE32(const void* memPtr)
258 if (MEM_isLittleEndian())
259 return MEM_read32(memPtr);
261 return MEM_swap32(MEM_read32(memPtr));
264 MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
266 if (MEM_isLittleEndian())
267 MEM_write32(memPtr, val32);
269 MEM_write32(memPtr, MEM_swap32(val32));
272 MEM_STATIC U64 MEM_readLE64(const void* memPtr)
274 if (MEM_isLittleEndian())
275 return MEM_read64(memPtr);
277 return MEM_swap64(MEM_read64(memPtr));
280 MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
282 if (MEM_isLittleEndian())
283 MEM_write64(memPtr, val64);
285 MEM_write64(memPtr, MEM_swap64(val64));
288 MEM_STATIC size_t MEM_readLEST(const void* memPtr)
291 return (size_t)MEM_readLE32(memPtr);
293 return (size_t)MEM_readLE64(memPtr);
296 MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
299 MEM_writeLE32(memPtr, (U32)val);
301 MEM_writeLE64(memPtr, (U64)val);
304 /*=== Big endian r/w ===*/
306 MEM_STATIC U32 MEM_readBE32(const void* memPtr)
308 if (MEM_isLittleEndian())
309 return MEM_swap32(MEM_read32(memPtr));
311 return MEM_read32(memPtr);
314 MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
316 if (MEM_isLittleEndian())
317 MEM_write32(memPtr, MEM_swap32(val32));
319 MEM_write32(memPtr, val32);
322 MEM_STATIC U64 MEM_readBE64(const void* memPtr)
324 if (MEM_isLittleEndian())
325 return MEM_swap64(MEM_read64(memPtr));
327 return MEM_read64(memPtr);
330 MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
332 if (MEM_isLittleEndian())
333 MEM_write64(memPtr, MEM_swap64(val64));
335 MEM_write64(memPtr, val64);
338 MEM_STATIC size_t MEM_readBEST(const void* memPtr)
341 return (size_t)MEM_readBE32(memPtr);
343 return (size_t)MEM_readBE64(memPtr);
346 MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
349 MEM_writeBE32(memPtr, (U32)val);
351 MEM_writeBE64(memPtr, (U64)val);
355 #if defined (__cplusplus)
359 #endif /* MEM_H_MODULE */