You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			236 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			236 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | "use strict"; | ||
|  | 
 | ||
|  | Object.defineProperty(exports, "__esModule", { | ||
|  |   value: true | ||
|  | }); | ||
|  | exports.alloc = alloc; | ||
|  | exports.free = free; | ||
|  | exports.resize = resize; | ||
|  | exports.readInt = readInt; | ||
|  | exports.readUInt = readUInt; | ||
|  | exports.writeInt64 = writeInt64; | ||
|  | exports.writeUInt64 = writeUInt64; | ||
|  | // Copyright 2012 The Obvious Corporation.
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * bufs: Buffer utilities. | ||
|  |  */ | ||
|  | 
 | ||
|  | /* | ||
|  |  * Module variables | ||
|  |  */ | ||
|  | 
 | ||
|  | /** Pool of buffers, where `bufPool[x].length === x`. */ | ||
|  | var bufPool = []; | ||
|  | /** Maximum length of kept temporary buffers. */ | ||
|  | 
 | ||
|  | var TEMP_BUF_MAXIMUM_LENGTH = 20; | ||
|  | /** Minimum exactly-representable 64-bit int. */ | ||
|  | 
 | ||
|  | var MIN_EXACT_INT64 = -0x8000000000000000; | ||
|  | /** Maximum exactly-representable 64-bit int. */ | ||
|  | 
 | ||
|  | var MAX_EXACT_INT64 = 0x7ffffffffffffc00; | ||
|  | /** Maximum exactly-representable 64-bit uint. */ | ||
|  | 
 | ||
|  | var MAX_EXACT_UINT64 = 0xfffffffffffff800; | ||
|  | /** | ||
|  |  * The int value consisting just of a 1 in bit #32 (that is, one more | ||
|  |  * than the maximum 32-bit unsigned value). | ||
|  |  */ | ||
|  | 
 | ||
|  | var BIT_32 = 0x100000000; | ||
|  | /** | ||
|  |  * The int value consisting just of a 1 in bit #64 (that is, one more | ||
|  |  * than the maximum 64-bit unsigned value). | ||
|  |  */ | ||
|  | 
 | ||
|  | var BIT_64 = 0x10000000000000000; | ||
|  | /* | ||
|  |  * Helper functions | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Masks off all but the lowest bit set of the given number. | ||
|  |  */ | ||
|  | 
 | ||
