$.buffer.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. 'use strict';
  2. var $ = require('./$')
  3. , global = require('./$.global')
  4. , $typed = require('./$.typed')
  5. , redefineAll = require('./$.redefine-all')
  6. , strictNew = require('./$.strict-new')
  7. , toInteger = require('./$.to-integer')
  8. , toLength = require('./$.to-length')
  9. , arrayFill = require('./$.array-fill')
  10. , $ArrayBuffer = global.ArrayBuffer
  11. , $DataView = global.DataView
  12. , Math = global.Math
  13. , parseInt = global.parseInt
  14. , abs = Math.abs
  15. , pow = Math.pow
  16. , min = Math.min
  17. , floor = Math.floor
  18. , log = Math.log
  19. , LN2 = Math.LN2
  20. , BYTE_LENGTH = 'byteLength';
  21. // pack / unpack based on
  22. // https://github.com/inexorabletash/polyfill/blob/v0.1.11/typedarray.js#L123-L264
  23. // TODO: simplify
  24. var signed = function(value, bits){
  25. var s = 32 - bits;
  26. return value << s >> s;
  27. };
  28. var unsigned = function(value, bits){
  29. var s = 32 - bits;
  30. return value << s >>> s;
  31. };
  32. var roundToEven = function(n){
  33. var w = floor(n)
  34. , f = n - w;
  35. return f < .5 ? w : f > .5 ? w + 1 : w % 2 ? w + 1 : w;
  36. };
  37. var packI8 = function(n){
  38. return [n & 0xff];
  39. };
  40. var unpackI8 = function(bytes){
  41. return signed(bytes[0], 8);
  42. };
  43. var packU8 = function(n){
  44. return [n & 0xff];
  45. };
  46. var unpackU8 = function(bytes){
  47. return unsigned(bytes[0], 8);
  48. };
  49. var packI16 = function(n){
  50. return [n & 0xff, n >> 8 & 0xff];
  51. };
  52. var unpackI16 = function(bytes){
  53. return signed(bytes[1] << 8 | bytes[0], 16);
  54. };
  55. var packU16 = function(n){
  56. return [n & 0xff, n >> 8 & 0xff];
  57. };
  58. var unpackU16 = function(bytes){
  59. return unsigned(bytes[1] << 8 | bytes[0], 16);
  60. };
  61. var packI32 = function(n){
  62. return [n & 0xff, n >> 8 & 0xff, n >> 16 & 0xff, n >> 24 & 0xff];
  63. };
  64. var unpackI32 = function(bytes){
  65. return signed(bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0], 32);
  66. };
  67. var packU32 = function(n){
  68. return [n & 0xff, n >> 8 & 0xff, n >> 16 & 0xff, n >> 24 & 0xff];
  69. };
  70. var unpackU32 = function(bytes){
  71. return unsigned(bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0], 32);
  72. };
  73. var packIEEE754 = function(v, ebits, fbits) {
  74. var bias = (1 << ebits - 1) - 1
  75. , s, e, f, i, bits, str, bytes;
  76. // Compute sign, exponent, fraction
  77. if (v !== v) {
  78. // NaN
  79. // http://dev.w3.org/2006/webapi/WebIDL/#es-type-mapping
  80. e = (1 << ebits) - 1;
  81. f = pow(2, fbits - 1);
  82. s = 0;
  83. } else if(v === Infinity || v === -Infinity){
  84. e = (1 << ebits) - 1;
  85. f = 0;
  86. s = v < 0 ? 1 : 0;
  87. } else if(v === 0){
  88. e = 0;
  89. f = 0;
  90. s = 1 / v === -Infinity ? 1 : 0;
  91. } else {
  92. s = v < 0;
  93. v = abs(v);
  94. if(v >= pow(2, 1 - bias)){
  95. e = min(floor(log(v) / LN2), 1023);
  96. var significand = v / pow(2, e);
  97. if(significand < 1){
  98. e -= 1;
  99. significand *= 2;
  100. }
  101. if(significand >= 2){
  102. e += 1;
  103. significand /= 2;
  104. }
  105. f = roundToEven(significand * pow(2, fbits));
  106. if(f / pow(2, fbits) >= 2){
  107. e = e + 1;
  108. f = 1;
  109. }
  110. if(e > bias){
  111. // Overflow
  112. e = (1 << ebits) - 1;
  113. f = 0;
  114. } else {
  115. // Normalized
  116. e = e + bias;
  117. f = f - pow(2, fbits);
  118. }
  119. } else {
  120. // Denormalized
  121. e = 0;
  122. f = roundToEven(v / pow(2, 1 - bias - fbits));
  123. }
  124. }
  125. // Pack sign, exponent, fraction
  126. bits = [];
  127. for(i = fbits; i; i -= 1){
  128. bits.push(f % 2 ? 1 : 0);
  129. f = floor(f / 2);
  130. }
  131. for(i = ebits; i; i -= 1){
  132. bits.push(e % 2 ? 1 : 0);
  133. e = floor(e / 2);
  134. }
  135. bits.push(s ? 1 : 0);
  136. bits.reverse();
  137. str = bits.join('');
  138. // Bits to bytes
  139. bytes = [];
  140. while(str.length){
  141. bytes.unshift(parseInt(str.slice(0, 8), 2));
  142. str = str.slice(8);
  143. }
  144. return bytes;
  145. };
  146. var unpackIEEE754 = function(bytes, ebits, fbits){
  147. var bits = []
  148. , i, j, b, str, bias, s, e, f;
  149. for(i = 0; i < bytes.length; ++i)for(b = bytes[i], j = 8; j; --j){
  150. bits.push(b % 2 ? 1 : 0);
  151. b = b >> 1;
  152. }
  153. bits.reverse();
  154. str = bits.join('');
  155. // Unpack sign, exponent, fraction
  156. bias = (1 << ebits - 1) - 1;
  157. s = parseInt(str.slice(0, 1), 2) ? -1 : 1;
  158. e = parseInt(str.slice(1, 1 + ebits), 2);
  159. f = parseInt(str.slice(1 + ebits), 2);
  160. // Produce number
  161. if(e === (1 << ebits) - 1)return f !== 0 ? NaN : s * Infinity;
  162. // Normalized
  163. else if(e > 0)return s * pow(2, e - bias) * (1 + f / pow(2, fbits));
  164. // Denormalized
  165. else if(f !== 0)return s * pow(2, -(bias - 1)) * (f / pow(2, fbits));
  166. return s < 0 ? -0 : 0;
  167. };
  168. var unpackF64 = function(b){
  169. return unpackIEEE754(b, 11, 52);
  170. };
  171. var packF64 = function(v){
  172. return packIEEE754(v, 11, 52);
  173. };
  174. var unpackF32 = function(b){
  175. return unpackIEEE754(b, 8, 23);
  176. };
  177. var packF32 = function(v){
  178. return packIEEE754(v, 8, 23);
  179. };
  180. var addGetter = function(C, key, internal){
  181. $.setDesc(C.prototype, key, {get: function(){ return this[internal]; }});
  182. };
  183. var get = function(view, bytes, index, conversion, isLittleEndian){
  184. var numIndex = +index
  185. , intIndex = toInteger(numIndex);
  186. if(numIndex != intIndex || intIndex < 0 || intIndex + bytes > view._l)throw RangeError();
  187. var store = view._b._b
  188. , start = intIndex + view._o
  189. , pack = store.slice(start, start + bytes);
  190. isLittleEndian || pack.reverse();
  191. return conversion(pack);
  192. };
  193. var set = function(view, bytes, index, conversion, value, isLittleEndian){
  194. var numIndex = +index
  195. , intIndex = toInteger(numIndex);
  196. if(numIndex != intIndex || intIndex < 0 || intIndex + bytes > view._l)throw RangeError();
  197. var store = view._b._b
  198. , start = intIndex + view._o
  199. , pack = conversion(+value);
  200. isLittleEndian || pack.reverse();
  201. for(var i = 0; i < bytes; i++)store[start + i] = pack[i];
  202. };
  203. if(!$typed.ABV){
  204. $ArrayBuffer = function ArrayBuffer(length){
  205. strictNew(this, $ArrayBuffer, 'ArrayBuffer');
  206. var numberLength = +length
  207. , byteLength = toLength(numberLength);
  208. if(numberLength != byteLength)throw RangeError();
  209. this._b = arrayFill.call(Array(byteLength), 0);
  210. this._l = byteLength;
  211. };
  212. addGetter($ArrayBuffer, BYTE_LENGTH, '_l');
  213. $DataView = function DataView(buffer, byteOffset, byteLength){
  214. strictNew(this, $DataView, 'DataView');
  215. if(!(buffer instanceof $ArrayBuffer))throw TypeError();
  216. var bufferLength = buffer._l
  217. , offset = toInteger(byteOffset);
  218. if(offset < 0 || offset > bufferLength)throw RangeError();
  219. byteLength = byteLength === undefined ? bufferLength - offset : toLength(byteLength);
  220. if(offset + byteLength > bufferLength)throw RangeError();
  221. this._b = buffer;
  222. this._o = offset;
  223. this._l = byteLength;
  224. };
  225. addGetter($DataView, 'buffer', '_b');
  226. addGetter($DataView, BYTE_LENGTH, '_l');
  227. addGetter($DataView, 'byteOffset', '_o');
  228. redefineAll($DataView.prototype, {
  229. getInt8: function getInt8(byteOffset){
  230. return get(this, 1, byteOffset, unpackI8);
  231. },
  232. getUint8: function getUint8(byteOffset){
  233. return get(this, 1, byteOffset, unpackU8);
  234. },
  235. getInt16: function getInt16(byteOffset /*, littleEndian */){
  236. return get(this, 2, byteOffset, unpackI16, arguments.length > 1 ? arguments[1] : undefined);
  237. },
  238. getUint16: function getUint16(byteOffset /*, littleEndian */){
  239. return get(this, 2, byteOffset, unpackU16, arguments.length > 1 ? arguments[1] : undefined);
  240. },
  241. getInt32: function getInt32(byteOffset /*, littleEndian */){
  242. return get(this, 4, byteOffset, unpackI32, arguments.length > 1 ? arguments[1] : undefined);
  243. },
  244. getUint32: function getUint32(byteOffset /*, littleEndian */){
  245. return get(this, 4, byteOffset, unpackU32, arguments.length > 1 ? arguments[1] : undefined);
  246. },
  247. getFloat32: function getFloat32(byteOffset /*, littleEndian */){
  248. return get(this, 4, byteOffset, unpackF32, arguments.length > 1 ? arguments[1] : undefined);
  249. },
  250. getFloat64: function getFloat64(byteOffset /*, littleEndian */){
  251. return get(this, 8, byteOffset, unpackF64, arguments.length > 1 ? arguments[1] : undefined);
  252. },
  253. setInt8: function setInt8(byteOffset, value){
  254. return set(this, 1, byteOffset, packI8, value);
  255. },
  256. setUint8: function setUint8(byteOffset, value){
  257. return set(this, 1, byteOffset, packU8, value);
  258. },
  259. setInt16: function setInt16(byteOffset, value /*, littleEndian */){
  260. return set(this, 2, byteOffset, packI16, value, arguments.length > 2 ? arguments[2] : undefined);
  261. },
  262. setUint16: function setUint16(byteOffset, value /*, littleEndian */){
  263. return set(this, 2, byteOffset, packU16, value, arguments.length > 2 ? arguments[2] : undefined);
  264. },
  265. setInt32: function setInt32(byteOffset, value /*, littleEndian */){
  266. return set(this, 4, byteOffset, packI32, value, arguments.length > 2 ? arguments[2] : undefined);
  267. },
  268. setUint32: function setUint32(byteOffset, value /*, littleEndian */){
  269. return set(this, 4, byteOffset, packU32, value, arguments.length > 2 ? arguments[2] : undefined);
  270. },
  271. setFloat32: function setFloat32(byteOffset, value /*, littleEndian */){
  272. return set(this, 4, byteOffset, packF32, value, arguments.length > 2 ? arguments[2] : undefined);
  273. },
  274. setFloat64: function setFloat64(byteOffset, value /*, littleEndian */){
  275. return set(this, 8, byteOffset, packF64, value, arguments.length > 2 ? arguments[2] : undefined);
  276. }
  277. });
  278. }
  279. require('./$.hide')($DataView.prototype, $typed.VIEW, true);
  280. module.exports = {
  281. ArrayBuffer: $ArrayBuffer,
  282. DataView: $DataView
  283. };