Skip to content

Commit

Permalink
fixes decoder refId garbage collection when calling .clear(). #75
Browse files Browse the repository at this point in the history
  • Loading branch information
endel committed Jul 14, 2020
1 parent c239aa6 commit 6cd1693
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 16 deletions.
16 changes: 5 additions & 11 deletions src/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface SchemaDecoderCallbacks {
onAdd?: (item: any, key: any) => void;
onRemove?: (item: any, key: any) => void;
onChange?: (item: any, key: any) => void;
clear();
clear(decoding?: boolean);
decode?(byte, it: decode.Iterator);
}

Expand Down Expand Up @@ -166,9 +166,6 @@ export abstract class Schema {
public assign(
props: { [prop in NonFunctionPropNames<this>]?: this[prop] }
) {
//
// TODO: recursivelly assign child Schema structures.
//
Object.assign(this, props);
return this;
}
Expand Down Expand Up @@ -247,14 +244,11 @@ export abstract class Schema {

if (operation === OPERATION.CLEAR) {
//
// TODO:
//
// flag all children refId's for garbage collection.
// (if not a collection of primitive type)
//
// $root.removeRef(refId);
// TODO: refactor me!
// The `.clear()` method is calling `$root.removeRef(refId)` is
// being called for each item inside this collection
//
(ref as SchemaDecoderCallbacks).clear();
(ref as SchemaDecoderCallbacks).clear(true);
continue;
}

Expand Down
2 changes: 1 addition & 1 deletion src/changes/ChangeTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ export class ChangeTree {
}
}

getType(index: number) {
getType(index?: number) {
if (this.ref['_definition']) {
const definition = (this.ref as Schema)['_definition'];
return definition.schema[ definition.fieldsByIndex[index] ];
Expand Down
9 changes: 8 additions & 1 deletion src/types/ArraySchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,20 @@ export class ArraySchema<V=any> implements Array<V>, SchemaDecoderCallbacks {
return this.$items.delete(index);
}

clear() {
clear(isDecoding?: boolean) {
// discard previous operations.
this.$changes.discard(true);

// clear previous indexes
this.$indexes.clear();

// flag child items for garbage collection.
if (isDecoding && typeof (this.$changes.getType()) !== "string") {
this.$items.forEach((item: V) => {
this.$changes.root.removeRef(item['$changes'].refId);
});
}

// clear items
this.$items.clear();

Expand Down
9 changes: 8 additions & 1 deletion src/types/CollectionSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,20 @@ export class CollectionSchema<V=any> implements SchemaDecoderCallbacks {
return this.$items.delete(index);
}

clear() {
clear(isDecoding?: boolean) {
// discard previous operations.
this.$changes.discard(true);

// clear previous indexes
this.$indexes.clear();

// flag child items for garbage collection.
if (isDecoding && typeof (this.$changes.getType()) !== "string") {
this.$items.forEach((item: V) => {
this.$changes.root.removeRef(item['$changes'].refId);
});
}

// clear items
this.$items.clear();

Expand Down
9 changes: 8 additions & 1 deletion src/types/MapSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,20 @@ export class MapSchema<V=any> implements Map<string, V>, SchemaDecoderCallbacks
return this.$items.delete(key);
}

clear() {
clear(isDecoding?: boolean) {
// discard previous operations.
this.$changes.discard(true);

// clear previous indexes
this.$indexes.clear();

// flag child items for garbage collection.
if (isDecoding && typeof (this.$changes.getType()) !== "string") {
this.$items.forEach((item: V) => {
this.$changes.root.removeRef(item['$changes'].refId);
});
}

// clear items
this.$items.clear();

Expand Down
9 changes: 8 additions & 1 deletion src/types/SetSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,20 @@ export class SetSchema<V=any> implements SchemaDecoderCallbacks {
return this.$items.delete(index);
}

clear() {
clear(isDecoding?: boolean) {
// discard previous operations.
this.$changes.discard(true);

// clear previous indexes
this.$indexes.clear();

// flag child items for garbage collection.
if (isDecoding && typeof (this.$changes.getType()) !== "string") {
this.$items.forEach((item: V) => {
this.$changes.root.removeRef(item['$changes'].refId);
});
}

// clear items
this.$items.clear();

Expand Down
33 changes: 33 additions & 0 deletions test/InstanceSharingTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,37 @@ describe("Instance sharing", () => {
const newRefCount = decodedState['$changes'].root.refs.size;
assert.equal(refCount - 4, newRefCount);
});

it("clearing ArraySchema", () => {
const state = new State();

const player1 = new Player().assign({
position: new Position().assign({
x: 10, y: 10
})
});
state.arrayOfPlayers.push(player1);
state.arrayOfPlayers.push(player1);
state.arrayOfPlayers.push(player1);

const player2 = new Player().assign({
position: new Position().assign({
x: 10, y: 10
})
});
state.arrayOfPlayers.push(player2);

const decodedState = new State();
decodedState.decode(state.encode());

const refCount = decodedState['$changes'].root.refs.size;
assert.equal(7, refCount);

state.arrayOfPlayers.clear();

decodedState.decode(state.encode());

const newRefCount = decodedState['$changes'].root.refs.size;
assert.equal(refCount - 4, newRefCount);
});
});

0 comments on commit 6cd1693

Please sign in to comment.