mirror of
				https://github.com/facebook/zstd.git
				synced 2025-11-03 20:33:11 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			396 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			396 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* ******************************************************************
 | 
						|
   mem.h
 | 
						|
   low-level memory access routines
 | 
						|
   Copyright (C) 2013-2015, Yann Collet.
 | 
						|
 | 
						|
   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
 | 
						|
 | 
						|
   Redistribution and use in source and binary forms, with or without
 | 
						|
   modification, are permitted provided that the following conditions are
 | 
						|
   met:
 | 
						|
 | 
						|
       * Redistributions of source code must retain the above copyright
 | 
						|
   notice, this list of conditions and the following disclaimer.
 | 
						|
       * Redistributions in binary form must reproduce the above
 | 
						|
   copyright notice, this list of conditions and the following disclaimer
 | 
						|
   in the documentation and/or other materials provided with the
 | 
						|
   distribution.
 | 
						|
 | 
						|
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
						|
   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
						|
   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
						|
   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
						|
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 | 
						|
    You can contact the author at :
 | 
						|
    - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
 | 
						|
    - Public forum : https://groups.google.com/forum/#!forum/lz4c
 | 
						|
****************************************************************** */
 | 
						|
#ifndef MEM_H_MODULE
 | 
						|
#define MEM_H_MODULE
 | 
						|
 | 
						|
#if defined (__cplusplus)
 | 
						|
extern "C" {
 | 
						|
#endif
 | 
						|
 | 
						|
/*-****************************************
 | 
						|
*  Dependencies
 | 
						|
******************************************/
 | 
						|
#include <stddef.h>     /* size_t, ptrdiff_t */
 | 
						|
#include <string.h>     /* memcpy */
 | 
						|
 | 
						|
 | 
						|
/*-****************************************
 | 
						|
*  Compiler specifics
 | 
						|
******************************************/
 | 
						|
#if defined(_MSC_VER)   /* Visual Studio */
 | 
						|
#   include <stdlib.h>  /* _byteswap_ulong */
 | 
						|
#   include <intrin.h>  /* _byteswap_* */
 | 
						|
#endif
 | 
						|
#if defined(__GNUC__)
 | 
						|
#  define MEM_STATIC static __inline __attribute__((unused))
 | 
						|
#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
 | 
						|
#  define MEM_STATIC static inline
 | 
						|
#elif defined(_MSC_VER)
 | 
						|
#  define MEM_STATIC static __inline
 | 
						|
#else
 | 
						|
#  define MEM_STATIC static  /* this version may generate warnings for unused static functions; disable the relevant warning */
 | 
						|
#endif
 | 
						|
 | 
						|
/* code only tested on 32 and 64 bits systems */
 | 
						|
#define MEM_STATIC_ASSERT(c)   { enum { XXH_static_assert = 1/(int)(!!(c)) }; }
 | 
						|
MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
 | 
						|
 | 
						|
 | 
						|
/*-**************************************************************
 | 
						|
*  Basic Types
 | 
						|
*****************************************************************/
 | 
						|
#if  !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
 | 
						|
# include <stdint.h>
 | 
						|
  typedef  uint8_t BYTE;
 | 
						|
  typedef uint16_t U16;
 | 
						|
  typedef  int16_t S16;
 | 
						|
  typedef uint32_t U32;
 | 
						|
  typedef  int32_t S32;
 | 
						|
  typedef uint64_t U64;
 | 
						|
  typedef  int64_t S64;
 | 
						|
#else
 | 
						|
  typedef unsigned char       BYTE;
 | 
						|
  typedef unsigned short      U16;
 | 
						|
  typedef   signed short      S16;
 | 
						|
  typedef unsigned int        U32;
 | 
						|
  typedef   signed int        S32;
 | 
						|
  typedef unsigned long long  U64;
 | 
						|
  typedef   signed long long  S64;
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/*-**************************************************************
 | 
						|
*  Memory I/O
 | 
						|
*****************************************************************/
 | 
						|
/* MEM_FORCE_MEMORY_ACCESS :
 | 
						|
 * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
 | 
						|
 * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
 | 
						|
 * The below switch allow to select different access method for improved performance.
 | 
						|
 * Method 0 (default) : use `memcpy()`. Safe and portable.
 | 
						|
 * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
 | 
						|
 *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
 | 
						|
 * Method 2 : direct access. This method is portable but violate C standard.
 | 
						|
 *            It can generate buggy code on targets depending on alignment.
 | 
						|
 *            In some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
 | 
						|
 * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
 | 
						|
 * Prefer these methods in priority order (0 > 1 > 2)
 | 
						|
 */
 | 
						|
#ifndef MEM_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */
 | 
						|
#  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__) )
 | 
						|
#    define MEM_FORCE_MEMORY_ACCESS 2
 | 
						|
#  elif defined(__INTEL_COMPILER) /*|| defined(_MSC_VER)*/ || \
 | 
						|
  (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))
 | 
						|
#    define MEM_FORCE_MEMORY_ACCESS 1
 | 
						|
