summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2024-03-20 11:42:08 -0300
committerEuAndreh <eu@euandre.org>2024-03-20 11:42:08 -0300
commit139b9ff653e1a1b9c316cb5651f220c687f11895 (patch)
treea7a2eafd64dc31828ef1313910d735e7ee5756ee
parenttests/rand.mjs: Add MersenneTwister random number generator (diff)
downloadpapod-139b9ff653e1a1b9c316cb5651f220c687f11895.tar.gz
papod-139b9ff653e1a1b9c316cb5651f220c687f11895.tar.xz
src/utils.mjs: Add take() and range()
-rw-r--r--src/utils.mjs40
-rw-r--r--tests/js/utils.mjs97
2 files changed, 137 insertions, 0 deletions
diff --git a/src/utils.mjs b/src/utils.mjs
index 9a600e7..19c8e37 100644
--- a/src/utils.mjs
+++ b/src/utils.mjs
@@ -58,3 +58,43 @@ export const first = a => a[0];
export const rest = a => a.slice(1);
export const butlast = a => a.slice(a, a.length - 1);
export const last = a => a[a.length - 1];
+
+export const take = function*(n, gen) {
+ let i = 0n;
+ for (const x of gen) {
+ if (i >= n) {
+ break;
+ }
+ i++;
+ yield x;
+ }
+};
+
+export const range = function*(x, y, step = 1n) {
+ if (x === undefined) {
+ let i = 0n;
+ while (true) {
+ yield i++;
+ }
+ }
+ const [from, to] = y === undefined ?
+ [0n, x] :
+ [x, y];
+ const fromn = BigInt(from);
+ const ton = BigInt(to);
+ const stepn = BigInt(step);
+ if (stepn === 0n) {
+ while (true) {
+ yield fromn;
+ }
+ }
+ if (step < 0n) {
+ for (let i = fromn; i > ton; i+= stepn) {
+ yield i;
+ }
+ } else {
+ for (let i = fromn; i < ton; i += stepn) {
+ yield i;
+ }
+ }
+};
diff --git a/tests/js/utils.mjs b/tests/js/utils.mjs
index 33bdac2..69fd54a 100644
--- a/tests/js/utils.mjs
+++ b/tests/js/utils.mjs
@@ -15,6 +15,8 @@ import {
rest,
butlast,
last,
+ take,
+ range,
} from "../../src/utils.mjs";
@@ -359,6 +361,99 @@ const test_last = async t => {
});
};
+const test_take = async t => {
+ t.start("take()");
+
+ await t.test("example usage", () => {
+ assert.deepEqual(Array.from(take(3, [1, 2, 3, 4, 5, 6])), [1, 2, 3]);
+ assert.deepEqual([...take(3, [1, 2, 3, 4, 5, 6])], [1, 2, 3]);
+
+ const gen = function*() {
+ yield* [1, 2, 3, 4, 5, 6];
+ }
+ assert.deepEqual([...take(3, gen())], [1, 2, 3]);
+
+ assert.deepEqual([...take(3, [1, 2])], [1, 2]);
+
+ assert.deepEqual([...take(1, [])], []);
+ assert.deepEqual([...take(0, [1])], []);
+ assert.deepEqual([...take(-1, [1])], []);
+ });
+};
+
+const test_range = async t => {
+ t.start("range()");
+
+ await t.test("empty values", () => {
+ const [] = range();
+
+ const [ a ] = range();
+ assert.equal(a, 0n);
+
+ const [ b, c, d, e ] = range();
+ assert.deepEqual(
+ [ b, c, d, e ],
+ [ 0n, 1n, 2n, 3n ],
+ );
+
+ assert.deepEqual(
+ Array.from(take(5, range())),
+ [ 0n, 1n, 2n, 3n, 4n ],
+ );
+
+ assert.deepEqual(
+ Array.from(take(1, range())),
+ [ 0n ],
+ );
+
+ assert.deepEqual(
+ Array.from(take(0, range())),
+ [],
+ );
+ });
+
+ await t.test("example usage", () => {
+ assert.deepEqual(
+ [...range(-5, 5)],
+ [ -5n, -4n, -3n, -2n, -1n, 0n, 1n, 2n, 3n, 4n ],
+ );
+ assert.deepEqual(
+ [...range(-100, 100, 10)],
+ [
+ -100n, -90n, -80n, -70n, -60n, -50n, -40n, -30n,
+ -20n, -10n, 0n, 10n, 20n, 30n, 40n, 50n, 60n,
+ 70n, 80n, 90n,
+ ],
+ );
+
+ assert.deepEqual([...range(0, 4, 2)], [0n, 2n]);
+ assert.deepEqual([...range(0, 5, 2)], [0n, 2n, 4n]);
+ assert.deepEqual([...range(0, 6, 2)], [0n, 2n, 4n]);
+ assert.deepEqual([...range(0, 7, 2)], [0n, 2n, 4n, 6n]);
+
+ assert.deepEqual(
+ [...range(100, 0, -10)],
+ [ 100n, 90n, 80n, 70n, 60n, 50n, 40n, 30n, 20n, 10n ]
+ );
+ assert.deepEqual(
+ [...range(10, -10, -1)],
+ [
+ 10n, 9n, 8n, 7n, 6n, 5n, 4n, 3n, 2n, 1n, 0n,
+ -1n, -2n, -3n, -4n, -5n, -6n, -7n, -8n, -9n,
+ ],
+ );
+
+ assert.deepEqual(
+ [...take(3, range(1, 10, 0))],
+ [ 1n, 1n, 1n ],
+ );
+ assert.deepEqual(
+ [...take(3, range(10, 1, 0))],
+ [ 10n, 10n, 10n ],
+ );
+ });
+};
+
await runner.runTests([
test_keys,
@@ -374,4 +469,6 @@ await runner.runTests([
test_rest,
test_butlast,
test_last,
+ test_take,
+ test_range,
]);