Projekt

Obecné

Profil

Stáhnout (4.54 KB) Statistiky
| Větev: | Revize:
1
// Copyright 2012 The Obvious Corporation.
2

    
3
/*
4
 * bufs: Buffer utilities.
5
 */
6

    
7
/*
8
 * Module variables
9
 */
10

    
11
/** Pool of buffers, where `bufPool[x].length === x`. */
12
var bufPool = [];
13
/** Maximum length of kept temporary buffers. */
14

    
15
var TEMP_BUF_MAXIMUM_LENGTH = 20;
16
/** Minimum exactly-representable 64-bit int. */
17

    
18
var MIN_EXACT_INT64 = -0x8000000000000000;
19
/** Maximum exactly-representable 64-bit int. */
20

    
21
var MAX_EXACT_INT64 = 0x7ffffffffffffc00;
22
/** Maximum exactly-representable 64-bit uint. */
23

    
24
var MAX_EXACT_UINT64 = 0xfffffffffffff800;
25
/**
26
 * The int value consisting just of a 1 in bit #32 (that is, one more
27
 * than the maximum 32-bit unsigned value).
28
 */
29

    
30
var BIT_32 = 0x100000000;
31
/**
32
 * The int value consisting just of a 1 in bit #64 (that is, one more
33
 * than the maximum 64-bit unsigned value).
34
 */
35

    
36
var BIT_64 = 0x10000000000000000;
37
/*
38
 * Helper functions
39
 */
40

    
41
/**
42
 * Masks off all but the lowest bit set of the given number.
43
 */
44

    
45
function lowestBit(num) {
46
  return num & -num;
47
}
48
/**
49
 * Gets whether trying to add the second number to the first is lossy
50
 * (inexact). The first number is meant to be an accumulated result.
51
 */
52

    
53

    
54
function isLossyToAdd(accum, num) {
55
  if (num === 0) {
56
    return false;
57
  }
58

    
59
  var lowBit = lowestBit(num);
60
  var added = accum + lowBit;
61

    
62
  if (added === accum) {
63
    return true;
64
  }
65

    
66
  if (added - lowBit !== accum) {
67
    return true;
68
  }
69

    
70
  return false;
71
}
72
/*
73
 * Exported functions
74
 */
75

    
76
/**
77
 * Allocates a buffer of the given length, which is initialized
78
 * with all zeroes. This returns a buffer from the pool if it is
79
 * available, or a freshly-allocated buffer if not.
80
 */
81

    
82

    
83
export function alloc(length) {
84
  var result = bufPool[length];
85

    
86
  if (result) {
87
    bufPool[length] = undefined;
88
  } else {
89
    result = new Buffer(length);
90
  }
91

    
92
  result.fill(0);
93
  return result;
94
}
95
/**
96
 * Releases a buffer back to the pool.
97
 */
98

    
99
export function free(buffer) {
100
  var length = buffer.length;
101

    
102
  if (length < TEMP_BUF_MAXIMUM_LENGTH) {
103
    bufPool[length] = buffer;
104
  }
105
}
106
/**
107
 * Resizes a buffer, returning a new buffer. Returns the argument if
108
 * the length wouldn't actually change. This function is only safe to
109
 * use if the given buffer was allocated within this module (since
110
 * otherwise the buffer might possibly be shared externally).
111
 */
112

    
113
export function resize(buffer, length) {
114
  if (length === buffer.length) {
115
    return buffer;
116
  }
117

    
118
  var newBuf = alloc(length);
119
  buffer.copy(newBuf);
120
  free(buffer);
121
  return newBuf;
122
}
123
/**
124
 * Reads an arbitrary signed int from a buffer.
125
 */
126

    
127
export function readInt(buffer) {
128
  var length = buffer.length;
129
  var positive = buffer[length - 1] < 0x80;
130
  var result = positive ? 0 : -1;
131
  var lossy = false; // Note: We can't use bit manipulation here, since that stops
132
  // working if the result won't fit in a 32-bit int.
133

    
134
  if (length < 7) {
135
    // Common case which can't possibly be lossy (because the result has
136
    // no more than 48 bits, and loss only happens with 54 or more).
137
    for (var i = length - 1; i >= 0; i--) {
138
      result = result * 0x100 + buffer[i];
139
    }
140
  } else {
141
    for (var _i = length - 1; _i >= 0; _i--) {
142
      var one = buffer[_i];
143
      result *= 0x100;
144

    
145
      if (isLossyToAdd(result, one)) {
146
        lossy = true;
147
      }
148

    
149
      result += one;
150
    }
151
  }
152

    
153
  return {
154
    value: result,
155
    lossy: lossy
156
  };
157
}
158
/**
159
 * Reads an arbitrary unsigned int from a buffer.
160
 */
161

    
162
export function readUInt(buffer) {
163
  var length = buffer.length;
164
  var result = 0;
165
  var lossy = false; // Note: See above in re bit manipulation.
166

    
167
  if (length < 7) {
168
    // Common case which can't possibly be lossy (see above).
169
    for (var i = length - 1; i >= 0; i--) {
170
      result = result * 0x100 + buffer[i];
171
    }
172
  } else {
173
    for (var _i2 = length - 1; _i2 >= 0; _i2--) {
174
      var one = buffer[_i2];
175
      result *= 0x100;
176

    
177
      if (isLossyToAdd(result, one)) {
178
        lossy = true;
179
      }
180

    
181
      result += one;
182
    }
183
  }
184

    
185
  return {
186
    value: result,
187
    lossy: lossy
188
  };
189
}
190
/**
191
 * Writes a little-endian 64-bit signed int into a buffer.
192
 */
193

    
194
export function writeInt64(value, buffer) {
195
  if (value < MIN_EXACT_INT64 || value > MAX_EXACT_INT64) {
196
    throw new Error("Value out of range.");
197
  }
198

    
199
  if (value < 0) {
200
    value += BIT_64;
201
  }
202

    
203
  writeUInt64(value, buffer);
204
}
205
/**
206
 * Writes a little-endian 64-bit unsigned int into a buffer.
207
 */
208

    
209
export function writeUInt64(value, buffer) {
210
  if (value < 0 || value > MAX_EXACT_UINT64) {
211
    throw new Error("Value out of range.");
212
  }
213

    
214
  var lowWord = value % BIT_32;
215
  var highWord = Math.floor(value / BIT_32);
216
  buffer.writeUInt32LE(lowWord, 0);
217
  buffer.writeUInt32LE(highWord, 4);
218
}
(2-2/4)