Skip to content

Instantly share code, notes, and snippets.

@nmaier
Created June 30, 2014 22:40
Show Gist options
  • Save nmaier/ab4bfe59e8c8fcdc5b90 to your computer and use it in GitHub Desktop.
Save nmaier/ab4bfe59e8c8fcdc5b90 to your computer and use it in GitHub Desktop.

Alright then, lets start with copy array a into b, by reusing and modifying memset.

function memcpy(dst, src, size) {
  for (var i = 0; i < size; ++i) {
    dst[i] = src[i];
  }
} 

Now, thats nice, but does not actually make sure that the arrays have the same CType, better add a check for that.

function memcpy(dst, src, size) {
  if (!dst.constructor.elementType &&
      dst.constructor.elementType != src.constructor.elementType) {
    throw Error("Invalid CType: not an array, or array type mismatch");
  }
  for (var i = 0; i < size; ++i) {
    dst[i] = src[i];
  }
}

That would be in theory good enough and is a reasonable memcpy implementation (although we could test if both arrays are the same and skip the copy in that case).

But we want memmove, which makes sure that if the arrays overlap data will be still copied correctly. To do that, we need to compare the addresses and if src.address() < dst.address() then we'll need to copy back to front, else if src.address() < dst.address() then copy front to back, or if both are equal, it is actually the same array and we can skip the copy.

So first, how do we compare pointers again? By some casting to a number and comparing the numbers.

function comparePointers(a, b) {
  return ctypes.UInt64.compare(
    ctypes.cast(a, ctypes.uintptr_t).value,
    ctypes.cast(b, ctypes.uintptr_t).value
    );
}

Now, back to memmove:

function memmove(dst, src, size) {
  if (!dst.constructor.elementType &&
      dst.constructor.elementType != src.constructor.elementType) {
    throw Error("Invalid CType: not an array, or array type mismatch");
  }
  let cmp = comparePointers(src.address(), dst.address());
  if (cmp == 0) {
    // arrays point to the same memory location == are the same; skip
    return;
  }
  if (cmp < 0) { // src < dst -> back to front
     for (var i = size - 1; i >= 0; --i) {
       dst[i] = src[i];
     }
     return;
  }
  // else; src > dst -> front to back
  for (var i = 0; i < size; ++i) {
    dst[i] = src[i];
  }
}

Lets try it out.

// I chose uint8_t randomly, but it should work with all POD types.
// These cannot overlap, but that does not really matter
var src = ctypes.uint8_t.array(100)();
memset(src, 0xee, src.length);
var dst = ctypes.uint8_t.array(90)();
memset(dst, 0x33, dst.length);

console.log(src[0], dst[0]);
// Should be 0xee == 238; 0x33 = 51

// Test 1; Copy a couple of bytes from src to dst
memmove(dst, src, 10);
console.log(dst[0], "==", src[0]);
console.log(dst[9], "==", src[9]);
console.log(dst[10], "!=", src[10]);

// Test2; Reset dst and copy dst to src
// This should trigger the other loop in memmove
memset(dst, 0x33, dst.length);
memmove(src, dst, 10);
console.log(dst[0], "==", src[0]);
console.log(dst[9], "==", src[9]);
console.log(dst[10], "!=", src[10]);
@nmaier
Copy link
Author

nmaier commented Jun 30, 2014

@Noitidart

Since I wrote this already when your question got deleted, here you are anyway...

@Noitidart
Copy link

Awwww mann thanks!! I tried to figure out memmove by finding the python library implementation:

And on the py hg thing i cant manage to search that crap then i downloaded the whole repo then searched it. And came across:
http://hg.python.org/cpython/rev/c0f165e1dbc0

They removed it from python library or something so i was having the hardest time doing it :(

Thanks so much man!!

@Noitidart
Copy link

Hey man does this line right here:
if (!dst.constructor.elementType && dst.constructor.elementType != src.constructor.elementType) {

Should that be a || instead of &&?

@Noitidart
Copy link

Whoa whoa @nmaier memmove is availabe in library!

https://msdn.microsoft.com/en-us/library/aa246469%28v=vs.60%29.aspx

var msv = ctypes.open('msvcrt');
var memmove = msv.declare('memmove', ctypes.winapi_abi, ctypes.void_t, ctypes.voidptr_t, ctypes.voidptr_t, ctypes.size_t)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment