blob: 0e357e53099a277b3ce6c2fcf58c052be914dd2d [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
190
191MEM_STATIC U16 MEM_readLE16(const void* memPtr)
192{
193 if (MEM_isLittleEndian())
194 return MEM_read16(memPtr);
Yann Colletae7aa062016-02-03 02:46:46 +0100195 else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100196 const BYTE* p = (const BYTE*)memPtr;
197 return (U16)(p[0] + (p[1]<<8));
198 }
199}
200
201MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
202{
Yann Colletae7aa062016-02-03 02:46:46 +0100203 if (MEM_isLittleEndian()) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100204 MEM_write16(memPtr, val);
Yann Colletae7aa062016-02-03 02:46:46 +0100205 } else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100206 BYTE* p = (BYTE*)memPtr;
207 p[0] = (BYTE)val;
208 p[1] = (BYTE)(val>>8);
209 }
210}
211
212MEM_STATIC U32 MEM_readLE32(const void* memPtr)
213{
214 if (MEM_isLittleEndian())
215 return MEM_read32(memPtr);
Yann Colletae7aa062016-02-03 02:46:46 +0100216 else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100217 const BYTE* p = (const BYTE*)memPtr;
218 return (U32)((U32)p[0] + ((U32)p[1]<<8) + ((U32)p[2]<<16) + ((U32)p[3]<<24));
219 }
220}
221
222MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
223{
Yann Colletae7aa062016-02-03 02:46:46 +0100224 if (MEM_isLittleEndian()) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100225 MEM_write32(memPtr, val32);
Yann Colletae7aa062016-02-03 02:46:46 +0100226 } else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100227 BYTE* p = (BYTE*)memPtr;
228 p[0] = (BYTE)val32;
229 p[1] = (BYTE)(val32>>8);
230 p[2] = (BYTE)(val32>>16);
231 p[3] = (BYTE)(val32>>24);
232 }
233}
234
235MEM_STATIC U64 MEM_readLE64(const void* memPtr)
236{
237 if (MEM_isLittleEndian())
238 return MEM_read64(memPtr);
Yann Colletae7aa062016-02-03 02:46:46 +0100239 else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100240 const BYTE* p = (const BYTE*)memPtr;
241 return (U64)((U64)p[0] + ((U64)p[1]<<8) + ((U64)p[2]<<16) + ((U64)p[3]<<24)
242 + ((U64)p[4]<<32) + ((U64)p[5]<<40) + ((U64)p[6]<<48) + ((U64)p[7]<<56));
243 }
244}
245
246MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
247{
Yann Colletae7aa062016-02-03 02:46:46 +0100248 if (MEM_isLittleEndian()) {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100249 MEM_write64(memPtr, val64);
Yann Colletae7aa062016-02-03 02:46:46 +0100250 } else {
Yann Colletb1f3f4b2015-10-18 22:18:32 +0100251 BYTE* p = (BYTE*)memPtr;
252 p[0] = (BYTE)val64;
253 p[1] = (BYTE)(val64>>8);
254 p[2] = (BYTE)(val64>>16);
255 p[3] = (BYTE)(val64>>24);
256 p[4] = (BYTE)(val64>>32);
257 p[5] = (BYTE)(val64>>40);
258 p[6] = (BYTE)(val64>>48);
259 p[7] = (BYTE)(val64>>56);
260 }
261}
262
263MEM_STATIC size_t MEM_readLEST(const void* memPtr)
264{
265 if (MEM_32bits())
266 return (size_t)MEM_readLE32(memPtr);
267 else
268 return (size_t)MEM_readLE64(memPtr);
269}
270
271MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
272{
273 if (MEM_32bits())
274 MEM_writeLE32(memPtr, (U32)val);
275 else
276 MEM_writeLE64(memPtr, (U64)val);
277}
278
279#if defined (__cplusplus)
280}
281#endif
282
283#endif /* MEM_H_MODULE */
284