ArrayBufferCopyAndDetach.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. 'use strict';
  2. var GetIntrinsic = require('get-intrinsic');
  3. var min = GetIntrinsic('%Math.min%');
  4. var $TypeError = require('es-errors/type');
  5. var $ArrayBuffer = GetIntrinsic('%ArrayBuffer%', true);
  6. var $Uint8Array = GetIntrinsic('%Uint8Array%', true);
  7. var callBound = require('call-bind/callBound');
  8. var byteLength = require('array-buffer-byte-length');
  9. var $maxByteLength = callBound('%ArrayBuffer.prototype.maxByteLength%', true);
  10. var copy = function copyAB(src, start, end) {
  11. var that = new $Uint8Array(src);
  12. if (typeof end === 'undefined') {
  13. end = that.length; // eslint-disable-line no-param-reassign
  14. }
  15. var result = new $ArrayBuffer(end - start);
  16. var resultArray = new $Uint8Array(result);
  17. for (var i = 0; i < resultArray.length; i++) {
  18. resultArray[i] = that[i + start];
  19. }
  20. return result;
  21. };
  22. var $abSlice = callBound('%ArrayBuffer.prototype.slice%', true)
  23. || function slice(ab, a, b) { // in node < 0.11, slice is an own nonconfigurable property
  24. return ab.slice ? ab.slice(a, b) : copy(ab, a, b); // node 0.8 lacks `slice`
  25. };
  26. var DetachArrayBuffer = require('./DetachArrayBuffer');
  27. var IsDetachedBuffer = require('./IsDetachedBuffer');
  28. var IsFixedLengthArrayBuffer = require('./IsFixedLengthArrayBuffer');
  29. var ToIndex = require('./ToIndex');
  30. var isArrayBuffer = require('is-array-buffer');
  31. var isSharedArrayBuffer = require('is-shared-array-buffer');
  32. module.exports = function ArrayBufferCopyAndDetach(arrayBuffer, newLength, preserveResizability) {
  33. if (preserveResizability !== 'PRESERVE-RESIZABILITY' && preserveResizability !== 'FIXED-LENGTH') {
  34. throw new $TypeError('`preserveResizability` must be ~PRESERVE-RESIZABILITY~ or ~FIXED-LENGTH~');
  35. }
  36. if (!isArrayBuffer(arrayBuffer) || isSharedArrayBuffer(arrayBuffer)) {
  37. throw new $TypeError('`arrayBuffer` must be an ArrayBuffer'); // steps 1 - 2
  38. }
  39. var abByteLength;
  40. var newByteLength;
  41. if (typeof newLength === 'undefined') { // step 3
  42. newByteLength = byteLength(arrayBuffer); // step 3.a
  43. abByteLength = newByteLength;
  44. } else { // step 4
  45. newByteLength = ToIndex(newLength); // step 4.a
  46. }
  47. if (IsDetachedBuffer(arrayBuffer)) {
  48. throw new $TypeError('`arrayBuffer` must not be detached'); // step 5
  49. }
  50. var newMaxByteLength;
  51. if (preserveResizability === 'PRESERVE-RESIZABILITY' && !IsFixedLengthArrayBuffer(arrayBuffer)) { // step 6
  52. newMaxByteLength = $maxByteLength(arrayBuffer); // step 6.a
  53. } else { // step 7
  54. newMaxByteLength = 'EMPTY'; // step 7.a
  55. }
  56. // commented out since there's no way to set or access this key
  57. // 8. If arrayBuffer.[[ArrayBufferDetachKey]] is not undefined, throw a TypeError exception.
  58. // 9. Let newBuffer be ? AllocateArrayBuffer(%ArrayBuffer%, newByteLength, newMaxByteLength).
  59. var newBuffer = newMaxByteLength === 'EMPTY' ? new $ArrayBuffer(newByteLength) : new $ArrayBuffer(newByteLength, { maxByteLength: newMaxByteLength });
  60. if (typeof abByteLength !== 'number') {
  61. abByteLength = byteLength(arrayBuffer);
  62. }
  63. var copyLength = min(newByteLength, abByteLength); // step 10
  64. if (newByteLength > copyLength) {
  65. var taNew = new $Uint8Array(newBuffer);
  66. var taOld = new $Uint8Array(arrayBuffer);
  67. for (var i = 0; i < copyLength; i++) {
  68. taNew[i] = taOld[i];
  69. }
  70. } else {
  71. newBuffer = $abSlice(arrayBuffer, 0, copyLength); // ? optimization for when the new buffer will not be larger than the old one
  72. }
  73. /*
  74. 11. Let fromBlock be arrayBuffer.[[ArrayBufferData]].
  75. 12. Let toBlock be newBuffer.[[ArrayBufferData]].
  76. 13. Perform CopyDataBlockBytes(toBlock, 0, fromBlock, 0, copyLength).
  77. 14. NOTE: Neither creation of the new Data Block nor copying from the old Data Block are observable. Implementations may implement this method as a zero-copy move or a realloc.
  78. */
  79. DetachArrayBuffer(arrayBuffer); // step 15
  80. return newBuffer; // step 16
  81. };