UNPKG

sorted-map

Version:

a sorted map based heavily upon redis' skip list implementation

714 lines (610 loc) 18.7 kB
var ProxyMap = require('./set-proxy/proxy'); describe('proxy skip map', function() { it('should support basic operations', function() { var skip = new ProxyMap(); expect(skip).to.have.length(0); expect(skip.values()).to.eql([]); expect(skip.slice()).to.eql([]); expect(skip.range()).to.eql([]); expect(function() { skip.set('__proto__', 14); }).to.throw(); skip.set('5a600e16', 8); skip.set('5a600e17', 9); expect(skip.set('5a600e18', 10)).to.equal(null); expect(skip.set('5a600e17', 12)).to.equal(9); expect(skip).to.have.length(3); expect(skip.values()).to.eql([{ key: '5a600e16', value: 8 }, { key: '5a600e18', value: 10 }, { key: '5a600e17', value: 12 }]); expect(skip.values()).to.eql(skip.slice()); expect(skip.values()).to.eql(skip.range()); expect(skip.has('5a600e16')).to.be.ok; expect(skip.has('5a600e17')).to.be.ok; expect(skip.has('5a600e18')).to.be.ok; expect(skip.has('5a600e19')).to.not.be.ok; expect(skip.get('5a600e16')).to.equal(8); expect(skip.get('5a600e17')).to.equal(12); expect(skip.get('5a600e18')).to.equal(10); expect(skip.get('5a600e19')).to.equal(null); expect(skip.del('5a600e16')).to.equal(8); expect(skip).to.have.length(2); expect(skip.del('5a600e16')).to.equal(null); expect(skip).to.have.length(2); expect(skip.has('5a600e16')).to.not.be.ok; expect(skip.values()).to.eql([{ key: '5a600e18', value: 10 }, { key: '5a600e17', value: 12 }]); expect(skip.values()).to.eql(skip.slice()); expect(skip.values()).to.eql(skip.range()); skip.set('5a600e16', 10); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); expect(skip).to.have.length(9); // no change, so should be O(1) skip.set('5a600e17', 12); expect(skip.rank('5a600e17')).to.equal(4); expect(skip).to.have.length(9); expect(skip.values()).to.eql([{ key: '5a600e16', value: 3 }, { key: '5a600e11', value: 6 }, { key: '5a600e18', value: 10 }, { key: '5a600e13', value: 11 }, { key: '5a600e17', value: 12 }, { key: '5a600e14', value: 14 }, { key: '5a600e10', value: 16 }, { key: '5a600e12', value: 17 }, { key: '5a600e15', value: 19 }]); expect(skip.values()).to.eql(skip.slice()); expect(skip.values()).to.eql(skip.range()); expect(skip.range(14, 16)).to.eql([{ key: '5a600e14', value: 14 }, { key: '5a600e10', value: 16 }]); }); describe('#set', function() { it('should implicitly delete', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(skip.set('5a600e14', null)).to.equal(14); expect(skip.set('5a600e19', null)).to.equal(null); expect(skip).to.have.length(8); }); }); describe('#values', function() { it('should support different fields', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(skip.keys()).to.eql(['5a600e16', '5a600e11', '5a600e18', '5a600e13', '5a600e17', '5a600e14', '5a600e10', '5a600e12', '5a600e15']); expect(skip.values(true)).to.eql([3, 6, 10, 11, 12, 14, 16, 17, 19]); }); }); describe('#range', function() { it('should support special ranges', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(skip.range(14)).to.eql([{ key: '5a600e14', value: 14 }, { key: '5a600e10', value: 16 }, { key: '5a600e12', value: 17 }, { key: '5a600e15', value: 19 }]); expect(skip.range(null, 10)).to.eql([{ key: '5a600e16', value: 3 }, { key: '5a600e11', value: 6 }, { key: '5a600e18', value: 10 }]); expect(skip.range(-Infinity, Infinity)).to.eql(skip.values()); expect(skip.range(null, null)).to.eql(skip.values()); }); }); describe('#count', function() { it('should count elements', function() { var skip = new ProxyMap(); expect(skip.count()).to.equal(0); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); skip.set('5a600e19', 14); skip.set('5a600f00', 30.0); skip.set('5a600f01', 30.5); skip.set('5a600f02', 31.0); skip.set('5a600f03', 31.5); skip.set('5a600f04', 32.0); skip.set('5a600f05', 32.0); skip.set('5a600f06', 32.0); expect(skip.count()).to.eql(skip.range().length); expect(skip.count(8)).to.eql(skip.range(8).length); expect(skip.count(3, 7)).to.eql(skip.range(3, 7).length); expect(skip.count(5, 14)).to.eql(skip.range(5, 14).length); expect(skip.count(5, 5)).to.eql(skip.range(5, 5).length); expect(skip.count(5, 0)).to.eql(skip.range(5, 0).length); expect(skip.count(30, 32)).to.eql(skip.range(30, 32).length); expect(skip.count(40)).to.eql(skip.range(40).length); }); }); describe('#slice', function() { it('should support special ranges', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); var array = skip.values(); expect(skip.slice()).to.eql(array); expect(skip.slice(2)).to.eql(array.slice(2)); expect(skip.slice(8)).to.eql(array.slice(8)); expect(skip.slice(0, 3)).to.eql(array.slice(0, 3)); expect(skip.slice(-1)).to.eql(array.slice(-1)); expect(skip.slice(-4)).to.eql(array.slice(-4)); expect(skip.slice(-4, -2)).to.eql(array.slice(-4, -2)); expect(skip.slice(-4, skip.length + 1000)).to.eql(array.slice(-4, skip.length + 1000)); }); }); describe('#intersect', function() { it('should intersect two sets', function() { var a = new ProxyMap(), b = new ProxyMap(); a.set('5a600e10', 16); a.set('5a600e12', 10); a.set('5a600e14', 9); a.set('5a600e15', 14); a.set('5a600e17', 20); a.set('5a600e18', 13); a.set('5a600e19', 15); a.set('5a600e1a', 19); a.set('5a600e1b', 7); a.set('5a600e1c', 13); a.set('5a600e1e', 10); b.set('5a600e10', 0); b.set('5a600e11', 15); b.set('5a600e13', 5); b.set('5a600e14', 3); b.set('5a600e15', 14); b.set('5a600e17', 12); b.set('5a600e19', 12); b.set('5a600e1b', 16); b.set('5a600e1c', 12); b.set('5a600e1d', 17); b.set('5a600e1f', 3); expect(ProxyMap.intersectKeys(a, b)).to.eql(['5a600e10', '5a600e14', '5a600e1c', '5a600e19', '5a600e17', '5a600e15', '5a600e1b']); expect(ProxyMap.intersectKeys(b, a)).to.eql(['5a600e1b', '5a600e14', '5a600e1c', '5a600e15', '5a600e19', '5a600e10', '5a600e17']); }); it('should intersect three sets', function() { var a = new ProxyMap(), b = new ProxyMap(), c = new ProxyMap(); a.set('5a600e10', 16); a.set('5a600e12', 10); a.set('5a600e14', 9); a.set('5a600e15', 14); a.set('5a600e17', 20); a.set('5a600e18', 13); a.set('5a600e19', 15); a.set('5a600e1a', 19); a.set('5a600e1b', 7); a.set('5a600e1c', 13); a.set('5a600e1e', 10); b.set('5a600e10', 0); b.set('5a600e11', 15); b.set('5a600e13', 5); b.set('5a600e14', 3); b.set('5a600e15', 14); b.set('5a600e17', 12); b.set('5a600e19', 12); b.set('5a600e1b', 16); b.set('5a600e1c', 12); b.set('5a600e1d', 17); b.set('5a600e1f', 3); c.set('5a600e10', 7); c.set('5a600e12', 20); c.set('5a600e13', 9); c.set('5a600e14', 19); c.set('5a600e16', 19); c.set('5a600e17', 1); c.set('5a600e18', 18); c.set('5a600e1a', 6); c.set('5a600e1c', 15); c.set('5a600e1f', 4); expect(ProxyMap.intersectKeys(c, a, b)).to.eql(['5a600e10', '5a600e14', '5a600e1c', '5a600e17']); expect(ProxyMap.intersectKeys(c, a, b)).to.eql(c.intersectKeys(a, b)); }); it('should intersect four sets', function() { var a = new ProxyMap(), b = new ProxyMap(), c = new ProxyMap(), d = new ProxyMap(); a.set('5a600e10', 16); a.set('5a600e12', 10); a.set('5a600e14', 9); a.set('5a600e15', 14); a.set('5a600e17', 20); a.set('5a600e18', 13); a.set('5a600e19', 15); a.set('5a600e1a', 19); a.set('5a600e1b', 7); a.set('5a600e1c', 13); a.set('5a600e1e', 10); b.set('5a600e10', 0); b.set('5a600e11', 15); b.set('5a600e13', 5); b.set('5a600e14', 3); b.set('5a600e15', 14); b.set('5a600e17', 12); b.set('5a600e19', 12); b.set('5a600e1b', 16); b.set('5a600e1c', 12); b.set('5a600e1d', 17); b.set('5a600e1f', 3); c.set('5a600e10', 7); c.set('5a600e12', 20); c.set('5a600e13', 9); c.set('5a600e14', 19); c.set('5a600e16', 19); c.set('5a600e17', 1); c.set('5a600e18', 18); c.set('5a600e1a', 6); c.set('5a600e1c', 15); c.set('5a600e1f', 4); d.set('5a600e1c', 400); d.set('5a600e17', 500); d.set('5a600e1f', 600); d.set('5a600e20', 700); expect(ProxyMap.intersectKeys(d, c, a, b)) .to.eql(['5a600e1c', '5a600e17']); expect(ProxyMap.intersectKeys(d, c, a, b)) .to.eql(d.intersectKeys(c, a, b)); }); }); describe('#rank', function() { it('should get the correct rank', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(skip.rank('5a600e12')).to.equal(7); expect(skip.rank('5a600e13')).to.equal(3); expect(skip.rank('5a600e16')).to.equal(0); expect(skip.rank('5a600e15')).to.equal(8); expect(skip.rank('not in set')).to.equal(-1); }); }); describe('#del', function() { it('should delete special elements', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(skip.del('5a600e15')).to.equal(19); expect(skip).to.have.length(8); expect(skip.del('5a600e16')).to.equal(3); expect(skip).to.have.length(7); expect(skip.values()).to.eql([{ key: '5a600e11', value: 6 }, { key: '5a600e18', value: 10 }, { key: '5a600e13', value: 11 }, { key: '5a600e17', value: 12 }, { key: '5a600e14', value: 14 }, { key: '5a600e10', value: 16 }, { key: '5a600e12', value: 17 }]); }); it('should delete many elements', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(skip.del('5a600e11')).to.equal(6); expect(skip.del('5a600e13')).to.equal(11); expect(skip.del('5a600e14')).to.equal(14); expect(skip.del('5a600e15')).to.equal(19); expect(skip.del('5a600e16')).to.equal(3); expect(skip.del('5a600e17')).to.equal(12); expect(skip.length).to.equal(3); expect(skip.values()).to.eql([{ key: '5a600e18', value: 10 }, { key: '5a600e10', value: 16 }, { key: '5a600e12', value: 17 }]); }); }); describe('#gut', function() { it('should strip out a range of elements', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(skip.gut(4, 14)).to.equal(5); expect(skip).to.have.length(4); expect(skip.values()).to.eql([{ key: '5a600e16', value: 3 }, { key: '5a600e10', value: 16 }, { key: '5a600e12', value: 17 }, { key: '5a600e15', value: 19 }]); }); it('should strip out all the elements', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(skip.gut(3, 19)).to.equal(9); expect(skip).to.have.length(0); expect(skip.values()).to.eql([]); }); }); describe('#gutSlice', function() { it('should strip out a slice of elements', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(skip.gutSlice(1, 6)).to.equal(5); expect(skip).to.have.length(4); expect(skip.values()).to.eql([{ key: '5a600e16', value: 3 }, { key: '5a600e10', value: 16 }, { key: '5a600e12', value: 17 }, { key: '5a600e15', value: 19 }]); }); it('should strip out all elements', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(skip.gutSlice(0, 9)).to.equal(9); expect(skip).to.have.length(0); expect(skip.values()).to.eql([]); }); }); describe('#empty', function() { it('should remove all elements', function() { var skip = new ProxyMap(); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); skip.empty(); expect(skip).to.have.length(0); expect(skip.values()).to.eql([]); }); }); describe('unique', function() { it('should ensure values are unique', function() { var skip = new ProxyMap({unique: true}); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(function() { skip.set('5a600e19', 11); }).to.throw(/unique/); // quick exit test expect(function() { skip.set('5a600dff', skip.head.next[skip.level - 1].next.value.value); }).to.throw(/unique/); // this test ensures the key < key check doesn't come into play expect(function() { skip.set('5a600dff', 11); }).to.throw(/unique/); expect(function() { skip.set('5a600e18', 10); }).to.not.throw(); expect(skip).to.have.length(9); expect(skip.values()).to.eql([{ key: '5a600e16', value: 3 }, { key: '5a600e11', value: 6 }, { key: '5a600e18', value: 10 }, { key: '5a600e13', value: 11 }, { key: '5a600e17', value: 12 }, { key: '5a600e14', value: 14 }, { key: '5a600e10', value: 16 }, { key: '5a600e12', value: 17 }, { key: '5a600e15', value: 19 }]) }); it('should revert keys if constraint broken during update', function() { var skip = new ProxyMap({unique: true}); skip.set('5a600e10', 16); skip.set('5a600e11', 6); skip.set('5a600e12', 17); skip.set('5a600e13', 11); skip.set('5a600e14', 14); skip.set('5a600e15', 19); skip.set('5a600e16', 3); skip.set('5a600e17', 12); skip.set('5a600e18', 10); expect(function() { skip.set('5a600e13', 14); }).to.throw(/unique/); expect(skip).to.have.length(9); expect(skip.get('5a600e13')).to.equal(11); }); }); });