blob: 8ac56ed9a4769e05fcb17551de6edd9de9c6d36a [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
42/******************************************
43* Includes
44******************************************/
45#include <stddef.h> /* size_t, ptrdiff_t */
46#include <string.h> /* memcpy */
47
48
49/******************************************
50* Compiler-specific
51******************************************/
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
63/****************************************************************
64* 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
86/****************************************************************
87* Memory I/O
88*****************************************************************/
89/* MEM_FORCE_MEMORY_ACCESS
90 * 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.
97 * It can generate buggy code on targets generating assembly depending on alignment.
98 * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
99 * 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);
188 else
189 {
190 const BYTE* p = (const BYTE*)memPtr;
191 return (U16)(p[0] + (p[1]<<8));
192 }
193}
194
195MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
196{
197 if (MEM_isLittleEndian())
198 {
199 MEM_write16(memPtr, val);
200 }
201 else
202 {
203 BYTE* p = (BYTE*)memPtr;
204 p[0] = (BYTE)val;
205 p[1] = (BYTE)(val>>8);
206 }
207}
208
209MEM_STATIC U32 MEM_readLE32(const void* memPtr)
210{
211 if (MEM_isLittleEndian())
212 return MEM_read32(memPtr);
213 else
214 {
215 const BYTE* p = (const BYTE*)memPtr;
216 return (U32)((U32)p[0] + ((U32)p[1]<<8) + ((U32)p[2]<<16) + ((U32)p[3]<<24));
217 }
218}
219
220MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
221{
222 if (MEM_isLittleEndian())
223 {
224 MEM_write32(memPtr, val32);
225 }
226 else
227 {
228 BYTE* p = (BYTE*)memPtr;
229 p[0] = (BYTE)val32;
230 p[1] = (BYTE)(val32>>8);
231 p[2] = (BYTE)(val32>>16);
232 p[3] = (BYTE)(val32>>24);
233 }
234}
235
236MEM_STATIC U64 MEM_readLE64(const void* memPtr)
237{
238 if (MEM_isLittleEndian())
239 return MEM_read64(memPtr);
240 else
241 {
242 const BYTE* p = (const BYTE*)memPtr;
243 return (U64)((U64)p[0] + ((U64)p[1]<<8) + ((U64)p[2]<<16) + ((U64)p[3]<<24)
244 + ((U64)p[4]<<32) + ((U64)p[5]<<40) + ((U64)p[6]<<48) + ((U64)p[7]<<56));
245 }
246}
247
248MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
249{
250 if (MEM_isLittleEndian())
251 {
252 MEM_write64(memPtr, val64);
253 }
254 else
255 {
256 BYTE* p = (BYTE*)memPtr;
257 p[0] = (BYTE)val64;
258 p[1] = (BYTE)(val64>>8);
259 p[2] = (BYTE)(val64>>16);
260 p[3] = (BYTE)(val64>>24);
261 p[4] = (BYTE)(val64>>32);
262 p[5] = (BYTE)(val64>>40);
263 p[6] = (BYTE)(val64>>48);
264 p[7] = (BYTE)(val64>>56);
265 }
266}
267
268MEM_STATIC size_t MEM_readLEST(const void* memPtr)
269{
270 if (MEM_32bits())
271 return (size_t)MEM_readLE32(memPtr);
272 else
273 return (size_t)MEM_readLE64(memPtr);
274}
275
276MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
277{
278 if (MEM_32bits())
279 MEM_writeLE32(memPtr, (U32)val);
280 else
281 MEM_writeLE64(memPtr, (U64)val);
282}
283
284#if defined (__cplusplus)
285}
286#endif
287
288#endif /* MEM_H_MODULE */
289