comparison contrib/python-zstandard/zstd/common/mem.h @ 30434:2e484bdea8c4

zstd: vendor zstd 1.1.1 zstd is a new compression format and it is awesome, yielding higher compression ratios and significantly faster compression and decompression operations compared to zlib (our current compression engine of choice) across the board. We want zstd to be a 1st class citizen in Mercurial and to eventually be the preferred compression format for various operations. This patch starts the formal process of supporting zstd by vendoring a copy of zstd. Why do we need to vendor zstd? Good question. First, zstd is relatively new and not widely available yet. If we didn't vendor zstd or distribute it with Mercurial, most users likely wouldn't have zstd installed or even available to install. What good is a feature if you can't use it? Vendoring and distributing the zstd sources gives us the highest liklihood that zstd will be available to Mercurial installs. Second, the Python bindings to zstd (which will be vendored in a separate changeset) make use of zstd APIs that are only available via static linking. One reason they are only available via static linking is that they are unstable and could change at any time. While it might be possible for the Python bindings to attempt to talk to different versions of the zstd C library, the safest thing to do is link against a specific, known-working version of zstd. This is why the Python zstd bindings themselves vendor zstd and why we must as well. This also explains why the added files are in a "python-zstandard" directory. The added files are from the 1.1.1 release of zstd (Git commit 4c0b44f8ced84c4c8edfa07b564d31e4fa3e8885 from https://github.com/facebook/zstd) and are added without modifications. Not all files from the zstd "distribution" have been added. Notably missing are files to support interacting with "legacy," pre-1.0 versions of zstd. The decision of which files to include is made by the upstream python-zstandard project (which I'm the author of). The files in this commit are a snapshot of the files from the 0.5.0 release of that project, Git commit e637c1b214d5f869cf8116c550dcae23ec13b677 from https://github.com/indygreg/python-zstandard.
author Gregory Szorc <gregory.szorc@gmail.com>
date Thu, 10 Nov 2016 21:45:29 -0800
parents
children b54a2984cdd4
comparison
equal deleted inserted replaced
30433:96f2f50d923f 30434:2e484bdea8c4
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 MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
95 MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
96
97 MEM_STATIC unsigned MEM_isLittleEndian(void)
98 {
99 const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
100 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 MEM_STATIC U16 MEM_read16(const void* memPtr)
143 {
144 U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
145 }
146
147 MEM_STATIC U32 MEM_read32(const void* memPtr)
148 {
149 U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
150 }
151
152 MEM_STATIC U64 MEM_read64(const void* memPtr)
153 {
154 U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
155 }
156
157 MEM_STATIC size_t MEM_readST(const void* memPtr)
158 {
159 size_t val; memcpy(&val, memPtr, sizeof(val)); return val;
160 }
161
162 MEM_STATIC void MEM_write16(void* memPtr, U16 value)
163 {
164 memcpy(memPtr, &value, sizeof(value));
165 }
166
167 MEM_STATIC void MEM_write32(void* memPtr, U32 value)
168 {
169 memcpy(memPtr, &value, sizeof(value));
170 }
171
172 MEM_STATIC void MEM_write64(void* memPtr, U64 value)
173 {
174 memcpy(memPtr, &value, sizeof(value));
175 }
176
177 #endif /* MEM_FORCE_MEMORY_ACCESS */
178
179 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 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 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 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 MEM_STATIC U16 MEM_readLE16(const void* memPtr)
222 {
223 if (MEM_isLittleEndian())
224 return MEM_read16(memPtr);
225 else {
226 const BYTE* p = (const BYTE*)memPtr;
227 return (U16)(p[0] + (p[1]<<8));
228 }
229 }
230
231 MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
232 {
233 if (MEM_isLittleEndian()) {
234 MEM_write16(memPtr, val);
235 } else {
236 BYTE* p = (BYTE*)memPtr;
237 p[0] = (BYTE)val;
238 p[1] = (BYTE)(val>>8);
239 }
240 }
241
242 MEM_STATIC U32 MEM_readLE24(const void* memPtr)
243 {
244 return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
245 }
246
247 MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
248 {
249 MEM_writeLE16(memPtr, (U16)val);
250 ((BYTE*)memPtr)[2] = (BYTE)(val>>16);
251 }
252
253 MEM_STATIC U32 MEM_readLE32(const void* memPtr)
254 {
255 if (MEM_isLittleEndian())
256 return MEM_read32(memPtr);
257 else
258 return MEM_swap32(MEM_read32(memPtr));
259 }
260
261 MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
262 {
263 if (MEM_isLittleEndian())
264 MEM_write32(memPtr, val32);
265 else
266 MEM_write32(memPtr, MEM_swap32(val32));
267 }
268
269 MEM_STATIC U64 MEM_readLE64(const void* memPtr)
270 {
271 if (MEM_isLittleEndian())
272 return MEM_read64(memPtr);
273 else
274 return MEM_swap64(MEM_read64(memPtr));
275 }
276
277 MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
278 {
279 if (MEM_isLittleEndian())
280 MEM_write64(memPtr, val64);
281 else
282 MEM_write64(memPtr, MEM_swap64(val64));
283 }
284
285 MEM_STATIC size_t MEM_readLEST(const void* memPtr)
286 {
287 if (MEM_32bits())
288 return (size_t)MEM_readLE32(memPtr);
289 else
290 return (size_t)MEM_readLE64(memPtr);
291 }
292
293 MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
294 {
295 if (MEM_32bits())
296 MEM_writeLE32(memPtr, (U32)val);
297 else
298 MEM_writeLE64(memPtr, (U64)val);
299 }
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 MEM_STATIC U32 MEM_readMINMATCH(const void* memPtr, U32 length)
354 {
355 switch (length)
356 {
357 default :
358 case 4 : return MEM_read32(memPtr);
359 case 3 : if (MEM_isLittleEndian())
360 return MEM_read32(memPtr)<<8;
361 else
362 return MEM_read32(memPtr)>>8;
363 }
364 }
365
366 #if defined (__cplusplus)
367 }
368 #endif
369
370 #endif /* MEM_H_MODULE */