functionalscript 0.11.7 → 0.11.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.11.7",
3
+ "version": "0.11.9",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "**/*.js",
@@ -13,7 +13,7 @@
13
13
  "test": "tsc && node --test --experimental-strip-types --experimental-test-coverage --test-coverage-include=**/module.f.ts",
14
14
  "index": "node ./fjs/module.ts r ./dev/index/module.f.ts",
15
15
  "fst": "node ./fjs/module.ts t",
16
- "fjs": "node ./fjs/module.ts",
16
+ "start": "node ./fjs/module.ts",
17
17
  "ci-update": "node ./fjs/module.ts r ./ci/module.f.ts",
18
18
  "update": "git clean -fdx && npm install && npm run index && npm run ci-update",
19
19
  "website": "node --experimental-strip-types ./fjs/module.ts r ./website/module.f.ts"
@@ -1,5 +1,5 @@
1
1
  import { bitLength, max } from "../bigint/module.f.js";
2
- import { empty, isVec, length, listToVec, msb, msbCmp, uint, unpack, vec, vec8 } from "../bit_vec/module.f.js";
2
+ import { empty, isVec, length, listToVec, msb, uint, unpack, vec, vec8 } from "../bit_vec/module.f.js";
3
3
  import { identity } from "../function/module.f.js";
4
4
  import { encode as b128encode, decode as b128decode } from "../base128/module.f.js";
5
5
  const pop = msb.popFront;
@@ -163,7 +163,7 @@ export const decodeSequence = (v) => {
163
163
  return result;
164
164
  };
165
165
  /** Encodes a SET payload with canonical byte ordering. */
166
- export const encodeSet = genericEncodeSequence(v => v.toSorted((a, b) => msbCmp(a)(b)));
166
+ export const encodeSet = genericEncodeSequence(v => v.toSorted((a, b) => msb.cmp(a)(b)));
167
167
  /** Decodes a SET payload. */
168
168
  export const decodeSet = decodeSequence;
169
169
  // encode
@@ -1,4 +1,4 @@
1
- import type { Fold, Reduce as OpReduce } from '../function/operator/module.f.ts';
1
+ import type { Binary, Fold, Reduce as OpReduce } from '../function/operator/module.f.ts';
2
2
  import { type List, type Thunk } from '../list/module.f.ts';
3
3
  import { type Nominal } from '../nominal/module.f.ts';
4
4
  import { type Sign } from '../function/compare/module.f.ts';
@@ -56,7 +56,13 @@ export declare const unpack: (v: Vec) => Unpacked;
56
56
  * Packs an unpacked representation back into a vector.
57
57
  */
58
58
  export declare const pack: ({ length, uint }: Unpacked) => Vec;
59
+ type Norm = (len: bigint) => {
60
+ readonly a: bigint;
61
+ readonly b: bigint;
62
+ };
63
+ type NormOp = Binary<Unpacked, Unpacked, Norm>;
59
64
  export type Reduce = OpReduce<Vec>;
65
+ export type PopFront<T> = (len: bigint) => (u: T) => readonly [bigint, T];
60
66
  /**
61
67
  * Represents operations for handling bit vectors with a specific bit order.
62
68
  *
@@ -121,7 +127,7 @@ export type BitOrder = {
121
127
  * const [uM1, rM1] = msb.popFront(16n)(vector) // [0xF500n, rM1 === empty]
122
128
  * ```
123
129
  */
124
- readonly popFront: (len: bigint) => (v: Vec) => readonly [bigint, Vec];
130
+ readonly popFront: PopFront<Vec>;
125
131
  /**
126
132
  * Concatenates two vectors.
127
133
  *
@@ -145,6 +151,17 @@ export type BitOrder = {
145
151
  * @returns A function that takes a second vector and returns the XOR result.
146
152
  */
147
153
  readonly xor: Reduce;
154
+ readonly unpackPopFront: PopFront<Unpacked>;
155
+ readonly norm: NormOp;
156
+ /**
157
+ * Lexically compares two vectors.
158
+ *
159
+ * a < b => -1
160
+ * a > b => 1
161
+ * a === b => 0
162
+ */
163
+ readonly cmp: (a: Vec) => (b: Vec) => Sign;
164
+ readonly unpackSplit: (len: bigint) => (u: Unpacked) => readonly [bigint, bigint];
148
165
  };
149
166
  /**
150
167
  * Implements operations for handling vectors in a least-significant-bit (LSb) first order.
@@ -177,7 +194,7 @@ export declare const u8ListToVec: ({ concat }: BitOrder) => (list: List<number>)
177
194
  * @param v The vector to be converted.
178
195
  * @returns A thunk that produces a list of unsigned 8-bit integers.
179
196
  */
