Passed
Push — master ( 2f7ce0...4f126f )
by Rafael S.
02:01
created

packer.js ➔ write32FTyped_   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
c 0
b 0
f 0
nc 2
nop 3
dl 0
loc 7
rs 10
1
/*
2
 * Copyright (c) 2017-2018 Rafael da Silva Rocha.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining
5
 * a copy of this software and associated documentation files (the
6
 * "Software"), to deal in the Software without restriction, including
7
 * without limitation the rights to use, copy, modify, merge, publish,
8
 * distribute, sublicense, and/or sell copies of the Software, and to
9
 * permit persons to whom the Software is furnished to do so, subject to
10
 * the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be
13
 * included in all copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
 *
23
 */
24
25
/**
26
 * @fileoverview Function to serialize binary data.
27
 * @see https://github.com/rochars/byte-data
28
 */
29
30
import Integer from './integer.js';
31
import {validateType} from './validation.js';
32
import {unpack, pack} from './IEEE754.js';
33
34
/**
35
 * A class to pack and unpack integers and floating-point numbers.
36
 * @extends {Integer}
37
 */
38
export default class Packer extends Integer {
39
  
40
  constructor() {
41
    super();
42
    /**
43
     * If TypedArrays are available or not
44
     * @type {boolean}
45
     */
46
    this.TYPED = typeof Uint8Array === 'function';
47
    /**
48
     * Use a Typed Array to check if the host is BE or LE. This will impact
49
     * on how 64-bit floating point numbers are handled.
50
     * @type {boolean}
51
     */
52
    let BE_ENV = false;
53
    if (this.TYPED) {
54
      BE_ENV = new Uint8Array(new Uint32Array([1]).buffer)[0] === 0;
55
    }
56
    /**
57
     * @type {number}
58
     * @private
59
     */
60
    this.HIGH_ = BE_ENV ? 1 : 0;
61
    /**
62
     * @type {number}
63
     * @private
64
     */
65
    this.LOW_ = BE_ENV ? 0 : 1;
66
    /**
67
     * @type {!Uint8Array|null}
68
     */
69
    let uInt8 = this.TYPED ? new Uint8Array(8) : null;
70
    /**
71
     * @type {!Uint32Array|null}
72
     * @private
73
     */
74
    this.ui32_ = this.TYPED ? new Uint32Array(uInt8.buffer) : null;
75
    /**
76
     * @type {!Float32Array|null}
77
     * @private
78
     */
79
    this.f32_ = this.TYPED ? new Float32Array(uInt8.buffer) : null;
80
    /**
81
     * @type {!Float64Array|null}
82
     * @private
83
     */
84
    this.f64_ = this.TYPED ? new Float64Array(uInt8.buffer) : null;
85
}
86
87
  /**
88
   * Set up the object to start serializing/deserializing a data type..
89
   * @param {!Object} theType The type definition.
90
   * @throws {Error} If the type definition is not valid.
91
   */
92
  setUp(theType) {
93
    validateType(theType);
94
    super.setUp({
95
      bits: theType.bits,
96
      signed: theType.float ? false : theType.signed});
97
    this.setReaderAndWriter_(theType);
98
  }
99
100
  /**
101
   * Read 1 16-bit float from bytes.
102
   * @see https://stackoverflow.com/a/8796597
103
   * @param {!Uint8Array|!Array<number>} bytes An array of bytes.
104
   * @param {number=} i The index to read.
105
   * @return {number}
106
   * @private
107
   */
108
  read16F_(bytes, i=0) {
109
    return unpack(bytes, i, 5, 11);
110
  }
111
112
  /**
113
   * Read 1 32-bit float from bytes.
114
   * @param {!Uint8Array|!Array<number>} bytes An array of bytes.
115
   * @param {number=} i The index to read.
116
   * @return {number}
117
   * @private
118
   */
119
  read32F_(bytes, i=0) {
120
    return unpack(bytes, i, 8, 23);
121
  }
122
123
  /**
124
 * Read 1 32-bit float from bytes using a TypedArray.
125
 * @param {!Uint8Array|!Array<number>} bytes An array of bytes.
126
 * @param {number=} i The index to read.
127
 * @return {number}
128
 * @private
129
 */
130
  read32FTyped_(bytes, i=0) {
131
    this.ui32_[0] = super.read(bytes, i);
132
    return this.f32_[0];
133
  }
134
135
  /**
136
   * Read 1 64-bit float from bytes.
137
   * @param {!Uint8Array|!Array<number>} bytes An array of bytes.
138
   * @param {number=} i The index to read.
139
   * @return {number}
140
   * @private
141
   */
142
  read64F_(bytes, i=0) {
143
    return unpack(bytes, i, 11, 52);
144
  }
145
146
  /**
147
   * Read 1 64-bit float from bytes using a TypedArray.
148
   * Thanks https://gist.github.com/kg/2192799
149
   * @param {!Uint8Array|!Array<number>} bytes An array of bytes.
150
   * @param {number=} i The index to read.
151
   * @return {number}
152
   * @private
153
   */
154
  read64FTyped_(bytes, i=0) {
155
    this.ui32_[this.HIGH_] = super.read(bytes, i);
156
    this.ui32_[this.LOW_] = super.read(bytes, i + 4);
157
    return this.f64_[0];
158
  }
159
160
  /**
161
   * Write one 16-bit float as a binary value.
162
   * @param {!Uint8Array|!Array<number>} bytes An array of bytes.
163
   * @param {number} number The number to write as bytes.
164
   * @param {number=} j The index being written in the byte buffer.
165
   * @return {number} The next index to write on the byte buffer.
166
   * @private
167
   */
168
  write16F_(bytes, number, j=0) {
169
    return pack(bytes, j, number, 5, 11);
170
  }
171
172
  /**
173
   * Write one 32-bit float as a binary value.
174
   * @param {!Uint8Array|!Array<number>} bytes An array of bytes.
175
   * @param {number} number The number to write as bytes.
176
   * @param {number=} j The index being written in the byte buffer.
177
   * @return {number} The next index to write on the byte buffer.
178
   * @private
179
   */
180
  write32F_(bytes, number, j=0) {
181
    return pack(bytes, j, number, 8, 23);
182
  }
183
184
  /**
185
   * Write one 32-bit float as a binary value using a TypedArray.
186
   * @param {!Uint8Array|!Array<number>} bytes An array of bytes.
187
   * @param {number} number The number to write as bytes.
188
   * @param {number=} j The index being written in the byte buffer.
189
   * @return {number} The next index to write on the byte buffer.
190
   * @private
191
   */
192
  write32FTyped_(bytes, number, j=0) {
193
    if (number !== number) {
194
      return this.write32F_(bytes, number, j);
195
    }
196
    this.f32_[0] = number;
197
    return super.write(bytes, this.ui32_[0], j);
198
  }
199
200
  /**
201
   * Write one 64-bit float as a binary value.
202
   * @param {!Uint8Array|!Array<number>} bytes An array of bytes.
203
   * @param {number} number The number to write as bytes.
204
   * @param {number=} j The index being written in the byte buffer.
205
   * @return {number} The next index to write on the byte buffer.
206
   * @private
207
   */
208
  write64F_(bytes, number, j=0) {
209
    return pack(bytes, j, number, 11, 52);
210
  }
211
212
  /**
213
   * Write one 64-bit float as a binary value using a TypedArray.
214
   * @param {!Uint8Array|!Array<number>} bytes An array of bytes.
215
   * @param {number} number The number to write as bytes.
216
   * @param {number=} j The index being written in the byte buffer.
217
   * @return {number} The next index to write on the byte buffer.
218
   * @private
219
   */
220
  write64FTyped_(bytes, number, j=0) {
221
    if (number !== number) {
222
      return this.write64F_(bytes, number, j);
223
    }
224
    this.f64_[0] = number;
225
    j = super.write(bytes, this.ui32_[this.HIGH_], j);
226
    return super.write(bytes, this.ui32_[this.LOW_], j);
227
  }
228
229
  /**
230
   * Set the functions to pack and unpack numbers.
231
   * @param {!Object} theType The type definition.
232
   * @private
233
   */
234
  setReaderAndWriter_(theType) {
235
    if (theType.float) {
236
      if (theType.bits == 16) {
237
        this.read = this.read16F_;
238
        this.write = this.write16F_;
239
      } else if(theType.bits == 32) {
240
        this.read = this.TYPED ? this.read32FTyped_ : this.read32F_;
241
        this.write = this.TYPED ? this.write32FTyped_ : this.write32F_;
242
      } else {
243
        this.read = this.TYPED ? this.read64FTyped_: this.read64F_;
244
        this.write = this.TYPED ? this.write64FTyped_ : this.write64F_;
245
      }
246
    } else {
247
      this.read = super.read;
248
      this.write = super.write;
249
    }
250
  }
251
}
252