Make sequence chunker function return (meta tuple, collection) pair (#1540)

Both Go and JS. Currently they return (any, value), but it's useful to
have the more specific return type.
This commit is contained in:
Ben Kalman
2016-05-18 16:01:13 -07:00
parent 778acf8454
commit 65f4ae358c
10 changed files with 26 additions and 77 deletions

View File

@@ -1,4 +1,5 @@
[ignore]
.*/dist
.*/node_modules/babel.*
.*/node_modules/babylon/.*
.*/node_modules/d3/.*

View File

@@ -1,55 +0,0 @@
// @flow
import {suite, test} from 'mocha';
import {assert} from 'chai';
import {SequenceChunker} from './sequence-chunker.js';
class ModBoundaryChecker {
mod: number;
constructor(mod: number) {
this.mod = mod;
}
get windowSize(): number {
return 1;
}
write(item: number): boolean {
return item % this.mod === 0;
}
}
function sumChunker(items: Array<number>): [number, any] {
let sum = 0;
for (let i = 0; i < items.length; i++) {
sum += items[i];
}
return [sum, items];
}
suite('SequenceChunker', () => {
async function testChunking(expect: Array<number>, from: number, to: number) {
const seq = new SequenceChunker(null, sumChunker, sumChunker,
new ModBoundaryChecker(3), () => new ModBoundaryChecker(5));
for (let i = from; i <= to; i++) {
seq.append(i);
}
assert.deepEqual(expect, await seq.done());
}
test('mod', async () => {
await testChunking([1], 1, 1);
await testChunking([3], 3, 3);
await testChunking([1, 2], 1, 2);
await testChunking([3, 4], 3, 4); // XX
await testChunking([1, 2, 3], 1, 3);
await testChunking([6, 4], 1, 4);
await testChunking([6, 15], 1, 6);
await testChunking([21, 7], 1, 7);
});
});

View File

@@ -2,6 +2,8 @@
import type {Sequence} from './sequence.js'; // eslint-disable-line no-unused-vars
import {invariant, notNull} from './assert.js';
import type {Collection} from './collection.js';
import type {MetaSequence, MetaTuple} from './meta-sequence.js';
import type {SequenceCursor} from './sequence.js';
export type BoundaryChecker<T> = {
@@ -9,18 +11,18 @@ export type BoundaryChecker<T> = {
windowSize: number;
}
export type NewBoundaryCheckerFn<T> = () => BoundaryChecker<T>;
export type NewBoundaryCheckerFn = () => BoundaryChecker<MetaTuple>;
export type makeChunkFn = (items: Array<any>) => [any, any];
export type makeChunkFn<T: Collection> = (items: Array<any>) => [MetaTuple, T];
export async function chunkSequence<S, T>(
export async function chunkSequence<C: Collection, S>(
cursor: ?SequenceCursor,
insert: Array<S>,
remove: number,
makeChunk: makeChunkFn,
parentMakeChunk: makeChunkFn,
makeChunk: makeChunkFn<C>,
parentMakeChunk: makeChunkFn<C>,
boundaryChecker: BoundaryChecker<S>,
newBoundaryChecker: NewBoundaryCheckerFn<T>): Promise<any> {
newBoundaryChecker: NewBoundaryCheckerFn): Promise<C> {
const chunker = new SequenceChunker(cursor, makeChunk, parentMakeChunk, boundaryChecker,
newBoundaryChecker);
@@ -42,21 +44,21 @@ export async function chunkSequence<S, T>(
return await chunker.done();
}
export class SequenceChunker<S, T, U:Sequence, V:Sequence> {
export class SequenceChunker<C: Collection, S, U:Sequence> {
_cursor: ?SequenceCursor<S, U>;
_isOnChunkBoundary: boolean;
_parent: ?SequenceChunker<T, T, V, V>;
_parent: ?SequenceChunker<C, MetaTuple, MetaSequence>;
_current: Array<S>;
_makeChunk: makeChunkFn;
_parentMakeChunk: makeChunkFn;
_makeChunk: makeChunkFn<C>;
_parentMakeChunk: makeChunkFn<C>;
_boundaryChecker: BoundaryChecker<S>;
_newBoundaryChecker: NewBoundaryCheckerFn<T>;
_newBoundaryChecker: NewBoundaryCheckerFn;
_used: boolean;
constructor(cursor: ?SequenceCursor, makeChunk: makeChunkFn,
parentMakeChunk: makeChunkFn,
boundaryChecker: BoundaryChecker<S>,
newBoundaryChecker: NewBoundaryCheckerFn<T>) {
newBoundaryChecker: NewBoundaryCheckerFn) {
this._cursor = cursor;
this._isOnChunkBoundary = false;
this._parent = null;
@@ -125,18 +127,19 @@ export class SequenceChunker<S, T, U:Sequence, V:Sequence> {
handleChunkBoundary() {
invariant(this._current.length > 0);
if (!this._parent) {
const parent = this._parent;
if (!parent) {
invariant(!this._isOnChunkBoundary);
this._isOnChunkBoundary = true;
} else {
invariant(this._current.length > 0);
const chunk = this._makeChunk(this._current)[0];
notNull(this._parent).append(chunk);
parent.append(chunk);
this._current = [];
}
}
async done(): Promise<any> {
async done(): Promise<C> {
if (this._cursor) {
await this.finalizeCursor();
}

View File

@@ -135,7 +135,7 @@ func newBlobLeafBoundaryChecker() boundaryChecker {
}
func newBlobLeafChunkFn(vr ValueReader) makeChunkFn {
return func(items []sequenceItem) (sequenceItem, Value) {
return func(items []sequenceItem) (metaTuple, Collection) {
buff := make([]byte, len(items))
for i, v := range items {

View File

@@ -102,7 +102,7 @@ func newIndexedMetaSequenceBoundaryChecker() boundaryChecker {
// If |sink| is not nil, chunks will be eagerly written as they're created. Otherwise they are
// written when the root is written.
func newIndexedMetaSequenceChunkFn(kind NomsKind, source ValueReader, sink ValueWriter) makeChunkFn {
return func(items []sequenceItem) (sequenceItem, Value) {
return func(items []sequenceItem) (metaTuple, Collection) {
tuples := make(metaSequenceData, len(items))
numLeaves := uint64(0)

View File

@@ -188,7 +188,7 @@ func newListLeafBoundaryChecker() boundaryChecker {
// If |sink| is not nil, chunks will be eagerly written as they're created. Otherwise they are
// written when the root is written.
func makeListLeafChunkFn(vr ValueReader, sink ValueWriter) makeChunkFn {
return func(items []sequenceItem) (sequenceItem, Value) {
return func(items []sequenceItem) (metaTuple, Collection) {
values := make([]Value, len(items))
for i, v := range items {

View File

@@ -218,7 +218,7 @@ func newMapLeafBoundaryChecker() boundaryChecker {
}
func makeMapLeafChunkFn(vr ValueReader) makeChunkFn {
return func(items []sequenceItem) (sequenceItem, Value) {
return func(items []sequenceItem) (metaTuple, Collection) {
mapData := make([]mapEntry, len(items), len(items))
for i, v := range items {

View File

@@ -134,7 +134,7 @@ func newOrderedMetaSequenceBoundaryChecker() boundaryChecker {
}
func newOrderedMetaSequenceChunkFn(kind NomsKind, vr ValueReader) makeChunkFn {
return func(items []sequenceItem) (sequenceItem, Value) {
return func(items []sequenceItem) (metaTuple, Collection) {
tuples := make(metaSequenceData, len(items))
numLeaves := uint64(0)

View File

@@ -23,7 +23,7 @@ type sequenceChunker struct {
}
// makeChunkFn takes a sequence of items to chunk, and returns the result of chunking those items, a tuple of a reference to that chunk which can itself be chunked + its underlying value.
type makeChunkFn func(values []sequenceItem) (sequenceItem, Value)
type makeChunkFn func(values []sequenceItem) (metaTuple, Collection)
func newEmptySequenceChunker(makeChunk, parentMakeChunk makeChunkFn, boundaryChk boundaryChecker, newBoundaryChecker newBoundaryCheckerFn) *sequenceChunker {
return newSequenceChunker(nil, makeChunk, parentMakeChunk, boundaryChk, newBoundaryChecker)

View File

@@ -192,7 +192,7 @@ func newSetLeafBoundaryChecker() boundaryChecker {
}
func makeSetLeafChunkFn(vr ValueReader) makeChunkFn {
return func(items []sequenceItem) (sequenceItem, Value) {
return func(items []sequenceItem) (metaTuple, Collection) {
setData := make([]Value, len(items), len(items))
for i, v := range items {