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

**URL:** <https://community.haxe.org/t/hashlink-ways-to-efficiently-assign-a-hashlink-array-in-an-extern/4667>\
**Category:** Haxe\
**Tags:** haxe-hl\
**Created:** [September 5, 2025, 12:13am UTC](https://community.haxe.org/t/hashlink-ways-to-efficiently-assign-a-hashlink-array-in-an-extern/4667 "2025-09-05T00:13:08Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![SomeGuyWhoLovesCodin](https://community.haxe.org/user_avatar/community.haxe.org/someguywholovescodin/32/2106_2.png) [@SomeGuyWhoLovesCodin](https://community.haxe.org/u/SomeGuyWhoLovesCodin)\
**Post date:** [September 5, 2025, 12:13am UTC](https://community.haxe.org/t/hashlink-ways-to-efficiently-assign-a-hashlink-array-in-an-extern/4667/1 "2025-09-05T00:13:08Z")

</div>

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

```haxe
@: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 {}

```

```cpp
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
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);

```

---

<div class="post-metadata">

**Author:** ![d0oo0p](https://community.haxe.org/user_avatar/community.haxe.org/d0oo0p/32/170_2.png) [@d0oo0p](https://community.haxe.org/u/d0oo0p)\
**Post date:** [September 10, 2025, 1:50pm UTC](https://community.haxe.org/t/hashlink-ways-to-efficiently-assign-a-hashlink-array-in-an-extern/4667/2 "2025-09-10T13:50:57Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![SomeGuyWhoLovesCodin](https://community.haxe.org/user_avatar/community.haxe.org/someguywholovescodin/32/2106_2.png) [@SomeGuyWhoLovesCodin](https://community.haxe.org/u/SomeGuyWhoLovesCodin)\
**Post date:** [September 11, 2025, 11:41am UTC](https://community.haxe.org/t/hashlink-ways-to-efficiently-assign-a-hashlink-array-in-an-extern/4667/3 "2025-09-11T11:41:25Z")

</div>

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:

```cpp
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

---

<div class="post-metadata">

**Author:** ![SomeGuyWhoLovesCodin](https://community.haxe.org/user_avatar/community.haxe.org/someguywholovescodin/32/2106_2.png) [@SomeGuyWhoLovesCodin](https://community.haxe.org/u/SomeGuyWhoLovesCodin)\
**Post date:** [September 11, 2025, 11:43am UTC](https://community.haxe.org/t/hashlink-ways-to-efficiently-assign-a-hashlink-array-in-an-extern/4667/4 "2025-09-11T11:43:46Z")

</div>

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.
