EdwardZZZ / articles

工作点滴记录
2 stars 0 forks source link

int64 #41

Open EdwardZZZ opened 6 years ago

EdwardZZZ commented 6 years ago
const arr = bigInt(n).toArray(128).value

const arr1 = arr.map((i) => {
    console.log((i | 0x80).toString(2), i.toString(2));
    return i | 0x80;
});

const arr2 = arr1.map((i) => {
    return i & 0x7f;
})
const Int64LE = require("int64-buffer").Int64LE;
const num = 1231321321014143212;
const big = new Int64LE(num);
console.log(typeof big.toString(10));
const bigInt = require("big-integer");

const num = '1231321321014143212';

// const big = bigInt(num);
// const bigArr = big.toArray(256);
// console.log(bigArr);
// console.log(bigInt.fromArray(bigArr.value, 256));

Buffer.prototype.writeInt64LE = function(value, offset, noAssert) {
    console.log(value);

    offset = offset >>> 0;
    let longLe = bigInt(value).toArray(256).value;
    if(longLe.length > 0){
        for(let i = 0; i < longLe.length; i++){
            this[ offset + i] = longLe[i];
        }
    }
    return offset + 8;
};

Buffer.prototype.readInt64LE = function(offset, noAssert) {
    offset = offset >>> 0;
    const arr = [];
    for(let i =0; i < 8; i++){
        arr[i] = this[offset + i];
    }
    return bigInt.fromArray(arr, 256).toString();
};

let buffer = Buffer.alloc(15);
buffer.writeInt64LE(1231321321014143212, 3);
console.log(buffer.readInt64LE(3));
EdwardZZZ commented 4 years ago

最后一位不操作,如果小于128停止读取,如果最后一位大于128则为负数,因此int64最长长度还是 9 个字节

    const Range = {
        16: [0x7fff, -0x8000, 2],
        32: [0x7fffffff, -0x80000000, 4],
        64: [0x7fffffffffffffff, -0x8000000000000000, 8],
    };

    readVarInt64(): string {
        const [, , len] = Range[64];
        let i = 0;
        let b = this.buffer[this.pos + i++];
        let result = Long.fromValue(b & 0x7f);

        while (i < len + 1) {
            if ((b & 0x80) !== 0) {
                b = this.buffer[this.pos + i++];
                if (i === 9) {
                    result = result.or(Long.fromValue(b).shiftLeft(56));
                } else {
                    result = result.or(Long.fromValue(b & 0x7f).shiftLeft(7 * (i - 1)));
                }
            } else {
                break;
            }
        }
        this.pos += i;
        return result.toString();
    }

    toBytes64LE(value: number | string): number[] {
        if (value >= 0 && value < 128) return [+value];

        const buf = [];
        const longValue = Long.fromValue(value);
        let r = longValue;
        while (+r !== 0 && buf.length < 9) {
            r = longValue.shiftRightUnsigned(7 * buf.length);

            if ((r.gt(0x7f) || longValue.isNegative()) && buf.length < 8) {
                buf.push(r.and(0x7f).or(0x80).toInt());
            } else {
                buf.push(r.toInt());
                break;
            }
        }
        return buf;
    }

    toBytesLE(value: number, n: number): number[] {
        if (value >= 0 && value < 128) return [value];

        const [, , len] = Range[n];

        const buf = [];
        let r = value;
        while (r !== 0 && buf.length < len + 1) {
            r = value >>> 7 * buf.length;

            if ((r > 0x7f || value < 0) && buf.length < len) {
                buf.push((r & 0x7f) | 0x80);
            } else {
                buf.push(n === 32 ? r : value >> 7 * buf.length);
                break;
            }
        }
        return buf;
    }
