Skip to content

Commit f647d5c

Browse files
feat(bidir-index): add iterator versions of object encoders/decoders
- add `encodeObjectIterator()` - add `decodeObjectIterator()` - add tests
1 parent af72f39 commit f647d5c

File tree

2 files changed

+124
-6
lines changed

2 files changed

+124
-6
lines changed

packages/bidir-index/src/encode.ts

+83-3
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,55 @@ export const encodeObject = <V, K extends string = string>(
4141
const keys = <K[]>Object.keys(obj);
4242
const ids = indexKeys ? index.addAll(keys) : index.getAll(keys);
4343
const res = new Array<V>(index.size).fill(defaultValue);
44-
for (let i = keys.length; i-- > 0; ) {
45-
const val = obj[keys[i]];
46-
if (val != null) res[ids[i]] = val;
44+
for (let id of ids) {
45+
const val = obj[index.getID(id)!];
46+
if (val != null) res[id] = val;
4747
}
4848
return res;
4949
};
5050

51+
/**
52+
* Similar to {@link encodeObject}, but implemented as an iterator for
53+
* processing multiple objects into a single flat iterable.
54+
*
55+
* @example
56+
* ```ts tangle:../export/encode-object-iterator.ts
57+
* import { defBidirIndex, encodeObjectIterator } from "@thi.ng/bidir-index";
58+
*
59+
* const index = defBidirIndex<string>();
60+
*
61+
* // source data objects
62+
* const data = [
63+
* { r: 1, g: 2, b: 3},
64+
* { x: 4, y: 5, z: 6}
65+
* ];
66+
*
67+
* // directly encode into a typedarray
68+
* const buf = new Uint8Array(encodeObjectIterator(index, data, 0));
69+
*
70+
* console.log(buf);
71+
* // Uint8Array(12) [ 1, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 6 ]
72+
* ```
73+
*
74+
* @param index
75+
* @param objects
76+
* @param defaultValue
77+
* @param indexKeys
78+
*/
79+
export const encodeObjectIterator = function* <V, K extends string = string>(
80+
index: BidirIndex<K>,
81+
objects: Partial<Record<K, V>>[],
82+
defaultValue: V,
83+
indexKeys = true
84+
) {
85+
if (indexKeys) {
86+
for (let o of objects) index.addAll(<K[]>Object.keys(o));
87+
}
88+
for (let o of objects) {
89+
yield* encodeObject(index, o, defaultValue, false);
90+
}
91+
};
92+
5193
/**
5294
* Reverse op of {@link encodeObject}. Takes an array of `values` and returns an
5395
* object with values mapped to keys based on their indexed position. If the
@@ -95,3 +137,41 @@ export const decodeObject = <V, K extends string = string>(
95137
}
96138
return res;
97139
};
140+
141+
/**
142+
* Reverse op of {@link encodeObjectIterator}. An iterator which takes an array
143+
* of encoded values and yields sequence of objects decoded via
144+
* {@link decodeObject}.
145+
*
146+
* @example
147+
* ```ts tangle:../export/decode-object-iterator.ts
148+
* import { defBidirIndex, decodeObjectIterator } from "@thi.ng/bidir-index";
149+
*
150+
* const index = defBidirIndex<string>();
151+
* index.addAll("rgbxyz");
152+
*
153+
* const data = [1, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 6];
154+
*
155+
* for(let obj of decodeObjectIterator(index, data, 6)) {
156+
* console.log(obj);
157+
* }
158+
*
159+
* // { r: 1, g: 2, b: 3, x: 0, y: 0, z: 0 }
160+
* // { r: 0, g: 0, b: 0, x: 4, y: 5, z: 6 }
161+
* ```
162+
*
163+
* @param index
164+
* @param values
165+
* @param size
166+
* @param defaults
167+
*/
168+
export function* decodeObjectIterator<V, K extends string = string>(
169+
index: Iterable<[K, number]>,
170+
values: V[],
171+
size: number,
172+
defaults?: Partial<Record<K, V>>
173+
) {
174+
for (let i = 0, num = values.length; i < num; i += size) {
175+
yield decodeObject(index, values.slice(i, i + size), defaults);
176+
}
177+
}

packages/bidir-index/test/encode.test.ts

+41-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,38 @@
11
// SPDX-License-Identifier: Apache-2.0
22
import { expect, test } from "bun:test";
3-
import { decodeObject, defBidirIndex, encodeObject } from "../src/index.js";
3+
import {
4+
decodeObject,
5+
decodeObjectIterator,
6+
defBidirIndex,
7+
encodeObject,
8+
encodeObjectIterator,
9+
} from "../src/index.js";
410

511
test("encodeObject", () => {
612
const index = defBidirIndex<string>();
7-
expect(encodeObject(index, { r: 255, g: 128, b: 64, a: 1 }, 0)).toEqual([
8-
255, 128, 64, 1,
13+
expect(encodeObject(index, { r: 1, g: 2, b: 3, a: 4 }, 0)).toEqual([
14+
1, 2, 3, 4,
915
]);
1016
expect(encodeObject(index, { b: 3, r: 1, g: 2 }, 4, false)).toEqual([
1117
1, 2, 3, 4,
1218
]);
19+
expect(
20+
encodeObject(index, { b: 3, r: 1, g: 2, x: 5, y: 6, z: 7 }, 0, false)
21+
).toEqual([1, 2, 3, 0]);
22+
});
23+
24+
test("encodeObjectBuffer", () => {
25+
const index = defBidirIndex<string>();
26+
expect([
27+
...encodeObjectIterator(
28+
index,
29+
[
30+
{ r: 1, g: 2, b: 3 },
31+
{ x: 4, y: 5, z: 6 },
32+
],
33+
0
34+
),
35+
]).toEqual([1, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 6]);
1336
});
1437

1538
test("decodeObject", () => {
@@ -25,3 +48,18 @@ test("decodeObject", () => {
2548
foo: "bar",
2649
});
2750
});
51+
52+
test("decodeObjectBuffer", () => {
53+
const index = defBidirIndex<string>();
54+
index.addAll("rgbxyz");
55+
expect([
56+
...decodeObjectIterator(
57+
index,
58+
[1, 2, 3, null, null, null, null, null, null, 4, 5, 6],
59+
index.size
60+
),
61+
]).toEqual([
62+
{ r: 1, g: 2, b: 3 },
63+
{ x: 4, y: 5, z: 6 },
64+
]);
65+
});

0 commit comments

Comments
 (0)