⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 erl_bits.c

📁 OTP是开放电信平台的简称
💻 C
📖 第 1 页 / 共 3 页
字号:
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. *  * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. *  * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' *  *     $Id$ */#ifdef HAVE_CONFIG_H#  include "config.h"#endif#include "sys.h"#include "erl_vm.h"#include "global.h"#include "erl_process.h"#include "error.h"#include "bif.h"#include "big.h"#include "erl_bits.h"#include "erl_binary.h"#ifdef MAX#undef MAX#endif#define MAX(x,y) (((x)>(y))?(x):(y))#ifdef MIN#undef MIN#endif#define MIN(x,y) (((x)<(y))?(x):(y))#if defined(WORDS_BIGENDIAN)# define BIT_ENDIAN_MACHINE 0#else# define BIT_ENDIAN_MACHINE BSF_LITTLE#endif#define BIT_IS_MACHINE_ENDIAN(x) (((x)&BSF_LITTLE) == BIT_ENDIAN_MACHINE)/* * MAKE_MASK(n) constructs a mask with n bits. * Example: MAKE_MASK(3) returns the binary number 00000111. */#define MAKE_MASK(n) ((1 << (n))-1)/* * MASK_BITS assign src to dst, but preserves the dst bits outside the mask. */#define MASK_BITS(src,dst,mask) (((src) & (mask)) | ((dst) & ~(mask)))static byte get_bit(byte b, size_t a_offs); #if defined(ERTS_SMP)/* the state resides in the current process' scheduler data */#elif defined(ERL_BITS_REENTRANT)/* reentrant API but with a hidden single global state, for testing only */struct erl_bits_state ErlBitsState_;#else/* non-reentrant API with a single global state */struct erl_bits_state ErlBitsState;#endif#define byte_buf	(ErlBitsState.byte_buf_)#define byte_buf_len	(ErlBitsState.byte_buf_len_)#ifdef ERTS_SMPstatic erts_smp_atomic_t bits_bufs_size;#endifUinterts_bits_bufs_size(void){#if defined(HEAP_FRAG_ELIM_TEST)    return 0;#else#ifdef ERTS_SMP    return (Uint) erts_smp_atomic_read(&bits_bufs_size);#else    ERL_BITS_DECLARE_STATEP;    return (Uint) (byte_buf_len + erts_bin_buf_len);#endif#endif}#if !defined(ERTS_SMP)static#endifvoiderts_bits_init_state(ERL_BITS_PROTO_0){    byte_buf_len = 1;    byte_buf = erts_alloc(ERTS_ALC_T_BITS_BUF, byte_buf_len);#if !defined(HEAP_FRAG_ELIM_TEST)    erts_bin_buf_len = 1;    erts_bin_buf = erts_alloc(ERTS_ALC_T_BITS_BUF, erts_bin_buf_len);#endif    erts_bin_offset = 0;#if defined(ERTS_SMP) && !defined(HEAP_FRAG_ELIM_TEST)    erts_smp_atomic_add(&bits_bufs_size, byte_buf_len + erts_bin_buf_len);#endif}#if defined(ERTS_SMP)voiderts_bits_destroy_state(ERL_BITS_PROTO_0){    erts_free(ERTS_ALC_T_BITS_BUF, byte_buf);#if !defined(HEAP_FRAG_ELIM_TEST)    erts_free(ERTS_ALC_T_BITS_BUF, erts_bin_buf);#endif}#endifvoiderts_init_bits(void){#if defined(ERTS_SMP)    erts_smp_atomic_init(&bits_bufs_size, 0);    /* erl_process.c calls erts_bits_init_state() on all state instances */#else    ERL_BITS_DECLARE_STATEP;    erts_bits_init_state(ERL_BITS_ARGS_0);#endif}#if !defined(HEAP_FRAG_ELIM_TEST)/**************************************************************** *** *** Matching binaries *** ****************************************************************/interts_bs_start_match(ERL_BITS_PROTO_1(Eterm Binary)){    erts_InitMatchBuf(Binary, return 0);    return 1;}interts_bs_skip_bits(ERL_BITS_PROTO_1(Uint num_bits)){    Uint new_offset = erts_mb.offset + num_bits;    if (erts_mb.size < new_offset) {	return 0;    } else {	erts_mb.offset = new_offset;	return 1;    }}interts_bs_skip_bits_all(ERL_BITS_PROTO_0){    erts_mb.offset = erts_mb.size;    return 1;}interts_bs_test_tail(ERL_BITS_PROTO_1(Uint num_bits)){    return erts_mb.size - erts_mb.offset == num_bits;}voiderts_bs_save(ERL_BITS_PROTO_1(int index)){    erts_save_mb[index] = erts_mb;}voiderts_bs_restore(ERL_BITS_PROTO_1(int index)){    erts_mb = erts_save_mb[index];}Etermerts_bs_get_integer(Process *p, Uint num_bits, unsigned flags){    Uint bytes;    Uint bits;    Uint offs;    byte bigbuf[64];    byte* LSB;    byte* MSB;    Uint* hp;    Uint v32;    int sgn = 0;    Eterm res = THE_NON_VALUE;    ErlBinMatchBuffer* mb;    ERL_BITS_DEFINE_STATEP(p);  /* This has to be at the end of the				   declarations since the macro				   sometimes expands to nothing.				   VC++ and old gcc does not like				   stray ';'s between declarations. */    mb = &erts_mb;    if (num_bits == 0) {	return SMALL_ZERO;    }    if (mb->size - mb->offset < num_bits) {	/* Asked for too many bits.  */	return THE_NON_VALUE;    }    bytes = NBYTES(num_bits);    if ((bits = BIT_OFFSET(num_bits)) == 0) {  /* number of bits in MSB */	bits = 8;    }    offs = 8 - bits;                  /* adjusted offset in MSB */    if (bytes <= sizeof bigbuf) {	LSB = bigbuf;    } else {	LSB = erts_alloc(ERTS_ALC_T_TMP, bytes);    }    MSB = LSB + bytes - 1;    /*     * Move bits to temporary buffer. We want the buffer to be stored in     * little-endian order, since bignums are little-endian.     */        if (flags & BSF_LITTLE) {	erts_copy_bits(mb->base, mb->offset, 1, LSB, 0, 1, num_bits);	*MSB >>= offs;		/* adjust msb */    } else {	*MSB = 0;	erts_copy_bits(mb->base, mb->offset, 1, MSB, offs, -1, num_bits);    }    mb->offset += num_bits;    /*     * Get the sign bit.     */    sgn = 0;    if ((flags & BSF_SIGNED) && (*MSB & (1<<(bits-1)))) {	byte* ptr = LSB; 	byte c = 1;	/* sign extend MSB */	*MSB |= ~MAKE_MASK(bits);	/* two's complement */	while (ptr <= MSB) {	    byte pd = ~(*ptr);	    byte d = pd + c;	    c = (d < pd);	    *ptr++ = d;	}	sgn = 1;    }    /* normalize */    while ((*MSB == 0) && (MSB > LSB)) {	MSB--;	bytes--;    }    /* Check for guaranteed small */    switch (bytes) {    case 1:	v32 = LSB[0];	goto big_small;    case 2:	v32 = LSB[0] + (LSB[1]<<8); 	goto big_small;     case 3: 	v32 = LSB[0] + (LSB[1]<<8) + (LSB[2]<<16); 	goto big_small;    case 4:	v32 = (Uint32)(LSB[0] + (LSB[1]<<8) + (LSB[2]<<16) + (LSB[3]<<24));#if !defined(ARCH_64)	if (!IS_USMALL(sgn, v32)) {	    hp = ArithAlloc(p, BIG_UINT_HEAP_SIZE);	    if (sgn) {		hp[0] = make_neg_bignum_header(1);	    } else {		hp[0] = make_pos_bignum_header(1);	    }	    BIG_DIGIT(hp,0) = DLOW(v32);	    BIG_DIGIT(hp,1) = DHIGH(v32);	    res = make_big(hp);	    break;	}#endif    big_small:	if (sgn) {	    res = make_small(-((Sint)v32));	} else {	    res = make_small(v32);	}	break;    default:	hp = ArithAlloc(p, 1+WSIZE(bytes));	res = bytes_to_big(LSB, bytes, sgn, hp);#if !defined(ARCH_64)	ASSERT(is_big(res));#else	/* 64 bit CPU: The result may be small. */	if (is_small(res)) {	    erts_arith_shrink(p, hp);	}#endif	break;    }    if (LSB != bigbuf) {	erts_free(ERTS_ALC_T_TMP, (void *) LSB);    }    return res;}Etermerts_bs_get_binary(Process *p, Uint num_bits, unsigned flags){    ErlBinMatchBuffer* mb;    ErlSubBin* sb;    ERL_BITS_DEFINE_STATEP(p); /* Has to be at the end of declarations */    mb = &erts_mb;    if (num_bits == 0) {		/* Empty binary. */	return new_binary_arith(p, NULL, 0);    }    if (mb->size - mb->offset < num_bits) {	/* Asked for too many bits.  */	return THE_NON_VALUE;    }    /*     * From now on, we can't fail.     */        sb = (ErlSubBin *) ArithAlloc(p, ERL_SUB_BIN_SIZE);    sb->thing_word = HEADER_SUB_BIN;    sb->orig = mb->orig;    sb->size = BYTE_OFFSET(num_bits);    sb->bitsize = BIT_OFFSET(num_bits);    sb->offs = BYTE_OFFSET(mb->offset);    sb->bitoffs = BIT_OFFSET(mb->offset);    mb->offset += num_bits;    return make_binary(sb);}Etermerts_bs_get_float(Process *p, Uint num_bits, unsigned flags){    Eterm* hp;    float f32;    double f64;    byte* fptr;    FloatDef f;    ErlBinMatchBuffer* mb;    ERL_BITS_DEFINE_STATEP(p); /* Has to be at the end of declarations */    mb = &erts_mb;    if (num_bits == 0) {	f.fd = 0.0;	hp = ArithAlloc(p, FLOAT_SIZE_OBJECT);	PUT_DOUBLE(f, hp);	ArithCheck(p);	return make_float(hp);    }    if (mb->size - mb->offset < num_bits) {	/* Asked for too many bits.  */	return THE_NON_VALUE;    }    if (num_bits == 32) {	fptr = (byte *) &f32;    } else if (num_bits == 64) {	fptr = (byte *) &f64;    } else {	return THE_NON_VALUE;    }    if (BIT_IS_MACHINE_ENDIAN(flags)) {	erts_copy_bits(mb->base, mb->offset, 1,		  fptr, 0, 1,		  num_bits);    } else {	erts_copy_bits(mb->base, mb->offset, 1,		  fptr + NBYTES(num_bits) - 1, 0, -1,		  num_bits);    }    ERTS_FP_CHECK_INIT(p);    if (num_bits == 32) {	ERTS_FP_ERROR_THOROUGH(p, f32, return THE_NON_VALUE);	f.fd = f32;    } else {	ERTS_FP_ERROR_THOROUGH(p, f64, return THE_NON_VALUE);	f.fd = f64;    }    mb->offset += num_bits;    hp = ArithAlloc(p, FLOAT_SIZE_OBJECT);    PUT_DOUBLE(f, hp);    ArithCheck(p);    return make_float(hp);}Etermerts_bs_get_binary_all(Process *p){    ErlSubBin* sb;    Uint size;    ERL_BITS_DEFINE_STATEP(p);    size = erts_mb.size-erts_mb.offset;    if (BIT_OFFSET(size) == 0) {	sb = (ErlSubBin *) ArithAlloc(p, ERL_SUB_BIN_SIZE);	sb->thing_word = HEADER_SUB_BIN;	sb->size = BYTE_OFFSET(size);	sb->bitsize = BIT_OFFSET(size);	sb->offs = BYTE_OFFSET(erts_mb.offset);	sb->bitoffs = BIT_OFFSET(erts_mb.offset);	sb->orig = erts_mb.orig;	erts_mb.offset = erts_mb.size;	return make_binary(sb);    }    return THE_NON_VALUE;}#endif/***************************************************************** *** *** New matching binaries functions *** *****************************************************************/#define HeapOnlyAlloc(p, sz)					\    (ASSERT_EXPR((sz) >= 0),					\     (ASSERT_EXPR(((HEAP_LIMIT(p) - HEAP_TOP(p)) >= (sz))),	\      (HEAP_TOP(p) = HEAP_TOP(p) + (sz), HEAP_TOP(p) - (sz))))#define ReadToVariable(v64, Buffer, x)		\  do{						\    int _i;					\    v64 = 0;					\    for(_i = 0; _i < x; _i++) {			\      v64 = ((Uint)Buffer[_i] <<(8*_i)) + v64;	\	}					\  }while(0)					\Etermerts_bs_start_match_2(Process *p, Eterm Binary, Uint Max){    if (!is_binary(Binary)) {	return THE_NON_VALUE;    } else { 	Eterm Orig;	Uint offs;	Uint* hp;	Uint NeededSize;	ErlBinMatchState *ms;	Uint bitoffs;	Uint bitsize;	Uint total_bin_size;	total_bin_size = binary_size(Binary);	if ((total_bin_size >> (8*sizeof(Uint)-3)) != 0) {	    return THE_NON_VALUE;	}	NeededSize = ERL_BIN_MATCHSTATE_SIZE(Max);	hp = HeapOnlyAlloc(p, NeededSize);	ms = (ErlBinMatchState *) hp;                         	ERTS_GET_REAL_BIN(Binary, Orig, offs, bitoffs, bitsize);	ms->thing_word = HEADER_BIN_MATCHSTATE(Max);	(ms->mb).orig = Orig;	(ms->mb).base = binary_bytes(Orig);	(ms->mb).offset = 8 * offs + bitoffs;	(ms->mb).size = total_bin_size * 8 + (ms->mb).offset + bitsize;	return make_matchstate(ms);    }    }Etermerts_bs_get_integer_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer* mb){    Uint bytes;    Uint bits;    Uint offs;    byte bigbuf[64];    byte* LSB;    byte* MSB;    Uint* hp;    Uint* hp_end;    Uint words_needed;    Uint actual;    Uint v32;    int sgn = 0;    Eterm res = THE_NON_VALUE;	    if (num_bits == 0) {	return SMALL_ZERO;    }        if (mb->size - mb->offset < num_bits) {	/* Asked for too many bits.  */	return THE_NON_VALUE;    }    bytes = NBYTES(num_bits);    if ((bits = BIT_OFFSET(num_bits)) == 0) {  /* number of bits in MSB */	bits = 8;    }    offs = 8 - bits;                  /* adjusted offset in MSB */    if (bytes <= sizeof bigbuf) {	LSB = bigbuf;    } else {	LSB = erts_alloc(ERTS_ALC_T_TMP, bytes);    }    MSB = LSB + bytes - 1;    /*     * Move bits to temporary buffer. We want the buffer to be stored in     * little-endian order, since bignums are little-endian.     */        if (flags & BSF_LITTLE) {	erts_copy_bits(mb->base, mb->offset, 1, LSB, 0, 1, num_bits);	*MSB >>= offs;		/* adjust msb */    } else {	*MSB = 0;	erts_copy_bits(mb->base, mb->offset, 1, MSB, offs, -1, num_bits);    }    mb->offset += num_bits;    /*     * Get the sign bit.     */    sgn = 0;    if ((flags & BSF_SIGNED) && (*MSB & (1<<(bits-1)))) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -