Какой самый простой способ скопировать объект ArrayBuffer?
Я работаю с объектами ArrayBuffer
, и я хотел бы их дублировать. Хотя это довольно легко с фактическими указателями и memcpy
, я не мог найти простой способ сделать это в Javascript.
Прямо сейчас, вот как я копирую свой ArrayBuffers
:
function copy(buffer)
{
var bytes = new Uint8Array(buffer);
var output = new ArrayBuffer(buffer.byteLength);
var outputBytes = new Uint8Array(output);
for (var i = 0; i < bytes.length; i++)
outputBytes[i] = bytes[i];
return output;
}
Есть ли более красивый способ?
Ответы
Ответ 1
ArrayBuffer
должен поддерживать slice
(http://www.khronos.org/registry/typedarray/specs/latest/), чтобы вы могли попробовать,
buffer.slice(0);
который работает в Chrome 18, но не в Firefox 10 или 11. Что касается Firefox, вам нужно скопировать его вручную. Вы можете обезглавить патч slice()
в Firefox, потому что Chrome slice()
будет превосходить ручную копию. Это будет выглядеть примерно так:
if (!ArrayBuffer.prototype.slice)
ArrayBuffer.prototype.slice = function (start, end) {
var that = new Uint8Array(this);
if (end == undefined) end = that.length;
var result = new ArrayBuffer(end - start);
var resultArray = new Uint8Array(result);
for (var i = 0; i < resultArray.length; i++)
resultArray[i] = that[i + start];
return result;
}
Затем вы можете позвонить,
buffer.slice(0);
чтобы скопировать массив как в Chrome, так и в Firefox.
Ответ 2
Я предпочитаю следующий метод
function copy(src) {
var dst = new ArrayBuffer(src.byteLength);
new Uint8Array(dst).set(new Uint8Array(src));
return dst;
}
Ответ 3
Похоже, что просто передача в исходном dataview выполняет копию:
var a = new Uint8Array([2,3,4,5]);
var b = new Uint8Array(a);
a[0] = 6;
console.log(a); // [6, 3, 4, 5]
console.log(b); // [2, 3, 4, 5]
Протестировано в FF 33 и Chrome 36.
Ответ 4
Хммм... если это Uint8Array, который вы хотите отрезать (что логически, должно быть), это может сработать.
if (!Uint8Array.prototype.slice && 'subarray' in Uint8Array.prototype)
Uint8Array.prototype.slice = Uint8Array.prototype.subarray;
Ответ 5
Более быстрая и немного более сложная версия chuckj ответа. Следует использовать операции копирования ~ ~ 8x на больших массивах Typed. В основном мы копируем как можно больше 8-байтовых блоков, а затем копируем оставшиеся 0-7 байтов. Это особенно полезно в текущей версии IE, так как у него нет метода среза, реализованного для ArrayBuffer.
if (!ArrayBuffer.prototype.slice)
ArrayBuffer.prototype.slice = function (start, end) {
if (end == undefined) end = that.length;
var length = end - start;
var lengthDouble = Math.floor(length / Float64Array.BYTES_PER_ELEMENT);
// ArrayBuffer that will be returned
var result = new ArrayBuffer(length);
var that = new Float64Array(this, start, lengthDouble)
var resultArray = new Float64Array(result, 0, lengthDouble);
for (var i = 0; i < resultArray.length; i++)
resultArray[i] = that[i];
// copying over the remaining bytes
that = new Uint8Array(this, start + lengthDouble * Float64Array.BYTES_PER_ELEMENT)
resultArray = new Uint8Array(result, lengthDouble * Float64Array.BYTES_PER_ELEMENT);
for (var i = 0; i < resultArray.length; i++)
resultArray[i] = that[i];
return result;
}
Ответ 6
Вот и все ответы просто великолепны!
Но что, если мне нужно изменить размер ArrayBuffer, как я понял, это означает, что мне нужно создать новый буфер через cray ArrayBuffer (oldSize * 2), а затем скопировать в него старый буфер. Любой способ сделать это быстро с помощью какого-либо метода "копирования"?
Ответ 7
В некоторых случаях (например, веб-аудио Audiobuffers) у вас есть только ссылка на 2 массива.
Так что если у вас есть array1 как float32Array и array2 как float32Array,
Вы должны сделать элемент за копией элемента.
Для этого вы можете использовать разные методы.
var ib=z.inputBuffer.getChannelData(0);
var ob=z.outputBuffer.getChannelData(0);
это
ib.forEach((chd,i)=>ob[i]=chd);
или это лучше и, вероятно, быстрее
ob.set(ib);
Это потому, что Array.set заполняет существующий массив несколькими данными (даже из другого массива)