UNPKG

5.14 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.alloc = alloc;
7exports.free = free;
8exports.resize = resize;
9exports.readInt = readInt;
10exports.readUInt = readUInt;
11exports.writeInt64 = writeInt64;
12exports.writeUInt64 = writeUInt64;
13// Copyright 2012 The Obvious Corporation.
14
15/*
16 * bufs: Buffer utilities.
17 */
18
19/*
20 * Module variables
21 */
22
23/** Pool of buffers, where `bufPool[x].length === x`. */
24var bufPool = [];
25/** Maximum length of kept temporary buffers. */
26
27var TEMP_BUF_MAXIMUM_LENGTH = 20;
28/** Minimum exactly-representable 64-bit int. */
29
30var MIN_EXACT_INT64 = -0x8000000000000000;
31/** Maximum exactly-representable 64-bit int. */
32
33var MAX_EXACT_INT64 = 0x7ffffffffffffc00;
34/** Maximum exactly-representable 64-bit uint. */
35
36var MAX_EXACT_UINT64 = 0xfffffffffffff800;
37/**
38 * The int value consisting just of a 1 in bit #32 (that is, one more
39 * than the maximum 32-bit unsigned value).
40 */
41
42var BIT_32 = 0x100000000;
43/**
44 * The int value consisting just of a 1 in bit #64 (that is, one more
45 * than the maximum 64-bit unsigned value).
46 */
47
48var BIT_64 = 0x10000000000000000;
49/*
50 * Helper functions
51 */
52
53/**
54 * Masks off all but the lowest bit set of the given number.
55 */
56
57function lowestBit(num) {
58 return num & -num;
59}
60/**
61 * Gets whether trying to add the second number to the first is lossy
62 * (inexact). The first number is meant to be an accumulated result.
63 */
64
65
66function isLossyToAdd(accum, num) {
67 if (num === 0) {
68 return false;
69 }
70
71 var lowBit = lowestBit(num);
72 var added = accum + lowBit;
73
74 if (added === accum) {
75 return true;
76 }
77
78 if (added - lowBit !== accum) {
79 return true;
80 }
81
82 return false;
83}
84/*
85 * Exported functions
86 */
87
88/**
89 * Allocates a buffer of the given length, which is initialized
90 * with all zeroes. This returns a buffer from the pool if it is
91 * available, or a freshly-allocated buffer if not.
92 */
93
94
95function alloc(length) {
96 var result = bufPool[length];
97
98 if (result) {
99 bufPool[length] = undefined;
100 } else {
101 result = new Uint8Array(length);
102 }
103
104 result.fill(0);
105 return result;
106}
107/**
108 * Releases a buffer back to the pool.
109 */
110
111
112function free(buffer) {
113 var length = buffer.length;
114
115 if (length < TEMP_BUF_MAXIMUM_LENGTH) {
116 bufPool[length] = buffer;
117 }
118}
119/**
120 * Resizes a buffer, returning a new buffer. Returns the argument if
121 * the length wouldn't actually change. This function is only safe to
122 * use if the given buffer was allocated within this module (since
123 * otherwise the buffer might possibly be shared externally).
124 */
125
126
127function resize(buffer, length) {
128 if (length === buffer.length) {
129 return buffer;
130 }
131
132 var newBuf = alloc(length);
133
134 for (var i = 0; i <= buffer.length; i++) {
135 newBuf[i] = buffer[i];
136 }
137
138 free(buffer);
139 return newBuf;
140}
141/**
142 * Reads an arbitrary signed int from a buffer.
143 */
144
145
146function readInt(buffer) {
147 var length = buffer.length;
148 var positive = buffer[length - 1] < 0x80;
149 var result = positive ? 0 : -1;
150 var lossy = false; // Note: We can't use bit manipulation here, since that stops
151 // working if the result won't fit in a 32-bit int.
152
153 if (length < 7) {
154 // Common case which can't possibly be lossy (because the result has
155 // no more than 48 bits, and loss only happens with 54 or more).
156 for (var i = length - 1; i >= 0; i--) {
157 result = result * 0x100 + buffer[i];
158 }
159 } else {
160 for (var _i = length - 1; _i >= 0; _i--) {
161 var one = buffer[_i];
162 result *= 0x100;
163
164 if (isLossyToAdd(result, one)) {
165 lossy = true;
166 }
167
168 result += one;
169 }
170 }
171
172 return {
173 value: result,
174 lossy: lossy
175 };
176}
177/**
178 * Reads an arbitrary unsigned int from a buffer.
179 */
180
181
182function readUInt(buffer) {
183 var length = buffer.length;
184 var result = 0;
185 var lossy = false; // Note: See above in re bit manipulation.
186
187 if (length < 7) {
188 // Common case which can't possibly be lossy (see above).
189 for (var i = length - 1; i >= 0; i--) {
190 result = result * 0x100 + buffer[i];
191 }
192 } else {
193 for (var _i2 = length - 1; _i2 >= 0; _i2--) {
194 var one = buffer[_i2];
195 result *= 0x100;
196
197 if (isLossyToAdd(result, one)) {
198 lossy = true;
199 }
200
201 result += one;
202 }
203 }
204
205 return {
206 value: result,
207 lossy: lossy
208 };
209}
210/**
211 * Writes a little-endian 64-bit signed int into a buffer.
212 */
213
214
215function writeInt64(value, buffer) {
216 if (value < MIN_EXACT_INT64 || value > MAX_EXACT_INT64) {
217 throw new Error("Value out of range.");
218 }
219
220 if (value < 0) {
221 value += BIT_64;
222 }
223
224 writeUInt64(value, buffer);
225}
226/**
227 * Writes a little-endian 64-bit unsigned int into a buffer.
228 */
229
230
231function writeUInt64(value, buffer) {
232 if (value < 0 || value > MAX_EXACT_UINT64) {
233 throw new Error("Value out of range.");
234 }
235
236 var lowWord = value % BIT_32;
237 var highWord = Math.floor(value / BIT_32);
238 buffer[0] = lowWord & 0xff;
239 buffer[1] = lowWord >> 8 & 0xff;
240 buffer[2] = lowWord >> 16 & 0xff;
241 buffer[3] = lowWord >> 24 & 0xff;
242 buffer[4] = highWord & 0xff;
243 buffer[5] = highWord >> 8 & 0xff;
244 buffer[6] = highWord >> 16 & 0xff;
245 buffer[7] = highWord >> 24 & 0xff;
246}
\No newline at end of file