blob: ceafd57b48bdfe14812c67c5fca0a6427d5db1fd [file] [log] [blame]
Yann Colletb1f3f4b2015-10-18 22:18:32 +01001/* ******************************************************************
2 mem.h
3 low-level memory access routines
4 Copyright (C) 2013-2015, Yann Collet.
5
6 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are
10 met:
11
12 * Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above
15 copyright notice, this list of conditions and the following disclaimer
16 in the documentation and/or other materials provided with the
17 distribution.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 You can contact the author at :
32 - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
33 - Public forum : https://groups.google.com/forum/#!forum/lz4c
34****************************************************************** */
35#ifndef MEM_H_MODULE
36#define MEM_H_MODULE
37
38#if defined (__cplusplus)
39extern "C" {
40#endif
41
Yann Colletae7aa062016-02-03 02:46:46 +010042/*-****************************************
43* Dependencies
Yann Colletb1f3f4b2015-10-18 22:18:32 +010044******************************************/
45#include <stddef.h> /* size_t, ptrdiff_t */
46#include <string.h> /* memcpy */
47
48
Yann Colletae7aa062016-02-03 02:46:46 +010049/*-****************************************
50* Compiler specifics
Yann Colletb1f3f4b2015-10-18 22:18:32 +010051******************************************/
Yann Collet89db5e02015-11-13 11:27:46 +010052#if defined(__GNUC__)
53# define MEM_STATIC static __attribute__((unused))
54#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
Yann Colletb1f3f4b2015-10-18 22:18:32 +010055# define MEM_STATIC static inline
56#elif defined(_MSC_VER)
57# define MEM_STATIC static __inline
Yann Colletb1f3f4b2015-10-18 22:18:32 +010058#else
59# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
60#endif
61
62
Yann Colletae7aa062016-02-03 02:46:46 +010063/*-**************************************************************
Yann Colletb1f3f4b2015-10-18 22:18:32 +010064* Basic Types
65*****************************************************************/
66#if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
67# include <stdint.h>
68 typedef uint8_t BYTE;
69 typedef uint16_t U16;
70 typedef int16_t S16;
71 typedef uint32_t U32;
72 typedef int32_t S32;
73 typedef uint64_t U64;
74 typedef int64_t S64;
75#else
76 typedef unsigned char BYTE;
77 typedef unsigned short U16;
78 typedef signed short S16;
79 typedef unsigned int U32;
80 typedef signed int S32;
81 typedef unsigned long long U64;
82 typedef signed long long S64;
83#endif
84
85
Yann Colletae7aa062016-02-03 02:46:46 +010086/*-**************************************************************
Yann Colletb1f3f4b2015-10-18 22:18:32 +010087* Memory I/O
88*****************************************************************/
Yann Collet44886612016-02-11 04:17:50 +010089/* MEM_FORCE_MEMORY_ACCESS :
Yann Colletb1f3f4b2015-10-18 22:18:32 +010090 * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
91 * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
92 * The below switch allow to select different access method for improved performance.
93 * Method 0 (default) : use `memcpy()`. Safe and portable.
94 * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
95 * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
96 * Method 2 : direct access. This method is portable but violate C standard.
Yann Colletae7aa062016-02-03 02:46:46 +010097 * It can generate buggy code on targets depending on alignment.
98 * In some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
Yann Colletb1f3f4b2015-10-18 22:18:32 +010099 * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
100 * Prefer these methods in priority order (0 > 1 > 2)
101 */
102#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
103# 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__) )
104# define MEM_FORCE_MEMORY_ACCESS 2
105# elif defined(__INTEL_COMPILER) || \
106 (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))
107# define MEM_FORCE_MEMORY_ACCESS 1
108# endif
109#endif
110
111MEM_STATIC unsigned MEM_32bits(void) { return sizeof(void*)==4; }
112MEM_STATIC unsigned MEM_64bits(void) { return sizeof(void*)==8; }
113
114MEM_STATIC unsigned MEM_isLittleEndian(void)
115{
116 const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
117 return one.c[0];
118}
119
120#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
121
Yann Collet7d360282016-02-12 00:07:30 +0100122/* violates C standard, by lying on structure alignment.
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100123Only use if no other choice to achieve best performance on target platform */
124MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
125MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
126MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
Yann Collet7d360282016-02-12 00:07:30 +0100127MEM_STATIC U64 MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100128
129MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
130MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
131MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
132
133#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
134
135/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
136/* currently only defined for gcc and icc */
Yann Collet7d360282016-02-12 00:07:30 +0100137typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign;
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100138
139MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
140MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
141MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
Yann Collet7d360282016-02-12 00:07:30 +0100142MEM_STATIC U64 MEM_readST(const void* ptr) { return ((const unalign*)ptr)->st; }
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100143
144MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
145MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
146MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; }
147
148#else
149
150/* default method, safe and standard.
151 can sometimes prove slower */
152
153MEM_STATIC U16 MEM_read16(const void* memPtr)
154{
155 U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
156}
157
158MEM_STATIC U32 MEM_read32(const void* memPtr)
159{
160 U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
161}
162
163MEM_STATIC U64 MEM_read64(const void* memPtr)
164{
165 U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
166}
167
Yann Collet7d360282016-02-12 00:07:30 +0100168MEM_STATIC size_t MEM_readST(const void* memPtr)
169{
170 size_t val; memcpy(&val, memPtr, sizeof(val)); return val;
171}
172
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100173MEM_STATIC void MEM_write16(void* memPtr, U16 value)
174{
175 memcpy(memPtr, &value, sizeof(value));
176}
177
178MEM_STATIC void MEM_write32(void* memPtr, U32 value)
179{
180 memcpy(memPtr, &value, sizeof(value));
181}
182
183MEM_STATIC void MEM_write64(void* memPtr, U64 value)
184{
185 memcpy(memPtr, &value, sizeof(value));
186}
187
Yann Collet44886612016-02-11 04:17:50 +0100188#endif /* MEM_FORCE_MEMORY_ACCESS */
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100189
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100190MEM_STATIC U16 MEM_readLE16(const void* memPtr)
191{
192 if (MEM_isLittleEndian())
193 return MEM_read16(memPtr);
Yann Colletae7aa062016-02-03 02:46:46 +0100194 else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100195 const BYTE* p = (const BYTE*)memPtr;
196 return (U16)(p[0] + (p[1]<<8));
197 }
198}
199
200MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
201{
Yann Colletae7aa062016-02-03 02:46:46 +0100202 if (MEM_isLittleEndian()) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100203 MEM_write16(memPtr, val);
Yann Colletae7aa062016-02-03 02:46:46 +0100204 } else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100205 BYTE* p = (BYTE*)memPtr;
206 p[0] = (BYTE)val;
207 p[1] = (BYTE)(val>>8);
208 }
209}
210
211MEM_STATIC U32 MEM_readLE32(const void* memPtr)
212{
213 if (MEM_isLittleEndian())
214 return MEM_read32(memPtr);
Yann Colletae7aa062016-02-03 02:46:46 +0100215 else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100216 const BYTE* p = (const BYTE*)memPtr;
217 return (U32)((U32)p[0] + ((U32)p[1]<<8) + ((U32)p[2]<<16) + ((U32)p[3]<<24));
218 }
219}
220
221MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
222{
Yann Colletae7aa062016-02-03 02:46:46 +0100223 if (MEM_isLittleEndian()) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100224 MEM_write32(memPtr, val32);
Yann Colletae7aa062016-02-03 02:46:46 +0100225 } else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100226 BYTE* p = (BYTE*)memPtr;
227 p[0] = (BYTE)val32;
228 p[1] = (BYTE)(val32>>8);
229 p[2] = (BYTE)(val32>>16);
230 p[3] = (BYTE)(val32>>24);
231 }
232}
233
234MEM_STATIC U64 MEM_readLE64(const void* memPtr)
235{
236 if (MEM_isLittleEndian())
237 return MEM_read64(memPtr);
Yann Colletae7aa062016-02-03 02:46:46 +0100238 else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100239 const BYTE* p = (const BYTE*)memPtr;
240 return (U64)((U64)p[0] + ((U64)p[1]<<8) + ((U64)p[2]<<16) + ((U64)p[3]<<24)
241 + ((U64)p[4]<<32) + ((U64)p[5]<<40) + ((U64)p[6]<<48) + ((U64)p[7]<<56));
242 }
243}
244
245MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
246{
Yann Colletae7aa062016-02-03 02:46:46 +0100247 if (MEM_isLittleEndian()) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100248 MEM_write64(memPtr, val64);
Yann Colletae7aa062016-02-03 02:46:46 +0100249 } else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100250 BYTE* p = (BYTE*)memPtr;
251 p[0] = (BYTE)val64;
252 p[1] = (BYTE)(val64>>8);
253 p[2] = (BYTE)(val64>>16);
254 p[3] = (BYTE)(val64>>24);
255 p[4] = (BYTE)(val64>>32);
256 p[5] = (BYTE)(val64>>40);
257 p[6] = (BYTE)(val64>>48);
258 p[7] = (BYTE)(val64>>56);
259 }
260}
261
262MEM_STATIC size_t MEM_readLEST(const void* memPtr)
263{
264 if (MEM_32bits())
265 return (size_t)MEM_readLE32(memPtr);
266 else
267 return (size_t)MEM_readLE64(memPtr);
268}
269
270MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
271{
272 if (MEM_32bits())
273 MEM_writeLE32(memPtr, (U32)val);
274 else
275 MEM_writeLE64(memPtr, (U64)val);
276}
277
inikepe2446b02016-03-07 10:07:08 +0100278 /* function safe only for comparisons */
279MEM_STATIC U32 MEM_readMINMATCH(const void* memPtr, U32 length)
280{
281 switch (length)
282 {
283 default :
284 case 4 : return MEM_read32(memPtr);
285 case 3 : if (MEM_isLittleEndian())
286 return MEM_read32(memPtr)<<8;
287 else
288 return MEM_read32(memPtr)>>8;
289 }
290}
291
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100292#if defined (__cplusplus)
293}
294#endif
295
296#endif /* MEM_H_MODULE */
297