#  endif
 | 
						|
#endif
 | 
						|
 | 
						|
MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
 | 
						|
MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
 | 
						|
 | 
						|
MEM_STATIC unsigned MEM_isLittleEndian(void)
 | 
						|
{
 | 
						|
    const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental  */
 | 
						|
    return one.c[0];
 | 
						|
}
 | 
						|
 | 
						|
#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
 | 
						|
 | 
						|
/* violates C standard, by lying on structure alignment.
 | 
						|
Only use if no other choice to achieve best performance on target platform */
 | 
						|
MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
 | 
						|
MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
 | 
						|
MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
 | 
						|
MEM_STATIC U64 MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }
 | 
						|
 | 
						|
MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
 | 
						|
MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
 | 
						|
MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
 | 
						|
 | 
						|
#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
 | 
						|
 | 
						|
/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
 | 
						|
/* currently only defined for gcc and icc */
 | 
						|
#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))
 | 
						|
	__pragma( pack(push, 1) )
 | 
						|
    typedef union { U16 u16; U32 u32; U64 u64; size_t st; } unalign;
 | 
						|
    __pragma( pack(pop) )
 | 
						|
#else
 | 
						|
    typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign;
 | 
						|
#endif
 | 
						|
 | 
						|
MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
 | 
						|
MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
 | 
						|
MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
 | 
						|
MEM_STATIC U64 MEM_readST(const void* ptr) { return ((const unalign*)ptr)->st; }
 | 
						|
 | 
						|
MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
 | 
						|
MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
 | 
						|
MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; }
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
/* default method, safe and standard.
 | 
						|
   can sometimes prove slower */
 | 
						|
 | 
						|
