bitset
Version:
A performance optimized infinite bit vector library
847 lines (576 loc) • 20 kB
JavaScript
const BitSet = require('bitset');
const assert = require('assert');
describe('BitSet', function () {
it('should Construct', function () {
var bs = new BitSet(19219);
assert.equal(bs.toString(10), '19219');
var bs = new BitSet;
assert.equal(bs.toString(32), '0');
var bs = new BitSet(-1);
assert.equal(bs.toString(2), '11111111111111111111111111111111');
});
it('should set an individual bit', function () {
var bs = new BitSet();
bs.set(31);
assert.equal(bs.get(31), 1);
});
it('should find first set', function () {
var bs = new BitSet();
bs.set(31);
assert.equal(bs.msb(), 31);
});
it('should not be able to find first set in an empty bitset', function () {
var bs = new BitSet();
assert.equal(bs.msb(), Infinity);
});
it('should unset a bit', function () {
var bs = new BitSet();
bs.set(31);
bs.clear(31);
assert.equal(bs.get(31), 0);
});
it('should Hex in - Hex out', function () {
var bs = new BitSet("0xD00000005");
assert.equal(bs.toString(16), 'd00000005');
var bs = new BitSet("0xff900018283821283");
assert.equal(bs.toString(16), 'ff900018283821283');
var bs = new BitSet("0x28123719b3bacf929cd9291929293818382939292");
assert.equal(bs.toString(16), '28123719b3bacf929cd9291929293818382939292');
var bs = new BitSet("0xd1b1bd81dbabd8ab8adbabcb8cb8c1b8c18bcb81b81b81b8caaaaaaaaafffffabababababa28328832838282838282828382834868682828");
assert.equal(bs.toString(16), 'd1b1bd81dbabd8ab8adbabcb8cb8c1b8c18bcb81b81b81b8caaaaaaaaafffffabababababa28328832838282838282828382834868682828');
});
it('should Get range', function () {
var bs = new BitSet("0xff900018283821283");
assert.equal(bs.slice(16, 32).toString(16), '8382');
var bs = new BitSet("0xff900018283821283");
assert.equal(bs.slice(16, 40).toString(2), '1100000101000001110000010');
var bs = new BitSet("0xff900018283821283");
assert.equal(bs.slice(130, 160).toString(8), '0');
});
it('should check empty', function () {
var bs = new BitSet();
assert.equal(bs.isEmpty(), true);
bs = bs.set(0);
assert.equal(bs.isEmpty(), false);
});
it('should flip/clear 2', function () {
var bs = new BitSet;
bs = bs.set(60);
bs = bs.flip();
bs = bs.flip(29, 35);
assert.equal(bs.toString(), "...11110111111111111111111111111000000011111111111111111111111111111");
});
it('should flip/clear 3', function () {
var bs = new BitSet;
bs = bs.set(60, 0); // Set size
bs = bs.flip(29, 35);
bs = bs.flip();
bs = bs.clear(50, 55);
assert.equal(bs.toString(), "...111100000011111111111111000000011111111111111111111111111111");
});
it('should flip/clear 4', function () {
var bs = new BitSet;
bs
.flip(0, 62)
.flip(29, 35);
assert.equal(bs.toString(), "111111111111111111111111111000000011111111111111111111111111111");
});
it('should eat own dogfood', function () {
var bs = new BitSet(4);
bs.not();
assert.equal(BitSet(bs.toArray()).toString(), bs.toString());
});
it('should flip range check', function () {
var bs = new BitSet;
assert.equal(bs.flip(-1, 0).toString(), '0');
assert.equal(bs.flip(1, 0).toString(), '0');
});
it('should And', function () {
var bs = new BitSet("0xff05");
assert.equal(bs.and("0xfe00").toString(16), 'fe00');
});
it('should Or', function () {
var bs = new BitSet(256);
assert.equal(bs.or(512).toString(16), '300');
});
it('should Xor', function () {
var bs = new BitSet("1010");
assert.equal(bs.xor("0011").toString(2), '1001');
});
it('should Equals', function () {
var bs = new BitSet('100000000000111010101');
assert.equal(bs.equals("100000000000111010101"), true);
var bs = new BitSet('111010101');
assert.equal(bs.equals("101010101"), false);
});
it('should Cardinality', function () {
var bs = new BitSet('1000000000000000000001101');
assert.equal(bs.cardinality(), 4);
});
it('should msbit', function () {
var bs = new BitSet('1000000000000000000001101');
assert.equal(bs.msb(), '1000000000000000000001101'.length - 1);
});
it('should msbit set', function () {
var bs = new BitSet;
bs = bs
.set(100)
.set(333);
assert.equal(bs.msb(), 333);
});
it('should slice negated', function () {
var bs = new BitSet(4);
bs = bs.not();
assert.equal(bs.toString(), '...1111011');
assert.equal(bs.slice(1).toString(), '...111101');
assert.equal(bs.slice(1, 3).toString(), '101');
});
it('should setRange 2', function () {
var bs = new BitSet;
bs = bs.setRange(0, 70);
bs = bs.setRange(30, 45, 0);
assert.equal(bs.toString(), "11111111111111111111111110000000000000000111111111111111111111111111111");
});
it('should setRange 3', function () {
var bs = new BitSet;
bs = bs.setRange(2, 12, "1111001111");
assert.equal(bs.toString(), "1111111111100");
});
it('should setRange 1', function () {
var bs = new BitSet;
bs = bs.setRange(3, 10);
assert.equal(bs.toString(), "11111111000");
});
it('should msbit should work negative numbers', function () {
var flipped = new BitSet().not();
assert.equal(flipped.msb(), Infinity);
});
it('should ntzit', function () {
assert.equal(new BitSet('10000000000110001000000000').ntz(), 9);
assert.equal(new BitSet('00000000000000000000000000').ntz(), Infinity);
assert.equal(new BitSet('10000000000000000000000000').ntz(), 25);
assert.equal(new BitSet('10000000100000000000000000000000000000000000').ntz(), 35);
});
it('should set', function () {
var bs = new BitSet;
bs
.set(4, 1) // Set bit on 4th pos
.set(0) // Set bit on 0th pos
.set(22, 1)
.set(33, 1); // Set
assert.equal(bs.toString(), '1000000000010000000000000000010001');
bs = bs.set(33, 0); // And reset
assert.equal(bs.toString(), '10000000000000000010001');
assert.equal(bs.msb(), 22);
bs = bs.set(330, 1);
assert.equal(bs.msb(), 330); // Thus, msb is on 330
});
it('should lsbit', function () {
assert.equal(
new BitSet('10000000000110001000000000').lsb(),
9
);
assert.equal(
new BitSet('00000000000000000000000000').lsb(),
0
);
assert.equal(
new BitSet('10000000000000000000000000').lsb(),
25
);
assert.equal(
new BitSet('10000000100000000000000000000000000000000000').lsb(),
35
);
});
it('should string and', function () {
var bsa = new BitSet();
bsa.set(0);
var bsb = new BitSet();
bsb.set(32);
bsa = bsa.and(bsb);
assert.equal(bsa.cardinality(), 0);
assert.equal(bsb.cardinality(), 1);
assert.equal(bsa.get(0), 0);
assert.equal(bsb.get(0), 0);
assert.equal(bsa.get(32), 0);
assert.equal(bsb.get(32), 1);
for (var i = 0; i < 64; i++) {
assert.equal(bsa.get(i), 0);
assert.equal(bsb.get(i), i === 32 ? 1 : 0);
}
assert.equal(bsa.toString(), '0');
assert.equal(bsb.toString(), '100000000000000000000000000000000');
});
it('should string or', function () {
var bsa = new BitSet();
var bsb = new BitSet();
bsa.set(0);
bsb.set(32);
bsa = bsa.or(bsb);
assert.equal(bsa.cardinality(), 2);
assert.equal(bsb.cardinality(), 1);
assert.equal(bsa.get(0), 1);
assert.equal(bsb.get(0), 0);
assert.equal(bsa.get(32), 1);
assert.equal(bsb.get(32), 1);
for (var i = 0; i < 64; i++) {
assert.equal(bsa.get(i), i === 0 || i === 32 ? 1 : 0);
assert.equal(bsb.get(i), i === 32 ? 1 : 0);
}
assert.equal(bsa.toString(), '100000000000000000000000000000001');
assert.equal(bsb.toString(), '100000000000000000000000000000000');
});
it('should pass setting in time', function (done) {
var bs = new BitSet;
var start = Date.now();
for (var i = 0; i < 1000000; i++) {
bs.set(i);
}
assert((Date.now() - start) < 50);
done();
});
it('should string set', function () {
var bs = new BitSet('1000000000010000000000000000010001');
assert.equal(bs.toString(), '1000000000010000000000000000010001');
});
it('should set auto scale', function () {
var bs = new BitSet;
bs = bs.set(512);
assert.equal(bs.get(511), 0);
assert.equal(bs.get(512), 1);
assert.equal(bs.get(513), 0);
});
it('should get', function () {
var bs = new BitSet();
bs = bs.set(4, 1); // Set bit on 4th pos
bs = bs.set(0); // Set bit on 0th pos
assert.equal(bs.get(4) + bs.get(0), 2);
});
it('should work with flipped bitset: and', function () {
var a = new BitSet(0);
var b = new BitSet(0);
a = a.set(1);
b = b.set(50);
var output = b.and(a.not());
// check bits are correctly set beyond length of a
assert.equal(1, output.get(50));
// check bits are correctly unset beyond length of a
assert.equal(0, output.get(51));
});
it('should work with different length scales: and', function () {
var a = new BitSet();
var b = new BitSet();
a = a.set(1);
b = b.set(50);
assert.equal(a.clone().and(b).toString(), b.clone().and(a).toString());
});
it('should work with different length scales: or', function () {
var a = new BitSet();
var b = new BitSet();
a = a.set(1);
b = b.set(50);
assert.equal(a.clone().or(b).toString(), b.clone().or(a).toString());
});
it('should work with different length scales: xor', function () {
var a = new BitSet();
var b = new BitSet();
a = a.set(1);
b = b.set(50);
assert.equal(a.clone().xor(b).toString(), b.clone().xor(a).toString());
});
it('should work with zero: xor', function () {
var a = new BitSet();
var b = new BitSet();
a = a.set(1);
a = b.set(50);
assert.equal(a.xor(b).toString(), b.xor(a).toString());
});
it('should work with inverted zero', function () {
var a = new BitSet();
a = a.not();
assert.equal(a.toString(), '...1111');
});
it('should cut off infinity', function () {
var a = new BitSet();
a = a.not();
assert.equal(a.toString(), '...1111');
a = a.and(0xff);
assert.equal(a.toString(), '11111111');
});
it('should and fuzz 00', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = 0;
b._ = 0;
assert.equal(a.and(b).toString(), '10000000111')
assert.equal(b.and(a).toString(), '10000000111')
});
it('should and fuzz 01', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = 0;
b._ = -1;
assert.equal(a.and(b).toString(), '10000000111')
assert.equal(b.and(a).toString(), '10000000111')
});
it('should and fuzz 10', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = -1;
b._ = 0;
assert.equal(a.and(b).toString(), '10100100000000000000000000010000000111')
assert.equal(b.and(a).toString(), '10100100000000000000000000010000000111')
});
it('should and fuzz 11', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = -1;
b._ = -1;
assert.equal(a.and(b).toString(), '...11110100100000000000000000000010000000111')
assert.equal(b.and(a).toString(), '...11110100100000000000000000000010000000111')
});
it('should or fuzz 00', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = 0;
b._ = 0;
assert.equal(a.or(b).toString(), '10100100010010101000110101011111111111')
assert.equal(b.or(a).toString(), '10100100010010101000110101011111111111')
});
it('should or fuzz 01', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = 0;
b._ = -1;
assert.equal(a.or(b).toString(), '...11110100100010010101000110101011111111111')
assert.equal(b.or(a).toString(), '...11110100100010010101000110101011111111111')
});
it('should or fuzz 10', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = -1;
b._ = 0;
assert.equal(a.or(b).toString(), '...11110100100010010101000110101011111111111')
assert.equal(b.or(a).toString(), '...11110100100010010101000110101011111111111')
});
it('should or fuzz 11', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = -1;
b._ = -1;
assert.equal(a.or(b).toString(), '...11110100100010010101000110101011111111111')
assert.equal(b.or(a).toString(), '...11110100100010010101000110101011111111111')
});
it('should xor fuzz 00', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = 0;
b._ = 0;
assert.equal(a.xor(b).toString(), '10100100010010101000110101001111111000')
assert.equal(b.xor(a).toString(), '10100100010010101000110101001111111000')
});
it('should xor fuzz 01', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = 0;
b._ = -1;
assert.equal(a.xor(b).toString(), '...11110100100010010101000110101001111111000')
assert.equal(b.xor(a).toString(), '...11110100100010010101000110101001111111000')
});
it('should xor fuzz 10', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = -1;
b._ = 0;
assert.equal(a.xor(b).toString(), '...111101011000010010101000110101001111111000')
assert.equal(b.xor(a).toString(), '...111101011000010010101000110101001111111000')
});
it('should xor fuzz 11', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = -1;
b._ = -1;
assert.equal(a.xor(b).toString(), '1111111111111111111111111101011000010010101000110101001111111000')
assert.equal(b.xor(a).toString(), '1111111111111111111111111101011000010010101000110101001111111000')
});
it('should andNot fuzz 00', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = 0;
b._ = 0;
assert.equal(a.andNot(b).toString(), '1100111000')
assert.equal(b.andNot(a).toString(), '10100100010010101000110101000011000000')
});
it('should andNot fuzz 01', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = 0;
b._ = -1;
assert.equal(a.andNot(b).toString(), '1100111000')
assert.equal(b.andNot(a).toString(), '...11110100100010010101000110101000011000000')
});
it('should andNot fuzz 10', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = -1;
b._ = 0;
assert.equal(a.andNot(b).toString(), '...111101011000000000000000000000001100111000')
assert.equal(b.andNot(a).toString(), '10010101000110101000011000000')
});
it('should andNot fuzz 11', function () {
var a = new BitSet;
var b = new BitSet;
a.data = [0b11100111111];
b.data = [0b10010101000110101010011000111, 0b101001];
a._ = -1;
b._ = -1;
assert.equal(a.andNot(b).toString(), '1111111111111111111111111101011000000000000000000000001100111000')
assert.equal(b.andNot(a).toString(), '10010101000110101000011000000')
});
it('should work with simple xor use case', function () {
var bsa = new BitSet
bsa.set(0);
bsa.set(1);
var bsb = new BitSet;
bsb.set(32);
bsb = bsb.set(1);
bsa = bsa.xor(bsb);
assert.equal(bsa.cardinality(), 2);
assert.equal(bsa.get(0), 1);
assert.equal(bsa.get(32), 1);
assert.equal(bsa.toArray().toString(), "0,32");
});
it('should get large undefined offsets', function () {
var a = new BitSet();
a = a.not();
assert.equal(a.get(2000), 1);
});
it('should work with empty checks', function () {
var a = new BitSet();
assert.equal(a.isEmpty(), true);
a.set(1000);
assert.equal(a.isEmpty(), false);
});
it('should work with inverting', function () {
var x = new BitSet;
x.set(4);
x.set(32);
x = x.not();
x.set(65, 0);
x = x.not();
x.set(8, 1);
assert.equal(x.cardinality(), 4);
assert.deepEqual(x.data, [272, 1, 2, 0, 0, 0, 0, 0, 0, 0]);
assert.deepEqual(x.toArray(), [4, 8, 32, 65]);
});
it('get higher bits correctly', function () {
var a = new BitSet([34]).not();
var b = new BitSet().set(34, 1).not();
assert.equal(a.get(80), b.get(80));
});
it('should withstand some fuzz', function () {
for (var i = 0; i < 100; i++) {
var foo = BitSet();
var x = 0;
var tmp = Math.random() * (1 << 24) | 0;
foo = foo.or(tmp);
x |= tmp;
var tmp = Math.random() * (1 << 24) | 0;
foo = foo.xor(tmp);
x ^= tmp;
var tmp = Math.random() * (1 << 24) | 0;
foo = foo.and(tmp);
x &= tmp;
// x = ~x;
//foo = foo.not();
assert.equal(x.toString(2), foo.toString(2));
}
});
it('should work with infinity strings', function () {
var x = BitSet('11').not().set(35, 0);
assert.equal(x.toString(2), '...1111011111111111111111111111111111111100');
});
it('should work with reported bug', function () {
var bs1 = new BitSet("101");
var ss = bs1.toString(); // expecting "101", actual "101" Note: bs1 = {length=1, [0]=5}
var a = bs1.get(1); // expecting 0, actual 0
var b = bs1.get(2); // expecting 1, actual 1
var bs2 = new BitSet("111");
ss = bs2.toString(); // expecting "111", actual "111" Note: bs2 = {length=1, [0]=7}
assert.equal(ss, '111');
var bs3 = bs2.clear(1);
ss = bs3.toString(); // expecting "101", actual "1" Note: bs3 = {length=2, [0]=1,[1]=0}
assert.equal(ss, '101');
var c = bs3.get(1); // expecting 0, actual 0
assert.equal(c, 0);
var d = bs3.get(2); // expecting 1, actual 0
assert.equal(d, 1);
var t = bs3.equals(bs1); // expecting true, actual false
assert.equal(t, true);
});
it('should clear', function () {
var bs1 = new BitSet("111101");
bs1.clear(5);
assert.equal(bs1.toString(), '11101');
bs1.clear();
assert.equal(bs1.toString(), '0');
});
it('should iterate', function () {
var val = "1111010101111010101010101111110010101010111110101001101010101011101010101111100011111100101011";
var bs = BitSet(val);
var str = "";
for (var b of bs) {
str += b;
}
assert.equal(str, val.split("").reverse().join(""));
});
it('should iterate zero', function () {
var val = "0";
var bs = BitSet(val);
var str = "";
for (var b of bs) {
str += b;
}
assert.equal(str, "");
});
it('should iterate one', function () {
var val = "1";
var bs = BitSet(val);
var str = "";
for (var b of bs) {
str += b;
}
assert.equal(str, val);
});
});