Batch copy to array (seeking champion)


We already have a useful typedArray.set(array, offset = 0), but I've run into quite a few glitches with that, cases where an end index would be incredibly useful and cases where I don't want to start at the beginning of array. However, that's just a minor nice-to-have to avoid an allocation. The bigger issue I've been running into is that there's no equivalent with arrays, and I'd say at least 1% of all my for loops that require indices (1 in 100 is a lot) could be outright replaced with this, with another of 2-3% having at least some use for it. (In peformance-critical code, this number ends up even more inflated, with as much as 5% of all loops being literally just this.) Array.prototype.copyWithin already exists, so I suspect it's as much a spec omission as anything, and in particular, the parameter order and handling proposed there is the same as that method. (The general intuition with my proposal is that array.copyWithin(...args) should be equivalent to array.set(array, ...args) in most cases.)

Seeking champion(s) and/or other involvement. No polyfills (yet), of course, though polyfills would be very straightforward to write.

Can't you do this with Array.prototype.splice?

In theory you could:

// array.set(other, offset)
array.splice(offset, other.length, ...other)

// array.set(other, offset, start, end)
var temp = other.slice(start, end)
array.splice(offset, temp.length, ...temp)

But there's a few issues with that:

  1. No implementation optimizes for it. (In fact, no implementation optimizes away argument spreads in general, even for obvious cases like array.push(...other).) Instead, other gets copied to the full arguments list, which is untenable for all but small arrays.
  2. It returns an entire array of all the removed values when returning, which is almost never used. (If you really need that, you can literally just do array.slice(index, index + other.length) beforehand.)
  3. Copying just a portion of an array to another is a surprisingly common need in my experience, and the above idiom is very expensive as it makes not one, but four different copies: one to slice, one to spread, one to save for the result, and one to store.

And since this occurs primarily in perf-sensitive locations, splice is just not practical for my use case. Even if hardware acceleration is used, it would still be slower unless your CPU supports SIMD with over 4 lanes for the pointer width of your addresses (not the case on any mobile CPU), memmove is smart enough to use it, and the engine is smart enough to use memmove (not the case in any engine AFAICT).

And keep in mind, this is something splice and friends could efficiently be built on - it's a lower-level primitive.