Mercurial > public > mercurial-scm > hg
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 */ |