EdwardZZZ commented 3 years ago
    const Range = {
        16: [0x7fff, -0x8000, 2],
        32: [0x7fffffff, -0x80000000, 4],
        64: [0x7fffffffffffffff, -0x8000000000000000, 8],
    };

    readVarInt64(): string {
        const [, , len] = Range[64];
        let i = 0;
        let b = this.buffer[this.pos + i++];
        let result = BigInt(b & 0x7f);

        while (i < len + 1) {
            if ((b & 0x80) !== 0) {
                b = this.buffer[this.pos + i++];
                if (i === 9) {
                    result |= BigInt(b > 7 ? b - 256 : b) << 56n;
                } else {
                    result |= BigInt(b & 0x7f) << BigInt(7 * (i - 1));
                }
            } else {
                break;
            }
        }
        this.pos += i;
        return result.toString();
    }

    toBytes64LE(value: number | string): number[] {
        if (value >= 0 && value < 128) return [+value];

        const buff = [];
        const longValue = BigInt(value);
        let r = longValue;
        while (r !== 0n && buff.length < 9) {
            r = longValue >> BigInt(7 * buff.length);

            if ((r > 0x7f || longValue < 0n ) && buff.length < 8) {
                buff.push(Number(r & BigInt(0x7f) | BigInt(0x80)));
            } else {
                buff.push(Number(r) & 0xff);
                break;
            }
        }
        return buf;
    }

    toBytesLE(value: number, n: number): number[] {
        if (value >= 0 && value < 128) return [value];

        const [, , len] = Range[n];

        const buf = [];
        let r = value;
        while (r !== 0 && buf.length < len + 1) {
            r = value >>> 7 * buf.length;

            if ((r > 0x7f || value < 0) && buf.length < len) {
                buf.push((r & 0x7f) | 0x80);
            } else {
                buf.push(n === 32 ? r : value >> 7 * buf.length);
                break;
            }
        }
        return buf;
    }
EdwardZZZ commented 3 years ago

/**
 * 扩展64位长整型写操作
 * **/
function writeInt(type = 'LE', value, offset = 0, noAssert) {
    if (!noAssert) {
        const [max, min, ext] = range[64];
        checkInt(this, value, offset, ext, max, min);
    }

    const val = bigInt(value).toArray(256);

    let arr = val.value;
    arr = type === 'LE' ? arr.reverse() : arr;

    if(arr.length > 0){
        for(let i = 0; i < 8; i++){
            if ( val.isNegative ) {
                if ( (type === 'LE' && i === 0) || (type === 'BE' && i === 7) ) {
                    this[ offset + i] = -arr[i] & 0xff;
                } else {
                    this[ offset + i] = ~arr[i] & 0xff;
                }
            } else {
                this[ offset + i] = arr[i];
            }
        }
    }

    return offset + 8;
}

function readInt(type = 'LE', offset = 0, noAssert) {
    if (!noAssert)
        checkOffset(offset, 8, this.length);

    const signNum = type === 'LE' ? this[offset + 7] : this[offset];
    const isNegative = signNum > 0x7f;

    let arr = [];
    for(let i =0; i < 8; i++){
        if (isNegative) {
            if ( (type === 'LE' && i === 0) || (type === 'BE' && i === 7) ) {
                arr[i] = -this[ offset + i] & 0xff;
            } else {
                arr[i] = ~this[ offset + i] & 0xff;
            }
        } else {
            arr[i] = this[offset + i];
        }
    }

    this.__readOffset = offset + 8;
    arr = type === 'LE' ? arr.reverse() : arr;
    return bigInt.fromArray(arr, 256, isNegative).toString();
}

/**
 * 写
 * @param {*} type 
 * @param {*} n 
 * @param {*} value 
 * @param {*} offset 
 * @param {*} noAssert 
 */
function writeVarInt(type = 'LE', n = 16, value, offset = 0, noAssert) {
    const [max, min, ext] = range[n];
    if (noAssert) {
        checkInt(this, value, offset, ext, max, min);
    }

    let arr = bigInt(value).toArray(128);
    let bytes = arr.value;

    if (bytes.length > this.length || bytes.length > ext + 1) {
        throw new RangeError(`ERR_INDEX_OUT_OF_RANGE int${n} value: ${value}`);
    }

    bytes = type === 'LE' ? bytes.reverse() : bytes;
    if (arr.isNegative) {
        bytes = bytes.concat(Array(ext + 1 - bytes.length).fill(0))
    }

    let _offset = offset;
    bytes.forEach((byte, index) => {
        // 处理用于判断首尾
        if (arr.isNegative) {
            if ((type === 'BE' && index === bytes.length - 1)
                || (type === 'LE' && index === 0)) {
                this[_offset++] = -byte;
            } else if ( n === 32 && byte < 0xf &&
                ( (type === 'BE' && index === 0) || (type === 'LE' && index === bytes.length - 1)) ) {
                this[_offset++] = ~byte & 0xf;
            } else {
                this[_offset++] = ~byte;
            }
        } else {
            if ((type === 'BE' && index === 0)
                || (type === 'LE' && index === bytes.length - 1)) {
                this[_offset++] = byte;
            } else {
                this[_offset++] = byte | 0x80;
            }
        }
    });

    return _offset;
};

