blob: 36ba06f062db2be706cb336581a1c12178280e14 [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 Colletae7aa062016-02-03 02:46:46 +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
122/* violates C standard on structure alignment.
123Only 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; }
127
128MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
129MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
130MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
131
132#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
133
134/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
135/* currently only defined for gcc and icc */
136typedef union { U16 u16; U32 u32; U64 u64; } __attribute__((packed)) unalign;
137
138MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
139MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
140MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
141
142MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
143MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
144MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; }
145
146#else
147
148/* default method, safe and standard.
149 can sometimes prove slower */
150
151MEM_STATIC U16 MEM_read16(const void* memPtr)
152{
153 U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
154}
155
156MEM_STATIC U32 MEM_read32(const void* memPtr)
157{
158 U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
159}
160
161MEM_STATIC U64 MEM_read64(const void* memPtr)
162{
163 U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
164}
165
166MEM_STATIC void MEM_write16(void* memPtr, U16 value)
167{
168 memcpy(memPtr, &value, sizeof(value));
169}
170
171MEM_STATIC void MEM_write32(void* memPtr, U32 value)
172{
173 memcpy(memPtr, &value, sizeof(value));
174}
175
176MEM_STATIC void MEM_write64(void* memPtr, U64 value)
177{
178 memcpy(memPtr, &value, sizeof(value));
179}
180
181#endif // MEM_FORCE_MEMORY_ACCESS
182
183
184MEM_STATIC U16 MEM_readLE16(const void* memPtr)
185{
186 if (MEM_isLittleEndian())
187 return MEM_read16(memPtr);
Yann Colletae7aa062016-02-03 02:46:46 +0100188 else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100189 const BYTE* p = (const BYTE*)memPtr;
190 return (U16)(p[0] + (p[1]<<8));
191 }
192}
193
194MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
195{
Yann Colletae7aa062016-02-03 02:46:46 +0100196 if (MEM_isLittleEndian()) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100197 MEM_write16(memPtr, val);
Yann Colletae7aa062016-02-03 02:46:46 +0100198 } else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100199 BYTE* p = (BYTE*)memPtr;
200 p[0] = (BYTE)val;
201 p[1] = (BYTE)(val>>8);
202 }
203}
204
205MEM_STATIC U32 MEM_readLE32(const void* memPtr)
206{
207 if (MEM_isLittleEndian())
208 return MEM_read32(memPtr);
Yann Colletae7aa062016-02-03 02:46:46 +0100209 else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100210 const BYTE* p = (const BYTE*)memPtr;
211 return (U32)((U32)p[0] + ((U32)p[1]<<8) + ((U32)p[2]<<16) + ((U32)p[3]<<24));
212 }
213}
214
215MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
216{
Yann Colletae7aa062016-02-03 02:46:46 +0100217 if (MEM_isLittleEndian()) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100218 MEM_write32(memPtr, val32);
Yann Colletae7aa062016-02-03 02:46:46 +0100219 } else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100220 BYTE* p = (BYTE*)memPtr;
221 p[0] = (BYTE)val32;
222 p[1] = (BYTE)(val32>>8);
223 p[2] = (BYTE)(val32>>16);
224 p[3] = (BYTE)(val32>>24);
225 }
226}
227
228MEM_STATIC U64 MEM_readLE64(const void* memPtr)
229{
230 if (MEM_isLittleEndian())
231 return MEM_read64(memPtr);
Yann Colletae7aa062016-02-03 02:46:46 +0100232 else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100233 const BYTE* p = (const BYTE*)memPtr;
234 return (U64)((U64)p[0] + ((U64)p[1]<<8) + ((U64)p[2]<<16) + ((U64)p[3]<<24)
235 + ((U64)p[4]<<32) + ((U64)p[5]<<40) + ((U64)p[6]<<48) + ((U64)p[7]<<56));
236 }
237}
238
239MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
240{
Yann Colletae7aa062016-02-03 02:46:46 +0100241 if (MEM_isLittleEndian()) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100242 MEM_write64(memPtr, val64);
Yann Colletae7aa062016-02-03 02:46:46 +0100243 } else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100244 BYTE* p = (BYTE*)memPtr;
245 p[0] = (BYTE)val64;
246 p[1] = (BYTE)(val64>>8);
247 p[2] = (BYTE)(val64>>16);
248 p[3] = (BYTE)(val64>>24);
249 p[4] = (BYTE)(val64>>32);
250 p[5] = (BYTE)(val64>>40);
251 p[6] = (BYTE)(val64>>48);
252 p[7] = (BYTE)(val64>>56);
253 }
254}
255
256MEM_STATIC size_t MEM_readLEST(const void* memPtr)
257{
258 if (MEM_32bits())
259 return (size_t)MEM_readLE32(memPtr);
260 else
261 return (size_t)MEM_readLE64(memPtr);
262}
263
264MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
265{
266 if (MEM_32bits())
267 MEM_writeLE32(memPtr, (U32)val);
268 else
269 MEM_writeLE64(memPtr, (U64)val);
270}
271
272#if defined (__cplusplus)
273}
274#endif
275
276#endif /* MEM_H_MODULE */
277