MEM_STATIC U16 MEM_read16(const void* memPtr)
 | 
						|
{
 | 
						|
    U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC U32 MEM_read32(const void* memPtr)
 | 
						|
{
 | 
						|
    U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC U64 MEM_read64(const void* memPtr)
 | 
						|
{
 | 
						|
    U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC size_t MEM_readST(const void* memPtr)
 | 
						|
{
 | 
						|
    size_t val; memcpy(&val, memPtr, sizeof(val)); return val;
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC void MEM_write16(void* memPtr, U16 value)
 | 
						|
{
 | 
						|
    memcpy(memPtr, &value, sizeof(value));
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC void MEM_write32(void* memPtr, U32 value)
 | 
						|
{
 | 
						|
    memcpy(memPtr, &value, sizeof(value));
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC void MEM_write64(void* memPtr, U64 value)
 | 
						|
{
 | 
						|
    memcpy(memPtr, &value, sizeof(value));
 | 
						|
}
 | 
						|
 | 
						|
#endif /* MEM_FORCE_MEMORY_ACCESS */
 | 
						|
 | 
						|
MEM_STATIC U32 MEM_swap32(U32 in)
 | 
						|
{
 | 
						|
#if defined(_MSC_VER)     /* Visual Studio */
 | 
						|
    return _byteswap_ulong(in);
 | 
						|
#elif defined (__GNUC__)
 | 
						|
    return __builtin_bswap32(in);
 | 
						|
#else
 | 
						|
    return  ((in << 24) & 0xff000000 ) |
 | 
						|
            ((in <<  8) & 0x00ff0000 ) |
 | 
						|
            ((in >>  8) & 0x0000ff00 ) |
 | 
						|
            ((in >> 24) & 0x000000ff );
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC U64 MEM_swap64(U64 in)
 | 
						|
{
 | 
						|
#if defined(_MSC_VER)     /* Visual Studio */
 | 
						|
    return _byteswap_uint64(in);
 | 
						|
#elif defined (__GNUC__)
 | 
						|
    return __builtin_bswap64(in);
 | 
						|
#else
 | 
						|
    return  ((in << 56) & 0xff00000000000000ULL) |
 | 
						|
            ((in << 40) & 0x00ff000000000000ULL) |
 | 
						|
            ((in << 24) & 0x0000ff0000000000ULL) |
 | 
						|
            ((in << 8)  & 0x000000ff00000000ULL) |
 | 
						|
            ((in >> 8)  & 0x00000000ff000000ULL) |
 | 
						|
            ((in >> 24) & 0x0000000000ff0000ULL) |
 | 
						|
            ((in >> 40) & 0x000000000000ff00ULL) |
 | 
						|
            ((in >> 56) & 0x00000000000000ffULL);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC size_t MEM_swapST(size_t in)
 | 
						|
{
 | 
						|
    if (MEM_32bits())
 | 
						|
        return (size_t)MEM_swap32((U32)in);
 | 
						|
    else
 | 
						|
        return (size_t)MEM_swap64((U64)in);
 | 
						|
}
 | 
						|
 | 
						|
/*=== Little endian r/w ===*/
 | 
						|
 | 
						|
MEM_STATIC U16 MEM_readLE16(const void* memPtr)
 | 
						|
{
 | 
						|
    if (MEM_isLittleEndian())
 | 
						|
        return MEM_read16(memPtr);
 | 
						|
    else {
 | 
						|
        const BYTE* p = (const BYTE*)memPtr;
 | 
						|
        return (U16)(p[0] + (p[1]<<8));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
 | 
						|
{
 | 
						|
    if (MEM_isLittleEndian()) {
 | 
						|
        MEM_write16(memPtr, val);
 | 
						|
    } else {
 | 
						|
        BYTE* p = (BYTE*)memPtr;
 | 
						|
        p[0] = (BYTE)val;
 | 
						|
        p[1] = (BYTE)(val>>8);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC U32 MEM_readLE24(const void* memPtr)
 | 
						|
{
 | 
						|
    return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
 | 
						|
{
 | 
						|
    MEM_writeLE16(memPtr, (U16)val);
 | 
						|
    ((BYTE*)memPtr)[2] = (BYTE)(val>>16);
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC U32 MEM_readLE32(const void* memPtr)
 | 
						|
{
 | 
						|
    if (MEM_isLittleEndian())
 | 
						|
        return MEM_read32(memPtr);
 | 
						|
    else
 | 
						|
        return MEM_swap32(MEM_read32(memPtr));
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
 | 
						|
{
 | 
						|
    if (MEM_isLittleEndian())
 | 
						|
        MEM_write32(memPtr, val32);
 | 
						|
    else
 | 
						|
        MEM_write32(memPtr, MEM_swap32(val32));
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC U64 MEM_readLE64(const void* memPtr)
 | 
						|
{
 | 
						|
    if (MEM_isLittleEndian())
 | 
						|
        return MEM_read64(memPtr);
 | 
						|
    else
 | 
						|
        return MEM_swap64(MEM_read64(memPtr));
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
 | 
						|
{
 | 
						|
    if (MEM_isLittleEndian())
 | 
						|
        MEM_write64(memPtr, val64);
 | 
						|
    else
 | 
						|
        MEM_write64(memPtr, MEM_swap64(val64));
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC size_t MEM_readLEST(const void* memPtr)
 | 
						|
{
 | 
						|
    if (MEM_32bits())
 | 
						|
        return (size_t)MEM_readLE32(memPtr);
 | 
						|
    else
 | 
						|
        return (size_t)MEM_readLE64(memPtr);
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
 | 
						|
{
 | 
						|
    if (MEM_32bits())
 | 
						|
        MEM_writeLE32(memPtr, (U32)val);
 | 
						|
    else
 | 
						|
        MEM_writeLE64(memPtr, (U64)val);
 | 
						|
}
 | 
						|
 | 
						|
/*=== Big endian r/w ===*/
 | 
						|
 | 
						|
MEM_STATIC U32 MEM_readBE32(const void* memPtr)
 | 
						|
{
 | 
						|
    if (MEM_isLittleEndian())
 | 
						|
        return MEM_swap32(MEM_read32(memPtr));
 | 
						|
    else
 | 
						|
        return MEM_read32(memPtr);
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
 | 
						|
{
 | 
						|
    if (MEM_isLittleEndian())
 | 
						|
        MEM_write32(memPtr, MEM_swap32(val32));
 | 
						|
    else
 | 
						|
        MEM_write32(memPtr, val32);
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC U64 MEM_readBE64(const void* memPtr)
 | 
						|
{
 | 
						|
    if (MEM_isLittleEndian())
 | 
						|
        return MEM_swap64(MEM_read64(memPtr));
 | 
						|
    else
 | 
						|
        return MEM_read64(memPtr);
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
 | 
						|
{
 | 
						|
    if (MEM_isLittleEndian())
 | 
						|
        MEM_write64(memPtr, MEM_swap64(val64));
 | 
						|
    else
 | 
						|
        MEM_write64(memPtr, val64);
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC size_t MEM_readBEST(const void* memPtr)
 | 
						|
{
 | 
						|
    if (MEM_32bits())
 | 
						|
        return (size_t)MEM_readBE32(memPtr);
 | 
						|
    else
 | 
						|
        return (size_t)MEM_readBE64(memPtr);
 | 
						|
}
 | 
						|
 | 
						|
MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
 | 
						|
{
 | 
						|
    if (MEM_32bits())
 | 
						|
        MEM_writeBE32(memPtr, (U32)val);
 | 
						|
    else
 | 
						|
        MEM_writeBE64(memPtr, (U64)val);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* function safe only for comparisons */
 | 
						|
MEM_STATIC U32 MEM_readMINMATCH(const void* memPtr, U32 length)
 | 
						|
{
 | 
						|
    switch (length)
 | 
						|
    {
 | 
						|
    default :
 | 
						|
    case 4 : return MEM_read32(memPtr);
 | 
						|
    case 3 : if (MEM_isLittleEndian())
 | 
						|
                return MEM_read32(memPtr)<<8;
 | 
						|
             else
 | 
						|
                return MEM_read32(memPtr)>>8;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#if defined (__cplusplus)
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#endif /* MEM_H_MODULE */
 |