/**
 * 读
 * @param {*} type 
 * @param {*} offset 
 * @param {*} noAssert 
 */
function readVarInt(type = 'LE', n = 16, offset = 0, noAssert) {
    let _offset = offset;

    if (this.length - _offset <= 0) {
        return 0;
    }

    let arr = [];
    /**
     * 标记count,用于计算优化字节长度的限制,否则while循环有可能一直运算下去
     * 当(count * 8) === n 时候,表示最大长度;分别是short:3、integer:5、long:9
     * **/
    let count = 0;
    while (true) {
        let b = this[_offset++];
        if (b === undef) break;

        if ((b & 0x80) !== 0x80 || (count << 3) === n ) {
            if (type === 'LE') {
                arr.push(b);
                break;
            } else {
                if (offset + 1 === _offset) {
                    arr.push(b);
                    continue;
                }
                break;
            }
        }
        arr.push(b);
        count++;
    }

    if (type === 'LE') {
        arr = arr.reverse();
    }

    // 是否是负数
    const [max, min, ext] = range[n];
    let isNegative = false;
    if (count === 2 || count === 8) {
        isNegative = (arr[0] & 0x80) !== 0;
    }
    if (count === 4 && n === 32) {
        isNegative = arr[0] > 7;
    }

    // 处理返回新的数组
    arr = arr.map((n, index) => {
        if (isNegative) {
            if (index === arr.length - 1) return -n & 0x7f;
            if (index === 0 && count === 4) return ~n & 0xf;
            return ~n & 0x7f
        }
        if (index === 0) return n;
        return n & 0x7f;
    });

    this.__readOffset = _offset;
    return (isNegative ? '-' : '') + bigInt.fromArray(arr, 128).toString();
}
EdwardZZZ commented 3 years ago
const shortArr = [
    [0, [0]],
    [-1, [-1, -1, -1]],
    [1, [1]],
    [-0x80, [-128, -1, -1]],
    [0x7f, [127]],
    [0x80, [-128, 1]],
    [-0x8000, [-128, -128, -2]],
    [0x7fff, [-1, -1, 1]],
];

const intArr = [
    [0, [0]],
    [-1, [-1, -1, -1, -1, 15]],
    [1, [1]],
    [-0x80, [-128, -1, -1, -1, 15]],
    [0x7f, [127]],
    [0x80, [-128, 1]],
    [-0x8000, [-128, -128, -2, -1, 15]],
    [0x7fff, [-1, -1, 1]],
    [-0x80000000, [-128, -128, -128, -128, 8]],
    [0x7fffffff, [-1, -1, -1, -1, 7]],
];

const longArr = [
    [0, [0]],
    [-1, [-1, -1, -1, -1, -1, -1, -1, -1, -1]],
    [1, [1]],
    [-0x80, [-128, -1, -1, -1, -1, -1, -1, -1, -1]],
    [0x7f, [127]],
    [0x80, [-128, 1]],
    [-0x8000, [-128, -128, -2, -1, -1, -1, -1, -1, -1]],
    [0x7fff, [-1, -1, 1]],
    [-0x80000000, [-128, -128, -128, -128, -8, -1, -1, -1, -1]],
    [0x7fffffff, [-1, -1, -1, -1, 7]],
    ['-9223372036854775808', [-128, -128, -128, -128, -128, -128, -128, -128, -128]],
    ['9223372036854775807', [-1, -1, -1, -1, -1, -1, -1, -1, 127]],
];