[79a0317] | 1 | import boolbase from "boolbase";
|
---|
| 2 | /**
|
---|
| 3 | * Returns a function that checks if an elements index matches the given rule
|
---|
| 4 | * highly optimized to return the fastest solution.
|
---|
| 5 | *
|
---|
| 6 | * @param parsed A tuple [a, b], as returned by `parse`.
|
---|
| 7 | * @returns A highly optimized function that returns whether an index matches the nth-check.
|
---|
| 8 | * @example
|
---|
| 9 | *
|
---|
| 10 | * ```js
|
---|
| 11 | * const check = nthCheck.compile([2, 3]);
|
---|
| 12 | *
|
---|
| 13 | * check(0); // `false`
|
---|
| 14 | * check(1); // `false`
|
---|
| 15 | * check(2); // `true`
|
---|
| 16 | * check(3); // `false`
|
---|
| 17 | * check(4); // `true`
|
---|
| 18 | * check(5); // `false`
|
---|
| 19 | * check(6); // `true`
|
---|
| 20 | * ```
|
---|
| 21 | */
|
---|
| 22 | export function compile(parsed) {
|
---|
| 23 | const a = parsed[0];
|
---|
| 24 | // Subtract 1 from `b`, to convert from one- to zero-indexed.
|
---|
| 25 | const b = parsed[1] - 1;
|
---|
| 26 | /*
|
---|
| 27 | * When `b <= 0`, `a * n` won't be lead to any matches for `a < 0`.
|
---|
| 28 | * Besides, the specification states that no elements are
|
---|
| 29 | * matched when `a` and `b` are 0.
|
---|
| 30 | *
|
---|
| 31 | * `b < 0` here as we subtracted 1 from `b` above.
|
---|
| 32 | */
|
---|
| 33 | if (b < 0 && a <= 0)
|
---|
| 34 | return boolbase.falseFunc;
|
---|
| 35 | // When `a` is in the range -1..1, it matches any element (so only `b` is checked).
|
---|
| 36 | if (a === -1)
|
---|
| 37 | return (index) => index <= b;
|
---|
| 38 | if (a === 0)
|
---|
| 39 | return (index) => index === b;
|
---|
| 40 | // When `b <= 0` and `a === 1`, they match any element.
|
---|
| 41 | if (a === 1)
|
---|
| 42 | return b < 0 ? boolbase.trueFunc : (index) => index >= b;
|
---|
| 43 | /*
|
---|
| 44 | * Otherwise, modulo can be used to check if there is a match.
|
---|
| 45 | *
|
---|
| 46 | * Modulo doesn't care about the sign, so let's use `a`s absolute value.
|
---|
| 47 | */
|
---|
| 48 | const absA = Math.abs(a);
|
---|
| 49 | // Get `b mod a`, + a if this is negative.
|
---|
| 50 | const bMod = ((b % absA) + absA) % absA;
|
---|
| 51 | return a > 1
|
---|
| 52 | ? (index) => index >= b && index % absA === bMod
|
---|
| 53 | : (index) => index <= b && index % absA === bMod;
|
---|
| 54 | }
|
---|
| 55 | /**
|
---|
| 56 | * Returns a function that produces a monotonously increasing sequence of indices.
|
---|
| 57 | *
|
---|
| 58 | * If the sequence has an end, the returned function will return `null` after
|
---|
| 59 | * the last index in the sequence.
|
---|
| 60 | *
|
---|
| 61 | * @param parsed A tuple [a, b], as returned by `parse`.
|
---|
| 62 | * @returns A function that produces a sequence of indices.
|
---|
| 63 | * @example <caption>Always increasing (2n+3)</caption>
|
---|
| 64 | *
|
---|
| 65 | * ```js
|
---|
| 66 | * const gen = nthCheck.generate([2, 3])
|
---|
| 67 | *
|
---|
| 68 | * gen() // `1`
|
---|
| 69 | * gen() // `3`
|
---|
| 70 | * gen() // `5`
|
---|
| 71 | * gen() // `8`
|
---|
| 72 | * gen() // `11`
|
---|
| 73 | * ```
|
---|
| 74 | *
|
---|
| 75 | * @example <caption>With end value (-2n+10)</caption>
|
---|
| 76 | *
|
---|
| 77 | * ```js
|
---|
| 78 | *
|
---|
| 79 | * const gen = nthCheck.generate([-2, 5]);
|
---|
| 80 | *
|
---|
| 81 | * gen() // 0
|
---|
| 82 | * gen() // 2
|
---|
| 83 | * gen() // 4
|
---|
| 84 | * gen() // null
|
---|
| 85 | * ```
|
---|
| 86 | */
|
---|
| 87 | export function generate(parsed) {
|
---|
| 88 | const a = parsed[0];
|
---|
| 89 | // Subtract 1 from `b`, to convert from one- to zero-indexed.
|
---|
| 90 | let b = parsed[1] - 1;
|
---|
| 91 | let n = 0;
|
---|
| 92 | // Make sure to always return an increasing sequence
|
---|
| 93 | if (a < 0) {
|
---|
| 94 | const aPos = -a;
|
---|
| 95 | // Get `b mod a`
|
---|
| 96 | const minValue = ((b % aPos) + aPos) % aPos;
|
---|
| 97 | return () => {
|
---|
| 98 | const val = minValue + aPos * n++;
|
---|
| 99 | return val > b ? null : val;
|
---|
| 100 | };
|
---|
| 101 | }
|
---|
| 102 | if (a === 0)
|
---|
| 103 | return b < 0
|
---|
| 104 | ? // There are no result — always return `null`
|
---|
| 105 | () => null
|
---|
| 106 | : // Return `b` exactly once
|
---|
| 107 | () => (n++ === 0 ? b : null);
|
---|
| 108 | if (b < 0) {
|
---|
| 109 | b += a * Math.ceil(-b / a);
|
---|
| 110 | }
|
---|
| 111 | return () => a * n++ + b;
|
---|
| 112 | }
|
---|
| 113 | //# sourceMappingURL=compile.js.map |
---|