Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmzstd/lib/common/mem.h
3158 views
1
/*
2
* Copyright (c) Meta Platforms, Inc. and affiliates.
3
* All rights reserved.
4
*
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).
8
* You may select, at your option, one of the above-listed licenses.
9
*/
10
11
#ifndef MEM_H_MODULE
12
#define MEM_H_MODULE
13
14
#if defined (__cplusplus)
15
extern "C" {
16
#endif
17
18
/*-****************************************
19
* Dependencies
20
******************************************/
21
#include <stddef.h> /* size_t, ptrdiff_t */
22
#include "compiler.h" /* __has_builtin */
23
#include "debug.h" /* DEBUG_STATIC_ASSERT */
24
#include "zstd_deps.h" /* ZSTD_memcpy */
25
26
27
/*-****************************************
28
* Compiler specifics
29
******************************************/
30
#if defined(_MSC_VER) /* Visual Studio */
31
# include <stdlib.h> /* _byteswap_ulong */
32
# include <intrin.h> /* _byteswap_* */
33
#endif
34
#if defined(__GNUC__)
35
# define MEM_STATIC static __inline __attribute__((unused))
36
#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
37
# define MEM_STATIC static inline
38
#elif defined(_MSC_VER)
39
# define MEM_STATIC static __inline
40
#else
41
# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
42
#endif
43
44
/*-**************************************************************
45
* Basic Types
46
*****************************************************************/
47
#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
48
# if defined(_AIX)
49
# include <inttypes.h>
50
# else
51
# include <stdint.h> /* intptr_t */
52
# endif
53
typedef uint8_t BYTE;
54
typedef uint8_t U8;
55
typedef int8_t S8;
56
typedef uint16_t U16;
57
typedef int16_t S16;
58
typedef uint32_t U32;
59
typedef int32_t S32;
60
typedef uint64_t U64;
61
typedef int64_t S64;
62
#else
63
# include <limits.h>
64
#if CHAR_BIT != 8
65
# error "this implementation requires char to be exactly 8-bit type"
66
#endif
67
typedef unsigned char BYTE;
68
typedef unsigned char U8;
69
typedef signed char S8;
70
#if USHRT_MAX != 65535
71
# error "this implementation requires short to be exactly 16-bit type"
72
#endif
73
typedef unsigned short U16;
74
typedef signed short S16;
75
#if UINT_MAX != 4294967295
76
# error "this implementation requires int to be exactly 32-bit type"
77
#endif
78
typedef unsigned int U32;
79
typedef signed int S32;
80
/* note : there are no limits defined for long long type in C90.
81
* limits exist in C99, however, in such case, <stdint.h> is preferred */
82
typedef unsigned long long U64;
83
typedef signed long long S64;
84
#endif
85
86
87
/*-**************************************************************
88
* Memory I/O API
89
*****************************************************************/
90
/*=== Static platform detection ===*/
91
MEM_STATIC unsigned MEM_32bits(void);
92
MEM_STATIC unsigned MEM_64bits(void);
93
MEM_STATIC unsigned MEM_isLittleEndian(void);
94
95
/*=== Native unaligned read/write ===*/
96
MEM_STATIC U16 MEM_read16(const void* memPtr);
97
MEM_STATIC U32 MEM_read32(const void* memPtr);
98
MEM_STATIC U64 MEM_read64(const void* memPtr);
99
MEM_STATIC size_t MEM_readST(const void* memPtr);
100
101
MEM_STATIC void MEM_write16(void* memPtr, U16 value);
102
MEM_STATIC void MEM_write32(void* memPtr, U32 value);
103
MEM_STATIC void MEM_write64(void* memPtr, U64 value);
104
105
/*=== Little endian unaligned read/write ===*/
106
MEM_STATIC U16 MEM_readLE16(const void* memPtr);
107
MEM_STATIC U32 MEM_readLE24(const void* memPtr);
108
MEM_STATIC U32 MEM_readLE32(const void* memPtr);
109
MEM_STATIC U64 MEM_readLE64(const void* memPtr);
110
MEM_STATIC size_t MEM_readLEST(const void* memPtr);
111
112
MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val);
113
MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val);
114
MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32);
115
MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64);
116
MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val);
117
118
/*=== Big endian unaligned read/write ===*/
119
MEM_STATIC U32 MEM_readBE32(const void* memPtr);
120
MEM_STATIC U64 MEM_readBE64(const void* memPtr);
121
MEM_STATIC size_t MEM_readBEST(const void* memPtr);
122
123
MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32);
124
MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64);
125
MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val);
126
127
/*=== Byteswap ===*/
128
MEM_STATIC U32 MEM_swap32(U32 in);
129
MEM_STATIC U64 MEM_swap64(U64 in);
130
MEM_STATIC size_t MEM_swapST(size_t in);
131
132
133
/*-**************************************************************
134
* Memory I/O Implementation
135
*****************************************************************/
136
/* MEM_FORCE_MEMORY_ACCESS : For accessing unaligned memory:
137
* Method 0 : always use `memcpy()`. Safe and portable.
138
* Method 1 : Use compiler extension to set unaligned access.
139
* Method 2 : direct access. This method is portable but violate C standard.
140
* It can generate buggy code on targets depending on alignment.
141
* Default : method 1 if supported, else method 0
142
*/
143
#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
144
# ifdef __GNUC__
145
# define MEM_FORCE_MEMORY_ACCESS 1
146
# endif
147
#endif
148
149
MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
150
MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
151
152
MEM_STATIC unsigned MEM_isLittleEndian(void)
153
{
154
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
155
return 1;
156
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
157
return 0;
158
#elif defined(__clang__) && __LITTLE_ENDIAN__
159
return 1;
160
#elif defined(__clang__) && __BIG_ENDIAN__
161
return 0;
162
#elif defined(_MSC_VER) && (_M_AMD64 || _M_IX86)
163
return 1;
164
#elif defined(__DMC__) && defined(_M_IX86)
165
return 1;
166
#else
167
const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
168
return one.c[0];
169
#endif
170
}
171
172
#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
173
174
/* violates C standard, by lying on structure alignment.
175
Only use if no other choice to achieve best performance on target platform */
176
MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
177
MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
178
MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
179
MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }
180
181
MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
182
MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
183
MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
184
185
#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
186
187
typedef __attribute__((aligned(1))) U16 unalign16;
188
typedef __attribute__((aligned(1))) U32 unalign32;
189
typedef __attribute__((aligned(1))) U64 unalign64;
190
typedef __attribute__((aligned(1))) size_t unalignArch;
191
192
MEM_STATIC U16 MEM_read16(const void* ptr) { return *(const unalign16*)ptr; }
193
MEM_STATIC U32 MEM_read32(const void* ptr) { return *(const unalign32*)ptr; }
194
MEM_STATIC U64 MEM_read64(const void* ptr) { return *(const unalign64*)ptr; }
195
MEM_STATIC size_t MEM_readST(const void* ptr) { return *(const unalignArch*)ptr; }
196
197
MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(unalign16*)memPtr = value; }
198
MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(unalign32*)memPtr = value; }
199
MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(unalign64*)memPtr = value; }
200
201
#else
202
203
/* default method, safe and standard.
204
can sometimes prove slower */
205
206
MEM_STATIC U16 MEM_read16(const void* memPtr)
207
{
208
U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
209
}
210
211
MEM_STATIC U32 MEM_read32(const void* memPtr)
212
{
213
U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
214
}
215
216
MEM_STATIC U64 MEM_read64(const void* memPtr)
217
{
218
U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
219
}
220
221
MEM_STATIC size_t MEM_readST(const void* memPtr)
222
{
223
size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
224
}
225
226
MEM_STATIC void MEM_write16(void* memPtr, U16 value)
227
{
228
ZSTD_memcpy(memPtr, &value, sizeof(value));
229
}
230
231
MEM_STATIC void MEM_write32(void* memPtr, U32 value)
232
{
233
ZSTD_memcpy(memPtr, &value, sizeof(value));
234
}
235
236
MEM_STATIC void MEM_write64(void* memPtr, U64 value)
237
{
238
ZSTD_memcpy(memPtr, &value, sizeof(value));
239
}
240
241
#endif /* MEM_FORCE_MEMORY_ACCESS */
242
243
MEM_STATIC U32 MEM_swap32_fallback(U32 in)
244
{
245
return ((in << 24) & 0xff000000 ) |
246
((in << 8) & 0x00ff0000 ) |
247
((in >> 8) & 0x0000ff00 ) |
248
((in >> 24) & 0x000000ff );
249
}
250
251
MEM_STATIC U32 MEM_swap32(U32 in)
252
{
253
#if defined(_MSC_VER) /* Visual Studio */
254
return _byteswap_ulong(in);
255
#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
256
|| (defined(__clang__) && __has_builtin(__builtin_bswap32))
257
return __builtin_bswap32(in);
258
#else
259
return MEM_swap32_fallback(in);
260
#endif
261
}
262
263
MEM_STATIC U64 MEM_swap64_fallback(U64 in)
264
{
265
return ((in << 56) & 0xff00000000000000ULL) |
266
((in << 40) & 0x00ff000000000000ULL) |
267
((in << 24) & 0x0000ff0000000000ULL) |
268
((in << 8) & 0x000000ff00000000ULL) |
269
((in >> 8) & 0x00000000ff000000ULL) |
270
((in >> 24) & 0x0000000000ff0000ULL) |
271
((in >> 40) & 0x000000000000ff00ULL) |
272
((in >> 56) & 0x00000000000000ffULL);
273
}
274
275
MEM_STATIC U64 MEM_swap64(U64 in)
276
{
277
#if defined(_MSC_VER) /* Visual Studio */
278
return _byteswap_uint64(in);
279
#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
280
|| (defined(__clang__) && __has_builtin(__builtin_bswap64))
281
return __builtin_bswap64(in);
282
#else
283
return MEM_swap64_fallback(in);
284
#endif
285
}
286
287
MEM_STATIC size_t MEM_swapST(size_t in)
288
{
289
if (MEM_32bits())
290
return (size_t)MEM_swap32((U32)in);
291
else
292
return (size_t)MEM_swap64((U64)in);
293
}
294
295
/*=== Little endian r/w ===*/
296
297
MEM_STATIC U16 MEM_readLE16(const void* memPtr)
298
{
299
if (MEM_isLittleEndian())
300
return MEM_read16(memPtr);
301
else {
302
const BYTE* p = (const BYTE*)memPtr;
303
return (U16)(p[0] + (p[1]<<8));
304
}
305
}
306
307
MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
308
{
309
if (MEM_isLittleEndian()) {
310
MEM_write16(memPtr, val);
311
} else {
312
BYTE* p = (BYTE*)memPtr;
313
p[0] = (BYTE)val;
314
p[1] = (BYTE)(val>>8);
315
}
316
}
317
318
MEM_STATIC U32 MEM_readLE24(const void* memPtr)
319
{
320
return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16);
321
}
322
323
MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
324
{
325
MEM_writeLE16(memPtr, (U16)val);
326
((BYTE*)memPtr)[2] = (BYTE)(val>>16);
327
}
328
329
MEM_STATIC U32 MEM_readLE32(const void* memPtr)
330
{
331
if (MEM_isLittleEndian())
332
return MEM_read32(memPtr);
333
else
334
return MEM_swap32(MEM_read32(memPtr));
335
}
336
337
MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
338
{
339
if (MEM_isLittleEndian())
340
MEM_write32(memPtr, val32);
341
else
342
MEM_write32(memPtr, MEM_swap32(val32));
343
}
344
345
MEM_STATIC U64 MEM_readLE64(const void* memPtr)
346
{
347
if (MEM_isLittleEndian())
348
return MEM_read64(memPtr);
349
else
350
return MEM_swap64(MEM_read64(memPtr));
351
}
352
353
MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
354
{
355
if (MEM_isLittleEndian())
356
MEM_write64(memPtr, val64);
357
else
358
MEM_write64(memPtr, MEM_swap64(val64));
359
}
360
361
MEM_STATIC size_t MEM_readLEST(const void* memPtr)
362
{
363
if (MEM_32bits())
364
return (size_t)MEM_readLE32(memPtr);
365
else
366
return (size_t)MEM_readLE64(memPtr);
367
}
368
369
MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
370
{
371
if (MEM_32bits())
372
MEM_writeLE32(memPtr, (U32)val);
373
else
374
MEM_writeLE64(memPtr, (U64)val);
375
}
376
377
/*=== Big endian r/w ===*/
378
379
MEM_STATIC U32 MEM_readBE32(const void* memPtr)
380
{
381
if (MEM_isLittleEndian())
382
return MEM_swap32(MEM_read32(memPtr));
383
else
384
return MEM_read32(memPtr);
385
}
386
387
MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
388
{
389
if (MEM_isLittleEndian())
390
MEM_write32(memPtr, MEM_swap32(val32));
391
else
392
MEM_write32(memPtr, val32);
393
}
394
395
MEM_STATIC U64 MEM_readBE64(const void* memPtr)
396
{
397
if (MEM_isLittleEndian())
398
return MEM_swap64(MEM_read64(memPtr));
399
else
400
return MEM_read64(memPtr);
401
}
402
403
MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
404
{
405
if (MEM_isLittleEndian())
406
MEM_write64(memPtr, MEM_swap64(val64));
407
else
408
MEM_write64(memPtr, val64);
409
}
410
411
MEM_STATIC size_t MEM_readBEST(const void* memPtr)
412
{
413
if (MEM_32bits())
414
return (size_t)MEM_readBE32(memPtr);
415
else
416
return (size_t)MEM_readBE64(memPtr);
417
}
418
419
MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
420
{
421
if (MEM_32bits())
422
MEM_writeBE32(memPtr, (U32)val);
423
else
424
MEM_writeBE64(memPtr, (U64)val);
425
}
426
427
/* code only tested on 32 and 64 bits systems */
428
MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
429
430
431
#if defined (__cplusplus)
432
}
433
#endif
434
435
#endif /* MEM_H_MODULE */
436
437