Skip to content

Commit

Permalink
feat(arrays): add rotate(), rotateTyped()
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Oct 26, 2023
1 parent 5485a78 commit c1d322e
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 0 deletions.
3 changes: 3 additions & 0 deletions packages/arrays/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@
"./quicksort": {
"default": "./quicksort.js"
},
"./rotate": {
"default": "./rotate.js"
},
"./shuffle": {
"default": "./shuffle.js"
},
Expand Down
1 change: 1 addition & 0 deletions packages/arrays/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export * from "./iterator.js";
export * from "./levenshtein.js";
export * from "./peek.js";
export * from "./quicksort.js";
export * from "./rotate.js";
export * from "./shuffle.js";
export * from "./sort-cached.js";
export * from "./starts-with.js";
Expand Down
46 changes: 46 additions & 0 deletions packages/arrays/src/rotate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { TypedArray } from "@thi.ng/api";

/**
* Rotates array by `num` items. If `num < 0` items are rotated left (towards
* the beginning of the array), otherwise to the right (end). The rotation
* distance will be `num % buf.length`. The function is no-op if the resulting
* distance is zero or `buf` is empty.
*
* @remarks
* Not suitable for typed arrays. Use {@link rotateTyped} for those.
*
* @param buf
* @param num
*/
export const rotate = <T>(buf: Array<T>, num: number) => {
if (!(num = __distance(buf, num))) return buf;
if (num < 0) {
buf.push(...buf.splice(0, -num));
} else {
buf.unshift(...buf.splice(-num));
}
return buf;
};

/**
* Same as {@link rotate}, but for optimized for typed arrays!
*
* @param buf
* @param num
*/
export const rotateTyped = (buf: TypedArray, num: number) => {
if (!(num = __distance(buf, num))) return buf;
if (num < 0) {
const tmp = buf.slice(0, -num);
buf.copyWithin(0, -num);
buf.set(tmp, buf.length + num);
} else if (num > 0) {
const tmp = buf.slice(buf.length - num);
buf.copyWithin(num, 0);
buf.set(tmp, 0);
}
return buf;
};

const __distance = (buf: ArrayLike<any>, num: number) =>
buf.length ? (num | 0) % buf.length : 0;

0 comments on commit c1d322e

Please sign in to comment.