|  | function lowestBit(num) { | ||
|  |   return num & -num; | ||
|  | } | ||
|  | /** | ||
|  |  * Gets whether trying to add the second number to the first is lossy | ||
|  |  * (inexact). The first number is meant to be an accumulated result. | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function isLossyToAdd(accum, num) { | ||
|  |   if (num === 0) { | ||
|  |     return false; | ||
|  |   } | ||
|  | 
 | ||
|  |   var lowBit = lowestBit(num); | ||
|  |   var added = accum + lowBit; | ||
|  | 
 | ||
|  |   if (added === accum) { | ||
|  |     return true; | ||
|  |   } | ||
|  | 
 | ||
|  |   if (added - lowBit !== accum) { | ||
|  |     return true; | ||
|  |   } | ||
|  | 
 | ||
|  |   return false; | ||
|  | } | ||
|  | /* | ||
|  |  * Exported functions | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Allocates a buffer of the given length, which is initialized | ||
|  |  * with all zeroes. This returns a buffer from the pool if it is | ||
|  |  * available, or a freshly-allocated buffer if not. | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function alloc(length) { | ||
|  |   var result = bufPool[length]; | ||
|  | 
 | ||
|  |   if (result) { | ||
|  |     bufPool[length] = undefined; | ||
|  |   } else { | ||
|  |     result = new Buffer(length); | ||
|  |   } | ||
|  | 
 | ||
|  |   result.fill(0); | ||
|  |   return result; | ||
|  | } | ||
|  | /** | ||
|  |  * Releases a buffer back to the pool. | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function free(buffer) { | ||
|  |   var length = buffer.length; | ||
|  | 
 | ||
|  |   if (length < TEMP_BUF_MAXIMUM_LENGTH) { | ||
|  |     bufPool[length] = buffer; | ||
|  |   } | ||
|  | } | ||
|  | /** | ||
|  |  * Resizes a buffer, returning a new buffer. Returns the argument if | ||
|  |  * the length wouldn't actually change. This function is only safe to | ||
|  |  * use if the given buffer was allocated within this module (since | ||
|  |  * otherwise the buffer might possibly be shared externally). | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function resize(buffer, length) { | ||
|  |   if (length === buffer.length) { | ||
|  |     return buffer; | ||
|  |   } | ||
|  | 
 | ||
|  |   var newBuf = alloc(length); | ||
|  |   buffer.copy(newBuf); | ||
|  |   free(buffer); | ||
|  |   return newBuf; | ||
|  | } | ||
|  | /** | ||
|  |  * Reads an arbitrary signed int from a buffer. | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function readInt(buffer) { | ||
|  |   var length = buffer.length; | ||
|  |   var positive = buffer[length - 1] < 0x80; | ||
|  |   var result = positive ? 0 : -1; | ||
|  |   var lossy = false; // Note: We can't use bit manipulation here, since that stops
 | ||
|  |   // working if the result won't fit in a 32-bit int.
 | ||
|  | 
 | ||
|  |   if (length < 7) { | ||
|  |     // Common case which can't possibly be lossy (because the result has
 | ||
|  |     // no more than 48 bits, and loss only happens with 54 or more).
 | ||
|  |     for (var i = length - 1; i >= 0; i--) { | ||
|  |       result = result * 0x100 + buffer[i]; | ||
|  |     } | ||
|  |   } else { | ||
|  |     for (var _i = length - 1; _i >= 0; _i--) { | ||
|  |       var one = buffer[_i]; | ||
|  |       result *= 0x100; | ||
|  | 
 | ||
|  |       if (isLossyToAdd(result, one)) { | ||
|  |         lossy = true; | ||
|  |       } | ||
|  | 
 | ||
|  |       result += one; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   return { | ||
|  |     value: result, | ||
|  |     lossy: lossy | ||
|  |   }; | ||
|  | } | ||
|  | /** | ||
|  |  * Reads an arbitrary unsigned int from a buffer. | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function readUInt(buffer) { | ||
|  |   var length = buffer.length; | ||
|  |   var result = 0; | ||
|  |   var lossy = false; // Note: See above in re bit manipulation.
 | ||
|  | 
 | ||
|  |   if (length < 7) { | ||
|  |     // Common case which can't possibly be lossy (see above).
 | ||
|  |     for (var i = length - 1; i >= 0; i--) { | ||
|  |       result = result * 0x100 + buffer[i]; | ||
|  |     } | ||
|  |   } else { | ||
|  |     for (var _i2 = length - 1; _i2 >= 0; _i2--) { | ||
|  |       var one = buffer[_i2]; | ||
|  |       result *= 0x100; | ||
|  | 
 | ||
|  |       if (isLossyToAdd(result, one)) { | ||
|  |         lossy = true; | ||
|  |       } | ||
|  | 
 | ||
|  |       result += one; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   return { | ||
|  |     value: result, | ||
|  |     lossy: lossy | ||
|  |   }; | ||
|  | } | ||
|  | /** | ||
|  |  * Writes a little-endian 64-bit signed int into a buffer. | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function writeInt64(value, buffer) { | ||
|  |   if (value < MIN_EXACT_INT64 || value > MAX_EXACT_INT64) { | ||
|  |     throw new Error("Value out of range."); | ||
|  |   } | ||
|  | 
 | ||
|  |   if (value < 0) { | ||
|  |     value += BIT_64; | ||
|  |   } | ||
|  | 
 | ||
|  |   writeUInt64(value, buffer); | ||
|  | } | ||
|  | /** | ||
|  |  * Writes a little-endian 64-bit unsigned int into a buffer. | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function writeUInt64(value, buffer) { | ||
|  |   if (value < 0 || value > MAX_EXACT_UINT64) { | ||
|  |     throw new Error("Value out of range."); | ||
|  |   } | ||
|  | 
 | ||
|  |   var lowWord = value % BIT_32; | ||
|  |   var highWord = Math.floor(value / BIT_32); | ||
|  |   buffer.writeUInt32LE(lowWord, 0); | ||
|  |   buffer.writeUInt32LE(highWord, 4); | ||
|  | } |