Passed
Push — master ( ea5ece...9c76fd )
by Rafael S.
01:41
created

src/gint.js   A

Size

Lines of Code 259

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
nc 1
dl 0
loc 259
rs 10
noi 0

1 Function

Rating   Name   Duplication   Size   Complexity  
A gint.js ➔ ??? 0 66 2
1
/**
2
 * gint: Generic integer.
3
 * A class to represent any integer from 1 to 53-Bit.
4
 * Copyright (c) 2017 Rafael da Silva Rocha.
5
 * https://github.com/rochars/byte-data
6
 */
7
8
/**
9
 * A class to represent any integer from 1 to 53-Bit.
10
 */
11
class GInt {
12
13
    /**
14
     * @param {Object} options The type definition.
15
     * @param {number} options.bits Number of bits used by data of this type.
16
     * @param {boolean} options.be True for big-endian.
17
     * @param {boolean} options.signed True for signed types.
18
     */
19
    constructor(options) {
20
        /**
21
         * The max number of bits used by data of this type.
22
         * @type {number}
23
         */
24
        this.bits = options["bits"];
25
        /**
26
         * If this type is big-endian or not.
27
         * @type {boolean}
28
         */
29
        this.be = options["be"];
30
        /**
31
         * If this type it is signed or not.
32
         * @type {boolean}
33
         */
34
        this.signed = options["signed"];
35
        /**
36
         * The base used to represent data of this type.
37
         * Default is 10.
38
         * @type {number}
39
         */
40
        this.base = options["base"] ? options["base"] : 10;
41
        /**
42
         * The function to read values of this type from buffers.
43
         * @type {Function}
44
         * @ignore
45
         */
46
        this.reader = this.read_;
47
        /**
48
         * The function to write values of this type to buffers.
49
         * @type {Function}
50
         * @ignore
51
         */
52
        this.writer = this.write_;
53
        /**
54
         * The number of bytes used by data of this type.
55
         * @type {number}
56
         * @ignore
57
         */
58
        this.offset = 0;
59
        /**
60
         * Min value for numbers of this type.
61
         * @type {number}
62
         * @ignore
63
         */
64
        this.min = -Infinity;
65
        /**
66
         * Max value for numbers of this type.
67
         * @type {number}
68
         * @ignore
69
         */
70
        this.max = Infinity;
71
        /**
72
         * The word size.
73
         * @type {number}
74
         * @ignore
75
         */
76
        this.realBits = this.bits;
77
        /**
78
         * The mask to be used in the last byte of this type.
79
         * @type {number}
80
         * @ignore
81
         */
82
        this.lastByteMask = 255;
83
        this.build_();
84
    }
85
86
    /**
87
     * Sign a number according to the type.
88
     * @param {number} num The number.
89
     * @return {number}
90
     * @ignore
91
     */
92
    sign(num) {
93
        if (num > this.max) {
94
            num -= (this.max * 2) + 2;
95
        }
96
        return num;
97
    }
98
99
    /**
100
     * Limit the value according to the bit depth in case of
101
     * overflow or underflow.
102
     * @param {number} value The data.
103
     * @return {number}
104
     * @ignore
105
     */
106
    overflow(value) {
107
        if (value > this.max) {
108
            value = this.max;
109
        } else if (value < this.min) {
110
            value = this.min;
111
        }
112
        return value;
113
    }
114
115
    /**
116
     * Read a integer number from a byte buffer.
117
     * @param {!Array<number>|Uint8Array} bytes An array of bytes.
118
     * @param {number} i The index to read.
119
     * @param {Object} type The type if other than this.
120
     * @return {number}
121
     * @private
122
     */
123
    read_(bytes, i, type=this) {
124
        let num = 0;
125
        let x = type.offset - 1;
126
        while (x > 0) {
127
            num = (bytes[x + i] << x * 8) | num;
128
            x--;
129
        }
130
        num = (bytes[i] | num) >>> 0;
131
        return this.overflow(this.sign(num));
132
    }
133
134
    /**
135
     * Read a integer number from a byte buffer by turning the bytes
136
     * to a string of bits.
137
     * @param {!Array<number>|Uint8Array} bytes An array of bytes.
138
     * @param {number} i The index to read.
139
     * @param {Object} type The type if other than this.
140
     * @return {number}
141
     * @private
142
     */
143
    readBits_(bytes, i, type=this) {
144
        let binary = "";
145
        let j = 0;
146
        while(j < type.offset) {
147
            let bits = bytes[i + j].toString(2);
148
            binary = Array(9 - bits.length).join("0") + bits + binary;
149
            j++;
150
        }
151
        return this.overflow(this.sign(parseInt(binary, 2)));
152
    }
153
154
    /**
155
     * Write one integer number to a byte buffer.
156
     * @param {!Array<number>} bytes An array of bytes.
157
     * @param {number} number The number.
158
     * @param {number} j The index being written in the byte buffer.
159
     * @param {Object} type The type.
160
     * @return {number} The next index to write on the byte buffer.
161
     * @private
162
     */
163
    write_(bytes, number, j, type=this) {
164
        number = this.overflow(number);
165
        let mask = 255;
166
        let len = type.offset;
167
        j = this.writeFirstByte_(bytes, number, j, type);
168
        for (let i = 2; i <= len; i++) {
169
            if (i == len) {
170
                mask = type.lastByteMask;
171
            }
172
            bytes[j++] = Math.floor(number / Math.pow(2, ((i - 1) * 8))) & mask;
173
        }
174
        return j;
175
    }
176
177
    /**
178
     * Build the type.
179
     * @private
180
     */
181
    build_() {
182
        this.validateWordSize_();
183
        this.setRealBits_();
184
        this.setLastByteMask_();
185
        this.setMinMax_();
186
        this.offset = this.bits < 8 ? 1 : Math.ceil(this.realBits / 8);
187
    }
188
189
    /**
190
     * Set the minimum and maximum values for the type.
191
     * @private
192
     */
193
    setMinMax_() {
194
        let max = Math.pow(2, this.bits);
195
        if (this.signed) {
196
            this.max = max / 2 -1;
197
            this.min = -max / 2;
198
        } else {
199
            this.max = max - 1;
200
            this.min = 0;
201
        }
202
    }
203
204
    validateWordSize_() {
205
        if (this.bits < 1 || this.bits > 64) {
206
            throw Error("Not a supported type.");
207
        }
208
    }
209
210
    /**
211
     * Set the real bit depth for data with bit count different from the
212
     * standard types (1, 2, 4, 8, 16, 32, 40, 48, 64): the closest bigger
213
     * standard number of bits. The data is then treated as data of the
214
     * standard type on all aspects except for the min and max values.
215
     * Ex: a 11-bit uInt is treated as 16-bit uInt with a max value of 2048.
216
     * @private
217
     */
218
    setRealBits_() {
219
        if (this.bits > 8) {
220
            if (this.bits <= 16) {
221
                this.realBits = 16;
222
            } else if (this.bits <= 24) {
223
                this.realBits = 24;
224
            } else if (this.bits <= 32) {
225
                this.realBits = 32;
226
            } else if (this.bits <= 40) {
227
                this.realBits = 40;
228
            } else if (this.bits <= 48) {
229
                this.realBits = 48;
230
            } else if (this.bits <= 56) {
231
                this.realBits = 56;
232
            } else {
233
                this.realBits = 64;
234
            }
235
        } else {
236
            this.realBits = this.bits;
237
        }
238
    }
239
240
    /**
241
     * Set the mask that should be used when writing the last byte of
242
     * data of the type.
243
     * @private
244
     */
245
    setLastByteMask_() {
246
        let r = 8 - (this.realBits - this.bits);
247
        this.lastByteMask = Math.pow(2, r > 0 ? r : 8) -1;
248
    }
249
250
    /**
251
     * Write the first byte of a integer number.
252
     * @param {!Array<number>} bytes An array of bytes.
253
     * @param {number} number The number.
254
     * @param {number} j The index being written in the byte buffer.
255
     * @param {Object} type The type.
256
     * @return {number} The next index to write on the byte buffer.
257
     * @private
258
     */
259
    writeFirstByte_(bytes, number, j, type=this) {
260
        if (type.bits < 8) {
261
            bytes[j++] = number < 0 ? number + Math.pow(2, type.bits) : number;
262
        } else {
263
            bytes[j++] = number & 255;
264
        }
265
        return j;
266
    }
267
}
268
269
module.exports = GInt;
270