Merge pull request #792 from rafael-atticlabs/betterCollections

JS Collection refactor, splore, crunchbase ui, & pitchmap update
This commit is contained in:
Erik Arvidsson
2015-12-17 12:35:59 -05:00
29 changed files with 545 additions and 557 deletions

View File

@@ -34,7 +34,7 @@
"watchify": "^3.6"
},
"scripts": {
"start": "cp node_modules/nvd3/build/nv.d3.css nv.d3.css; NOMS_SERVER=http://localhost:8000 NOMS_DATASET_ID=crunchbase/index watchify -o out.js -v -d src/main.js",
"start": "cp node_modules/nvd3/build/nv.d3.css nv.d3.css; NOMS_SERVER=http://localhost:8000 NOMS_DATASET_ID=crunchbase/index watchify -o out.js -v -d node_modules/babel-regenerator-runtime/runtime.js src/main.js",
"build": "./.npm_build_helper.sh",
"test": "rm -f out.js && eslint src/ && flow src/"
},

View File

@@ -1,7 +0,0 @@
// @flow
export function invariant(exp: any, message: string = 'Invariant violated') {
if (!exp) {
throw new Error(message);
}
}

View File

@@ -1,8 +1,8 @@
// @flow
import {readValue, Struct, makeType, Ref, registerPackage} from 'noms';
import {invariant} from './assert.js';
import type {ChunkStore, Package} from 'noms';
import {invariant, Kind, NomsMap, NomsSet, SetLeafSequence, makeCompoundType, makePrimitiveType} from 'noms';
type RoundTypeEnum = 0 | 1 | 2;
const Seed = 0;
@@ -34,15 +34,14 @@ export default class DataManager {
_datasetId: string;
_keyClass: any;
_quarterClass: any;
_index: Map<string, Ref>;
_datasetP: ?Promise<Map<Ref, Ref>>;
_datasetP: ?Promise<NomsMap<Ref, Ref>>;
_packageP: ?Promise<Package>;
_categorySetP: ?Promise<Set<Struct>>;
_timeSetP: ?Promise<Set<Struct>>;
_seedSetP: ?Promise<Set<Struct>>;
_seriesASetP: ?Promise<Set<Struct>>;
_seriesBSetP: ?Promise<Set<Struct>>;
_categorySetP: ?Promise<NomsSet<Struct>>;
_timeSetP: ?Promise<NomsSet<Struct>>;
_seedSetP: ?Promise<NomsSet<Struct>>;
_seriesASetP: ?Promise<NomsSet<Struct>>;
_seriesBSetP: ?Promise<NomsSet<Struct>>;
_data: ?DataArray;
_time: ?TimeOption;
@@ -55,7 +54,6 @@ export default class DataManager {
this._quarterClass = null;
this._datasetP = null;
this._packageP = null;
this._index = new Map();
this._timeSetP = null;
this._categorySetP = null;
@@ -68,7 +66,7 @@ export default class DataManager {
this._category = '';
}
async _getDataset(): Promise<Map<Ref, Ref>> {
async _getDataset(): Promise<NomsMap<Ref, Ref>> {
if (this._datasetP) {
return this._datasetP;
}
@@ -82,8 +80,6 @@ export default class DataManager {
let ds = await this._getDataset();
this._packageP = getKeyPackage(ds, this._store);
this._index = convertMap(ds);
invariant(this._packageP);
return this._packageP;
}
@@ -137,19 +133,23 @@ export default class DataManager {
await Promise.all([this._seedSetP, this._seriesASetP, this._seriesBSetP,
this._timeSetP, this._categorySetP]);
let baseSet = intersectRounds(timeSet, categorySet);
let baseSet = await timeSet.intersect(categorySet);
let sets = await Promise.all([baseSet.intersect(seedSet),
baseSet.intersect(seriesASet), baseSet.intersect(seriesBSet)]);
let ptiles = await Promise.all([percentiles(sets[0]), percentiles(sets[1]),
percentiles(sets[2])]);
return this._data = [
{
values: percentiles(intersectRounds(baseSet, seedSet)),
values: ptiles[0],
key: 'Seed'
},
{
values: percentiles(intersectRounds(baseSet, seriesASet)),
values: ptiles[1],
key: 'A'
},
{
values: percentiles(intersectRounds(baseSet, seriesBSet)),
values: ptiles[2],
key: 'B'
}
];
@@ -167,31 +167,35 @@ export default class DataManager {
return k.ref;
}
async _getSetOfRounds(p: KeyParam): Promise<Set<Struct>> {
let s = (await this._getKeyRef(p)).toString();
let v = this._index.get(s);
if (v === undefined) {
return new Set();
async _getSetOfRounds(p: KeyParam): Promise<NomsSet<Struct>> {
let r = await this._getKeyRef(p);
invariant(this._datasetP);
let map = await this._datasetP;
let setRef = await map.get(r);
if (setRef === undefined) {
// TODO: Cleanup the NomsSet api (it shouldn't be this hard to create an emptySet)
return new NomsSet(this._store, setTr, new SetLeafSequence(setTr, []));
}
let set = readValue(v, this._store);
return set || new Set();
}
return readValue(setRef, this._store);
}
}
// TODO: This is actually the wrong type. Fix when we have JS codegen.
const setTr = makeCompoundType(Kind.Set, makeCompoundType(Kind.Ref, makePrimitiveType(Kind.Value)));
/**
* Loads the first key in the index and gets the package from the type.
*/
async function getKeyPackage(index: Map<Ref, Ref>, store: ChunkStore):
async function getKeyPackage(index: NomsMap<Ref, Ref>, store: ChunkStore):
Promise<Package> {
let ref;
for (let v of index.keys()) {
ref = v;
break;
}
invariant(ref instanceof Ref);
let key = await readValue(ref, store);
let pkg = await readValue(key.type.packageRef, store);
let kv = await index.first();
invariant(kv);
let ref = kv[0];
let key: Struct = await readValue(ref, store);
invariant(key);
let pkg: Package = await readValue(key.type.packageRef, store);
invariant(pkg);
registerPackage(pkg);
return pkg;
}
@@ -208,46 +212,27 @@ function getStructClass(pkg, name) {
};
}
async function getDataset(id: string, httpStore: ChunkStore): any {
async function getDataset(id: string, httpStore: ChunkStore): Promise<NomsMap<Ref, Ref>> {
let rootRef = await httpStore.getRoot();
let datasets = await readValue(rootRef, httpStore);
let commitRef = datasets.get(id);
let commit = await readValue(commitRef, httpStore);
let datasets: Map<string, Ref> = await readValue(rootRef, httpStore);
let commitRef = await datasets.get(id);
invariant(commitRef);
let commit: Struct = await readValue(commitRef, httpStore);
invariant(commit);
return commit.get('value');
}
function convertMap<T>(map: Map<Ref, T>): Map<string, T> {
let m = new Map();
map.forEach((v, k) => {
m.set(k.toString(), v);
});
return m;
}
function intersectRounds(a: Set<Struct>, b: Set<Struct>): Set<Struct> {
let sa = new Set();
a.forEach(v => {
sa.add(v.ref.toString());
});
let s = new Set();
b.forEach(v => {
if (sa.has(v.ref.toString())) {
s.add(v);
}
});
return s;
}
function percentiles(s: Set<Struct>): Array<{x: number, y: number}> {
async function percentiles(s: NomsSet<Struct>): Promise<Array<{x: number, y: number}>> {
let arr: Array<number> = [];
for (let round of s) {
await s.forEach(round => {
let v = round.get('Raised');
if (v > 0) {
arr.push(v);
}
});
}
arr.sort((a, b) => a - b);
let len = arr.length;
if (len === 0) {

View File

@@ -1,7 +1,7 @@
// @flow
import React from 'react';
import {readValue, HttpStore, Ref, Struct} from 'noms';
import {HttpStore, NomsList, notNull, readValue, Ref} from 'noms';
const IMAGE_WIDTH_PX = 286;
const IMAGE_HEIGHT_PX = 324;
@@ -17,13 +17,18 @@ function feetToPixels(f: number): number {
}
type Props = {
pitchListRef: Ref,
pitchListRefP: Promise<?Ref>,
httpStore: HttpStore
};
type Point = {
x: number,
y: number
};
type State = {
loaded: boolean,
pitchList: ?Array<Struct>
pointList: Array<Point>
};
export default class HeatMap extends React.Component<void, Props, State> {
@@ -32,7 +37,7 @@ export default class HeatMap extends React.Component<void, Props, State> {
this.state = {
loaded: false,
pitchList: null
pointList: []
};
}
@@ -41,11 +46,20 @@ export default class HeatMap extends React.Component<void, Props, State> {
return;
}
let pitchList = await readValue(this.props.pitchListRef, this.props.httpStore);
if (Array.isArray(pitchList)) {
let pitchListRef = notNull(await this.props.pitchListRefP);
let pitchList = await readValue(pitchListRef, this.props.httpStore);
if (pitchList instanceof NomsList) {
let pointList = [];
await pitchList.forEach(p => {
pointList.push({
x: -1 + ORIGIN_X_PIXELS + feetToPixels(p.get('X')),
y: -1 + ORIGIN_Z_PIXELS - feetToPixels(p.get('Z'))
});
});
this.setState({
loaded: true,
pitchList: pitchList
pointList: pointList
});
} else {
throw new Error('Unexpected type of pitchList');
@@ -77,27 +91,15 @@ export default class HeatMap extends React.Component<void, Props, State> {
}
getPoints(): Array<any> {
if (!this.state.loaded) {
return [];
}
if (!this.state.pitchList) {
throw new Error('pitchList not loaded');
}
return this.state.pitchList.map(p => {
let w = 2;
let h = 2;
let x = - w / 2 + ORIGIN_X_PIXELS + feetToPixels(p.get('X'));
let y = - h / 2 + ORIGIN_Z_PIXELS - feetToPixels(p.get('Z'));
return this.state.pointList.map(p => {
return <div style={
{
position: 'absolute',
left: x,
top: y,
left: p.x,
top: p.y,
background: 'rgba(0,255,0,0.4)',
width: w,
height: h,
width: '2px',
height: '2px',
boxShadow: '0px 0px 16px 16px rgba(0,255,0,0.4)',
borderRadius: '50%'
}

View File

@@ -3,68 +3,67 @@
import HeatMap from './heat_map.js';
import React from 'react';
import ReactDOM from 'react-dom';
import {readValue, HttpStore, Ref} from 'noms';
import {HttpStore, invariant, NomsMap, readValue, Ref, Struct} from 'noms';
let httpStore: HttpStore;
window.addEventListener('load', async () => {
httpStore = new HttpStore('http://localhost:8000');
let rootRef = await httpStore.getRoot();
let datasets = await readValue(rootRef, httpStore);
let commitRef = datasets.get('mlb/heatmap');
let commit = await readValue(commitRef, httpStore);
let datasets:NomsMap<string, Ref> = await readValue(rootRef, httpStore);
let commitRef = await datasets.get('mlb/heatmap');
invariant(commitRef);
let commit:Struct = await readValue(commitRef, httpStore);
let pitchersMap = commit.get('value');
renderPitchersMap(pitchersMap);
let pitchers = [];
await pitchersMap.forEach((ref, pitcher) => {
pitchers.push(pitcher);
});
pitchers.sort();
renderPitchersMap(pitchersMap, pitchers);
});
type Props = {
pitchersMap: Map<string, Ref>
pitchersMap: NomsMap<string, Ref>,
pitchers: Array<string>
};
type State = {
currentPitcher: string,
pitchers: Array<string>
currentPitcher: string
};
class PitcherList extends React.Component<void, Props, State> {
constructor(props) {
super(props);
let pitchers = [];
this.props.pitchersMap.forEach((ref, pitcher) => {
pitchers.push(pitcher);
});
pitchers.sort();
this.state = {
currentPitcher: pitchers[0],
pitchers: pitchers
currentPitcher: props.pitchers[0]
};
}
render() : React.Element {
let currentPitcher = this.state.currentPitcher;
let pitchListRef = this.props.pitchersMap.get(currentPitcher);
let pitchListRefP = this.props.pitchersMap.get(currentPitcher);
let onChangePitcher = e => {
this.setState({
currentPitcher: e.target.value,
pitchers: this.state.pitchers
currentPitcher: e.target.value
});
};
return <div>
<select onChange={onChangePitcher} defaultValue={currentPitcher}>{
this.state.pitchers.map(pitcher => {
this.props.pitchers.map(pitcher => {
return <option key={pitcher} value={pitcher}>{pitcher}</option>;
})
}</select>
<HeatMap key={currentPitcher} pitchListRef={pitchListRef} httpStore={httpStore}/>
<HeatMap key={currentPitcher} pitchListRefP={pitchListRefP} httpStore={httpStore}/>
</div>;
}
}
function renderPitchersMap(map: Map) {
function renderPitchersMap(map: NomsMap<string, Ref>, pitchers: Array<string>) {
let renderNode = document.getElementById('heatmap');
ReactDOM.render(<PitcherList pitchersMap={map}/>, renderNode);
ReactDOM.render(<PitcherList pitchersMap={map} pitchers={pitchers}/>, renderNode);
}

View File

@@ -1,10 +1,10 @@
// @flow
import {layout, NodeGraph, TreeNode} from './buchheim.js';
import Layout from './layout.js';
import React from 'react'; // eslint-disable-line no-unused-vars
import ReactDOM from 'react-dom';
import {CompoundList, CompoundMap, CompoundSet, ListLeaf, MapLeaf, readValue, SetLeaf, HttpStore, Ref, Struct} from 'noms';
import {HttpStore, invariant, IndexedMetaSequence, ListLeafSequence, MapLeafSequence, OrderedMetaSequence, NomsList, NomsMap, NomsSet, readValue, Ref, SetLeafSequence, Struct} from 'noms';
import {layout, NodeGraph, TreeNode} from './buchheim.js';
let data: NodeGraph = {nodes: {}, links: {}};
let rootRef: Ref;
@@ -39,6 +39,20 @@ function formatKeyString(v: any): string {
function handleChunkLoad(ref: Ref, val: any, fromRef: ?string) {
let counter = 0;
function processMetaSequence(id, sequence: IndexedMetaSequence | OrderedMetaSequence, name: string) {
data.nodes[id] = {name: name};
sequence.items.forEach(tuple => {
let kid = process(ref, formatKeyString(tuple.value), id);
if (kid) {
data.nodes[kid].isOpen = true;
process(ref, tuple.ref, kid);
} else {
throw new Error('No kid id.');
}
});
}
function process(ref, val, fromId): ?string {
if (typeof val === 'undefined') {
return null;
@@ -68,28 +82,45 @@ function handleChunkLoad(ref: Ref, val: any, fromRef: ?string) {
if (val instanceof Blob) {
data.nodes[id] = {name: `Blob (${val.size})`};
} else if (val instanceof ListLeaf) {
data.nodes[id] = {name: `List (${val.length})`};
val.items.forEach(c => process(ref, c, id));
} else if (val instanceof SetLeaf) {
data.nodes[id] = {name: `Set (${val.size})`};
val.items.forEach(c => process(ref, c, id));
} else if (val instanceof MapLeaf) {
data.nodes[id] = {name: `Map (${val.size})`};
val.items.forEach(entry => {
let k = entry.key;
let v = entry.value;
// TODO: handle non-string keys
let kid = process(ref, k, id);
if (kid) {
// Start map keys open, just makes it easier to use.
data.nodes[kid].isOpen = true;
} else if (val instanceof NomsList) {
let sequence = val.sequence;
if (sequence instanceof ListLeafSequence) {
data.nodes[id] = {name: `List (${val.length})`};
sequence.items.forEach(c => process(ref, c, id));
} else {
invariant(sequence instanceof IndexedMetaSequence);
processMetaSequence(id, sequence, 'ListNode');
}
} else if (val instanceof NomsSet) {
let sequence = val.sequence;
if (sequence instanceof SetLeafSequence) {
data.nodes[id] = {name: `Set (${val.size})`};
sequence.items.forEach(c => process(ref, c, id));
} else {
invariant(sequence instanceof OrderedMetaSequence);
processMetaSequence(id, sequence, 'SetNode');
}
} else if (val instanceof NomsMap) {
let sequence = val.sequence;
if (sequence instanceof MapLeafSequence) {
data.nodes[id] = {name: `Map (${val.size})`};
sequence.items.forEach(entry => {
let k = entry.key;
let v = entry.value;
// TODO: handle non-string keys
let kid = process(ref, k, id);
if (kid) {
data.nodes[kid].isOpen = true;
process(ref, v, kid);
} else {
throw new Error('No kid id.');
}
});
process(ref, v, kid);
} else {
throw new Error('No kid id.');
}
});
} else {
invariant(sequence instanceof OrderedMetaSequence);
processMetaSequence(id, sequence, 'MapNode');
}
} else if (val instanceof Ref) {
let refStr = val.toString();
data.nodes[id] = {
@@ -114,45 +145,6 @@ function handleChunkLoad(ref: Ref, val: any, fromRef: ?string) {
throw new Error('No kid id.');
}
});
} else if (val instanceof CompoundList) {
data.nodes[id] = {name: 'ListNode'};
val.items.forEach(tuple => {
let kid = process(ref, formatKeyString(tuple.value), id);
if (kid) {
// Start map keys open, just makes it easier to use.
data.nodes[kid].isOpen = true;
process(ref, tuple.ref, kid);
} else {
throw new Error('No kid id.');
}
});
} else if (val instanceof CompoundMap) {
data.nodes[id] = {name: 'MapNode'};
val.items.forEach(tuple => {
let kid = process(ref, formatKeyString(tuple.value), id);
if (kid) {
// Start map keys open, just makes it easier to use.
data.nodes[kid].isOpen = true;
process(ref, tuple.ref, kid);
} else {
throw new Error('No kid id.');
}
});
} else if (val instanceof CompoundSet) {
data.nodes[id] = {name: 'SetNode'};
val.items.forEach(tuple => {
let kid = process(ref, formatKeyString(tuple.value), id);
if (kid) {
// Start map keys open, just makes it easier to use.
data.nodes[kid].isOpen = true;
process(ref, tuple.ref, kid);
} else {
throw new Error('No kid id.');
}
});
}
return id;

View File

@@ -1,7 +0,0 @@
// @flow
export function invariant(exp: boolean, message: string = 'Invariant violated') {
if (!exp) {
throw new Error(message);
}
}

View File

@@ -1,7 +1,6 @@
// @flow
import {invariant} from './assert.js';
import {readValue} from 'noms';
import {invariant, readValue} from 'noms';
import eq from './eq.js';
import React from 'react';
import type {ChunkStore} from 'noms';

View File

@@ -46,7 +46,7 @@ export function deserialize(buffer: ArrayBuffer): Array<Chunk> {
invariant(buffer.byteLength - offset >= chunkHeaderSize, 'Invalid chunk buffer');
let refArray = new Uint8Array(buffer, offset, sha1Size);
let ref = new Ref(new Uint8Array(refArray));
let ref = Ref.fromDigest(new Uint8Array(refArray));
offset += sha1Size;
let sizeReadArray = new Uint8Array(buffer, offset, chunkLengthSize);

17
js/src/collection.js Normal file
View File

@@ -0,0 +1,17 @@
// @flow
import type {ChunkStore} from './chunk_store.js';
import {Type} from './type.js';
import {ValueBase} from './value.js';
import type {Sequence} from './sequence.js'; // eslint-disable-line no-unused-vars
export class Collection<S:Sequence> extends ValueBase {
sequence: S;
cs: ChunkStore;
constructor(cs: ChunkStore, type: Type, sequence: S) {
super(type);
this.cs = cs;
this.sequence = sequence;
}
}

View File

@@ -10,11 +10,11 @@ import {Field, makeCompoundType, makeEnumType, makePrimitiveType, makeStructType
import {indexTypeForMetaSequence, MetaTuple, newMetaSequenceFromData} from './meta_sequence.js';
import {invariant, notNull} from './assert.js';
import {isPrimitiveKind, Kind} from './noms_kind.js';
import {ListLeaf} from './list.js';
import {ListLeafSequence, NomsList} from './list.js';
import {lookupPackage, Package, readPackage} from './package.js';
import {MapLeaf} from './map.js';
import {NomsMap, MapLeafSequence} from './map.js';
import {setDecodeNomsValue} from './read_value.js';
import {SetLeaf} from './set.js';
import {NomsSet, SetLeafSequence} from './set.js';
const typedTag = 't ';
const blobTag = 'b ';
@@ -135,17 +135,17 @@ class JsonArrayReader {
return list;
}
async readListLeaf(t: Type, pkg: ?Package): Promise<ListLeaf> {
async readListLeafSequence(t: Type, pkg: ?Package): Promise<ListLeafSequence> {
let seq = await this.readSequence(t, pkg);
return new ListLeaf(this._cs, t, seq);
return new ListLeafSequence(t, seq);
}
async readSetLeaf(t: Type, pkg: ?Package): Promise<SetLeaf> {
async readSetLeafSequence(t: Type, pkg: ?Package): Promise<SetLeafSequence> {
let seq = await this.readSequence(t, pkg);
return new SetLeaf(this._cs, t, seq);
return new SetLeafSequence(t, seq);
}
async readMapLeaf(t: Type, pkg: ?Package): Promise<MapLeaf> {
async readMapLeafSequence(t: Type, pkg: ?Package): Promise<MapLeafSequence> {
let keyType = t.elemTypes[0];
let valueType = t.elemTypes[1];
let entries = [];
@@ -155,24 +155,19 @@ class JsonArrayReader {
entries.push({key: k, value: v});
}
return new MapLeaf(this._cs, t, entries);
return new MapLeafSequence(t, entries);
}
readEnum(): number {
return this.readUint();
}
async maybeReadMetaSequence(t: Type, pkg: ?Package): Promise<any> {
if (!this.readBool()) {
return null;
}
let r2 = new JsonArrayReader(this.readArray(), this._cs);
async readMetaSequence(t: Type, pkg: ?Package): Promise<any> {
let data: Array<MetaTuple> = [];
let indexType = indexTypeForMetaSequence(t);
while (!r2.atEnd()) {
let ref = r2.readRef();
let v = await r2.readValueWithoutTag(indexType, pkg);
while (!this.atEnd()) {
let ref = this.readRef();
let v = await this.readValueWithoutTag(indexType, pkg);
data.push(new MetaTuple(ref, v));
}
@@ -204,11 +199,9 @@ class JsonArrayReader {
// TODO: Verify read values match tagged kinds.
switch (t.kind) {
case Kind.Blob:
let ms = await this.maybeReadMetaSequence(t, pkg);
if (ms) {
return ms;
}
let isMeta = this.readBool();
// https://github.com/attic-labs/noms/issues/798
invariant(!isMeta, 'CompoundBlob not supported');
return this.readBlob();
case Kind.Bool:
@@ -233,22 +226,20 @@ class JsonArrayReader {
return this.readValueWithoutTag(t2, pkg);
}
case Kind.List: {
let ms = await this.maybeReadMetaSequence(t, pkg);
if (ms) {
return ms;
}
let isMeta = this.readBool();
let r2 = new JsonArrayReader(this.readArray(), this._cs);
return r2.readListLeaf(t, pkg);
let sequence = isMeta ?
await r2.readMetaSequence(t, pkg) :
await r2.readListLeafSequence(t, pkg);
return new NomsList(this._cs, t, sequence);
}
case Kind.Map: {
let ms = await this.maybeReadMetaSequence(t, pkg);
if (ms) {
return ms;
}
let isMeta = this.readBool();
let r2 = new JsonArrayReader(this.readArray(), this._cs);
return r2.readMapLeaf(t, pkg);
let sequence = isMeta ?
await r2.readMetaSequence(t, pkg) :
await r2.readMapLeafSequence(t, pkg);
return new NomsMap(this._cs, t, sequence);
}
case Kind.Package:
return Promise.resolve(this.readPackage(t, pkg));
@@ -257,13 +248,12 @@ class JsonArrayReader {
// for refs.
return Promise.resolve(this.readRef());
case Kind.Set: {
let ms = await this.maybeReadMetaSequence(t, pkg);
if (ms) {
return ms;
}
let isMeta = this.readBool();
let r2 = new JsonArrayReader(this.readArray(), this._cs);
return r2.readSetLeaf(t, pkg);
let sequence = isMeta ?
await r2.readMetaSequence(t, pkg) :
await r2.readSetLeafSequence(t, pkg);
return new NomsSet(this._cs, t, sequence);
}
case Kind.Enum:
case Kind.Struct:

View File

@@ -5,19 +5,21 @@ import MemoryStore from './memory_store.js';
import Ref from './ref.js';
import Struct from './struct.js';
import test from './async_test.js';
import type {float64, int32, int64, uint8, uint16, uint32, uint64} from './primitives.js';
import type {TypeDesc} from './type.js';
import {assert} from 'chai';
import {decodeNomsValue, JsonArrayReader} from './decode.js';
import {Field, makeCompoundType, makeEnumType, makePrimitiveType, makeStructType, makeType, Type} from './type.js';
import {invariant} from './assert.js';
import {IndexedMetaSequence, MetaTuple} from './meta_sequence.js';
import {invariant, notNull} from './assert.js';
import {Kind} from './noms_kind.js';
import {ListLeaf, CompoundList} from './list.js';
import {MapLeaf} from './map.js';
import {MetaTuple} from './meta_sequence.js';
import {ListLeafSequence, NomsList} from './list.js';
import {MapLeafSequence, NomsMap} from './map.js';
import {NomsSet, SetLeafSequence} from './set.js';
import {readValue} from './read_value.js';
import {registerPackage, Package} from './package.js';
import {SetLeaf} from './set.js';
import {suite} from 'mocha';
import {Value} from './value.js';
import {writeValue} from './encode.js';
suite('Decode', () => {
@@ -92,11 +94,11 @@ suite('Decode', () => {
let ms = new MemoryStore();
let a = [Kind.List, Kind.Int32, false, ['0', '1', '2', '3']];
let r = new JsonArrayReader(a, ms);
let v = await r.readTopLevelValue();
invariant(v instanceof ListLeaf);
let v:NomsList<int32> = await r.readTopLevelValue();
invariant(v instanceof NomsList);
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int32));
let l = new ListLeaf(ms, tr, [0, 1, 2, 3]);
let l = new NomsList(ms, tr, new ListLeafSequence(tr, [0, 1, 2, 3]));
assert.isTrue(l.equals(v));
});
@@ -105,8 +107,9 @@ suite('Decode', () => {
let ms = new MemoryStore();
let a = [Kind.List, Kind.Value, false, [Kind.Int32, '1', Kind.String, 'hi', Kind.Bool, true]];
let r = new JsonArrayReader(a, ms);
let v = await r.readTopLevelValue();
invariant(v instanceof ListLeaf);
let v:NomsList<Value> = await r.readTopLevelValue();
invariant(v instanceof NomsList);
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Value));
assert.isTrue(v.type.equals(tr));
assert.strictEqual(1, await v.get(0));
@@ -119,10 +122,10 @@ suite('Decode', () => {
let a = [Kind.Value, Kind.List, Kind.Int8, false, ['0', '1', '2']];
let r = new JsonArrayReader(a, ms);
let v = await r.readTopLevelValue();
invariant(v instanceof ListLeaf);
invariant(v instanceof NomsList);
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int8));
let l = new ListLeaf(ms, tr, [0, 1, 2]);
let l = new NomsList(ms, tr, new ListLeafSequence(tr, [0, 1, 2]));
assert.isTrue(l.equals(v));
});
@@ -130,20 +133,21 @@ suite('Decode', () => {
let ms = new MemoryStore();
let ltr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int32));
let r1 = writeValue(new ListLeaf(ms, ltr, [0, 1]), ltr, ms);
let r2 = writeValue(new ListLeaf(ms, ltr, [2, 3]), ltr, ms);
let r3 = writeValue(new ListLeaf(ms, ltr, [4, 5]), ltr, ms);
let r1 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [0, 1])), ltr, ms);
let r2 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [2, 3])), ltr, ms);
let r3 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [4, 5])), ltr, ms);
let tuples = [
new MetaTuple(r1, 2),
new MetaTuple(r2, 4),
new MetaTuple(r3, 6)
];
let l = new CompoundList(ms, ltr, tuples);
let l:NomsList<int32> = new NomsList(ms, ltr, new IndexedMetaSequence(ltr, tuples));
invariant(l instanceof NomsList);
let a = [Kind.List, Kind.Int32, true, [r1.toString(), '2', r2.toString(), '4', r3.toString(), '6']];
let r = new JsonArrayReader(a, ms);
let v = await r.readTopLevelValue();
invariant(v instanceof CompoundList);
invariant(v instanceof NomsList);
assert.isTrue(v.ref.equals(l.ref));
});
@@ -151,11 +155,23 @@ suite('Decode', () => {
let ms = new MemoryStore();
let a = [Kind.Map, Kind.Int64, Kind.Float64, false, ['0', '1', '2', '3']];
let r = new JsonArrayReader(a, ms);
let v = await r.readTopLevelValue();
invariant(v instanceof MapLeaf);
let v:NomsMap<int64, float64> = await r.readTopLevelValue();
invariant(v instanceof NomsMap);
let t = makeCompoundType(Kind.Map, makePrimitiveType(Kind.Int64), makePrimitiveType(Kind.Float64));
let m = new MapLeaf(ms, t, [{key: 0, value: 1}, {key: 2, value: 3}]);
let m = new NomsMap(ms, t, new MapLeafSequence(t, [{key: 0, value: 1}, {key: 2, value: 3}]));
assert.isTrue(v.equals(m));
});
test('read map of ref to uint64', async () => {
let ms = new MemoryStore();
let a = [Kind.Map, Kind.Ref, Kind.Value, Kind.Uint64, false, ['sha1-0000000000000000000000000000000000000001', '2', 'sha1-0000000000000000000000000000000000000002', '4']];
let r = new JsonArrayReader(a, ms);
let v:NomsMap<Ref, uint64> = await r.readTopLevelValue();
invariant(v instanceof NomsMap);
let t = makeCompoundType(Kind.Map, makeCompoundType(Kind.Ref, makePrimitiveType(Kind.Value)), makePrimitiveType(Kind.Uint64));
let m = new NomsMap(ms, t, new MapLeafSequence(t, [{key: new Ref('sha1-0000000000000000000000000000000000000001'), value: 2}, {key: new Ref('sha1-0000000000000000000000000000000000000002'), value: 4}]));
assert.isTrue(v.equals(m));
});
@@ -163,11 +179,11 @@ suite('Decode', () => {
let ms = new MemoryStore();
let a = [Kind.Value, Kind.Map, Kind.Uint64, Kind.Uint32, false, ['0', '1', '2', '3']];
let r = new JsonArrayReader(a, ms);
let v = await r.readTopLevelValue();
invariant(v instanceof MapLeaf);
let v:NomsMap<uint64, uint32> = await r.readTopLevelValue();
invariant(v instanceof NomsMap);
let t = makeCompoundType(Kind.Map, makePrimitiveType(Kind.Uint64), makePrimitiveType(Kind.Uint32));
let m = new MapLeaf(ms, t, [{key: 0, value: 1}, {key: 2, value: 3}]);
let m = new NomsMap(ms, t, new MapLeafSequence(t, [{key: 0, value: 1}, {key: 2, value: 3}]));
assert.isTrue(v.equals(m));
});
@@ -175,11 +191,11 @@ suite('Decode', () => {
let ms = new MemoryStore();
let a = [Kind.Set, Kind.Uint8, false, ['0', '1', '2', '3']];
let r = new JsonArrayReader(a, ms);
let v = await r.readTopLevelValue();
invariant(v instanceof SetLeaf);
let v:NomsSet<uint8> = await r.readTopLevelValue();
invariant(v instanceof NomsSet);
let t = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Uint8));
let s = new SetLeaf(ms, t, [0, 1, 2, 3]);
let s = new NomsSet(ms, t, new SetLeafSequence(t, [0, 1, 2, 3]));
assert.isTrue(v.equals(s));
});
@@ -187,14 +203,16 @@ suite('Decode', () => {
let ms = new MemoryStore();
let a = [Kind.Value, Kind.Set, Kind.Uint16, false, ['0', '1', '2', '3']];
let r = new JsonArrayReader(a, ms);
let v = await r.readTopLevelValue();
let v:NomsSet<uint16> = await r.readTopLevelValue();
invariant(v instanceof NomsSet);
let t = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Uint16));
let s = new SetLeaf(ms, t, [0, 1, 2, 3]);
let s = new NomsSet(ms, t, new SetLeafSequence(t, [0, 1, 2, 3]));
assert.isTrue(v.equals(s));
});
function assertStruct(s: Struct, desc: TypeDesc, data: {[key: string]: any}) {
function assertStruct(s: ?Struct, desc: TypeDesc, data: {[key: string]: any}) {
notNull(s);
invariant(s instanceof Struct, 'expected instanceof struct');
assert.deepEqual(desc, s.desc);
@@ -287,7 +305,7 @@ suite('Decode', () => {
assertStruct(v, tr.desc, {
b: true,
l: new ListLeaf(ms, ltr, [0, 1, 2]),
l: new NomsList(ms, ltr, new ListLeafSequence(ltr, [0, 1, 2])),
s: 'hi'
});
});
@@ -399,11 +417,10 @@ suite('Decode', () => {
let a = [Kind.Value, Kind.Map, Kind.String, Kind.Unresolved, pkg.ref.toString(), '0', false, ['bar', false, '2', 'baz', false, '1', 'foo', true, '3']];
let r = new JsonArrayReader(a, ms);
let v = await r.readTopLevelValue();
let v:NomsMap<string, Struct> = await r.readTopLevelValue();
invariant(v instanceof NomsMap);
invariant(v instanceof MapLeaf);
assert.strictEqual(3, v.size);
assertStruct(await v.get('foo'), tr.desc, {b: true, i: 3});
assertStruct(await v.get('bar'), tr.desc, {b: false, i: 2});
assertStruct(await v.get('baz'), tr.desc, {b: false, i: 1});
@@ -412,10 +429,10 @@ suite('Decode', () => {
test('decodeNomsValue', async () => {
let ms = new MemoryStore();
let chunk = Chunk.fromString(`t [${Kind.Value}, ${Kind.Set}, ${Kind.Uint16}, false, ["0", "1", "2", "3"]]`);
let v = await decodeNomsValue(chunk, new MemoryStore());
let v:NomsSet<uint16> = await decodeNomsValue(chunk, new MemoryStore());
let t = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Uint16));
let s = new SetLeaf(ms, t, [0, 1, 2, 3]);
let s:NomsSet<uint16> = new NomsSet(ms, t, new SetLeafSequence(t, [0, 1, 2, 3]));
assert.isTrue(v.equals(s));
});

View File

@@ -6,16 +6,16 @@ import Struct from './struct.js';
import type {ChunkStore} from './chunk_store.js';
import type {NomsKind} from './noms_kind.js';
import {encode as encodeBase64} from './base64.js';
import {EnumDesc, makePrimitiveType, StructDesc, Type} from './type.js';
import {indexTypeForMetaSequence} from './meta_sequence.js';
import {invariant, notNull} from './assert.js';
import {isPrimitiveKind, Kind} from './noms_kind.js';
import {ListLeaf} from './list.js';
import {ListLeafSequence, NomsList} from './list.js';
import {lookupPackage, Package} from './package.js';
import {makePrimitiveType, EnumDesc, StructDesc, Type} from './type.js';
import {MapLeaf} from './map.js';
import {MapLeafSequence, NomsMap} from './map.js';
import {NomsSet, SetLeafSequence} from './set.js';
import {Sequence} from './sequence.js';
import {setEncodeNomsValue} from './get_ref.js';
import {SetLeaf} from './set.js';
const typedTag = 't ';
@@ -139,29 +139,31 @@ class JsonArrayWriter {
this.writeInt(v); // TODO: Verify value fits in type
break;
case Kind.List: {
invariant(v instanceof Sequence);
if (this.maybeWriteMetaSequence(v, t, pkg)) {
invariant(v instanceof NomsList);
let sequence = v.sequence;
if (this.maybeWriteMetaSequence(sequence, t, pkg)) {
break;
}
invariant(v instanceof ListLeaf);
invariant(sequence instanceof ListLeafSequence);
let w2 = new JsonArrayWriter(this._cs);
let elemType = t.elemTypes[0];
v.items.forEach(sv => w2.writeValue(sv, elemType));
sequence.items.forEach(sv => w2.writeValue(sv, elemType));
this.write(w2.array);
break;
}
case Kind.Map: {
invariant(v instanceof Sequence);
if (this.maybeWriteMetaSequence(v, t, pkg)) {
invariant(v instanceof NomsMap);
let sequence = v.sequence;
if (this.maybeWriteMetaSequence(sequence, t, pkg)) {
break;
}
invariant(v instanceof MapLeaf);
invariant(sequence instanceof MapLeafSequence);
let w2 = new JsonArrayWriter(this._cs);
let keyType = t.elemTypes[0];
let valueType = t.elemTypes[1];
v.items.forEach(entry => {
sequence.items.forEach(entry => {
w2.writeValue(entry.key, keyType);
w2.writeValue(entry.value, valueType);
});
@@ -187,16 +189,17 @@ class JsonArrayWriter {
break;
}
case Kind.Set: {
invariant(v instanceof Sequence);
if (this.maybeWriteMetaSequence(v, t, pkg)) {
invariant(v instanceof NomsSet);
let sequence = v.sequence;
if (this.maybeWriteMetaSequence(sequence, t, pkg)) {
break;
}
invariant(v instanceof SetLeaf);
invariant(sequence instanceof SetLeafSequence);
let w2 = new JsonArrayWriter(this._cs);
let elemType = t.elemTypes[0];
let elems = [];
v.items.forEach(v => {
sequence.items.forEach(v => {
elems.push(v);
});
elems.forEach(elem => w2.writeValue(elem, elemType));

View File

@@ -8,14 +8,14 @@ import Ref from './ref.js';
import Struct from './struct.js';
import test from './async_test.js';
import type {NomsKind} from './noms_kind.js';
import {encodeNomsValue, JsonArrayWriter} from './encode.js';
import {Field, makeCompoundType, makeEnumType, makePrimitiveType, makeStructType, makeType, Type} from './type.js';
import {JsonArrayWriter, encodeNomsValue} from './encode.js';
import {IndexedMetaSequence, MetaTuple} from './meta_sequence.js';
import {Kind} from './noms_kind.js';
import {ListLeaf, CompoundList} from './list.js';
import {MapLeaf} from './map.js';
import {MetaTuple} from './meta_sequence.js';
import {ListLeafSequence, NomsList} from './list.js';
import {MapLeafSequence, NomsMap} from './map.js';
import {NomsSet, SetLeafSequence} from './set.js';
import {Package, registerPackage} from './package.js';
import {SetLeaf} from './set.js';
import {writeValue} from './encode.js';
suite('Encode', () => {
@@ -61,7 +61,7 @@ suite('Encode', () => {
let w = new JsonArrayWriter(ms);
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int32));
let l = new ListLeaf(ms, tr, [0, 1, 2, 3]);
let l = new NomsList(ms, tr, new ListLeafSequence(tr, [0, 1, 2, 3]));
w.writeTopLevel(tr, l);
assert.deepEqual([Kind.List, Kind.Int32, false, ['0', '1', '2', '3']], w.array);
});
@@ -72,7 +72,10 @@ suite('Encode', () => {
let it = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int16));
let tr = makeCompoundType(Kind.List, it);
let v = new ListLeaf(ms, tr, [new ListLeaf(ms, it, [0]), new ListLeaf(ms, it, [1, 2, 3])]);
let v = new NomsList(ms, tr, new ListLeafSequence(tr, [
new NomsList(ms, tr, new ListLeafSequence(it, [0])),
new NomsList(ms, tr, new ListLeafSequence(it, [1, 2, 3]))
]));
w.writeTopLevel(tr, v);
assert.deepEqual([Kind.List, Kind.List, Kind.Int16, false, [false, ['0'], false, ['1', '2', '3']]], w.array);
});
@@ -82,7 +85,7 @@ suite('Encode', () => {
let w = new JsonArrayWriter(ms);
let tr = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Uint32));
let v = new SetLeaf(ms, tr, [0, 1, 2, 3]);
let v = new NomsSet(ms, tr, new SetLeafSequence(tr, [0, 1, 2, 3]));
w.writeTopLevel(tr, v);
assert.deepEqual([Kind.Set, Kind.Uint32, false, ['0', '1', '2', '3']], w.array);
});
@@ -93,7 +96,10 @@ suite('Encode', () => {
let st = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Int32));
let tr = makeCompoundType(Kind.Set, st);
let v = new SetLeaf(ms, tr, [new SetLeaf(ms, st, [0]), new SetLeaf(ms, st, [1, 2, 3])]);
let v = new NomsSet(ms, tr, new SetLeafSequence(tr, [
new NomsSet(ms, tr, new SetLeafSequence(st, [0])),
new NomsSet(ms, tr, new SetLeafSequence(st, [1, 2, 3]))
]));
w.writeTopLevel(tr, v);
assert.deepEqual([Kind.Set, Kind.Set, Kind.Int32, false, [false, ['0'], false, ['1', '2', '3']]], w.array);
@@ -104,7 +110,7 @@ suite('Encode', () => {
let w = new JsonArrayWriter(ms);
let tr = makeCompoundType(Kind.Map, makePrimitiveType(Kind.String), makePrimitiveType(Kind.Bool));
let v = new MapLeaf(ms, tr, [{key: 'a', value: false}, {key:'b', value:true}]);
let v = new NomsMap(ms, tr, new MapLeafSequence(tr, [{key: 'a', value: false}, {key:'b', value:true}]));
w.writeTopLevel(tr, v);
assert.deepEqual([Kind.Map, Kind.String, Kind.Bool, false, ['a', false, 'b', true]], w.array);
});
@@ -117,10 +123,9 @@ suite('Encode', () => {
let vt = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Bool));
let tr = makeCompoundType(Kind.Map, kt, vt);
let s = new SetLeaf(ms, vt, [true]);
let m1 = new MapLeaf(ms, kt, [{key: 'a', value: 0}]);
let v = new MapLeaf(ms, tr, [{key: m1, value: s}]);
let s = new NomsSet(ms, vt, new SetLeafSequence(vt, [true]));
let m1 = new NomsMap(ms, kt, new MapLeafSequence(kt, [{key: 'a', value: 0}]));
let v = new NomsMap(ms, kt, new MapLeafSequence(tr, [{key: m1, value: s}]));
w.writeTopLevel(tr, v);
assert.deepEqual([Kind.Map, Kind.Map, Kind.String, Kind.Int64, Kind.Set, Kind.Bool, false, [false, ['a', '0'], false, [true]]], w.array);
});
@@ -221,11 +226,11 @@ suite('Encode', () => {
let pkgRef = pkg.ref;
let type = makeType(pkgRef, 0);
let v = new Struct(type, typeDef, {l: new ListLeaf(ms, ltr, ['a', 'b'])});
let v = new Struct(type, typeDef, {l: new NomsList(ms, ltr, new ListLeafSequence(ltr, ['a', 'b']))});
w.writeTopLevel(type, v);
assert.deepEqual([Kind.Unresolved, pkgRef.toString(), '0', false, ['a', 'b']], w.array);
v = new Struct(type, typeDef, {l: new ListLeaf(ms, ltr, [])});
v = new Struct(type, typeDef, {l: new NomsList(ms, ltr, new ListLeafSequence(ltr, []))});
w = new JsonArrayWriter(ms);
w.writeTopLevel(type, v);
assert.deepEqual([Kind.Unresolved, pkgRef.toString(), '0', false, []], w.array);
@@ -275,7 +280,7 @@ suite('Encode', () => {
let pkgRef = pkg.ref;
let typ = makeType(pkgRef, 0);
let listType = makeCompoundType(Kind.List, typ);
let l = new ListLeaf(ms, listType, [0, 1, 2]);
let l = new NomsList(ms, listType, new ListLeafSequence(listType, [0, 1, 2]));
w.writeTopLevel(listType, l);
assert.deepEqual([Kind.List, Kind.Unresolved, pkgRef.toString(), '0', false, ['0', '1', '2']], w.array);
@@ -286,15 +291,15 @@ suite('Encode', () => {
let w = new JsonArrayWriter(ms);
let ltr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int32));
let r1 = writeValue(new ListLeaf(ms, ltr, [0, 1]), ltr, ms);
let r2 = writeValue(new ListLeaf(ms, ltr, [2, 3]), ltr, ms);
let r3 = writeValue(new ListLeaf(ms, ltr, [4, 5]), ltr, ms);
let r1 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [0, 1])), ltr, ms);
let r2 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [2, 3])), ltr, ms);
let r3 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [4, 5])), ltr, ms);
let tuples = [
new MetaTuple(r1, 2),
new MetaTuple(r2, 4),
new MetaTuple(r3, 6)
];
let l = new CompoundList(ms, ltr, tuples);
let l = new NomsList(ms, ltr, new IndexedMetaSequence(ltr, tuples));
w.writeTopLevel(ltr, l);
assert.deepEqual([Kind.List, Kind.Int32, true, [r1.toString(), '2', r2.toString(), '4', r3.toString(), '6']], w.array);

View File

@@ -1,5 +1,6 @@
// @flow
import type {ChunkStore} from './chunk_store.js';
import {notNull} from './assert.js';
import {search, Sequence, SequenceCursor} from './sequence.js';
@@ -8,12 +9,12 @@ export class IndexedSequence<T> extends Sequence<T> {
throw new Error('override');
}
async newCursorAt(idx: number): Promise<IndexedSequenceCursor> {
async newCursorAt(cs: ChunkStore, idx: number): Promise<IndexedSequenceCursor> {
let cursor: ?IndexedSequenceCursor = null;
let sequence: ?IndexedSequence = this;
while (sequence) {
cursor = new IndexedSequenceCursor(cursor, sequence, 0);
cursor = new IndexedSequenceCursor(cs, cursor, sequence, 0);
idx -= cursor.advanceToOffset(idx);
sequence = await cursor.getChildSequence();
}

View File

@@ -1,22 +1,18 @@
// @flow
import type {ChunkStore} from './chunk_store.js';
import type {valueOrPrimitive} from './value.js'; // eslint-disable-line no-unused-vars
import {Collection} from './collection.js';
import {IndexedSequence} from './indexed_sequence.js';
import {invariant} from './assert.js';
import {Kind} from './noms_kind.js';
import {MetaTuple, registerMetaValue} from './meta_sequence.js';
import {Type} from './type.js';
export class NomsList<K: valueOrPrimitive, T> extends IndexedSequence<T> {
async get(idx: number): Promise<K> {
invariant(idx < this.length, idx + ' >= ' + this.length);
let cursor = await this.newCursorAt(idx);
export class NomsList<T: valueOrPrimitive> extends Collection<IndexedSequence> {
async get(idx: number): Promise<T> {
// TODO (when |length| works) invariant(idx < this.length, idx + ' >= ' + this.length);
let cursor = await this.sequence.newCursorAt(this.cs, idx);
return cursor.getCurrent();
}
async forEach(cb: (v: K, i: number) => void): Promise<void> {
let cursor = await this.newCursorAt(0);
async forEach(cb: (v: T, i: number) => void): Promise<void> {
let cursor = await this.sequence.newCursorAt(this.cs, 0);
return cursor.iter((v, i) => {
cb(v, i);
return false;
@@ -24,46 +20,16 @@ export class NomsList<K: valueOrPrimitive, T> extends IndexedSequence<T> {
}
get length(): number {
return this.items.length;
if (this.sequence instanceof ListLeafSequence) {
return this.sequence.items.length;
}
throw new Error('not implemented');
}
}
export class ListLeaf<T: valueOrPrimitive> extends NomsList<T, T> {
export class ListLeafSequence<T: valueOrPrimitive> extends IndexedSequence<T> {
getOffset(idx: number): number {
return idx;
}
}
export class CompoundList<T: valueOrPrimitive> extends NomsList<T, MetaTuple<number>> {
offsets: Array<number>;
constructor(cs: ChunkStore, type: Type, items: Array<MetaTuple<number>>) {
super(cs, type, items);
this.isMeta = true;
this.offsets = [];
let cum = 0;
for (let i = 0; i < items.length; i++) {
let length = items[i].value;
this.offsets.push(cum + length - 1);
cum += length;
}
}
getOffset(idx: number): number {
return this.offsets[idx];
}
async getChildSequence(idx: number): Promise<?NomsList> {
let mt = this.items[idx];
let ms = await mt.readValue(this.cs);
invariant(ms instanceof NomsList);
return ms;
}
get length(): number {
return this.offsets[this.items.length - 1] + 1;
}
}
registerMetaValue(Kind.List, (cs, type, tuples) => new CompoundList(cs, type, tuples));

View File

@@ -5,17 +5,17 @@ import {suite} from 'mocha';
import MemoryStore from './memory_store.js';
import test from './async_test.js';
import {CompoundList, ListLeaf} from './list.js';
import {IndexedMetaSequence, MetaTuple} from './meta_sequence.js';
import {Kind} from './noms_kind.js';
import {ListLeafSequence, NomsList} from './list.js';
import {makeCompoundType, makePrimitiveType} from './type.js';
import {MetaTuple} from './meta_sequence.js';
import {writeValue} from './encode.js';
suite('ListLeaf', () => {
suite('ListLeafSequence', () => {
test('get', async () => {
let ms = new MemoryStore();
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.String));
let l = new ListLeaf(ms, tr, ['z', 'x', 'a', 'b']);
let l = new NomsList(ms, tr, new ListLeafSequence(tr, ['z', 'x', 'a', 'b']));
assert.strictEqual('z', await l.get(0));
assert.strictEqual('x', await l.get(1));
assert.strictEqual('a', await l.get(2));
@@ -25,7 +25,7 @@ suite('ListLeaf', () => {
test('forEach', async () => {
let ms = new MemoryStore();
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int32));
let l = new ListLeaf(ms, tr, [4, 2, 10, 16]);
let l = new NomsList(ms, tr, new ListLeafSequence(tr, [4, 2, 10, 16]));
let values = [];
await l.forEach((v, i) => { values.push(v, i); });
@@ -34,24 +34,24 @@ suite('ListLeaf', () => {
});
suite('CompoundList', () => {
function build(): CompoundList {
function build(): NomsList {
let ms = new MemoryStore();
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.String));
let l1 = new ListLeaf(ms, tr, ['a', 'b']);
let l1 = new NomsList(ms, tr, new ListLeafSequence(tr, ['a', 'b']));
let r1 = writeValue(l1, tr, ms);
let l2 = new ListLeaf(ms, tr, ['e', 'f']);
let l2 = new NomsList(ms, tr, new ListLeafSequence(tr, ['e', 'f']));
let r2 = writeValue(l2, tr, ms);
let l3 = new ListLeaf(ms, tr, ['h', 'i']);
let l3 = new NomsList(ms, tr, new ListLeafSequence(tr, ['h', 'i']));
let r3 = writeValue(l3, tr, ms);
let l4 = new ListLeaf(ms, tr, ['m', 'n']);
let l4 = new NomsList(ms, tr, new ListLeafSequence(tr, ['m', 'n']));
let r4 = writeValue(l4, tr, ms);
let m1 = new CompoundList(ms, tr, [new MetaTuple(r1, 2), new MetaTuple(r2, 2)]);
let m1 = new NomsList(ms, tr, new IndexedMetaSequence(tr, [new MetaTuple(r1, 2), new MetaTuple(r2, 2)]));
let rm1 = writeValue(m1, tr, ms);
let m2 = new CompoundList(ms, tr, [new MetaTuple(r3, 2), new MetaTuple(r4, 2)]);
let m2 = new NomsList(ms, tr, new IndexedMetaSequence(tr, [new MetaTuple(r3, 2), new MetaTuple(r4, 2)]));
let rm2 = writeValue(m2, tr, ms);
let l = new CompoundList(ms, tr, [new MetaTuple(rm1, 4), new MetaTuple(rm2, 4)]);
let l = new NomsList(ms, tr, new IndexedMetaSequence(tr, [new MetaTuple(rm1, 4), new MetaTuple(rm2, 4)]));
return l;
}

View File

@@ -1,22 +1,23 @@
// @flow
import type {ChunkStore} from './chunk_store.js';
import type {valueOrPrimitive} from './value.js'; // eslint-disable-line no-unused-vars
import {Collection} from './collection.js';
import {equals} from './value.js';
import {invariant} from './assert.js';
import {Kind} from './noms_kind.js';
import {MetaTuple, registerMetaValue} from './meta_sequence.js';
import {OrderedSequence} from './ordered_sequence.js';
import {Type} from './type.js';
type Entry<K: valueOrPrimitive, V: valueOrPrimitive> = {
key: K,
value: V
};
export class NomsMap<K: valueOrPrimitive, V: valueOrPrimitive, T> extends OrderedSequence<K, T> {
export class NomsMap<K: valueOrPrimitive, V: valueOrPrimitive> extends Collection<OrderedSequence> {
async has(key: K): Promise<boolean> {
let cursor = await this.sequence.newCursorAt(this.cs, key);
return cursor.valid && equals(cursor.getCurrentKey(), key);
}
async first(): Promise<?[K, V]> {
let cursor = await this.newCursorAt(null);
let cursor = await this.sequence.newCursorAt(this.cs, null);
if (!cursor.valid) {
return undefined;
}
@@ -26,7 +27,7 @@ export class NomsMap<K: valueOrPrimitive, V: valueOrPrimitive, T> extends Ordere
}
async get(key: K): Promise<?V> {
let cursor = await this.newCursorAt(key);
let cursor = await this.sequence.newCursorAt(this.cs, key);
if (!cursor.valid) {
return undefined;
}
@@ -36,7 +37,7 @@ export class NomsMap<K: valueOrPrimitive, V: valueOrPrimitive, T> extends Ordere
}
async forEach(cb: (v: V, k: K) => void): Promise<void> {
let cursor = await this.newCursorAt(null);
let cursor = await this.sequence.newCursorAt(this.cs, null);
return cursor.iter(entry => {
cb(entry.value, entry.key);
return false;
@@ -44,37 +45,16 @@ export class NomsMap<K: valueOrPrimitive, V: valueOrPrimitive, T> extends Ordere
}
get size(): number {
return this.items.length;
if (this.sequence instanceof MapLeafSequence) {
return this.sequence.items.length;
}
throw new Error('Not implemented');
}
}
export class MapLeaf<K: valueOrPrimitive, V: valueOrPrimitive> extends NomsMap<K, V, Entry<K, V>> {
export class MapLeafSequence<K: valueOrPrimitive, V: valueOrPrimitive> extends OrderedSequence<K, Entry<K, V>> {
getKey(idx: number): K {
return this.items[idx].key;
}
}
export class CompoundMap<K: valueOrPrimitive, V: valueOrPrimitive> extends NomsMap<K, V, MetaTuple<K>> {
constructor(cs: ChunkStore, type: Type, items: Array<MetaTuple>) {
super(cs, type, items);
this.isMeta = true;
}
getKey(idx: number): K {
return this.items[idx].value;
}
async getChildSequence(idx: number): Promise<?MapLeaf> {
let mt = this.items[idx];
let ms = await mt.readValue(this.cs);
invariant(ms instanceof NomsMap);
return ms;
}
get size(): number {
throw new Error('not implemented');
}
}
registerMetaValue(Kind.Map, (cs, type, tuples) => new CompoundMap(cs, type, tuples));

View File

@@ -5,17 +5,18 @@ import {suite} from 'mocha';
import MemoryStore from './memory_store.js';
import test from './async_test.js';
import {CompoundMap, MapLeaf} from './map.js';
import type {ChunkStore} from './chunk_store.js';
import {Kind} from './noms_kind.js';
import {makeCompoundType, makePrimitiveType} from './type.js';
import {MetaTuple} from './meta_sequence.js';
import {MapLeafSequence, NomsMap} from './map.js';
import {MetaTuple, OrderedMetaSequence} from './meta_sequence.js';
import {writeValue} from './encode.js';
suite('MapLeaf', () => {
test('has', async () => {
let ms = new MemoryStore();
let tr = makeCompoundType(Kind.Map, makePrimitiveType(Kind.String), makePrimitiveType(Kind.Bool));
let m = new MapLeaf(ms, tr, [{key: 'a', value: false}, {key:'k', value:true}]);
let m = new NomsMap(ms, tr, new MapLeafSequence(tr, [{key: 'a', value: false}, {key:'k', value:true}]));
assert.isTrue(await m.has('a'));
assert.isFalse(await m.has('b'));
assert.isTrue(await m.has('k'));
@@ -25,7 +26,7 @@ suite('MapLeaf', () => {
test('first/get', async () => {
let ms = new MemoryStore();
let tr = makeCompoundType(Kind.Map, makePrimitiveType(Kind.String), makePrimitiveType(Kind.Int32));
let m = new MapLeaf(ms, tr, [{key: 'a', value: 4}, {key:'k', value:8}]);
let m = new NomsMap(ms, tr, new MapLeafSequence(tr, [{key: 'a', value: 4}, {key:'k', value:8}]));
assert.deepEqual(['a', 4], await m.first());
@@ -38,7 +39,7 @@ suite('MapLeaf', () => {
test('forEach', async () => {
let ms = new MemoryStore();
let tr = makeCompoundType(Kind.Map, makePrimitiveType(Kind.String), makePrimitiveType(Kind.Int32));
let m = new MapLeaf(ms, tr, [{key: 'a', value: 4}, {key:'k', value:8}]);
let m = new NomsMap(ms, tr, new MapLeafSequence(tr, [{key: 'a', value: 4}, {key:'k', value:8}]));
let kv = [];
await m.forEach((v, k) => { kv.push(k, v); });
@@ -47,29 +48,29 @@ suite('MapLeaf', () => {
});
suite('CompoundMap', () => {
function build(): Array<CompoundMap> {
let ms = new MemoryStore();
function build(cs: ChunkStore): Array<NomsMap> {
let tr = makeCompoundType(Kind.Map, makePrimitiveType(Kind.String), makePrimitiveType(Kind.Bool));
let l1 = new MapLeaf(ms, tr, [{key: 'a', value: false}, {key:'b', value:false}]);
let r1 = writeValue(l1, tr, ms);
let l2 = new MapLeaf(ms, tr, [{key: 'e', value: true}, {key:'f', value:true}]);
let r2 = writeValue(l2, tr, ms);
let l3 = new MapLeaf(ms, tr, [{key: 'h', value: false}, {key:'i', value:true}]);
let r3 = writeValue(l3, tr, ms);
let l4 = new MapLeaf(ms, tr, [{key: 'm', value: true}, {key:'n', value:false}]);
let r4 = writeValue(l4, tr, ms);
let l1 = new NomsMap(cs, tr, new MapLeafSequence(tr, [{key: 'a', value: false}, {key:'b', value:false}]));
let r1 = writeValue(l1, tr, cs);
let l2 = new NomsMap(cs, tr, new MapLeafSequence(tr, [{key: 'e', value: true}, {key:'f', value:true}]));
let r2 = writeValue(l2, tr, cs);
let l3 = new NomsMap(cs, tr, new MapLeafSequence(tr, [{key: 'h', value: false}, {key:'i', value:true}]));
let r3 = writeValue(l3, tr, cs);
let l4 = new NomsMap(cs, tr, new MapLeafSequence(tr, [{key: 'm', value: true}, {key:'n', value:false}]));
let r4 = writeValue(l4, tr, cs);
let m1 = new CompoundMap(ms, tr, [new MetaTuple(r1, 'b'), new MetaTuple(r2, 'f')]);
let rm1 = writeValue(m1, tr, ms);
let m2 = new CompoundMap(ms, tr, [new MetaTuple(r3, 'i'), new MetaTuple(r4, 'n')]);
let rm2 = writeValue(m2, tr, ms);
let m1 = new NomsMap(cs, tr, new OrderedMetaSequence(tr, [new MetaTuple(r1, 'b'), new MetaTuple(r2, 'f')]));
let rm1 = writeValue(m1, tr, cs);
let m2 = new NomsMap(cs, tr, new OrderedMetaSequence(tr, [new MetaTuple(r3, 'i'), new MetaTuple(r4, 'n')]));
let rm2 = writeValue(m2, tr, cs);
let c = new CompoundMap(ms, tr, [new MetaTuple(rm1, 'f'), new MetaTuple(rm2, 'n')]);
let c = new NomsMap(cs, tr, new OrderedMetaSequence(tr, [new MetaTuple(rm1, 'f'), new MetaTuple(rm2, 'n')]));
return [c, m1, m2];
}
test('get', async () => {
let [c] = build();
let ms = new MemoryStore();
let [c] = build(ms);
assert.strictEqual(false, await c.get('a'));
assert.strictEqual(false, await c.get('b'));
@@ -88,8 +89,8 @@ suite('CompoundMap', () => {
});
test('first/has', async () => {
let [c, m1, m2] = build();
let ms = new MemoryStore();
let [c, m1, m2] = build(ms);
assert.deepEqual(['a', false], await c.first());
assert.deepEqual(['a', false], await m1.first());
@@ -112,7 +113,8 @@ suite('CompoundMap', () => {
});
test('forEach', async () => {
let [c] = build();
let ms = new MemoryStore();
let [c] = build(ms);
let kv = [];
await c.forEach((v, k) => { kv.push(k, v); });

View File

@@ -2,10 +2,12 @@
import Ref from './ref.js';
import type {ChunkStore} from './chunk_store.js';
import type {NomsKind} from './noms_kind.js';
import type {valueOrPrimitive} from './value.js'; // eslint-disable-line no-unused-vars
import {CompoundDesc, makeCompoundType, makePrimitiveType, Type} from './type.js';
import {invariant, notNull} from './assert.js';
import {IndexedSequence} from './indexed_sequence.js';
import {invariant} from './assert.js';
import {Kind} from './noms_kind.js';
import {OrderedSequence} from './ordered_sequence.js';
import {readValue} from './read_value.js';
import {Sequence} from './sequence.js';
@@ -19,23 +21,73 @@ export class MetaTuple<K> {
this.ref = ref;
this.value = value;
}
}
readValue(cs: ChunkStore): Promise<any> {
return readValue(this.ref, cs);
export class IndexedMetaSequence extends IndexedSequence<MetaTuple<number>> {
offsets: Array<number>;
constructor(type: Type, items: Array<MetaTuple<number>>) {
super(type, items);
this.isMeta = true;
this.offsets = [];
let cum = 0;
for (let i = 0; i < items.length; i++) {
let length = items[i].value;
this.offsets.push(cum + length - 1);
cum += length;
}
}
async getChildSequence(cs: ChunkStore, idx: number): Promise<?IndexedSequence> {
if (!this.isMeta) {
return null;
}
let mt = this.items[idx];
let collection = await readValue(mt.ref, cs);
invariant(collection && collection.sequence instanceof IndexedSequence);
return collection.sequence;
}
getOffset(idx: number): number {
return this.offsets[idx];
}
}
export type metaBuilderFn = (cs: ChunkStore, t: Type, tuples: Array<MetaTuple>) => MetaSequence;
export class OrderedMetaSequence<K: valueOrPrimitive> extends OrderedSequence<K, MetaTuple<K>> {
constructor(type: Type, items: Array<MetaTuple>) {
super(type, items);
this.isMeta = true;
}
let metaFuncMap: Map<NomsKind, metaBuilderFn> = new Map();
async getChildSequence(cs: ChunkStore, idx: number): Promise<?OrderedSequence> {
if (!this.isMeta) {
return null;
}
export function newMetaSequenceFromData(cs: ChunkStore, t: Type, data: Array<MetaTuple>): MetaSequence {
let ctor = notNull(metaFuncMap.get(t.kind));
return ctor(cs, t, data);
let mt = this.items[idx];
let collection = await readValue(mt.ref, cs);
invariant(collection && collection.sequence instanceof OrderedSequence);
return collection.sequence;
}
getKey(idx: number): K {
return this.items[idx].value;
}
}
export function registerMetaValue(k: NomsKind, bf: metaBuilderFn) {
metaFuncMap.set(k, bf);
export function newMetaSequenceFromData(cs: ChunkStore, type: Type, tuples: Array<MetaTuple>): MetaSequence {
switch (type.kind) {
case Kind.Map:
case Kind.Set:
return new OrderedMetaSequence(type, tuples);
case Kind.List:
return new IndexedMetaSequence(type, tuples);
case Kind.Blob:
throw new Error('Not implemented');
default:
throw new Error('Not reached');
}
}
let indexedSequenceIndexType = makePrimitiveType(Kind.Uint64);

View File

@@ -7,10 +7,13 @@ export {default as MemoryStore} from './memory_store.js';
export {default as Ref} from './ref.js';
export {default as Struct} from './struct.js';
export {encodeNomsValue} from './encode.js';
export {invariant, notNull} from './assert.js';
export {isPrimitiveKind, Kind} from './noms_kind.js';
export {ListLeafSequence, NomsList} from './list.js';
export {lookupPackage, Package, readPackage, registerPackage} from './package.js';
export {NomsList, ListLeaf, CompoundList} from './list.js';
export {NomsMap, MapLeaf, CompoundMap} from './map.js';
export {NomsSet, SetLeaf, CompoundSet} from './set.js';
export {NomsMap, MapLeafSequence} from './map.js';
export {NomsSet, SetLeafSequence} from './set.js';
export {OrderedMetaSequence, IndexedMetaSequence} from './meta_sequence.js';
export {readValue} from './read_value.js';
export {
CompoundDesc,
@@ -22,11 +25,11 @@ export {
makeStructType,
makeType,
makeUnresolvedType,
packageType,
PrimitiveDesc,
StructDesc,
Type,
typeType,
packageType,
UnresolvedDesc
} from './type.js';

View File

@@ -1,8 +1,9 @@
// @flow
import type {ChunkStore} from './chunk_store.js';
import type {valueOrPrimitive} from './value.js'; // eslint-disable-line no-unused-vars
import {invariant, notNull} from './assert.js';
import {less, equals} from './value.js';
import {less} from './value.js';
import {search, Sequence, SequenceCursor} from './sequence.js';
export class OrderedSequence<K: valueOrPrimitive, T> extends Sequence<T> {
@@ -12,12 +13,12 @@ export class OrderedSequence<K: valueOrPrimitive, T> extends Sequence<T> {
// -cursor positioned at
// -first value, if |key| is null
// -first value >= |key|
async newCursorAt(key: ?K): Promise<OrderedSequenceCursor> {
async newCursorAt(cs: ChunkStore, key: ?K): Promise<OrderedSequenceCursor> {
let cursor: ?OrderedSequenceCursor = null;
let sequence: ?OrderedSequence = this;
while (sequence) {
cursor = new OrderedSequenceCursor(cursor, sequence, 0);
cursor = new OrderedSequenceCursor(cs, cursor, sequence, 0);
if (key) {
if (!cursor._seekTo(key)) {
return cursor; // invalid
@@ -33,11 +34,6 @@ export class OrderedSequence<K: valueOrPrimitive, T> extends Sequence<T> {
getKey(idx: number): K { // eslint-disable-line no-unused-vars
throw new Error('override');
}
async has(key: K): Promise<boolean> {
let cursor = await this.newCursorAt(key);
return cursor.valid && equals(cursor.getCurrentKey(), key);
}
}
export class OrderedSequenceCursor<T, K: valueOrPrimitive> extends SequenceCursor<T, OrderedSequence> {

View File

@@ -2,9 +2,15 @@
import Rusha from 'rusha';
import type {Value} from './value.js';
import {invariant} from './assert.js';
const r = new Rusha();
const sha1Size = 20;
const pattern = /^sha1-([0-9a-f]{40})$/;
const pattern = /^(sha1-[0-9a-f]{40})$/;
const sha1Prefix = 'sha1-';
const emtpyRefStr = sha1Prefix + '0'.repeat(40);
function uint8ArrayToHex(a: Uint8Array): string {
let hex = '';
@@ -31,46 +37,36 @@ function hexToUint8(s: string): Uint8Array {
}
export default class Ref {
digest: Uint8Array;
_refStr: string;
constructor(digest: Uint8Array = new Uint8Array(sha1Size)) {
this.digest = digest;
constructor(refStr: string = emtpyRefStr) {
this._refStr = refStr;
}
get ref(): Ref {
return this;
}
get digest(): Uint8Array {
return hexToUint8(this._refStr.substring(5));
}
isEmpty(): boolean {
for (let i = 0; i < sha1Size; i++) {
if (this.digest[i] !== 0) {
return false;
}
}
return true;
return this._refStr === emtpyRefStr;
}
equals(other: Ref): boolean {
for (let i = 0; i < sha1Size; i++) {
if (this.digest[i] !== other.digest[i]) {
return false;
}
}
return true;
equals(other: Value): boolean {
invariant(other instanceof Ref);
return this._refStr === other._refStr;
}
compare(other: Ref): number {
for (let i = 0; i < sha1Size; i++) {
if (this.digest[i] < other.digest[i]) {
return -1;
} else if (this.digest[i] > other.digest[i]) {
return 1;
}
}
return 0;
less(other: Value): boolean {
invariant(other instanceof Ref);
return this._refStr < other._refStr;
}
toString(): string {
return 'sha1-' + uint8ArrayToHex(this.digest);
return this._refStr;
}
static parse(s: string): Ref {
@@ -79,11 +75,14 @@ export default class Ref {
throw Error('Could not parse ref: ' + s);
}
return new Ref(hexToUint8(m[1]));
return new Ref(m[1]);
}
static fromDigest(digest: Uint8Array = new Uint8Array(sha1Size)) {
return new Ref(sha1Prefix + uint8ArrayToHex(digest));
}
static fromData(data: Uint8Array): Ref {
let digest = r.rawDigest(data);
return new Ref(new Uint8Array(digest.buffer));
return new Ref(sha1Prefix + r.digest(data));
}
}

View File

@@ -56,11 +56,11 @@ suite('Ref', () => {
test('isEmpty', () => {
let digest = new Uint8Array(20);
let r = new Ref(digest);
let r = Ref.fromDigest(digest);
assert.isTrue(r.isEmpty());
digest[0] = 10;
r = new Ref(digest);
r = Ref.fromDigest(digest);
assert.isFalse(r.isEmpty());
r = new Ref();

View File

@@ -3,32 +3,32 @@
import type {ChunkStore} from './chunk_store.js';
import {invariant, notNull} from './assert.js';
import {Type} from './type.js';
import {Value} from './value.js';
import {ValueBase} from './value.js';
export class Sequence<T> extends Value {
cs: ChunkStore;
export class Sequence<T> extends ValueBase {
items: Array<T>;
isMeta: boolean;
constructor(cs: ChunkStore, type: Type, items: Array<T>) {
constructor(type: Type, items: Array<T>) {
super(type);
this.cs = cs;
this.items = items;
this.isMeta = false;
}
getChildSequence(idx: number): Promise<?Sequence> { // eslint-disable-line no-unused-vars
getChildSequence(cs: ChunkStore, idx: number): Promise<?Sequence> { // eslint-disable-line no-unused-vars
return Promise.resolve(null);
}
}
export class SequenceCursor<T, S:Sequence> {
cs: ChunkStore;
parent: ?SequenceCursor;
sequence: S;
idx: number;
constructor(parent: ?SequenceCursor, sequence: S, idx: number) {
constructor(cs: ChunkStore, parent: ?SequenceCursor, sequence: S, idx: number) {
this.cs = cs;
this.parent = parent;
this.sequence = sequence;
this.idx = idx;
@@ -48,7 +48,7 @@ export class SequenceCursor<T, S:Sequence> {
}
getChildSequence(): Promise<?S> {
return this.sequence.getChildSequence(this.idx);
return this.sequence.getChildSequence(this.cs, this.idx);
}
getCurrent(): T {
@@ -125,10 +125,6 @@ export class SequenceCursor<T, S:Sequence> {
return false;
}
copy(): SequenceCursor {
return new SequenceCursor(this.parent ? this.parent.copy() : null, this.sequence, this.idx);
}
async iter(cb: (v: T, i: number) => boolean): Promise<void> {
let idx = 0;
while (this.valid) {

View File

@@ -1,22 +1,24 @@
// @flow
import type {ChunkStore} from './chunk_store.js';
import type {valueOrPrimitive} from './value.js'; // eslint-disable-line no-unused-vars
import {Collection} from './collection.js';
import {equals, less} from './value.js';
import {invariant} from './assert.js';
import {Kind} from './noms_kind.js';
import {OrderedSequence} from './ordered_sequence.js';
import {registerMetaValue, MetaTuple} from './meta_sequence.js';
import {Type} from './type.js';
export class NomsSet<K:valueOrPrimitive, T> extends OrderedSequence<K, T> {
export class NomsSet<T:valueOrPrimitive> extends Collection<OrderedSequence> {
async has(key: T): Promise<boolean> {
let cursor = await this.sequence.newCursorAt(this.cs, key);
return cursor.valid && equals(cursor.getCurrentKey(), key);
}
async first(): Promise<?T> {
let cursor = await this.newCursorAt(null);
let cursor = await this.sequence.newCursorAt(this.cs, null);
return cursor.valid ? cursor.getCurrent() : null;
}
async forEach(cb: (v: T) => void): Promise<void> {
let cursor = await this.newCursorAt(null);
let cursor = await this.sequence.newCursorAt(this.cs, null);
return cursor.iter(v => {
cb(v);
return false;
@@ -24,10 +26,14 @@ export class NomsSet<K:valueOrPrimitive, T> extends OrderedSequence<K, T> {
}
get size(): number {
return this.items.length;
if (this.sequence instanceof SetLeafSequence) {
return this.sequence.items.length;
}
throw new Error('not implemented');
}
async intersect(...sets: Array<NomsSet>): Promise<NomsSet> {
async intersect(...sets: Array<NomsSet<T>>): Promise<NomsSet<T>> {
if (sets.length === 0) {
return this;
}
@@ -37,16 +43,17 @@ export class NomsSet<K:valueOrPrimitive, T> extends OrderedSequence<K, T> {
invariant(sets[i].type.equals(this.type));
}
let cursor = await this.newCursorAt(null);
let cursor = await this.sequence.newCursorAt(this.cs, null);
if (!cursor.valid) {
return this;
}
let values: Array<K> = [];
let values: Array<T> = [];
for (let i = 0; cursor.valid && i < sets.length; i++) {
let first = cursor.getCurrent();
let next = await sets[i].newCursorAt(first);
let set: NomsSet = sets[i];
let next = await set.sequence.newCursorAt(set.cs, first);
if (!next.valid) {
break;
}
@@ -61,40 +68,16 @@ export class NomsSet<K:valueOrPrimitive, T> extends OrderedSequence<K, T> {
}
// TODO: Chunk the resulting set.
return new SetLeaf(this.cs, this.type, values);
return new NomsSet(this.cs, this.type, new SetLeafSequence(this.type, values));
}
}
export class SetLeaf<K:valueOrPrimitive> extends NomsSet<K, K> {
export class SetLeafSequence<K:valueOrPrimitive> extends OrderedSequence<K, K> {
getKey(idx: number): K {
return this.items[idx];
}
}
export class CompoundSet<K:valueOrPrimitive> extends NomsSet<K, MetaTuple<K>> {
constructor(cs: ChunkStore, type: Type, items: Array<MetaTuple>) {
super(cs, type, items);
this.isMeta = true;
}
getKey(idx: number): K {
return this.items[idx].value;
}
async getChildSequence(idx: number): Promise<?SetLeaf> {
let mt = this.items[idx];
let ms = await mt.readValue(this.cs);
invariant(ms instanceof NomsSet);
return ms;
}
get size(): number {
throw new Error('not implemented');
}
}
registerMetaValue(Kind.Set, (cs, type, tuples) => new CompoundSet(cs, type, tuples));
type OrderedCursor<K: valueOrPrimitive> = {
valid: boolean;
getCurrent(): K;

View File

@@ -5,18 +5,21 @@ import {suite} from 'mocha';
import MemoryStore from './memory_store.js';
import test from './async_test.js';
import {CompoundSet, NomsSet, SetLeaf} from './set.js';
import {notNull} from './assert.js';
import type {ChunkStore} from './chunk_store.js';
import {invariant} from './assert.js';
import {Kind} from './noms_kind.js';
import {makeCompoundType, makePrimitiveType} from './type.js';
import {MetaTuple} from './meta_sequence.js';
import {MetaTuple, OrderedMetaSequence} from './meta_sequence.js';
import {NomsSet, SetLeafSequence} from './set.js';
import {notNull} from './assert.js';
import {OrderedSequence} from './ordered_sequence.js';
import {writeValue} from './encode.js';
suite('SetLeaf', () => {
test('first/has', async () => {
let ms = new MemoryStore();
let tr = makeCompoundType(Kind.Set, makePrimitiveType(Kind.String));
let s = new SetLeaf(ms, tr, ['a', 'k']);
let s = new NomsSet(ms, tr, new SetLeafSequence(tr, ['a', 'k']));
assert.strictEqual('a', await s.first());
@@ -29,7 +32,7 @@ suite('SetLeaf', () => {
test('forEach', async () => {
let ms = new MemoryStore();
let tr = makeCompoundType(Kind.Set, makePrimitiveType(Kind.String));
let m = new SetLeaf(ms, tr, ['a', 'b']);
let m = new NomsSet(ms, tr, new SetLeafSequence(tr, ['a', 'b']));
let values = [];
await m.forEach((k) => { values.push(k); });
@@ -38,16 +41,14 @@ suite('SetLeaf', () => {
});
suite('CompoundSet', () => {
function build(values: Array<string>): NomsSet {
let ms = new MemoryStore();
function build(cs: ChunkStore, values: Array<string>): NomsSet {
let tr = makeCompoundType(Kind.Set, makePrimitiveType(Kind.String));
assert.isTrue(values.length > 1 && Math.log2(values.length) % 1 === 0);
let tuples = [];
for (let i = 0; i < values.length; i += 2) {
let l = new SetLeaf(ms, tr, [values[i], values[i + 1]]);
let r = writeValue(l, tr, ms);
let l = new NomsSet(cs, tr, new SetLeafSequence(tr, [values[i], values[i + 1]]));
let r = writeValue(l, tr, cs);
tuples.push(new MetaTuple(r, values[i + 1]));
}
@@ -55,8 +56,8 @@ suite('CompoundSet', () => {
while (tuples.length > 1) {
let next = [];
for (let i = 0; i < tuples.length; i += 2) {
last = new CompoundSet(ms, tr, [tuples[i], tuples[i + 1]]);
let r = writeValue(last, tr, ms);
last = new NomsSet(cs, tr, new OrderedMetaSequence(tr, [tuples[i], tuples[i + 1]]));
let r = writeValue(last, tr, cs);
next.push(new MetaTuple(r, tuples[i + 1].value));
}
@@ -67,7 +68,8 @@ suite('CompoundSet', () => {
}
test('first/has', async () => {
let c = build(['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
let ms = new MemoryStore();
let c = build(ms, ['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
assert.strictEqual('a', await c.first());
assert.isTrue(await c.has('a'));
assert.isTrue(await c.has('b'));
@@ -86,7 +88,8 @@ suite('CompoundSet', () => {
});
test('forEach', async () => {
let c = build(['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
let ms = new MemoryStore();
let c = build(ms, ['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
let values = [];
await c.forEach((k) => { values.push(k); });
assert.deepEqual(['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n'], values);
@@ -104,9 +107,12 @@ suite('CompoundSet', () => {
}
test('advanceTo', async () => {
let c = build(['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
let ms = new MemoryStore();
let cursor = await c.newCursorAt(null);
let c = build(ms, ['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
invariant(c.sequence instanceof OrderedSequence);
let cursor = await c.sequence.newCursorAt(c.cs, null);
assert.ok(cursor);
assert.strictEqual('a', cursor.getCurrent());
@@ -119,10 +125,12 @@ suite('CompoundSet', () => {
assert.isFalse(await cursor.advanceTo('z')); // not found
assert.isFalse(cursor.valid);
cursor = await c.newCursorAt('x'); // not found
invariant(c.sequence instanceof OrderedSequence);
cursor = await c.sequence.newCursorAt(ms, 'x'); // not found
assert.isFalse(cursor.valid);
cursor = await c.newCursorAt('e');
invariant(c.sequence instanceof OrderedSequence);
cursor = await c.sequence.newCursorAt(ms, 'e');
assert.ok(cursor);
assert.strictEqual('e', cursor.getCurrent());
@@ -141,10 +149,12 @@ suite('CompoundSet', () => {
});
async function testIntersect(expect: Array<string>, seqs: Array<Array<string>>) {
let first = build(seqs[0]);
let ms = new MemoryStore();
let first = build(ms, seqs[0]);
let sets:Array<NomsSet> = [];
for (let i = 1; i < seqs.length; i++) {
sets.push(build(seqs[i]));
sets.push(build(ms, seqs[i]));
}
let result = await first.intersect(...sets);

View File

@@ -2,11 +2,11 @@
import {Field, StructDesc, Type} from './type.js';
import {invariant, notNull} from './assert.js';
import {Value} from './value.js';
import {ValueBase} from './value.js';
type StructData = {[key: string]: any};
export default class Struct extends Value {
export default class Struct extends ValueBase {
desc: StructDesc;
unionField: ?Field;

View File

@@ -6,7 +6,12 @@ import {ensureRef} from './get_ref.js';
import {invariant} from './assert.js';
import {Type} from './type.js';
export class Value {
export type Value = {
ref: Ref;
equals(other: Value): boolean;
}
export class ValueBase {
type: Type;
_ref: ?Ref;
@@ -31,16 +36,16 @@ export function less(v1: any, v2: any): boolean {
if (typeof v1 === 'object') {
invariant(typeof v2 === 'object');
if (v1 instanceof Value) {
if (v1 instanceof ValueBase) {
v1 = v1.ref;
}
if (v2 instanceof Value) {
if (v2 instanceof ValueBase) {
v2 = v2.ref;
}
invariant(v1 instanceof Ref);
invariant(v2 instanceof Ref);
return v1.compare(v2) < 0;
return v1.less(v2);
}
if (typeof v1 === 'string') {