interface: first pass at writing BigIntArrOrderedMap for flatGraphs

This commit is contained in:
Logan Allen 2021-05-11 15:56:14 -05:00
parent 8291daf256
commit dbb58bd00d
5 changed files with 215 additions and 2 deletions

View File

@ -347,12 +347,18 @@ export default class GraphApi extends BaseApi<StoreState> {
this.store.handleEvent({ data });
}
async getDeepNodesUpTo(ship: string, resource: string, startTime = null, count: number) {
async getDeepNewest(ship: string, resource: string, startTime = null, count: number) {
const start = startTime ? decToUd(startTime) : null;
const data = await this.scry<any>('graph-store',
`/deep-nodes-up-to/${ship}/${resource}/${count}/${start}`
);
this.store.handleEvent({ data });
const node = data['graph-update'];
this.store.handleEvent({
data: {
'graph-update-flat': node,
'graph-update': node
},
});
}
getGraphSubset(ship: string, resource: string, start: string, end: string) {

View File

@ -1,5 +1,6 @@
import { GraphNode } from '@urbit/api';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import BigIntArrayOrderedMap from '@urbit/api/lib/BigIntArrayOrderedMap';
import bigInt, { BigInteger } from 'big-integer';
import produce from 'immer';
import _ from 'lodash';
@ -22,6 +23,12 @@ export const GraphReducer = (json) => {
if(loose) {
reduceState<GraphState, any>(useGraphState, loose, [addNodesLoose]);
}
const flat = _.get(json, 'graph-update-flat', false);
if (flat) {
reduceState<GraphState, any>(useGraphState, loose, [addNodesFlat]);
}
};
const addNodesLoose = (json: any, state: GraphState): GraphState => {
@ -39,6 +46,45 @@ const addNodesLoose = (json: any, state: GraphState): GraphState => {
return state;
};
const addNodesFlat = (json: any, state: GraphState): GraphState => {
const data = _.get(json, 'add-nodes', false);
if (data) {
if (!('flatGraphs' in state)) {
return state;
}
const resource = data.resource.ship + '/' + data.resource.name;
if (!(resource in state.flatGraphs)) {
state.flatGraphs[resource] = new BigIntArrayOrderedMap();
}
const indices = Array.from(Object.keys(data.nodes));
indices.forEach((index) => {
const node = data.nodes[index];
if (index.split('/').length === 0) {
return;
}
const indexArr = index.split('/').slice(1).map((ind) => {
return bigInt(ind);
});
if (indexArr.length === 0) {
return state;
}
state.flatGraphs[resource] =
state.flatGraphs[resource].set(
indexArr,
produce(node, (draft) => {
draft.children = mapifyChildren({});
})
);
});
}
return state;
};
const keys = (json, state: GraphState): GraphState => {
const data = _.get(json, 'keys', false);
if (data) {

View File

@ -2,6 +2,7 @@ import { Association, deSig, GraphNode, Graphs, resourceFromPath } from '@urbit/
import { useCallback } from 'react';
import { BaseState, createState } from './base';
export interface GraphState extends BaseState<GraphState> {
graphs: Graphs;
graphKeys: Set<string>;
@ -10,6 +11,7 @@ export interface GraphState extends BaseState<GraphState> {
[index: string]: GraphNode;
}
};
flatGraphs: FlatGraphs;
pendingIndices: Record<string, any>;
graphTimesentMap: Record<string, any>;
// getKeys: () => Promise<void>;

View File

@ -1,5 +1,7 @@
import { Patp } from "..";
import BigIntOrderedMap from "../lib/BigIntOrderedMap";
import BigIntArrayOrderedMap from "../lib/BigIntArrayOrderedMap";
export interface TextContent {
text: string;
@ -64,6 +66,15 @@ export interface GraphNode {
post: Post;
}
export interface FlatGraphNode {
children: null;
post: Post;
}
export type Graph = BigIntOrderedMap<GraphNode>;
export type Graphs = { [rid: string]: Graph };
export type FlatGraph = BigIntArrayOrderedMap<FlatGraphNode>;
export type FlatGraphs = { [rid: string]: FlatGraph };

View File

@ -0,0 +1,148 @@
import produce, { immerable, castImmutable, castDraft, setAutoFreeze, enablePatches } from 'immer';
import bigInt, { BigInteger } from "big-integer";
setAutoFreeze(false);
enablePatches();
function sortBigInt(a: BigInteger[], b: BigInteger[]) {
if (a.lt(b)) {
return 1;
} else if (a.eq(b)) {
return 0;
} else {
return -1;
}
}
function stringToBigIntArr(str: string) {
return str.split('/').slice(1).map((ind) => {
return bigInt(ind);
});
}
function arrToString(arr: BigInteger[]) {
let string = '';
arr.forEach((key) => {
string = string + `/${key.toString()}`;
});
}
function sortBigIntArr(a: BigInteger[], b: BigInteger[]) {
let aLen = a.length;
let bLen = b.length;
let i = 0;
while (i < aLen && i < bLen) {
if (a[i].lt(b[i])) {
return 1;
} else if (a[i].gt(b[i])) {
return -1;
} else {
i++;
}
}
return aLen - bLen;
}
export default class BigIntArrayOrderedMap<V> implements Iterable<[BigInteger[], V]> {
root: Record<string, V> = {}
cachedIter: [BigInteger[], V][] = null;
[immerable] = true;
constructor(items: [BigInteger[], V][] = []) {
items.forEach(([key, val]) => {
this.set(key, val);
});
}
get size() {
return Object.keys(this.root).length;
}
get(key: BigInteger[]) {
return this.root[arrToString(key)] ?? null;
}
gas(items: [BigInteger[], V][]) {
return produce(this, draft => {
items.forEach(([key, value]) => {
draft.root[arrToString(key)] = castDraft(value);
});
draft.generateCachedIter();
},
(patches) => {
//console.log(`gassed with ${JSON.stringify(patches, null, 2)}`);
});
}
set(key: BigInteger[], value: V) {
return produce(this, draft => {
draft.root[key.toString()] = castDraft(value);
draft.cachedIter = null;
});
}
clear() {
return produce(this, draft => {
draft.cachedIter = [];
draft.root = {}
});
}
has(key: BigInteger[]) {
return arrToString(key) in this.root;
}
delete(key: BigInteger[]) {
const result = produce(this, draft => {
delete draft.root[arrToString(key)];
draft.cachedIter = null;
});
return result;
}
[Symbol.iterator](): IterableIterator<[BigInteger[], V]> {
let idx = 0;
let result = this.generateCachedIter();
return {
[Symbol.iterator]: this[Symbol.iterator],
next: (): IteratorResult<[BigInteger[], V]> => {
if (idx < result.length) {
return { value: result[idx++], done: false };
}
return { done: true, value: null };
},
};
}
peekLargest() {
const sorted = Array.from(this);
return sorted[0] as [BigInteger[], V] | null;
}
peekSmallest() {
const sorted = Array.from(this);
return sorted[sorted.length - 1] as [BigInteger[], V] | null;
}
keys() {
return Array.from(this).map(([k,v]) => k);
}
generateCachedIter() {
if(this.cachedIter) {
return [...this.cachedIter];
}
const result = Object.keys(this.root).map(key => {
const num = stringtoBigIntArr(key);
return [num, this.root[key]] as [BigInteger[], V];
}).sort(([a], [b]) => sortBigIntArr(a,b));
this.cachedIter = result;
return [...result];
}
}