180
- export declare const u8List: ({ popFront }: BitOrder) => (v: Vec) => Thunk<number>;
197
+ export declare const u8List: ({ unpackSplit }: BitOrder) => (v: Vec) => Thunk<number>;
181
198
  /**
182
199
  * Concatenates a list of vectors using the provided bit order.
183
200
  */
@@ -187,13 +204,4 @@ export declare const listToVec: ({ concat }: BitOrder) => (list: List<Vec>) => V
187
204
  */
188
205
  export declare const repeat: Fold<bigint, Vec>;
189
206
  export declare const isVec: <T>(v: Vec | T) => v is Vec;
190
- /**
191
- * Lexically compares two vectors based on their unsigned integer values,
192
- * normalizing them to the same length. If the values are equal,
193
- * the shorter vector is considered smaller.
194
- *
195
- * a < b => -1
196
- * a > b => 1
197
- * a === b => 0
198
- */
199
- export declare const msbCmp: (av: Vec) => (bv: Vec) => Sign;
207
+ export {};
@@ -23,7 +23,7 @@
23
23
  */
24
24
  import { bitLength, mask, max, min, xor } from "../bigint/module.f.js";
25
25
  import { flip } from "../function/module.f.js";
26
- import { entries, fold, iterable } from "../list/module.f.js";
26
+ import { fold, iterable } from "../list/module.f.js";
27
27
  import { asBase, asNominal } from "../nominal/module.f.js";
28
28
  import { repeat as mRepeat } from "../monoid/module.f.js";
29
29
  import { cmp } from "../function/compare/module.f.js";
