sequences return a compare func used for diffs (#1771)

This commit is contained in:
Mike Gray
2016-06-09 23:17:14 -04:00
committed by GitHub
parent c77bc3fc3a
commit f94b91a5d2
19 changed files with 95 additions and 54 deletions
+6
View File
@@ -17,6 +17,7 @@ import Ref from './ref.js';
import SequenceChunker from './sequence-chunker.js';
import type {BoundaryChecker, makeChunkFn} from './sequence-chunker.js';
import {Kind} from './noms-kind.js';
import type {EqualsFn} from './edit-distance.js';
export default class Blob extends Collection<IndexedSequence> {
constructor(bytes: Uint8Array) {
@@ -134,6 +135,11 @@ export class BlobLeafSequence extends IndexedSequence<number> {
getOffset(idx: number): number {
return idx;
}
getCompareFn(other: IndexedSequence): EqualsFn {
return (idx: number, otherIdx: number) =>
this.items[idx] === other.items[otherIdx];
}
}
const blobWindowSize = 64;
+1 -4
View File
@@ -7,7 +7,6 @@
import type {Splice} from './edit-distance.js';
import {calcSplices, SPLICE_ADDED, SPLICE_AT, SPLICE_FROM,
SPLICE_REMOVED} from './edit-distance.js';
import {equals} from './compare.js';
import {IndexedMetaSequence} from './meta-sequence.js';
import {invariant} from './assert.js';
import type {IndexedSequence} from './indexed-sequence.js';
@@ -50,9 +49,7 @@ export function diff(last: IndexedSequence, lastHeight: number, lastOffset: numb
invariant(last.isMeta === current.isMeta);
invariant(lastHeight === currentHeight);
const splices = calcSplices(last.length, current.length, last.isMeta ?
(l, c) => equals(last.items[l].ref, current.items[c].ref) :
(l, c) => equals(last.items[l], current.items[c]));
const splices = calcSplices(last.length, current.length, last.getCompareFn(current));
const splicesP = splices.map(splice => {
if (!last.isMeta || splice[SPLICE_REMOVED] === 0 || splice[SPLICE_ADDED] === 0) {
+8
View File
@@ -8,12 +8,20 @@ import {AsyncIterator} from './async-iterator.js';
import type {AsyncIteratorResult} from './async-iterator.js';
import {notNull} from './assert.js';
import Sequence, {search, SequenceCursor} from './sequence.js';
import type {EqualsFn} from './edit-distance.js';
import {equals} from './compare.js';
export class IndexedSequence<T> extends Sequence<T> {
getOffset(idx: number): number { // eslint-disable-line no-unused-vars
throw new Error('override');
}
getCompareFn(other: IndexedSequence): EqualsFn {
return (idx: number, otherIdx: number) =>
// $FlowIssue
equals(this.items[idx], other.items[otherIdx]);
}
async newCursorAt(idx: number): Promise<IndexedSequenceCursor> {
let cursor: ?IndexedSequenceCursor = null;
let sequence: ?IndexedSequence = this;
+5 -3
View File
@@ -23,6 +23,7 @@ import {OrderedSequence, OrderedSequenceCursor, OrderedSequenceIterator} from
import diff from './ordered-sequence-diff.js';
import {ValueBase} from './value.js';
import {Kind} from './noms-kind.js';
import type {EqualsFn} from './edit-distance.js';
export type MapEntry<K: Value, V: Value> = [K, V];
@@ -196,9 +197,10 @@ export class MapLeafSequence<K: Value, V: Value> extends
return this.items[idx][KEY];
}
equalsAt(idx: number, other: MapEntry<K, V>): boolean {
const entry = this.items[idx];
return equals(entry[KEY], other[KEY]) && equals(entry[VALUE], other[VALUE]);
getCompareFn(other: OrderedSequence): EqualsFn {
return (idx: number, otherIdx: number) =>
equals(this.items[idx][KEY], other.items[otherIdx][KEY]) &&
equals(this.items[idx][VALUE], other.items[otherIdx][VALUE]);
}
get chunks(): Array<Ref> {
+9 -3
View File
@@ -23,7 +23,7 @@ import List from './list.js';
import Map from './map.js';
import Set from './set.js';
import Blob from './blob.js';
import {equals} from './compare.js';
import type {EqualsFn} from './edit-distance.js';
export type MetaSequence = Sequence<MetaTuple>;
@@ -145,6 +145,11 @@ export class IndexedMetaSequence extends IndexedSequence<MetaTuple<number>> {
getOffset(idx: number): number {
return this._offsets[idx] - 1;
}
getCompareFn(other: IndexedSequence): EqualsFn {
return (idx: number, otherIdx: number) =>
this.items[idx].ref.targetHash.equals(other.items[otherIdx].ref.targetHash);
}
}
export function newMapMetaSequence<K: Value>(vr: ?ValueReader,
@@ -194,8 +199,9 @@ export class OrderedMetaSequence<K: Value> extends OrderedSequence<K, MetaTuple<
return this.items[idx].value;
}
equalsAt(idx: number, other: MetaTuple): boolean {
return equals(this.items[idx].ref, other.ref);
getCompareFn(other: OrderedSequence): EqualsFn {
return (idx: number, otherIdx: number) =>
this.items[idx].ref.targetHash.equals(other.items[otherIdx].ref.targetHash);
}
}
+2 -2
View File
@@ -29,7 +29,7 @@ export default async function diff<K: Value, T>(
await fastForward(lastCur, currentCur);
while (lastCur.valid && currentCur.valid &&
!lastCur.sequence.equalsAt(lastCur.idx, currentCur.getCurrent())) {
!lastCur.sequence.getCompareFn(currentCur.sequence)(lastCur.idx, currentCur.idx)) {
const lastKey = lastCur.getCurrentKey(), currentKey = currentCur.getCurrentKey();
if (equals(lastKey, currentKey)) {
@@ -109,5 +109,5 @@ async function doFastForward(allowPastEnd: boolean,
}
function isCurrentEqual(a: SequenceCursor, b: SequenceCursor): boolean {
return a.sequence.equalsAt(a.idx, b.getCurrent());
return a.sequence.getCompareFn(b.sequence)(a.idx, b.idx);
}
+2 -4
View File
@@ -10,6 +10,7 @@ import type Value from './value.js'; // eslint-disable-line no-unused-vars
import {invariant, notNull} from './assert.js';
import {compare} from './compare.js';
import search from './binary-search.js';
import type {EqualsFn} from './edit-distance.js';
import Sequence, {SequenceCursor} from './sequence.js';
import {ValueBase} from './value.js';
@@ -47,10 +48,7 @@ export class OrderedSequence<K: Value, T> extends Sequence<T> {
throw new Error('override');
}
/**
* Returns true if the item in this sequence at |idx| is equal to |other|.
*/
equalsAt(idx: number, other: any): boolean { // eslint-disable-line no-unused-vars
getCompareFn(other: OrderedSequence): EqualsFn { // eslint-disable-line no-unused-vars
throw new Error('override');
}
}
+4 -2
View File
@@ -26,6 +26,7 @@ import {sha1Size} from './hash.js';
import {removeDuplicateFromOrdered} from './map.js';
import {getValueChunks} from './sequence.js';
import {Kind} from './noms-kind.js';
import type {EqualsFn} from './edit-distance.js';
const setWindowSize = 1;
const setPattern = ((1 << 6) | 0) - 1;
@@ -201,8 +202,9 @@ export class SetLeafSequence<K: Value> extends OrderedSequence<K, K> {
return this.items[idx];
}
equalsAt(idx: number, other: any): boolean {
return equals(this.items[idx], other);
getCompareFn(other: OrderedSequence): EqualsFn {
return (idx: number, otherIdx: number) =>
equals(this.items[idx], other.items[otherIdx]);
}
get chunks(): Array<Ref> {