Repository navigation
Description
Appending a numeric value to a specialized Array constructs a temporary boxed Dynamic, passes it through the virtual __push interface, then immediately converts it back to the backing array's numeric element type. Indexed appends use the existing Variant setter path and avoid that box/unbox round trip.
This is common buffer and collection building, rather than a rare input pattern. The boxed values also create avoidable GC work.
Tested at d734565 on Windows x64, Haxe 4.3.7, MSVC 19.44.35213, release HXCPP_M64.
The probe builds an Array using either:
for (i in 1...n) array.push(i + 1000);or:
for (i in 1...n) array[i] = i + 1000;Both start with the same first numeric element, have the same final length and contents, and use the same specialized backing type. Float cases use i + 1000.5. Values are outside the small constant-box cache. Capacity is either reserved before timing or allowed to grow normally. Array construction, reserve and full value verification are outside timing. One warmup, median of seven samples, full GC before each sample, one million final elements.
| Elements | Capacity reserved | push | Indexed append |
|---|---|---|---|
| Int | yes | 6.960 ms | 2.216 ms |
| Float | yes | 5.891 ms | 2.662 ms |
| Int | no | 8.502 ms | 4.663 ms |
| Float | no | 11.128 ms | 6.766 ms |
With capacity reserved, push was about 3.1 times slower for ints and 2.2 times slower for floats. These are focused append timings, not an application-wide speedup or measurements of an implemented fix.
Generated C++ calls array->push(value) for the first path and array->set(index,value) for the control. In include/cpp/VirtualArray.h, push and Add call EnsureStorage(inVal) and then base->__push(Dynamic(inVal)). The numeric Array_obj::_push override converts that Dynamic to ELEM. The indexed setter instead calls base->set(index,inVal), whose cpp::Variant argument stores numeric payloads directly without allocating a numeric wrapper.
Avoid the temporary numeric box for specialized dynamic-array appends, using the existing typed/Variant machinery where appropriate. Preserve push's returned length, widening, null behavior, fixed backing arrays, exact Int64 values, special floats and GC barriers. The same push/Add pattern should be considered together. This can be addressed entirely within libhxcpp without compiler or stdlib changes.
I added conventional local coverage first in test/regression/DynamicArrayPush, with Main.hx, build.hxml and stdout.txt. It checks integer and Float contents, push return values, mixed pushes, exact Int64 preservation during widening, a shared fixed backing array, NaN/infinities and negative zero. All checks pass on the current runtime; the test protects behavior during an optimization and contains no timing assertions.
No runtime implementation changes have been made.
Activity
Append numbers and strings to Array<Dynamic> without boxing them