Skip to content

Instantly share code, notes, and snippets.

@Noitidart
Forked from nmaier/memmove.md
Last active August 29, 2015 14:03
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 Noitidart/2d9b44b18493f9339629 to your computer and use it in GitHub Desktop.
Save Noitidart/2d9b44b18493f9339629 to your computer and use it in GitHub Desktop.
_ff-addon-tutorial-JSCtypesMemmove - How to use memmove from js-ctypes. Tutorial by @nmaier.
Cu.import('resource://gre/modules/ctypes.jsm');
/*
* Alright then, lets start with copy array `a` into `b`, by reusing and modifying `memset`.
* Note: memset refered to is found here: http://stackoverflow.com/questions/24466228/memset-has-no-dll-so-how-ctype-it
*/
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`](http://stackoverflow.com/a/3572519/484441), 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.
* Note: Topic on comparing pointers: http://stackoverflow.com/a/24353278/1828637
*/
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]);
@Noitidart
Copy link
Author

README

Rev1

Rev2

  • Renamed to .js and added in ctypes.jsm so when people search and are trying to target Firefox they will be able to find this gist
  • Renamed typed to _ff-addon-snippet

Rev3

  • Had forgot to import ctypes.jsm in Rev2 so I did it now

Rev4

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