Hashlink: Ways to efficiently assign a hashlink array in an extern

I’ve been trying to find ways but none worked. I’m basically doing this:

@:hlNative("chart_file", "insertNotes") public static function insertNotes(values:hl.types.ArrayObj):Void {}
@:hlNative("chart_file", "removeNotes") public static function removeNotes(values:hl.types.ArrayObj):Void {}
HL_PRIM void HL_NAME(insertNotes)(varray* arr) {
    int64_t* ptr = hl_aptr(arr, int64_t);
    std::vector<int64_t> newNotes(ptr, ptr + arr->size);
    if (newNotes.empty()) return;

    int64_t oldLen = length;
    int64_t insCount = newNotes.size();
    int64_t newLen = oldLen + insCount;

    if (!remap(newLen)) throw std::runtime_error("resize failed");

    ensureScratch(oldLen + insCount);
    int64_t* oldCopy = scratchBuf;
    memcpy(oldCopy, data, oldLen * sizeof(int64_t));
    int64_t* newCopy = scratchBuf + oldLen;
    memcpy(newCopy, newNotes.data(), insCount * sizeof(int64_t));

    int64_t i = 0, j = 0, k = 0;
    while (i < oldLen && j < insCount) {
        int64_t tTime = extractTime(oldCopy[i]);
        int64_t dTime = extractTime(newCopy[j]);
        data[k++] = (tTime <= dTime) ? oldCopy[i++] : newCopy[j++];
    }
    while (i < oldLen) data[k++] = oldCopy[i++];
    while (j < insCount) data[k++] = newCopy[j++];

    length = newLen;
}

HL_PRIM void HL_NAME(removeNotes)(varray* arr) {
    int64_t* ptr = hl_aptr(arr, int64_t);
    std::vector<int64_t> toRemove(ptr, ptr + arr->size);
    if (toRemove.empty() || length == 0) return;

    int64_t write = 0, j = 0;
    for (int64_t i = 0; i < length; ++i) {
        if (j < (int64_t)toRemove.size() && data[i] == toRemove[j]) {
            ++j; // skip
        } else {
            if (write != i) data[write] = data[i];
            ++write;
        }
    }
    if (write != length) {
        if (!remap(write)) throw std::runtime_error("shrink failed in removeNotes");
    }
}

These extern functions are what I’m trying to pass a haxe array from.
Here’s the test sample (don’t mind the other things)

haxe.Timer.delay(function() {
	// START CHART SAMPLE
	var stamp = haxe.Timer.stamp();
	trace("Insert 1,000,000 notes (array)");
	Chart.load("assets/songs/god-eater");
	var arr = new Array<MetaNote>();
	for (i in 0...1000000) {
		arr.push(new MetaNote(Tools.betterInt64FromFloat((50.0 + (50.0 * i)) * 100),
			Math.floor(/*100*/0 * 0.2), // Equal to `note.duration / 5`.
			i % 9,
			0,
		1));
		//Sys.println(i);
	}
	Sys.println("Insert 1,000,000 notes (function)");
	var stamp2 = haxe.Timer.stamp();
	File.insertNotes(arr);
	Sys.println('Done! Took ${(haxe.Timer.stamp() - stamp2) * 1000}ms');
	// Remove notes
	var stamp3 = haxe.Timer.stamp();
	Sys.println("Remove 1,000,000 notes (function)");
	Sys.println(arr.length);
	File.removeNotes(arr);
	Sys.println('Done! Took ${(haxe.Timer.stamp() - stamp3) * 1000}ms');
	Sys.println('Inserting 1,000,000 notes fully done! Took ${(haxe.Timer.stamp() - stamp) * 1000}ms');
	Chart.destroy();
}, 8000);

Hm, no doing it like that isnt just going to work i think…

What are you trying to accomplish? Adding notes to an array and copying them out in c to a memory buffer?

What is MetaNote ? A c struct haxe class with @:struct or just a plain class / object?
To pass an array from Haxe usually you would use hl.NativeArray.

I ended up using the hl.bytes approach where I call the extern function using hl.Bytes.getArray(arr) and then in the extern you just:

HL_PRIM void HL_NAME(removeNotes)(vbyte* arr, int64_t len) {
    unsigned long long* ptr = (unsigned long long*)arr;
    //int64_t len = sizeof(ptr) / sizeof(int64_t);
    //printf("%s\n", std::to_string(len).c_str());
    std::vector<int64_t> toRemove(ptr, ptr + len);
    //...

Because I found out how to initialize an std vector from a pointer and no copy even occurs! That’s nice. So, I just casted the pointer as an unsigned long long and since a pointer doesn’t have a length I just added a length argument for simplification.

Anyway, hope anyone uses this method if they choose it or whatever thanks

Also MetaNote is an abstract out of Int64 with properties that fit inside the type using bit manipulation. Dimensionscape and I worked on it together and now it’s sitting there as a simple type.