Path: blob/main/sys/contrib/zstd/lib/common/mem.h
106144 views
/*1* Copyright (c) Yann Collet, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under both the BSD-style license (found in the5* LICENSE file in the root directory of this source tree) and the GPLv2 (found6* in the COPYING file in the root directory of this source tree).7* You may select, at your option, one of the above-listed licenses.8*/910#ifndef MEM_H_MODULE11#define MEM_H_MODULE1213#if defined (__cplusplus)14extern "C" {15#endif1617/*-****************************************18* Dependencies19******************************************/20#include <stddef.h> /* size_t, ptrdiff_t */21#include "compiler.h" /* __has_builtin */22#include "debug.h" /* DEBUG_STATIC_ASSERT */23#include "zstd_deps.h" /* ZSTD_memcpy */242526/*-****************************************27* Compiler specifics28******************************************/29#if defined(_MSC_VER) /* Visual Studio */30# include <stdlib.h> /* _byteswap_ulong */31# include <intrin.h> /* _byteswap_* */32#endif33#if defined(__GNUC__)34# define MEM_STATIC static __inline __attribute__((unused))35#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)36# define MEM_STATIC static inline37#elif defined(_MSC_VER)38# define MEM_STATIC static __inline39#else40# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */41#endif4243/*-**************************************************************44* Basic Types45*****************************************************************/46#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )47# if defined(_AIX)48# include <inttypes.h>49# else50# include <stdint.h> /* intptr_t */51# endif52typedef uint8_t BYTE;53typedef uint8_t U8;54typedef int8_t S8;55typedef uint16_t U16;56typedef int16_t S16;57typedef uint32_t U32;58typedef int32_t S32;59typedef uint64_t U64;60typedef int64_t S64;61#else62# include <limits.h>63#if CHAR_BIT != 864# error "this implementation requires char to be exactly 8-bit type"65#endif66typedef unsigned char BYTE;67typedef unsigned char U8;68typedef signed char S8;69#if USHRT_MAX != 6553570# error "this implementation requires short to be exactly 16-bit type"71#endif72typedef unsigned short U16;73typedef signed short S16;74#if UINT_MAX != 429496729575# error "this implementation requires int to be exactly 32-bit type"76#endif77typedef unsigned int U32;78typedef signed int S32;79/* note : there are no limits defined for long long type in C90.80* limits exist in C99, however, in such case, <stdint.h> is preferred */81typedef unsigned long long U64;82typedef signed long long S64;83#endif848586/*-**************************************************************87* Memory I/O API88*****************************************************************/89/*=== Static platform detection ===*/90MEM_STATIC unsigned MEM_32bits(void);91MEM_STATIC unsigned MEM_64bits(void);92MEM_STATIC unsigned MEM_isLittleEndian(void);9394/*=== Native unaligned read/write ===*/95MEM_STATIC U16 MEM_read16(const void* memPtr);96MEM_STATIC U32 MEM_read32(const void* memPtr);97MEM_STATIC U64 MEM_read64(const void* memPtr);98MEM_STATIC size_t MEM_readST(const void* memPtr);99100MEM_STATIC void MEM_write16(void* memPtr, U16 value);101MEM_STATIC void MEM_write32(void* memPtr, U32 value);102MEM_STATIC void MEM_write64(void* memPtr, U64 value);103104/*=== Little endian unaligned read/write ===*/105MEM_STATIC U16 MEM_readLE16(const void* memPtr);106MEM_STATIC U32 MEM_readLE24(const void* memPtr);107MEM_STATIC U32 MEM_readLE32(const void* memPtr);108MEM_STATIC U64 MEM_readLE64(const void* memPtr);109MEM_STATIC size_t MEM_readLEST(const void* memPtr);110111MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val);112MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val);113MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32);114MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64);115MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val);116117/*=== Big endian unaligned read/write ===*/118MEM_STATIC U32 MEM_readBE32(const void* memPtr);119MEM_STATIC U64 MEM_readBE64(const void* memPtr);120MEM_STATIC size_t MEM_readBEST(const void* memPtr);121122MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32);123MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64);124MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val);125126/*=== Byteswap ===*/127MEM_STATIC U32 MEM_swap32(U32 in);128MEM_STATIC U64 MEM_swap64(U64 in);129MEM_STATIC size_t MEM_swapST(size_t in);130131132/*-**************************************************************133* Memory I/O Implementation134*****************************************************************/135/* MEM_FORCE_MEMORY_ACCESS :136* By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.137* Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.138* The below switch allow to select different access method for improved performance.139* Method 0 (default) : use `memcpy()`. Safe and portable.140* Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable).141* This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.142* Method 2 : direct access. This method is portable but violate C standard.143* It can generate buggy code on targets depending on alignment.144* In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6)145* See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.146* Prefer these methods in priority order (0 > 1 > 2)147*/148#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */149# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__)150# define MEM_FORCE_MEMORY_ACCESS 1151# endif152#endif153154MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }155MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }156157MEM_STATIC unsigned MEM_isLittleEndian(void)158{159#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)160return 1;161#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)162return 0;163#elif defined(__clang__) && __LITTLE_ENDIAN__164return 1;165#elif defined(__clang__) && __BIG_ENDIAN__166return 0;167#elif defined(_MSC_VER) && (_M_AMD64 || _M_IX86)168return 1;169#elif defined(__DMC__) && defined(_M_IX86)170return 1;171#else172const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */173return one.c[0];174#endif175}176177#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)178179/* violates C standard, by lying on structure alignment.180Only use if no other choice to achieve best performance on target platform */181MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }182MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }183MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }184MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }185186MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }187MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }188MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }189190#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)191192/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */193/* currently only defined for gcc and icc */194#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))195__pragma( pack(push, 1) )196typedef struct { U16 v; } unalign16;197typedef struct { U32 v; } unalign32;198typedef struct { U64 v; } unalign64;199typedef struct { size_t v; } unalignArch;200__pragma( pack(pop) )201#else202typedef struct { U16 v; } __attribute__((packed)) unalign16;203typedef struct { U32 v; } __attribute__((packed)) unalign32;204typedef struct { U64 v; } __attribute__((packed)) unalign64;205typedef struct { size_t v; } __attribute__((packed)) unalignArch;206#endif207208MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; }209MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; }210MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; }211MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; }212213MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; }214MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; }215MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; }216217#else218219/* default method, safe and standard.220can sometimes prove slower */221222MEM_STATIC U16 MEM_read16(const void* memPtr)223{224U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;225}226227MEM_STATIC U32 MEM_read32(const void* memPtr)228{229U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;230}231232MEM_STATIC U64 MEM_read64(const void* memPtr)233{234U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;235}236237MEM_STATIC size_t MEM_readST(const void* memPtr)238{239size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;240}241242MEM_STATIC void MEM_write16(void* memPtr, U16 value)243{244ZSTD_memcpy(memPtr, &value, sizeof(value));245}246247MEM_STATIC void MEM_write32(void* memPtr, U32 value)248{249ZSTD_memcpy(memPtr, &value, sizeof(value));250}251252MEM_STATIC void MEM_write64(void* memPtr, U64 value)253{254ZSTD_memcpy(memPtr, &value, sizeof(value));255}256257#endif /* MEM_FORCE_MEMORY_ACCESS */258259MEM_STATIC U32 MEM_swap32(U32 in)260{261#if defined(_MSC_VER) /* Visual Studio */262return _byteswap_ulong(in);263#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \264|| (defined(__clang__) && __has_builtin(__builtin_bswap32))265return __builtin_bswap32(in);266#else267return ((in << 24) & 0xff000000 ) |268((in << 8) & 0x00ff0000 ) |269((in >> 8) & 0x0000ff00 ) |270((in >> 24) & 0x000000ff );271#endif272}273274MEM_STATIC U64 MEM_swap64(U64 in)275{276#if defined(_MSC_VER) /* Visual Studio */277return _byteswap_uint64(in);278#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \279|| (defined(__clang__) && __has_builtin(__builtin_bswap64))280return __builtin_bswap64(in);281#else282return ((in << 56) & 0xff00000000000000ULL) |283((in << 40) & 0x00ff000000000000ULL) |284((in << 24) & 0x0000ff0000000000ULL) |285((in << 8) & 0x000000ff00000000ULL) |286((in >> 8) & 0x00000000ff000000ULL) |287((in >> 24) & 0x0000000000ff0000ULL) |288((in >> 40) & 0x000000000000ff00ULL) |289((in >> 56) & 0x00000000000000ffULL);290#endif291}292293MEM_STATIC size_t MEM_swapST(size_t in)294{295if (MEM_32bits())296return (size_t)MEM_swap32((U32)in);297else298return (size_t)MEM_swap64((U64)in);299}300301/*=== Little endian r/w ===*/302303MEM_STATIC U16 MEM_readLE16(const void* memPtr)304{305if (MEM_isLittleEndian())306return MEM_read16(memPtr);307else {308const BYTE* p = (const BYTE*)memPtr;309return (U16)(p[0] + (p[1]<<8));310}311}312313MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)314{315if (MEM_isLittleEndian()) {316MEM_write16(memPtr, val);317} else {318BYTE* p = (BYTE*)memPtr;319p[0] = (BYTE)val;320p[1] = (BYTE)(val>>8);321}322}323324MEM_STATIC U32 MEM_readLE24(const void* memPtr)325{326return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16);327}328329MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)330{331MEM_writeLE16(memPtr, (U16)val);332((BYTE*)memPtr)[2] = (BYTE)(val>>16);333}334335MEM_STATIC U32 MEM_readLE32(const void* memPtr)336{337if (MEM_isLittleEndian())338return MEM_read32(memPtr);339else340return MEM_swap32(MEM_read32(memPtr));341}342343MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)344{345if (MEM_isLittleEndian())346MEM_write32(memPtr, val32);347else348MEM_write32(memPtr, MEM_swap32(val32));349}350351MEM_STATIC U64 MEM_readLE64(const void* memPtr)352{353if (MEM_isLittleEndian())354return MEM_read64(memPtr);355else356return MEM_swap64(MEM_read64(memPtr));357}358359MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)360{361if (MEM_isLittleEndian())362MEM_write64(memPtr, val64);363else364MEM_write64(memPtr, MEM_swap64(val64));365}366367MEM_STATIC size_t MEM_readLEST(const void* memPtr)368{369if (MEM_32bits())370return (size_t)MEM_readLE32(memPtr);371else372return (size_t)MEM_readLE64(memPtr);373}374375MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)376{377if (MEM_32bits())378MEM_writeLE32(memPtr, (U32)val);379else380MEM_writeLE64(memPtr, (U64)val);381}382383/*=== Big endian r/w ===*/384385MEM_STATIC U32 MEM_readBE32(const void* memPtr)386{387if (MEM_isLittleEndian())388return MEM_swap32(MEM_read32(memPtr));389else390return MEM_read32(memPtr);391}392393MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)394{395if (MEM_isLittleEndian())396MEM_write32(memPtr, MEM_swap32(val32));397else398MEM_write32(memPtr, val32);399}400401MEM_STATIC U64 MEM_readBE64(const void* memPtr)402{403if (MEM_isLittleEndian())404return MEM_swap64(MEM_read64(memPtr));405else406return MEM_read64(memPtr);407}408409MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)410{411if (MEM_isLittleEndian())412MEM_write64(memPtr, MEM_swap64(val64));413else414MEM_write64(memPtr, val64);415}416417MEM_STATIC size_t MEM_readBEST(const void* memPtr)418{419if (MEM_32bits())420return (size_t)MEM_readBE32(memPtr);421else422return (size_t)MEM_readBE64(memPtr);423}424425MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)426{427if (MEM_32bits())428MEM_writeBE32(memPtr, (U32)val);429else430MEM_writeBE64(memPtr, (U64)val);431}432433/* code only tested on 32 and 64 bits systems */434MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }435436437#if defined (__cplusplus)438}439#endif440441#endif /* MEM_H_MODULE */442443444