ArrayBufferCopyAndDetach.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. 'use strict';
  2. var GetIntrinsic = require('get-intrinsic');
  3. var min = require('math-intrinsics/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-bound');
  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. // https://262.ecma-international.org/15.0/#sec-arraybuffercopyanddetach
  33. module.exports = function ArrayBufferCopyAndDetach(arrayBuffer, newLength, preserveResizability) {
  34. if (preserveResizability !== 'PRESERVE-RESIZABILITY' && preserveResizability !== 'FIXED-LENGTH') {
  35. throw new $TypeError('`preserveResizability` must be ~PRESERVE-RESIZABILITY~ or ~FIXED-LENGTH~');
  36. }
  37. if (!isArrayBuffer(arrayBuffer) || isSharedArrayBuffer(arrayBuffer)) {
  38. throw new $TypeError('`arrayBuffer` must be a non-shared ArrayBuffer'); // steps 1 - 2
  39. }
  40. var abByteLength;
  41. var newByteLength;
  42. if (typeof newLength === 'undefined') { // step 3
  43. newByteLength = byteLength(arrayBuffer); // step 3.a
  44. abByteLength = newByteLength;
  45. } else { // step 4
  46. newByteLength = ToIndex(newLength); // step 4.a
  47. }
  48. if (IsDetachedBuffer(arrayBuffer)) {
  49. throw new $TypeError('`arrayBuffer` must not be detached'); // step 5
  50. }
  51. var newMaxByteLength;
  52. if (preserveResizability === 'PRESERVE-RESIZABILITY' && !IsFixedLengthArrayBuffer(arrayBuffer)) { // step 6
  53. newMaxByteLength = $maxByteLength(arrayBuffer); // step 6.a
  54. } else { // step 7
  55. newMaxByteLength = 'EMPTY'; // step 7.a
  56. }
  57. // commented out since there's no way to set or access this key
  58. // 8. If arrayBuffer.[[ArrayBufferDetachKey]] is not undefined, throw a TypeError exception.
  59. // 9. Let newBuffer be ? AllocateArrayBuffer(%ArrayBuffer%, newByteLength, newMaxByteLength).
  60. var newBuffer = newMaxByteLength === 'EMPTY' ? new $ArrayBuffer(newByteLength) : new $ArrayBuffer(newByteLength, { maxByteLength: newMaxByteLength });
  61. if (typeof abByteLength !== 'number') {
  62. abByteLength = byteLength(arrayBuffer);
  63. }
  64. var copyLength = min(newByteLength, abByteLength); // step 10
  65. if (newByteLength > copyLength || newMaxByteLength !== 'EMPTY') {
  66. var taNew = new $Uint8Array(newBuffer);
  67. var taOld = new $Uint8Array(arrayBuffer);
  68. for (var i = 0; i < copyLength; i++) {
  69. taNew[i] = taOld[i];
  70. }
  71. } else {
  72. newBuffer = $abSlice(arrayBuffer, 0, copyLength); // ? optimization for when the new buffer will not be larger than the old one
  73. }
  74. /*
  75. 11. Let fromBlock be arrayBuffer.[[ArrayBufferData]].
  76. 12. Let toBlock be newBuffer.[[ArrayBufferData]].
  77. 13. Perform CopyDataBlockBytes(toBlock, 0, fromBlock, 0, copyLength).
  78. 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.
  79. */
  80. DetachArrayBuffer(arrayBuffer); // step 15
  81. return newBuffer; // step 16
  82. };