Skip to content

Instantly share code, notes, and snippets.

@shibukawa
Last active August 29, 2015 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shibukawa/18c04fce35eda662edaa to your computer and use it in GitHub Desktop.
Save shibukawa/18c04fce35eda662edaa to your computer and use it in GitHub Desktop.
memcpy for JS
var endIndex = srcIndex + length;
while (srcIndex < endIndex) {
buffer[dstIndex++] = buffer[srcIndex++];
}
var length = 200;
function makeBuffer() {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = i;
}
return array;
}
function memcpy(array, srcIndex, dstIndex, length) {
if ((dstIndex - srcIndex) < length) {
copyUint8(array, srcIndex, dstIndex, length);
return;
}
switch ((srcIndex % 4) * 4 + dstIndex % 4) {
case 0: // 0 vs 0
copyUint32(array, srcIndex >>> 2, dstIndex >>> 2, length >>> 2);
switch (length % 4) {
case 1:
array[dstIndex + length - 1] = array[srcIndex + length - 1];
break;
case 2:
copyUint16(array, (srcIndex + length - 2) >>> 1, (dstIndex + length - 2) >>> 1, 1);
break;
case 3:
copyUint16(array, (srcIndex + length - 2) >>> 1, (dstIndex + length - 2) >>> 1, 1);
array[dstIndex + length - 1] = array[srcIndex + length - 1];
break;
}
break;
case 1: // 0 vs 1
copyUint8(array, srcIndex, dstIndex, length);
break;
case 2: // 0 vs 2
copyUint16(array, srcIndex >>> 1, dstIndex >>> 1, length >>> 1);
if (length % 2) {
array[dstIndex + length - 1] = array[srcIndex + length - 1];
}
break;
case 3: // 0 vs 3
copyUint8(array, srcIndex, dstIndex, length);
break;
case 4: // 1 vs 0
copyUint8(array, srcIndex, dstIndex, length);
break;
case 5: // 1 vs 1
array[dstIndex] = array[srcIndex];
copyUint16(array, (srcIndex + 1) >>> 1, (dstIndex + 1 ) >>> 1, 1);
copyUint32(array, (3 + srcIndex) >>> 2, (3 + dstIndex >>> 2), (length - 3) >>> 2);
switch (length % 4) {
case 0:
array[dstIndex + length - 1] = array[srcIndex + length - 1];
break;
case 1:
copyUint16(array, (srcIndex + length - 2) >>> 1, (dstIndex + length - 2) >>> 1, 1);
break;
case 2:
copyUint16(array, (srcIndex + length - 2) >>> 1, (dstIndex + length - 2) >>> 1, 1);
array[dstIndex + length - 1] = array[srcIndex + length - 1];
break;
}
break;
case 6: // 1 vs 2
copyUint8(array, srcIndex, dstIndex, length);
break;
case 7: // 1 vs 3
copyUint8(array, srcIndex, dstIndex, length);
array[dstIndex] = array[srcIndex];
copyUint16(array, (1 + srcIndex) >>> 1, (1 + dstIndex) >>> 1, (length - 1) >>> 1);
if ((srcIndex + length) % 2) {
array[dstIndex + length - 1] = array[srcIndex + length - 1];
}
break;
case 8: // 2 vs 0
copyUint16(array, srcIndex >>> 1, dstIndex >>> 1, length >>> 1);
if (length % 2) {
array[dstIndex + length - 1] = array[srcIndex + length - 1];
}
break;
case 9: // 2 vs 1
copyUint8(array, srcIndex, dstIndex, length);
break;
case 10: // 2 vs 2
copyUint16(array, srcIndex >>> 1, dstIndex >>> 1, 1);
copyUint32(array, (2 + srcIndex) >>> 2, (2 + dstIndex >>> 2), (length - 2) >>> 2);
switch (length % 4) {
case 0:
copyUint16(array, (srcIndex + length - 2) >>> 1, (dstIndex + length - 2) >>> 1, 1);
break;
case 1:
copyUint16(array, (srcIndex + length - 2) >>> 1, (dstIndex + length - 2) >>> 1, 1);
array[dstIndex + length - 1] = array[srcIndex + length - 1];
break;
case 3:
array[dstIndex + length - 1] = array[srcIndex + length - 1];
break;
}
break;
case 11: // 2 vs 3
copyUint8(array, srcIndex, dstIndex, length);
break;
case 12: // 3 vs 0
copyUint8(array, srcIndex, dstIndex, length);
break;
case 13: // 3 vs 1
copyUint8(array, srcIndex, dstIndex, length);
array[dstIndex] = array[srcIndex];
copyUint16(array, (1 + srcIndex) >>> 1, (1 + dstIndex) >>> 1, (length - 1) >>> 1);
if ((srcIndex + length) % 2) {
array[dstIndex + length - 1] = array[srcIndex + length - 1];
}
break;
case 14: // 3 vs 2
copyUint8(array, srcIndex, dstIndex, length);
break;
case 15: // 3 vs 3
array[dstIndex] = array[srcIndex];
copyUint32(array, (1 + srcIndex) >>> 2, (1 + dstIndex >>> 2), (length - 1) >>> 2);
switch (length % 4) {
case 0:
copyUint16(array, (srcIndex + length - 2) >>> 1, (dstIndex + length - 2) >>> 1, 1);
array[dstIndex + length - 1] = array[srcIndex + length - 1];
break;
case 2:
array[dstIndex + length - 1] = array[srcIndex + length - 1];
break;
case 3:
copyUint16(array, (srcIndex + length - 2) >>> 1, (dstIndex + length - 2) >>> 1, 1);
break;
}
break;
}
}
function copyUint8(array, srcIndex, dstIndex, length) {
var endIndex = srcIndex + length;
while(srcIndex < endIndex) {
array[dstIndex++] = array[srcIndex++];
}
}
function copyUint16(array, srcIndex, dstIndex, length) {
var srcIndex = srcIndex * 2;
var dstIndex = dstIndex * 2;
var endIndex = srcIndex + length * 2;
while(srcIndex < endIndex) {
array[dstIndex++] = array[srcIndex++];
}
}
function copyUint32(array, srcIndex, dstIndex, length) {
var srcIndex = srcIndex * 4;
var dstIndex = dstIndex * 4;
var endIndex = srcIndex + length * 4;
while(srcIndex < endIndex) {
array[dstIndex++] = array[srcIndex++];
}
}
function dump(src, dst, l, array1, array2) {
console.log("src:", src, "dst:", dst, "length:", l);
console.log("memcpy:", array1.join(", "));
console.log("original :", array2.join(", "));
console.log("\n");
}
function compare(src, dst, l, array1, array2) {
for (var i = 0; i < length; i++) {
if (array1[i] !== array2[i]) {
dump(src, dst, l, array1, array2);
return;
}
}
}
function test(callback) {
for (var s=0; s < length - 8; s++) {
for (var l=4; l * 2 + s < length; l++) {
for (var o=0; l + s + o < length; o++) {
var src = s;
var dst = s + o;
callback(src, dst, l);
}
}
}
}
test(function(src, dst, l) {
var buffer1 = makeBuffer();
var buffer2 = makeBuffer();
memcpy(buffer1, src, dst, l);
copyUint8(buffer2, src, dst, l);
compare(src, dst, l, buffer1, buffer2);
});
/*
* Copy memory block within same ArrayBuffer like ArrayBuffer.copyWithin()
*/
function _memcpy(output8 : Uint8Array, output16 : Uint16Array, output32 : Uint32Array, dstIndex : int, srcIndex : int, length : int) : void {
if ((dstIndex - srcIndex) < length) {
var endIndex = srcIndex + length;
while (srcIndex < endIndex) {
output8[dstIndex++] = output8[srcIndex++];
}
return;
}
switch ((srcIndex % 4) * 4 + dstIndex % 4) {
case 1: // 0 vs 1
case 3: // 0 vs 3
case 4: // 1 vs 0
case 6: // 1 vs 2
case 9: // 2 vs 1
case 11: // 2 vs 3
case 12: // 3 vs 0
case 14: // 3 vs 2
var endIndex = srcIndex + length;
while (srcIndex < endIndex) {
output8[dstIndex++] = output8[srcIndex++];
}
break;
case 2: // 0 vs 2
case 8: // 2 vs 0
var dstIndex2 = dstIndex >>> 1;
var srcIndex2 = srcIndex >>> 1;
var endIndex2 = srcIndex2 + (length >>> 1);
while (srcIndex2 < endIndex2) {
output16[dstIndex2++] = output16[srcIndex2++];
}
if (length % 2) {
output8[dstIndex + length - 1] = output8[srcIndex + length - 1];
}
break;
case 7: // 1 vs 3
case 13: // 3 vs 1
output8[dstIndex] = output8[srcIndex];
var dstIndex2 = (1 + dstIndex) >>> 1;
var srcIndex2 = (1 + srcIndex) >>> 1;
var endIndex2 = srcIndex2 + ((length - 1) >>> 1);
while (srcIndex2 < endIndex2) {
output16[dstIndex2++] = output16[srcIndex2++];
}
if ((srcIndex + length) % 2) {
output8[dstIndex + length - 1] = output8[srcIndex + length - 1];
}
break;
case 0: // 0 vs 0
var dstIndex4 = dstIndex >>> 2;
var srcIndex4 = srcIndex >>> 2;
var endIndex4 = srcIndex4 + (length >>> 2);
while (srcIndex4 < endIndex4) {
output32[dstIndex4++] = output32[srcIndex4++];
}
switch (length % 4) {
case 1:
output8[dstIndex + length - 1] = output8[srcIndex + length - 1];
break;
case 2:
output16[(dstIndex + length - 2) >>> 1] = output16[(srcIndex + length - 2) >>> 1];
break;
case 3:
output16[(dstIndex + length - 2) >>> 1] = output16[(srcIndex + length - 2) >>> 1];
output8[dstIndex + length - 1] = output8[srcIndex + length - 1];
break;
}
break;
case 5: // 1 vs 1
output8[dstIndex] = output8[srcIndex];
output16[(dstIndex + 1) >>> 1] = output16[(srcIndex + 1) >>> 1];
var dstIndex4 = (3 + dstIndex) >>> 2;
var srcIndex4 = (3 + srcIndex) >>> 2;
var endIndex4 = srcIndex4 + ((length - 3) >>> 2);
while (srcIndex4 < endIndex4) {
output32[dstIndex4++] = output32[srcIndex4++];
}
switch (length % 4) {
case 0:
output8[dstIndex + length - 1] = output8[srcIndex + length - 1];
break;
case 1:
output16[(dstIndex + length - 2) >>> 1] = output16[(srcIndex + length - 2) >>> 1];
break;
case 2:
output16[(dstIndex + length - 2) >>> 1] = output16[(srcIndex + length - 2) >>> 1];
output8[dstIndex + length - 1] = output8[srcIndex + length - 1];
break;
}
break;
case 10: // 2 vs 2
output16[dstIndex >>> 1] = output16[srcIndex >>> 1];
var dstIndex4 = (2 + dstIndex) >>> 2;
var srcIndex4 = (2 + srcIndex) >>> 2;
var endIndex4 = srcIndex4 + ((length - 2) >>> 2);
while (srcIndex4 < endIndex4) {
output32[dstIndex4++] = output32[srcIndex4++];
}
switch (length % 4) {
case 0:
output16[(dstIndex + length - 2) >>> 1] = output16[(srcIndex + length - 2) >>> 1];
break;
case 1:
output16[(dstIndex + length - 2) >>> 1] = output16[(srcIndex + length - 2) >>> 1];
output8[dstIndex + length - 1] = output8[srcIndex + length - 1];
break;
case 3:
output8[dstIndex + length - 1] = output8[srcIndex + length - 1];
break;
}
break;
case 15: // 3 vs 3
output8[dstIndex] = output8[srcIndex];
var dstIndex4 = (1 + dstIndex) >>> 2;
var srcIndex4 = (1 + srcIndex) >>> 2;
var endIndex4 = srcIndex4 + ((length - 1) >>> 2);
while (srcIndex4 < endIndex4) {
output32[dstIndex4++] = output32[srcIndex4++];
}
switch (length % 4) {
case 0:
output16[(dstIndex + length - 2) >>> 1] = output16[(srcIndex + length - 2) >>> 1];
output8[dstIndex + length - 1] = output8[srcIndex + length - 1];
break;
case 2:
output8[dstIndex + length - 1] = output8[srcIndex + length - 1];
break;
case 3:
output16[(dstIndex + length - 2) >>> 1] = output16[(srcIndex + length - 2) >>> 1];
break;
}
break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment