diff --git a/packages/arrays/src/index.ts b/packages/arrays/src/index.ts index ffa20f967b..739c4ed3a2 100644 --- a/packages/arrays/src/index.ts +++ b/packages/arrays/src/index.ts @@ -8,6 +8,7 @@ export * from "./find"; export * from "./fill-range"; export * from "./fuzzy-match"; export * from "./is-sorted"; +export * from "./insert"; export * from "./into"; export * from "./iterator"; export * from "./levenshtein"; diff --git a/packages/arrays/src/insert.ts b/packages/arrays/src/insert.ts new file mode 100644 index 0000000000..f4cf0b0c97 --- /dev/null +++ b/packages/arrays/src/insert.ts @@ -0,0 +1,35 @@ +/** + * Inserts `x` into `buf` at index `i` and ensures that array length doesn't + * grow beyond max `k` items (default: unbounded). + * + * @remarks + * The function will have no effect iff `i<0` or `i>=k` or `k<1`. If + * `buf.length` is larger than `k`, only the index range [i..k) will be + * modified. + * + * In benchmarking with 8, 16, 32, 64 element arrays, this function is + * consistently 7-16x faster than `Array.prototype.copyWithin`. See + * `/bench/insert.ts` + * + * @param buf + * @param x + * @param i + * @param k + */ +export const insert = (buf: T[], x: T, i: number, k = Infinity) => + i < 0 || i >= k || k < 1 ? buf : insertUnsafe(buf, x, i, k); + +/** + * Same as {@link insert} but without any bounds/index checks. + * + * @param buf + * @param x + * @param i + * @param k + */ +export const insertUnsafe = (buf: T[], x: T, i: number, k = Infinity) => { + let j = buf.length < k ? buf.length + 1 : k; + for (; --j > i; ) buf[j] = buf[j - 1]; + buf[i] = x; + return buf; +};