Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Computations as records #32

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ export const reduce = <
nf?: NF
): MapCell<R, NF> => {
const coll = collector<MapCell<R, NF>>(proxy);
return proxy.map(
return proxy.mapNoPrevious(
[arr],
(cells) =>
async (cells) =>
coll(
proxy.mapNoPrevious(
cells,
Expand Down
54 changes: 54 additions & 0 deletions src/cell.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import { isEqual } from "./isEqual.test";

import { reduce } from "./array";
import { cellify } from "./cellify";
import { SheetProxy } from "./proxy";
import { Sheet } from "./sheet";

describe("writable", () => {
Expand Down Expand Up @@ -241,3 +244,54 @@
url.set("https://images.dog.ceo/breeds/frise-bichon/1.jpg");
expect(l).toEqual(["frise-bichon"]); // cspell:disable-line
});

test("subscriber keeps working when pointer is updated", async () => {
const sheet = new Sheet();
const proxy = new SheetProxy(sheet);
const a = proxy.new(1, "a");
let sum = 0;
a.subscribe((v) => {
sum += v;
});
expect(sum).toBe(1);
const b = proxy.new(2, "b");
expect(sum).toBe(1); // unchanged
a.set(b);
expect(sum).toBe(3); // b
b.set(3);
expect(sum).toBe(6); // b update
});

test("subscriber keeps working when pointer is updated with pointer chain", async () => {
const sheet = new Sheet();
const proxy = new SheetProxy(sheet);
const a = proxy.new(1, "a");
let sum = 0;
a.subscribe((v) => {
sum += v;
});
expect(sum).toBe(1);
const b = proxy.new(2, "b");
const c = proxy.new(b, "c");
expect(sum).toBe(1); // unchanged
a.set(c);
expect(sum).toBe(3); // b
b.set(3);
expect(sum).toBe(6); // b update
});

test("subscriber keeps working with mapped pointers", async () => {
const sheet = new Sheet();
const proxy = new SheetProxy(sheet);
const one = proxy.new(1, "one");
const arr = cellify(proxy, [one, 2, 3]);
const sum = reduce(proxy, arr, (acc, elt) => acc + elt, 0);
let count = 0;
sum.subscribe((v) => count++);
await proxy.working.wait();
expect(count).toBe(1);
one.set(2);
expect(count).toBe(2);
arr.update((arr) => [...arr, proxy.new(4, "4")]);
expect(count).toBe(3);

Check failure on line 296 in src/cell.test.ts

View workflow job for this annotation

GitHub Actions / Build

src/cell.test.ts > subscriber keeps working with mapped pointers

AssertionError: expected 2 to be 3 // Object.is equality - Expected + Received - 3 + 2 ❯ src/cell.test.ts:296:17

Check failure on line 296 in src/cell.test.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

src/cell.test.ts > subscriber keeps working with mapped pointers

AssertionError: expected 2 to be 3 // Object.is equality - Expected + Received - 3 + 2 ❯ src/cell.test.ts:296:17

Check failure on line 296 in src/cell.test.ts

View workflow job for this annotation

GitHub Actions / Build

src/cell.test.ts > subscriber keeps working with mapped pointers

AssertionError: expected 2 to be 3 // Object.is equality - Expected + Received - 3 + 2 ❯ src/cell.test.ts:296:17
});
22 changes: 14 additions & 8 deletions src/cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ export type PendingArray<V, CanBeError> = Promise<
>;

/** Array of (maybe pending) computation results */
export type MaybePendingDict<V, CanBeError> = (
| PendingMaybe<V, CanBeError>
| MaybeResultOrPointer<V, CanBeError>
)[];
export type MaybePendingDict<V, CanBeError> = Record<
number,
PendingMaybe<V, CanBeError> | MaybeResultOrPointer<V, CanBeError>
>;

export type Not<T extends boolean> = T extends true ? false : true;

Expand Down Expand Up @@ -97,7 +97,10 @@ abstract class SubscribeBench<V> {
dispatch(
value,
(value) => {
if (value instanceof Canceled) return;
if (value instanceof Canceled) {
console.log("canceled", value);
return;
}
// if their is no value, wait for the
// next update for the first notification
if (value !== undefined) {
Expand Down Expand Up @@ -895,9 +898,12 @@ export class MapCell<V, NF extends boolean> extends Cell<V, true, NF> {
* @param provided dependencies provided by the sheet as their computation have been triggered before.
* @returns The list of promise of values for all dependencies (in the order of the dependencies)
*/
private _gatherDependencies(provided: {
[key: number]: PendingMaybe<V, boolean> | MaybeResultOrPointer<V, boolean>;
}): PendingArray<V, boolean> | MaybeResultOrPointer<V, boolean>[] {
private _gatherDependencies(
provided: Record<
number,
PendingMaybe<V, boolean> | MaybeResultOrPointer<V, boolean>
>
): PendingArray<V, boolean> | MaybeResultOrPointer<V, boolean>[] {
const deps: (PendingMaybe<V, boolean> | V)[] = [];
this.sheet.debug([this.id], "gathering deps values", {
id: this.id,
Expand Down
16 changes: 9 additions & 7 deletions src/cellify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import { collector } from "./gc";
import type { SheetProxy } from "./proxy";

// Cellified computes a cellified type.
export type Cellified<T> = T extends object
? T extends Array<infer U>
? ValueCell<Cellified<U>[]>
: ValueCell<{
[P in keyof T]: Cellified<T[P]>;
}>
: ValueCell<T>;
export type Cellified<T> = T extends AnyCell<infer U>
? AnyCell<U>
: T extends object
? T extends Array<infer U>
? ValueCell<Cellified<U>[]>
: ValueCell<{
[P in keyof T]: Cellified<T[P]>;
}>
: ValueCell<T>;

// Uncellified computes an uncellified type.
export type Uncellified<T> = T extends AnyCell<infer U>
Expand Down
18 changes: 9 additions & 9 deletions src/sheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ import { dispatch, dispatchPromiseOrValueArray } from "./promise";
import { SheetProxy } from "./proxy";
import type { AnyCellArray } from "./types";

type Computations<V> = (
| Pending<V | Canceled, true>
| CellResult<V | Canceled, true>
)[];
type Computations<V> = Record<
number,
Pending<V | Canceled, true> | CellResult<V | Canceled, true>
>;
type IterationResult<V> = {
computations: Computations<V>;
updated: Set<number>;
Expand Down Expand Up @@ -545,7 +545,7 @@ export class Sheet {
);
};

const computations: Computations<V> = [];
const computations: Computations<V> = {};
const release = this.working.startNewComputation();
for (const id of roots) {
computations[id] = dispatch(
Expand Down Expand Up @@ -668,7 +668,7 @@ export class Sheet {
// Form now on, we need updatable pointers to be up-to-date to continue
const newComputations = this.computeUpdatable(toBeRecomputed, computations);
const borderComputation = dispatchPromiseOrValueArray(
newComputations,
Object.values(newComputations),
// wait for all new computations to be over before proceeding to the next step
(newComputations) => {
// finding all canceled computations
Expand Down Expand Up @@ -700,7 +700,7 @@ export class Sheet {
borderComputation,
({ computationsOfBorder, nextIteration }) => {
return dispatchPromiseOrValueArray(
computationsOfBorder,
Object.values(computationsOfBorder),
(computationsOfBorder) => {
//checking for canceled computations
this.registerCancelAndDone(
Expand Down Expand Up @@ -797,7 +797,7 @@ export class Sheet {
return res;
}

private dependentCells(id) {
private dependentCells(id: number) {
return Array.from(
new Set([...(this.g.get(id) || []), ...this._pointers.get(id)])
);
Expand Down Expand Up @@ -879,7 +879,7 @@ export class Sheet {
): Computations<V> {
const order = toBeRecomputed.slice(); // slice copies the array
let currentCellId: number | undefined;
const newComputations = [];
const newComputations = {};

// biome-ignore lint/suspicious/noAssignInExpressions: shorter, still explicit
while ((currentCellId = order.pop()) !== undefined) {
Expand Down
Loading