Permalink
Browse files

Change listeners on LRU Set and Map

  • Loading branch information...
1 parent 870211b commit a0c0d15194f938da29b3c8d7b31f795e107cfd3c @kriskowal committed Dec 29, 2012
Showing with 78 additions and 12 deletions.
  1. +33 −10 lru-set.js
  2. +45 −2 spec/lru-map-spec.js
View
@@ -5,6 +5,7 @@ var Set = require("./set");
var GenericCollection = require("./generic-collection");
var GenericSet = require("./generic-set");
var PropertyChanges = require("./listen/property-changes");
+var RangeChanges = require("./listen/range-changes");
module.exports = LruSet;
@@ -28,6 +29,7 @@ function LruSet(values, maxLength, equals, hash, getDefault) {
Object.addEach(LruSet.prototype, GenericCollection.prototype);
Object.addEach(LruSet.prototype, GenericSet.prototype);
Object.addEach(LruSet.prototype, PropertyChanges.prototype);
+Object.addEach(LruSet.prototype, RangeChanges.prototype);
LruSet.prototype.constructClone = function (values) {
return new this.constructor(
@@ -55,27 +57,48 @@ LruSet.prototype.get = function (value) {
};
LruSet.prototype.add = function (value) {
- if (this.store.has(value)) {
+ var found = this.store.has(value);
+ // if the value already exists, we delete it and add it back again so it
+ // appears at the end of the list of values to truncate
+ var length = this.length;
+ if (found) {
this.store["delete"](value);
- this.length--;
+ length--;
+ }
+ // before change
+ if (!found && this.dispachesRangeChanges) {
+ this.dispatchBeforeRangeChange([value], [], 0);
}
this.store.add(value);
- this.length++;
+ length++;
+ // only assign to length once to avoid jitter on length observers
+ this.length = length;
+ // after change
+ if (!found && this.dispatchesRangeChanges) {
+ this.dispatchRangeChange([value], [], 0);
+ }
+ // truncate if necessary
if (this.store.length > this.maxLength) {
var eldest = this.store.order.head.next;
- this.store["delete"](eldest.value);
- this.length--;
- return false;
+ this["delete"](eldest.value);
+ return false; // did not grow
}
- return true;
+ return !found; // whether it grew
};
LruSet.prototype["delete"] = function (value) {
- if (this.store["delete"](value)) {
+ var found = this.store.has(value);
+ if (found) {
+ if (this.dispatchesRangeChanges) {
+ this.dispatchBeforeRangeChange([], [value], 0);
+ }
+ this.store["delete"](value);
this.length--;
- return true;
+ if (this.dispatchesRangeChanges) {
+ this.dispatcheRangeChange([], [value], 0);
+ }
}
- return false;
+ return found;
};
LruSet.prototype.one = function () {
View
@@ -8,14 +8,57 @@ describe("LruMap", function () {
describeDict(LruMap);
describeMap(LruMap);
- it("should remote stale items", function () {
+ it("should remove stale items", function () {
var map = LruMap({a: 10, b: 20, c: 30}, 3);
map.get("b");
map.set("d", 40);
expect(map.keys()).toEqual(['c', 'b', 'd']);
expect(map.length).toBe(3);
});
-});
+ it("should not grow when re-adding", function () {
+ var map = LruMap({a: 10, b: 20, c: 30}, 3);
+
+ expect(map.keys()).toEqual(['a', 'b', 'c']);
+ expect(map.length).toBe(3);
+
+ map.get("b");
+ expect(map.keys()).toEqual(['a', 'c', 'b']);
+ expect(map.length).toBe(3);
+
+ map.set("c", 40);
+ expect(map.keys()).toEqual(['a', 'b', 'c']);
+ expect(map.length).toBe(3);
+ });
+
+ it("should grow when adding new values", function () {
+ var map = LruMap({}, 3);
+ expect(map.length).toBe(0);
+
+ map.set("a", 10);
+ expect(map.length).toBe(1);
+ map.set("a", 10);
+ expect(map.length).toBe(1);
+
+ map.set("b", 20);
+ expect(map.length).toBe(2);
+ map.set("b", 20);
+ expect(map.length).toBe(2);
+ map.set("c", 30);
+ expect(map.length).toBe(3);
+ map.set("c", 30);
+ expect(map.length).toBe(3);
+
+ // stops growing
+ map.set("d", 40);
+ expect(map.length).toBe(3);
+ map.set("d", 40);
+ expect(map.length).toBe(3);
+
+ map.set("e", 50);
+ expect(map.length).toBe(3);
+ });
+
+});

0 comments on commit a0c0d15

Please sign in to comment.