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

View File

@@ -18,8 +18,11 @@ func (bl blobLeafSequence) getOffset(idx int) uint64 {
return uint64(idx)
}
func (bl blobLeafSequence) equalsAt(idx int, other interface{}) bool {
return bl.data[idx] == other
func (bl blobLeafSequence) getCompareFn(other sequence) compareFn {
otherbl := other.(blobLeafSequence)
return func(idx, otherIdx int) bool {
return bl.data[idx] == otherbl.data[otherIdx]
}
}
// sequence interface

View File

@@ -42,8 +42,9 @@ func indexedSequenceDiff(last indexedSequence, lastHeight int, lastOffset uint64
return indexedSequenceDiff(last, lastHeight, lastOffset, currentChild, currentHeight-1, currentOffset, newLoadLimit)
}
compareFn := last.getCompareFn(current)
initialSplices := calcSplices(uint64(last.seqLen()), uint64(current.seqLen()), func(i uint64, j uint64) bool {
return last.equalsAt(int(i), current.getItem(int(j)))
return compareFn(int(i), int(j))
})
finalSplices := []Splice{}

View File

@@ -14,7 +14,6 @@ import (
type indexedSequence interface {
sequence
getOffset(idx int) uint64
equalsAt(idx int, other interface{}) bool
}
type indexedMetaSequence struct {
@@ -43,16 +42,13 @@ func newIndexedMetaSequence(tuples metaSequenceData, t *Type, vr ValueReader) in
cum += mt.uint64Value()
offsets = append(offsets, cum)
}
leafCount := offsets[len(offsets)-1]
return indexedMetaSequence{
metaSequenceObject{tuples, t, vr},
metaSequenceObject{tuples, t, vr, leafCount},
offsets,
}
}
func (ims indexedMetaSequence) numLeaves() uint64 {
return ims.offsets[len(ims.offsets)-1]
}
func (ims indexedMetaSequence) getOffset(idx int) uint64 {
// TODO: precompute these on the construction
offsets := []uint64{}
@@ -65,8 +61,11 @@ func (ims indexedMetaSequence) getOffset(idx int) uint64 {
return ims.offsets[idx] - 1
}
func (ims indexedMetaSequence) equalsAt(idx int, other interface{}) bool {
return ims.getItem(idx).(metaTuple).ref.Equals(other.(metaTuple).ref)
func (ims indexedMetaSequence) getCompareFn(other sequence) compareFn {
oms := other.(indexedMetaSequence)
return func(idx, otherIdx int) bool {
return ims.tuples[idx].ref.TargetHash() == oms.tuples[otherIdx].ref.TargetHash()
}
}
func newCursorAtIndex(seq indexedSequence, idx uint64) *sequenceCursor {

View File

@@ -24,8 +24,11 @@ func (ll listLeafSequence) getOffset(idx int) uint64 {
return uint64(idx)
}
func (ll listLeafSequence) equalsAt(idx int, other interface{}) bool {
return ll.values[idx].Equals(other.(Value))
func (ll listLeafSequence) getCompareFn(other sequence) compareFn {
oll := other.(listLeafSequence)
return func(idx, otherIdx int) bool {
return ll.values[idx].Equals(oll.values[otherIdx])
}
}
// sequence interface

View File

@@ -79,10 +79,13 @@ func (ml mapLeafSequence) getKey(idx int) Value {
return ml.data[idx].key
}
func (ml mapLeafSequence) equalsAt(idx int, other interface{}) bool {
entry := ml.data[idx]
otherEntry := other.(mapEntry)
return entry.key.Equals(otherEntry.key) && entry.value.Equals(otherEntry.value)
func (ml mapLeafSequence) getCompareFn(other sequence) compareFn {
oml := other.(mapLeafSequence)
return func(idx, otherIdx int) bool {
entry := ml.data[idx]
otherEntry := oml.data[otherIdx]
return entry.key.Equals(otherEntry.key) && entry.value.Equals(otherEntry.value)
}
}
// Collection interface

View File

@@ -56,9 +56,10 @@ func (msd metaSequenceData) last() metaTuple {
}
type metaSequenceObject struct {
tuples metaSequenceData
t *Type
vr ValueReader
tuples metaSequenceData
t *Type
vr ValueReader
leafCount uint64
}
func (ms metaSequenceObject) data() metaSequenceData {
@@ -90,6 +91,10 @@ func (ms metaSequenceObject) Type() *Type {
return ms.t
}
func (ms metaSequenceObject) numLeaves() uint64 {
return ms.leafCount
}
// metaSequence interface
func (ms metaSequenceObject) getChildSequence(idx int) sequence {
mt := ms.tuples[idx]

View File

@@ -15,12 +15,10 @@ import (
type orderedSequence interface {
sequence
getKey(idx int) Value
equalsAt(idx int, other interface{}) bool
}
type orderedMetaSequence struct {
metaSequenceObject
leafCount uint64
}
func newSetMetaSequence(tuples metaSequenceData, vr ValueReader) orderedMetaSequence {
@@ -53,21 +51,19 @@ func newOrderedMetaSequence(tuples metaSequenceData, t *Type, vr ValueReader) or
}
return orderedMetaSequence{
metaSequenceObject{tuples, t, vr},
leafCount,
metaSequenceObject{tuples, t, vr, leafCount},
}
}
func (oms orderedMetaSequence) numLeaves() uint64 {
return oms.leafCount
}
func (oms orderedMetaSequence) getKey(idx int) Value {
return oms.tuples[idx].value
}
func (oms orderedMetaSequence) equalsAt(idx int, other interface{}) bool {
return oms.tuples[idx].ref.Equals(other.(metaTuple).ref)
func (oms orderedMetaSequence) getCompareFn(other sequence) compareFn {
ooms := other.(orderedMetaSequence)
return func(idx, otherIdx int) bool {
return oms.tuples[idx].ref.TargetHash() == ooms.tuples[otherIdx].ref.TargetHash()
}
}
func newCursorAtKey(seq orderedSequence, key Value, forInsertion bool, last bool) *sequenceCursor {

View File

@@ -22,7 +22,7 @@ func orderedSequenceDiff(last orderedSequence, current orderedSequence) (added [
fastForward(lastCur, currentCur)
for lastCur.valid() && currentCur.valid() &&
!lastCur.seq.(orderedSequence).equalsAt(lastCur.idx, currentCur.current()) {
!lastCur.seq.getCompareFn(currentCur.seq)(lastCur.idx, currentCur.idx) {
lastKey := getCurrentKey(lastCur)
currentKey := getCurrentKey(currentCur)
if lastKey.Equals(currentKey) {
@@ -96,6 +96,5 @@ func doFastForward(allowPastEnd bool, a *sequenceCursor, b *sequenceCursor) (aHa
}
func isCurrentEqual(a *sequenceCursor, b *sequenceCursor) bool {
aSeq := a.seq.(orderedSequence)
return aSeq.equalsAt(a.idx, b.current())
return a.seq.getCompareFn(b.seq)(a.idx, b.idx)
}

View File

@@ -6,6 +6,8 @@ package types
type sequenceItem interface{}
type compareFn func(x int, y int) bool
type sequence interface {
getItem(idx int) sequenceItem
seqLen() int
@@ -13,4 +15,5 @@ type sequence interface {
valueReader() ValueReader
Chunks() []Ref
Type() *Type
getCompareFn(other sequence) compareFn
}

View File

@@ -28,6 +28,13 @@ func (ts testSequence) numLeaves() uint64 {
return uint64(len(ts.items))
}
func (ts testSequence) getCompareFn(other sequence) compareFn {
obl := other.(testSequence)
return func(idx, otherIdx int) bool {
return ts.items[idx] == obl.items[otherIdx]
}
}
func (ts testSequence) valueReader() ValueReader {
panic("not reached")
}

View File

@@ -52,7 +52,10 @@ func (sl setLeafSequence) getKey(idx int) Value {
return sl.data[idx]
}
func (sl setLeafSequence) equalsAt(idx int, other interface{}) bool {
entry := sl.data[idx]
return entry.Equals(other.(Value))
func (sl setLeafSequence) getCompareFn(other sequence) compareFn {
osl := other.(setLeafSequence)
return func(idx, otherIdx int) bool {
entry := sl.data[idx]
return entry.Equals(osl.data[otherIdx])
}
}

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;

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) {

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;

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> {

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);
}
}

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);
}

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');
}
}

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> {