@@ -97,8 +97,6 @@ export const unpack = (v) => ({
97
97
  * Packs an unpacked representation back into a vector.
98
98
  */
99
99
  export const pack = ({ length, uint }) => vec(length)(uint);
100
- const lsbNorm = ({ length: al, uint: a }) => ({ length: bl, uint: b }) => (len) => ({ a, b });
101
- const msbNorm = ({ length: al, uint: a }) => ({ length: bl, uint: b }) => (len) => ({ a: a << (len - al), b: b << (len - bl) });
102
100
  /**
103
101
  * Normalizes two vectors to the same length before applying a bigint reducer.
104
102
  */
@@ -109,6 +107,41 @@ const op = (norm) => (op) => ap => bp => {
109
107
  const { a, b } = norm(au)(bu)(len);
110
108
  return vec(len)(op(a)(b));
111
109
  };
110
+ const bo = ({ front, removeFront, concat, norm, uintCmp, unpackSplit }) => {
111
+ const unpackPopFront = (len) => {
112
+ const m = mask(len);
113
+ const us = unpackSplit(len);
114
+ return (v) => {
115
+ const [uint, rest] = us(v);
116
+ return [uint & m, { length: v.length - len, uint: rest }];
117
+ };
118
+ };
119
+ return {
120
+ front,
121
+ removeFront,
122
+ concat,
123
+ xor: op(norm)(xor),
124
+ unpackPopFront,
125
+ popFront: len => {
126
+ const f = unpackPopFront(len);
127
+ return v => {
128
+ const [uint, u] = f(unpack(v));
129
+ return [uint, pack(u)];
130
+ };
131
+ },
132
+ norm,
133
+ cmp: a => b => {
134
+ const au = unpack(a);
135
+ const bu = unpack(b);
136
+ const al = au.length;
137
+ const bl = bu.length;
138
+ const { a: aui, b: bui } = norm(au)(bu)(min(al)(bl));
139
+ const c = uintCmp(aui)(bui);
140
+ return c === 0 ? cmp(al)(bl) : c;
141
+ },
142
+ unpackSplit,
143
+ };
144
+ };
112
145
  /**
113
146
  * Implements operations for handling vectors in a least-significant-bit (LSb) first order.
114
147
  *
@@ -116,7 +149,7 @@ const op = (norm) => (op) => ap => bp => {
116
149
  *
117
150
  * Usually associated with Little-Endian (LE) byte order.
118
151
  */
119
- export const lsb = {
152
+ export const lsb = bo({
120
153
  front: len => {
121
154
  const m = mask(len);
122
155
  return v => uint(v) & m;
@@ -125,20 +158,18 @@ export const lsb = {
125
158
  const { length, uint } = unpack(v);
126
159
  return vec(length - len)(uint >> len);
127
160
  },
128
- popFront: len => {
129
- const m = mask(len);
130
- return v => {
131
- const { length, uint } = unpack(v);
132
- return [uint & m, vec(length - len)(uint >> len)];
133
- };
134
- },
135
161
  concat: (a) => (b) => {
136
162
  const { length: al, uint: au } = unpack(a);
137
163
  const { length: bl, uint: bu } = unpack(b);
138
164
  return vec(al + bl)((bu << al) | au);
139
165
  },
140
- xor: op(lsbNorm)(xor)
141
- };
166
+ norm: ({ uint: a }) => ({ uint: b }) => () => ({ a, b }),
167
+ uintCmp: a => b => {
168
+ const diff = a ^ b;
169
+ return diff === 0n ? 0 : (a & (diff & -diff)) === 0n ? -1 : 1;
170
+ },
171
+ unpackSplit: len => ({ uint }) => [uint, uint >> len]
172
+ });
142
173
  /**
143
174
  * Implements operations for handling vectors in a most-significant-bit (MSb) first order.
144
175
  *
@@ -146,7 +177,7 @@ export const lsb = {
146
177
  *
147
178
  * Usually associated with Big-Endian (BE) byte order.
148
179
  */
149
- export const msb = {
180
+ export const msb = bo({
150
181
  front: len => {
151
182
  const m = mask(len);
152
183
  return v => {
@@ -158,17 +189,11 @@ export const msb = {
158
189
  const { length, uint } = unpack(v);
159
190
  return vec(length - len)(uint);
160
191
  },
161
- popFront: len => {
162
- const m = mask(len);
163
- return v => {
164
- const { length, uint } = unpack(v);
165
- const d = length - len;
166
- return [(uint >> d) & m, vec(d)(uint)];
167
- };
168
- },
169
192
  concat: flip(lsb.concat),
170
- xor: op(msbNorm)(xor)
171
- };
193
+ norm: ({ length: al, uint: a }) => ({ length: bl, uint: b }) => len => ({ a: a << (len - al), b: b << (len - bl) }),
194
+ uintCmp: cmp,
195
+ unpackSplit: len => ({ length, uint }) => [uint >> (length - len), uint]
196
+ });
172
197
  /**
173
198
  * Converts a list of unsigned 8-bit integers to a bit vector using the provided bit order.
174
199
  *
@@ -211,15 +236,30 @@ export const u8ListToVec = ({ concat }) => (list) => {
211
236
  * @param v The vector to be converted.
212
237
  * @returns A thunk that produces a list of unsigned 8-bit integers.
213
238
  */
214
- export const u8List = ({ popFront }) => {
215
- const f = (v) => () => {
216
- if (v === empty) {
217
- return null;
239
+ export const u8List = ({ unpackSplit }) => (v) => {
240
+ if (v === empty) {
241
+ return () => null;
242
+ }
243
+ const f = (stack) => () => {
244
+ while (true) {
245
+ const [first, rest] = stack;
246
+ const { length, uint } = first;
247
+ if (length <= 8n) {
248
+ // the last unpack split is required to align data.
249
+ const v = length < 8n ? unpackSplit(8n)(first)[0] : uint;
250
+ return { first: Number(v), tail: rest !== undefined ? f(rest) : null };
251
+ }
252
+ // `length` is bigger than `8n` so `newLen` is `8n` or bigger.
253
+ const aLength = ((length + 7n) >> 4n) << 3n;
254
+ const bLength = length - aLength;
255
+ const [a, b] = unpackSplit(aLength)(first);
256
+ stack = [
257
+ { length: aLength, uint: a & mask(aLength) },
258
+ [{ length: bLength, uint: b & mask(bLength) }, rest],
259
+ ];
218
260
  }
219
- const [first, tail] = popFront(8n)(v);
220
- return { first: Number(first), tail: f(tail) };
221
261
  };
222
- return f;
262
+ return f([unpack(v), undefined]);
223
263
  };
224
264
  /**
225
265
  * Concatenates a list of vectors using the provided bit order.
@@ -230,21 +270,3 @@ export const listToVec = ({ concat }) => fold(flip(concat))(empty);
230
270
  */
231
271
  export const repeat = mRepeat({ identity: empty, operation: lsb.concat });
232
272
  export const isVec = (v) => typeof v === 'bigint';
233
- /**
234
- * Lexically compares two vectors based on their unsigned integer values,
235
- * normalizing them to the same length. If the values are equal,
236
- * the shorter vector is considered smaller.
237
- *
238
- * a < b => -1
239
- * a > b => 1
240
- * a === b => 0
241
- */
242
- export const msbCmp = (av) => (bv) => {
243
- const au = unpack(av);
244
- const bu = unpack(bv);
245
- const al = au.length;
246
- const bl = bu.length;
247
- const { a, b } = msbNorm(au)(bu)(min(al)(bl));
248
- const result = cmp(a)(b);
249
- return result !== 0 ? result : cmp(al)(bl);
250
- };
@@ -37,7 +37,9 @@ declare const _default: {
37
37
  lsbXor: () => void;
38
38
  msbXor: () => void;
39
39
  repeat: () => void;
40
+ lsbCmp: () => void;
40
41
  msbCmp: () => void;
41
- u8ListToVec: () => void;
42
+ u8ListToVec: () => () => void;
43
+ u8ListUnaligned: () => void;
42
44
  };
43
45
  export default _default;
@@ -1,7 +1,7 @@
1
1
  import { mask } from "../bigint/module.f.js";
2
2
  import { asBase, asNominal } from "../nominal/module.f.js";
3
- import { length, empty, uint, vec, lsb, msb, repeat, vec8, msbCmp, u8ListToVec } from "./module.f.js";
4
- import { repeat as listRepeat } from "../list/module.f.js";
3
+ import { length, empty, uint, vec, lsb, msb, repeat, vec8, u8ListToVec, u8List } from "./module.f.js";
4
+ import { repeat as listRepeat, toArray } from "../list/module.f.js";
5
5
  const unsafeVec = (a) => asNominal(a);
6
6
  // 0x8 = 0b1000 = 0 + 8
7
7
  // 0x9 = 0b1001 = 1 + 8
@@ -430,9 +430,23 @@ export default {
430
430
  throw 'repeat failed';
431
431
  }
432
432
  },
433
+ lsbCmp: () => {
434
+ const c = (a) => (b) => (r) => {
435
+ const result = lsb.cmp(a)(b);
436
+ if (result !== r) {
437
+ throw `result: ${result}, expected: ${r}`;
438
+ }
439
+ };
440
+ c(vec(4n)(0x5n))(vec(4n)(0x5n))(0); // [1,0,1,0] == [1,0,1,0]
441
+ c(vec(4n)(0x5n))(vec(4n)(0x6n))(1); // bit0: 1 > 0
442
+ c(vec(4n)(0x6n))(vec(4n)(0x5n))(-1); // bit0: 0 < 1
443
+ c(vec(4n)(0x5n))(vec(5n)(0x5n))(-1); // equal prefix, shorter is less
444
+ c(vec(5n)(0x5n))(vec(4n)(0x5n))(1); // equal prefix, longer is greater
445
+ c(vec(4n)(0x5n))(vec(5n)(0xan))(1); // bit0: 1 > 0
446
+ },
433
447
  msbCmp: () => {
434
448
  const c = (a) => (b) => (r) => {
435
- const result = msbCmp(a)(b);
449
+ const result = msb.cmp(a)(b);
436
450
  if (result !== r) {
437
451
  throw `result: ${result}, expected: ${r}`;
438
452
  }
@@ -447,5 +461,26 @@ export default {
447
461
  u8ListToVec: () => {
448
462
  // 131_072 is too much for Bun
449
463
  const x = u8ListToVec(msb)(listRepeat(0x12)(131_071));
464
+ return () => {
465
+ const m = u8List(msb)(x);
466
+ const y = toArray(m);
467
+ if (y.length !== 131_071) {
468
+ throw `y.lenght: ${y.length}`;
469
+ }
470
+ };
471
+ },
472
+ u8ListUnaligned: () => {
473
+ const x = vec(9n)(0x83n);
474
+ const a = toArray(u8List(msb)(x));
475
+ if (a.length !== 2) {
476
+ throw `a.lenght: ${a.length}`;
477
+ }
478
+ const [a0, a1] = a;
479
+ if (a0 !== 0x41) {
480
+ throw `a0: ${a0.toString(16)}`;
481
+ }
482
+ if (a1 !== 0x80) {
483
+ throw `a1: ${a1.toString(16)}`;
484
+ }
450
485
  }
451
486
  };
@@ -4,7 +4,7 @@ type NotLazy<T> = Result<T> | Concat<T> | readonly T[];
4
4
  type Empty = null;
5
5
  export type Result<T> = Empty | NonEmpty<T>;
6
6
  export type Thunk<T> = () => List<T>;
7
- type NonEmpty<T> = {
7
+ export type NonEmpty<T> = {
8
8
  readonly first: T;
9
9
  readonly tail: List<T>;
10
10
  };