├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── app
└── BitSet.js
├── package.json
└── spec
├── BitsetSpec.js
└── support
└── jasmine.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
27 | node_modules
28 | api.md
29 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 0.12
4 | - 0.10
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 mattkrick
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # fast-bitset
2 |
3 | [](https://travis-ci.org/mattkrick/fast-bitset)
4 |
5 | [](https://gitter.im/mattkrick/fast-bitset?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6 |
7 | A fast bitset with some nice methods.
8 |
9 | ##Features
10 | - Outperforms all other bitset packages in terms of speed and space
11 | - All bit operations execute in O(1) time (does not iterate through bits)
12 | - Useful methods for graph algorithms
13 | - Any array that stores booleans can safely be replaced by a bitset for improved speed
14 | - Uses 64x less space than a nontyped array
15 |
16 | ##Installation
17 | `npm install fast-bitset --save`
18 |
19 | ##License
20 | MIT
21 |
22 | ##API
23 |
24 | * [BitSet](#BitSet)
25 | * [new BitSet(nBitsOrKey)](#new_BitSet_new)
26 | * [.get(idx)](#BitSet+get) ⇒ boolean
27 | * [.set(idx)](#BitSet+set) ⇒ boolean
28 | * [.setRange(from, to)](#BitSet+setRange) ⇒ boolean
29 | * [.unset(idx)](#BitSet+unset) ⇒ boolean
30 | * [.unsetRange(from, to)](#BitSet+unsetRange) ⇒ boolean
31 | * [.toggle(idx)](#BitSet+toggle) ⇒ boolean
32 | * [.toggleRange(from, to)](#BitSet+toggleRange) ⇒ boolean
33 | * [.clear()](#BitSet+clear) ⇒ boolean
34 | * [.clone()](#BitSet+clone) ⇒ [BitSet](#BitSet)
35 | * [.dehydrate()](#BitSet+dehydrate) ⇒ string
36 | * [.and(bsOrIdx)](#BitSet+and) ⇒ [BitSet](#BitSet)
37 | * [.or(bsOrIdx)](#BitSet+or) ⇒ [BitSet](#BitSet)
38 | * [.xor(bsOrIdx)](#BitSet+xor) ⇒ [BitSet](#BitSet)
39 | * [.forEach(func)](#BitSet+forEach)
40 | * [.circularShift(number)](#BitSet+circularShift) ⇒ Bitset
41 | * [.getCardinality()](#BitSet+getCardinality) ⇒ number
42 | * [.getIndices()](#BitSet+getIndices) ⇒ Array
43 | * [.isSubsetOf(bs)](#BitSet+isSubsetOf) ⇒ Boolean
44 | * [.isEmpty()](#BitSet+isEmpty) ⇒ boolean
45 | * [.isEqual(bs)](#BitSet+isEqual) ⇒ boolean
46 | * [.toString()](#BitSet+toString) ⇒ string
47 | * [.ffs(_startWord)](#BitSet+ffs) ⇒ number
48 | * [.ffz(_startWord)](#BitSet+ffz) ⇒ number
49 | * [.fls(_startWord)](#BitSet+fls) ⇒ number
50 | * [.flz(_startWord)](#BitSet+flz) ⇒ number
51 | * [.nextSetBit(idx)](#BitSet+nextSetBit) ⇒ number
52 | * [.nextUnsetBit(idx)](#BitSet+nextUnsetBit) ⇒ number
53 | * [.previousSetBit(idx)](#BitSet+previousSetBit) ⇒ number
54 | * [.previousUnsetBit(idx)](#BitSet+previousUnsetBit) ⇒ number
55 |
56 |
57 | ### new BitSet(nBitsOrKey)
58 | Create a new bitset. Accepts either the maximum number of bits, or a dehydrated bitset
59 |
60 |
61 | | Param | Type | Description |
62 | | --- | --- | --- |
63 | | nBitsOrKey | number
| string
| Number of bits in the set or dehydrated bitset. For speed and space concerns, the initial number of bits cannot be increased. |
64 |
65 |
66 | ### bitSet.get(idx) ⇒ boolean
67 | Check whether a bit at a specific index is set
68 |
69 | **Kind**: instance method of [BitSet](#BitSet)
70 | **Returns**: boolean
- true if bit is set, else false
71 |
72 | | Param | Type | Description |
73 | | --- | --- | --- |
74 | | idx | number
| the position of a single bit to check |
75 |
76 |
77 | ### bitSet.set(idx) ⇒ boolean
78 | Set a single bit
79 |
80 | **Kind**: instance method of [BitSet](#BitSet)
81 | **Returns**: boolean
- true if set was successful, else false
82 |
83 | | Param | Type | Description |
84 | | --- | --- | --- |
85 | | idx | number
| the position of a single bit to set |
86 |
87 |
88 | ### bitSet.setRange(from, to) ⇒ boolean
89 | Set a range of bits
90 |
91 | **Kind**: instance method of [BitSet](#BitSet)
92 | **Returns**: boolean
- true if set was successful, else false
93 |
94 | | Param | Type | Description |
95 | | --- | --- | --- |
96 | | from | number
| the starting index of the range to set |
97 | | to | number
| the ending index of the range to set |
98 |
99 |
100 | ### bitSet.unset(idx) ⇒ boolean
101 | Unset a single bit
102 |
103 | **Kind**: instance method of [BitSet](#BitSet)
104 | **Returns**: boolean
- true if set was successful, else false
105 |
106 | | Param | Type | Description |
107 | | --- | --- | --- |
108 | | idx | number
| the position of a single bit to unset |
109 |
110 |
111 | ### bitSet.unsetRange(from, to) ⇒ boolean
112 | Unset a range of bits
113 |
114 | **Kind**: instance method of [BitSet](#BitSet)
115 | **Returns**: boolean
- true if set was successful, else false
116 |
117 | | Param | Type | Description |
118 | | --- | --- | --- |
119 | | from | number
| the starting index of the range to unset |
120 | | to | number
| the ending index of the range to unset |
121 |
122 |
123 | ### bitSet.toggle(idx) ⇒ boolean
124 | Toggle a single bit
125 |
126 | **Kind**: instance method of [BitSet](#BitSet)
127 | **Returns**: boolean
- true if set was successful, else false
128 |
129 | | Param | Type | Description |
130 | | --- | --- | --- |
131 | | idx | number
| the position of a single bit to toggle |
132 |
133 |
134 | ### bitSet.toggleRange(from, to) ⇒ boolean
135 | Toggle a range of bits
136 |
137 | **Kind**: instance method of [BitSet](#BitSet)
138 | **Returns**: boolean
- true if set was successful, else false
139 |
140 | | Param | Type | Description |
141 | | --- | --- | --- |
142 | | from | number
| the starting index of the range to toggle |
143 | | to | number
| the ending index of the range to toggle |
144 |
145 |
146 | ### bitSet.clear() ⇒ boolean
147 | Clear an entire bitset
148 |
149 | **Kind**: instance method of [BitSet](#BitSet)
150 | **Returns**: boolean
- true
151 |
152 | ### bitSet.clone() ⇒ [BitSet](#BitSet)
153 | Clone a bitset
154 |
155 | **Kind**: instance method of [BitSet](#BitSet)
156 | **Returns**: [BitSet](#BitSet)
- an copy (by value) of the calling bitset
157 |
158 | ### bitSet.dehydrate() ⇒ string
159 | Turn the bitset into a comma separated string that skips leading & trailing 0 words.
160 | Ends with the number of leading 0s and MAX_BIT.
161 | Useful if you need the bitset to be an object key (eg dynamic programming).
162 | Can rehydrate by passing the result into the constructor
163 |
164 | **Kind**: instance method of [BitSet](#BitSet)
165 | **Returns**: string
- representation of the bitset
166 |
167 | ### bitSet.and(bsOrIdx) ⇒ [BitSet](#BitSet)
168 | Perform a bitwise AND on 2 bitsets or 1 bitset and 1 index.
169 | Both bitsets must have the same number of words, no length check is performed to prevent and overflow.
170 |
171 | **Kind**: instance method of [BitSet](#BitSet)
172 | **Returns**: [BitSet](#BitSet)
- a new bitset that is the bitwise AND of the two
173 |
174 | | Param | Type | Description |
175 | | --- | --- | --- |
176 | | bsOrIdx | [BitSet](#BitSet)
| Number
| a bitset or single index to check (useful for LP, DP problems) |
177 |
178 |
179 | ### bitSet.or(bsOrIdx) ⇒ [BitSet](#BitSet)
180 | Perform a bitwise OR on 2 bitsets or 1 bitset and 1 index.
181 | Both bitsets must have the same number of words, no length check is performed to prevent and overflow.
182 |
183 | **Kind**: instance method of [BitSet](#BitSet)
184 | **Returns**: [BitSet](#BitSet)
- a new bitset that is the bitwise OR of the two
185 |
186 | | Param | Type | Description |
187 | | --- | --- | --- |
188 | | bsOrIdx | [BitSet](#BitSet)
| Number
| a bitset or single index to check (useful for LP, DP problems) |
189 |
190 |
191 | ### bitSet.xor(bsOrIdx) ⇒ [BitSet](#BitSet)
192 | Perform a bitwise XOR on 2 bitsets or 1 bitset and 1 index.
193 | Both bitsets must have the same number of words, no length check is performed to prevent and overflow.
194 |
195 | **Kind**: instance method of [BitSet](#BitSet)
196 | **Returns**: [BitSet](#BitSet)
- a new bitset that is the bitwise XOR of the two
197 |
198 | | Param | Type | Description |
199 | | --- | --- | --- |
200 | | bsOrIdx | [BitSet](#BitSet)
| Number
| a bitset or single index to check (useful for LP, DP problems) |
201 |
202 |
203 | ### bitSet.forEach(func)
204 | Run a custom function on every set bit. Faster than iterating over the entire bitset with a `get()`
205 | Source code includes a nice pattern to follow if you need to break the for-loop early
206 |
207 | **Kind**: instance method of [BitSet](#BitSet)
208 |
209 | | Param | Type | Description |
210 | | --- | --- | --- |
211 | | func | function
| the function to pass the next set bit to |
212 |
213 |
214 | ### bitSet.circularShift(number) ⇒ Bitset
215 | Circular shift bitset by an offset
216 |
217 | **Kind**: instance method of [BitSet](#BitSet)
218 | **Returns**: Bitset
- a new bitset that is rotated by the offset
219 |
220 | | Param | Type | Description |
221 | | --- | --- | --- |
222 | | number | Number
| of positions that the bitset that will be shifted to the right. Using a negative number will result in a left shift. |
223 |
224 |
225 | ### bitSet.getCardinality() ⇒ number
226 | Get the cardinality (count of set bits) for the entire bitset
227 |
228 | **Kind**: instance method of [BitSet](#BitSet)
229 | **Returns**: number
- cardinality
230 |
231 | ### bitSet.getIndices() ⇒ Array
232 | Get the indices of all set bits. Useful for debugging, uses `forEach` internally
233 |
234 | **Kind**: instance method of [BitSet](#BitSet)
235 | **Returns**: Array
- Indices of all set bits
236 |
237 | ### bitSet.isSubsetOf(bs) ⇒ Boolean
238 | Checks if one bitset is subset of another. Same thing can be done using _and_ operation and equality check,
239 | but then new BitSet would be created, and if one is only interested in yes/no information it would be a waste of memory
240 | and additional GC strain.
241 |
242 | **Kind**: instance method of [BitSet](#BitSet)
243 | **Returns**: Boolean
- `true` if provided bitset is a subset of this bitset, `false` otherwise
244 |
245 | | Param | Type | Description |
246 | | --- | --- | --- |
247 | | bs | [BitSet](#BitSet)
| a bitset to check |
248 |
249 |
250 | ### bitSet.isEmpty() ⇒ boolean
251 | Quickly determine if a bitset is empty
252 |
253 | **Kind**: instance method of [BitSet](#BitSet)
254 | **Returns**: boolean
- true if the entire bitset is empty, else false
255 |
256 | ### bitSet.isEqual(bs) ⇒ boolean
257 | Quickly determine if both bitsets are equal (faster than checking if the XOR of the two is === 0).
258 | Both bitsets must have the same number of words, no length check is performed to prevent and overflow.
259 |
260 | **Kind**: instance method of [BitSet](#BitSet)
261 | **Returns**: boolean
- true if the entire bitset is empty, else false
262 |
263 | | Param | Type |
264 | | --- | --- |
265 | | bs | [BitSet](#BitSet)
|
266 |
267 |
268 | ### bitSet.toString() ⇒ string
269 | Get a string representation of the entire bitset, including leading 0s (useful for debugging)
270 |
271 | **Kind**: instance method of [BitSet](#BitSet)
272 | **Returns**: string
- a base 2 representation of the entire bitset
273 |
274 | ### bitSet.ffs(_startWord) ⇒ number
275 | Find first set bit (useful for processing queues, breadth-first tree searches, etc.)
276 |
277 | **Kind**: instance method of [BitSet](#BitSet)
278 | **Returns**: number
- the index of the first set bit in the bitset, or -1 if not found
279 |
280 | | Param | Type | Description |
281 | | --- | --- | --- |
282 | | _startWord | number
| the word to start with (only used internally by nextSetBit) |
283 |
284 |
285 | ### bitSet.ffz(_startWord) ⇒ number
286 | Find first zero (unset bit)
287 |
288 | **Kind**: instance method of [BitSet](#BitSet)
289 | **Returns**: number
- the index of the first unset bit in the bitset, or -1 if not found
290 |
291 | | Param | Type | Description |
292 | | --- | --- | --- |
293 | | _startWord | number
| the word to start with (only used internally by nextUnsetBit) |
294 |
295 |
296 | ### bitSet.fls(_startWord) ⇒ number
297 | Find last set bit
298 |
299 | **Kind**: instance method of [BitSet](#BitSet)
300 | **Returns**: number
- the index of the last set bit in the bitset, or -1 if not found
301 |
302 | | Param | Type | Description |
303 | | --- | --- | --- |
304 | | _startWord | number
| the word to start with (only used internally by previousSetBit) |
305 |
306 |
307 | ### bitSet.flz(_startWord) ⇒ number
308 | Find last zero (unset bit)
309 |
310 | **Kind**: instance method of [BitSet](#BitSet)
311 | **Returns**: number
- the index of the last unset bit in the bitset, or -1 if not found
312 |
313 | | Param | Type | Description |
314 | | --- | --- | --- |
315 | | _startWord | number
| the word to start with (only used internally by previousUnsetBit) |
316 |
317 |
318 | ### bitSet.nextSetBit(idx) ⇒ number
319 | Find first set bit, starting at a given index
320 |
321 | **Kind**: instance method of [BitSet](#BitSet)
322 | **Returns**: number
- the index of the next set bit >= idx, or -1 if not found
323 |
324 | | Param | Type | Description |
325 | | --- | --- | --- |
326 | | idx | number
| the starting index for the next set bit |
327 |
328 |
329 | ### bitSet.nextUnsetBit(idx) ⇒ number
330 | Find first unset bit, starting at a given index
331 |
332 | **Kind**: instance method of [BitSet](#BitSet)
333 | **Returns**: number
- the index of the next unset bit >= idx, or -1 if not found
334 |
335 | | Param | Type | Description |
336 | | --- | --- | --- |
337 | | idx | number
| the starting index for the next unset bit |
338 |
339 |
340 | ### bitSet.previousSetBit(idx) ⇒ number
341 | Find last set bit, up to a given index
342 |
343 | **Kind**: instance method of [BitSet](#BitSet)
344 | **Returns**: number
- the index of the next unset bit <= idx, or -1 if not found
345 |
346 | | Param | Type | Description |
347 | | --- | --- | --- |
348 | | idx | number
| the starting index for the next unset bit (going in reverse) |
349 |
350 |
351 | ### bitSet.previousUnsetBit(idx) ⇒ number
352 | Find last unset bit, up to a given index
353 |
354 | **Kind**: instance method of [BitSet](#BitSet)
355 | **Returns**: number
- the index of the next unset bit <= idx, or -1 if not found
356 |
357 | | Param | Type | Description |
358 | | --- | --- | --- |
359 | | idx | number
| the starting index for the next unset bit (going in reverse) |
360 |
--------------------------------------------------------------------------------
/app/BitSet.js:
--------------------------------------------------------------------------------
1 | //Matt Krick, matt.krick@gmail.com, MIT License
2 |
3 | //each bin holds bits 0 - 30, totaling 31 (sign takes up last bit)
4 | var BITS_PER_INT = 31;
5 | //used for ffs of a word in O(1) time. LUTs get a bad wrap, they are fast.
6 | var multiplyDeBruijnBitPosition = [0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
7 | 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9];
8 |
9 | /**
10 | *
11 | * Create a new bitset. Accepts either the maximum number of bits, or a dehydrated bitset
12 | * @param {number|string} nBitsOrKey - Number of bits in the set or dehydrated bitset.
13 | * For speed and space concerns, the initial number of bits cannot be increased.
14 | * @constructor
15 | */
16 | BitSet = function (nBitsOrKey) {
17 | var wordCount, arrVals, front, leadingZeros, i;
18 | if (typeof nBitsOrKey === 'number') {
19 | nBitsOrKey = nBitsOrKey || BITS_PER_INT; //default to 1 word
20 | wordCount = Math.ceil(nBitsOrKey / BITS_PER_INT);
21 | this.arr = new Uint32Array(wordCount);
22 | this.MAX_BIT = nBitsOrKey - 1;
23 | } else {
24 | arrVals = JSON.parse("[" + nBitsOrKey + "]");
25 | this.MAX_BIT = arrVals.pop();
26 | leadingZeros = arrVals.pop();
27 | if (leadingZeros > 0) {
28 | front = [];
29 | for (i = 0; i < leadingZeros; i++) front[i] = 0;
30 | for (i = 0; i < arrVals.length; i++) front[leadingZeros + i] = arrVals[i];
31 | arrVals = front;
32 | }
33 | wordCount = Math.ceil((this.MAX_BIT + 1) / BITS_PER_INT);
34 | this.arr = new Uint32Array(wordCount)
35 | this.arr.set(arrVals);
36 | }
37 | };
38 |
39 | /**
40 | * Check whether a bit at a specific index is set
41 | * @param {number} idx the position of a single bit to check
42 | * @returns {boolean} true if bit is set, else false
43 | */
44 | BitSet.prototype.get = function (idx) {
45 | var word = this._getWord(idx);
46 | return (word === -1) ? false : (((this.arr[word] >> (idx % BITS_PER_INT)) & 1) === 1);
47 | };
48 |
49 | /**
50 | * Set a single bit
51 | * @param {number} idx the position of a single bit to set
52 | * @returns {boolean} true if set was successful, else false
53 | */
54 | BitSet.prototype.set = function (idx) {
55 | var word = this._getWord(idx);
56 | if (word === -1) return false;
57 | this.arr[word] |= 1 << (idx % BITS_PER_INT);
58 | return true;
59 | };
60 |
61 | /**
62 | * Set a range of bits
63 | * @param {number} from the starting index of the range to set
64 | * @param {number} to the ending index of the range to set
65 | * @returns {boolean} true if set was successful, else false
66 | */
67 | BitSet.prototype.setRange = function (from, to) {
68 | return this._doRange(from, to, _setFunc);
69 | };
70 |
71 | /**
72 | * Unset a single bit
73 | * @param {number} idx the position of a single bit to unset
74 | * @returns {boolean} true if set was successful, else false
75 | */
76 | BitSet.prototype.unset = function (idx) {
77 | var word = this._getWord(idx);
78 | if (word === -1) return false;
79 | this.arr[word] &= ~(1 << (idx % BITS_PER_INT));
80 | return true;
81 | };
82 |
83 | /**
84 | * Unset a range of bits
85 | * @param {number} from the starting index of the range to unset
86 | * @param {number} to the ending index of the range to unset
87 | * @returns {boolean} true if set was successful, else false
88 | */
89 | BitSet.prototype.unsetRange = function (from, to) {
90 | return this._doRange(from, to, _unsetFunc);
91 | };
92 |
93 | /**
94 | * Toggle a single bit
95 | * @param {number} idx the position of a single bit to toggle
96 | * @returns {boolean} true if set was successful, else false
97 | */
98 | BitSet.prototype.toggle = function (idx) {
99 | var word = this._getWord(idx);
100 | if (word === -1) return false;
101 | this.arr[word] ^= (1 << (idx % BITS_PER_INT));
102 | return true;
103 | };
104 |
105 | /**
106 | * Toggle a range of bits
107 | * @param {number} from the starting index of the range to toggle
108 | * @param {number} to the ending index of the range to toggle
109 | * @returns {boolean} true if set was successful, else false
110 | */
111 | BitSet.prototype.toggleRange = function (from, to) {
112 | return this._doRange(from, to, _toggleFunc);
113 | };
114 |
115 | /**
116 | *
117 | * Clear an entire bitset
118 | * @returns {boolean} true
119 | */
120 | BitSet.prototype.clear = function () {
121 | for (var i = 0; i < this.arr.length; i++) {
122 | this.arr[i] = 0;
123 | }
124 | return true;
125 | };
126 |
127 | /**
128 | * Clone a bitset
129 | * @returns {BitSet} an copy (by value) of the calling bitset
130 | */
131 | BitSet.prototype.clone = function () {
132 | return new BitSet(this.dehydrate());
133 | };
134 |
135 | /**
136 | *
137 | * Turn the bitset into a comma separated string that skips leading & trailing 0 words.
138 | * Ends with the number of leading 0s and MAX_BIT.
139 | * Useful if you need the bitset to be an object key (eg dynamic programming).
140 | * Can rehydrate by passing the result into the constructor
141 | * @returns {string} representation of the bitset
142 | */
143 | BitSet.prototype.dehydrate = function () {
144 | var i, lastUsedWord, s;
145 | var leadingZeros = 0;
146 | for (i = 0; i < this.arr.length; i++) {
147 | if (this.arr[i] !== 0) break;
148 | leadingZeros++;
149 | }
150 | for (i = this.arr.length - 1; i >= leadingZeros; i--) {
151 | if (this.arr[i] !== 0) {
152 | lastUsedWord = i;
153 | break;
154 | }
155 | }
156 | s = '';
157 | for (i = leadingZeros; i <= lastUsedWord; i++) {
158 | s += (this.arr[i] + ',');
159 | }
160 | s += (leadingZeros + ',' + this.MAX_BIT); //leading 0s, stop numbers
161 | return s;
162 | };
163 |
164 | /**
165 | *
166 | * Perform a bitwise AND on 2 bitsets or 1 bitset and 1 index.
167 | * Both bitsets must have the same number of words, no length check is performed to prevent and overflow.
168 | * @param {BitSet | Number} bsOrIdx a bitset or single index to check (useful for LP, DP problems)
169 | * @returns {BitSet} a new bitset that is the bitwise AND of the two
170 | */
171 | BitSet.prototype.and = function (bsOrIdx) {
172 | return this._op(bsOrIdx, _and);
173 | };
174 |
175 | /**
176 | *
177 | * Perform a bitwise OR on 2 bitsets or 1 bitset and 1 index.
178 | * Both bitsets must have the same number of words, no length check is performed to prevent and overflow.
179 | * @param {BitSet | Number} bsOrIdx a bitset or single index to check (useful for LP, DP problems)
180 | * @returns {BitSet} a new bitset that is the bitwise OR of the two
181 | */
182 | BitSet.prototype.or = function (bsOrIdx) {
183 | return this._op(bsOrIdx, _or);
184 | };
185 |
186 | /**
187 | *
188 | * Perform a bitwise XOR on 2 bitsets or 1 bitset and 1 index.
189 | * Both bitsets must have the same number of words, no length check is performed to prevent and overflow.
190 | * @param {BitSet | Number} bsOrIdx a bitset or single index to check (useful for LP, DP problems)
191 | * @returns {BitSet} a new bitset that is the bitwise XOR of the two
192 | */
193 | BitSet.prototype.xor = function (bsOrIdx) {
194 | return this._op(bsOrIdx, _xor);
195 | };
196 |
197 | /**
198 | * Run a custom function on every set bit. Faster than iterating over the entire bitset with a `get()`
199 | * Source code includes a nice pattern to follow if you need to break the for-loop early
200 | * @param {Function} func the function to pass the next set bit to
201 | */
202 | BitSet.prototype.forEach = function (func) {
203 | for (var i = this.ffs(); i !== -1; i = this.nextSetBit(i + 1)) {
204 | func(i);
205 | }
206 | };
207 |
208 | /**
209 | * Circular shift bitset by an offset
210 | * @param {Number} number of positions that the bitset that will be shifted to the right.
211 | * Using a negative number will result in a left shift.
212 | * @returns {Bitset} a new bitset that is rotated by the offset
213 | */
214 |
215 | BitSet.prototype.circularShift = function(offset) {
216 | offset = -offset;
217 |
218 | var S = this; // source BitSet (this)
219 | var MASK_SIGN = 0x7fffffff;
220 | var BITS = S.MAX_BIT+1;
221 | var WORDS = S.arr.length;
222 | var BITS_LAST_WORD = BITS_PER_INT - (WORDS*BITS_PER_INT - BITS);
223 |
224 | var T = new BitSet(BITS); // target BitSet (the shifted bitset)
225 |
226 | var s; var t = 0; // (s)ource and (t)arget word indices
227 | var i; var j = 0; // current bit indices for source (i) and target (j) words
228 | var z = 0; // bit index for entire sequence.
229 |
230 | offset = (BITS + (offset % BITS)) % BITS // positive, within length
231 | var s = ~~(offset / BITS_PER_INT) % WORDS
232 | var i = offset % BITS_PER_INT
233 | while (z < BITS){
234 | var sourceWordLength = s === WORDS - 1 ? BITS_LAST_WORD : BITS_PER_INT
235 | var bits = S.arr[s]
236 |
237 | if (i > 0) {
238 | bits = bits >>> i;
239 | }
240 | if (j > 0) {
241 | bits = bits << j;
242 | }
243 |
244 | T.arr[t] = T.arr[t] | bits
245 |
246 | var bitsAdded = Math.min(BITS_PER_INT-j,sourceWordLength - i);
247 | z += bitsAdded;
248 | j += bitsAdded;
249 | if(j >= BITS_PER_INT){
250 | T.arr[t] = T.arr[t] & MASK_SIGN
251 | j = 0; t++;
252 | }
253 | i += bitsAdded;
254 | if(i >= sourceWordLength){ i = 0; s++;}
255 | if(s >= WORDS){ s -= WORDS;}
256 | }
257 | T.arr[WORDS-1] = T.arr[WORDS-1] & (MASK_SIGN >>> (BITS_PER_INT-BITS_LAST_WORD));
258 | return T;
259 | };
260 |
261 | /**
262 | * Get the cardinality (count of set bits) for the entire bitset
263 | * @returns {number} cardinality
264 | */
265 | BitSet.prototype.getCardinality = function () {
266 | var setCount = 0;
267 | for (var i = this.arr.length - 1; i >= 0; i--) {
268 | var j = this.arr[i];
269 | j = j - ((j >> 1) & 0x55555555);
270 | j = (j & 0x33333333) + ((j >> 2) & 0x33333333);
271 | setCount += ((((j + (j >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24);
272 | }
273 | return setCount;
274 | };
275 |
276 | /**
277 | * Get the indices of all set bits. Useful for debugging, uses `forEach` internally
278 | * @returns {Array} Indices of all set bits
279 | */
280 | BitSet.prototype.getIndices = function () {
281 | var indices = [];
282 | this.forEach(function (i) {
283 | indices.push(i);
284 | });
285 | return indices;
286 | };
287 |
288 | /**
289 | * Checks if one bitset is subset of another. Same thing can be done using _and_ operation and equality check,
290 | * but then new BitSet would be created, and if one is only interested in yes/no information it would be a waste of memory
291 | * and additional GC strain.
292 | * @param {BitSet} bs a bitset to check
293 | * @returns {Boolean} `true` if provided bitset is a subset of this bitset, `false` otherwise
294 | */
295 | BitSet.prototype.isSubsetOf = function (bs) {
296 | var arr1 = this.arr;
297 | var arr2 = bs.arr;
298 | var len = arr1.length;
299 | for (var i = 0; i < len; i++) {
300 | if ((arr1[i] & arr2[i]) !== arr1[i]) {
301 | return false;
302 | }
303 | }
304 | return true;
305 | }
306 |
307 | /**
308 | * Quickly determine if a bitset is empty
309 | * @returns {boolean} true if the entire bitset is empty, else false
310 | */
311 | BitSet.prototype.isEmpty = function () {
312 | var i, arr;
313 | arr = this.arr;
314 | for (i = 0; i < arr.length; i++) {
315 | if (arr[i]) {
316 | return false;
317 | }
318 | }
319 | return true;
320 | };
321 |
322 | /**
323 | *
324 | * Quickly determine if both bitsets are equal (faster than checking if the XOR of the two is === 0).
325 | * Both bitsets must have the same number of words, no length check is performed to prevent and overflow.
326 | * @param {BitSet} bs
327 | * @returns {boolean} true if the entire bitset is empty, else false
328 | */
329 | BitSet.prototype.isEqual = function (bs) {
330 | var i;
331 | for (i = 0; i < this.arr.length; i++) {
332 | if (this.arr[i] !== bs.arr[i]) {
333 | return false;
334 | }
335 | }
336 | return true;
337 | };
338 |
339 | /**
340 | * Get a string representation of the entire bitset, including leading 0s (useful for debugging)
341 | * @returns {string} a base 2 representation of the entire bitset
342 | */
343 | BitSet.prototype.toString = function () {
344 | var i, str, fullString = '';
345 | for (i = this.arr.length - 1; i >= 0; i--) {
346 | str = this.arr[i].toString(2);
347 | fullString += ('0000000000000000000000000000000' + str).slice(-BITS_PER_INT);
348 | }
349 | return fullString;
350 | };
351 |
352 | /**
353 | * Find first set bit (useful for processing queues, breadth-first tree searches, etc.)
354 | * @param {number} _startWord the word to start with (only used internally by nextSetBit)
355 | * @returns {number} the index of the first set bit in the bitset, or -1 if not found
356 | */
357 | BitSet.prototype.ffs = function (_startWord) {
358 | var setVal, i, fs = -1;
359 | _startWord = _startWord || 0;
360 | for (i = _startWord; i < this.arr.length; i++) {
361 | setVal = this.arr[i];
362 | if (setVal === 0) continue;
363 | fs = _lsb(setVal) + i * BITS_PER_INT;
364 | break;
365 | }
366 | return fs <= this.MAX_BIT ? fs : -1;
367 | };
368 |
369 | /**
370 | * Find first zero (unset bit)
371 | * @param {number} _startWord the word to start with (only used internally by nextUnsetBit)
372 | * @returns {number} the index of the first unset bit in the bitset, or -1 if not found
373 | */
374 | BitSet.prototype.ffz = function (_startWord) {
375 | var i, setVal, fz = -1;
376 | _startWord = _startWord || 0;
377 | for (i = _startWord; i < this.arr.length; i++) {
378 | setVal = this.arr[i];
379 | if (setVal === 0x7fffffff) continue;
380 | setVal ^= 0x7fffffff;
381 | fz = _lsb(setVal) + i * BITS_PER_INT;
382 | break;
383 | }
384 | return fz <= this.MAX_BIT ? fz : -1;
385 | };
386 |
387 | /**
388 | *
389 | * Find last set bit
390 | * @param {number} _startWord the word to start with (only used internally by previousSetBit)
391 | * @returns {number} the index of the last set bit in the bitset, or -1 if not found
392 | */
393 | BitSet.prototype.fls = function (_startWord) {
394 | var i, setVal, ls = -1;
395 | if (_startWord === undefined) _startWord = this.arr.length - 1;
396 | for (i = _startWord; i >= 0; i--) {
397 | setVal = this.arr[i];
398 | if (setVal === 0) continue;
399 | ls = _msb(setVal) + i * BITS_PER_INT;
400 | break;
401 | }
402 | return ls;
403 | };
404 |
405 | /**
406 | *
407 | * Find last zero (unset bit)
408 | * @param {number} _startWord the word to start with (only used internally by previousUnsetBit)
409 | * @returns {number} the index of the last unset bit in the bitset, or -1 if not found
410 | */
411 | BitSet.prototype.flz = function (_startWord) {
412 | var i, setVal, ls = -1;
413 | if (_startWord === undefined) _startWord = this.arr.length - 1;
414 | for (i = _startWord; i >= 0; i--) {
415 | setVal = this.arr[i];
416 | if (i === this.arr.length - 1) {
417 | var wordIdx = this.MAX_BIT % BITS_PER_INT;
418 | var unusedBitCount = BITS_PER_INT - wordIdx - 1;
419 | setVal |= ((1 << unusedBitCount) - 1) << (wordIdx + 1);
420 | }
421 | if (setVal === 0x7fffffff) continue;
422 | setVal ^= 0x7fffffff;
423 | ls = _msb(setVal) + i * BITS_PER_INT;
424 | break;
425 | }
426 | return ls;
427 | };
428 |
429 | /**
430 | * Find first set bit, starting at a given index
431 | * @param {number} idx the starting index for the next set bit
432 | * @returns {number} the index of the next set bit >= idx, or -1 if not found
433 | */
434 | BitSet.prototype.nextSetBit = function (idx) {
435 | var startWord = this._getWord(idx);
436 | if (startWord === -1) return -1;
437 | var wordIdx = idx % BITS_PER_INT;
438 | var len = BITS_PER_INT - wordIdx;
439 | var mask = ((1 << (len)) - 1) << wordIdx;
440 | var reducedWord = this.arr[startWord] & mask;
441 | if (reducedWord > 0) {
442 | return _lsb(reducedWord) + startWord * BITS_PER_INT;
443 | }
444 | return this.ffs(startWord + 1);
445 | };
446 |
447 | /**
448 | * Find first unset bit, starting at a given index
449 | * @param {number} idx the starting index for the next unset bit
450 | * @returns {number} the index of the next unset bit >= idx, or -1 if not found
451 | */
452 | BitSet.prototype.nextUnsetBit = function (idx) {
453 | var startWord = this._getWord(idx);
454 | if (startWord === -1) return -1;
455 | var mask = ((1 << (idx % BITS_PER_INT)) - 1);
456 | var reducedWord = this.arr[startWord] | mask;
457 | if (reducedWord === 0x7fffffff) {
458 | return this.ffz(startWord + 1);
459 | }
460 | return _lsb(0x7fffffff ^ reducedWord) + startWord * BITS_PER_INT;
461 | };
462 |
463 | /**
464 | * Find last set bit, up to a given index
465 | * @param {number} idx the starting index for the next unset bit (going in reverse)
466 | * @returns {number} the index of the next unset bit <= idx, or -1 if not found
467 | */
468 | BitSet.prototype.previousSetBit = function (idx) {
469 | var startWord = this._getWord(idx);
470 | if (startWord === -1) return -1;
471 | var mask = 0x7fffffff >>> (BITS_PER_INT - (idx % BITS_PER_INT) - 1);
472 | var reducedWord = this.arr[startWord] & mask;
473 | if (reducedWord > 0) {
474 | return _msb(reducedWord) + startWord * BITS_PER_INT;
475 | }
476 | return this.fls(startWord - 1);
477 | };
478 |
479 | /**
480 | * Find last unset bit, up to a given index
481 | * @param {number} idx the starting index for the next unset bit (going in reverse)
482 | * @returns {number} the index of the next unset bit <= idx, or -1 if not found
483 | */
484 | BitSet.prototype.previousUnsetBit = function (idx) {
485 | var startWord = this._getWord(idx);
486 | if (startWord === -1) return -1;
487 | var wordIdx = idx % BITS_PER_INT;
488 | var mask = ((1 << (BITS_PER_INT - wordIdx - 1)) - 1) << wordIdx + 1;
489 | var reducedWord = this.arr[startWord] | mask;
490 | if (reducedWord === 0x7fffffff) {
491 | return this.flz(startWord - 1);
492 | }
493 | return _msb(0x7fffffff ^ reducedWord) + startWord * BITS_PER_INT;
494 | };
495 |
496 | /**
497 | *
498 | * @param {number} idx position of bit in bitset
499 | * @returns {number} the word where the index is located, or -1 if out of range
500 | * @private
501 | */
502 | BitSet.prototype._getWord = function (idx) {
503 | return (idx < 0 || idx > this.MAX_BIT) ? -1 : ~~(idx / BITS_PER_INT);
504 | };
505 |
506 | /**
507 | * Shared function for setting, unsetting, or toggling a range of bits
508 | * @param {number} from the starting index of the range to set
509 | * @param {number} to the ending index of the range to set
510 | * @param {Function} func function to run (set, unset, or toggle)
511 | * @returns {boolean} true if set was successful, else false
512 | * @private
513 | */
514 | BitSet.prototype._doRange = function (from, to, func) {
515 | var i, curStart, curEnd, len;
516 | if (to < from) {
517 | to ^= from;
518 | from ^= to;
519 | to ^= from;
520 | }
521 | var startWord = this._getWord(from);
522 | var endWord = this._getWord(to);
523 | if (startWord === -1 || endWord === -1) return false;
524 | for (i = startWord; i <= endWord; i++) {
525 | curStart = (i === startWord) ? from % BITS_PER_INT : 0;
526 | curEnd = (i === endWord) ? to % BITS_PER_INT : BITS_PER_INT - 1;
527 | len = curEnd - curStart + 1;
528 | this.arr[i] = func(this.arr[i], len, curStart);
529 |
530 | }
531 | return true;
532 | };
533 |
534 | /**
535 | * Both bitsets must have the same number of words, no length check is performed to prevent and overflow.
536 | * @param {BitSet | Number} bsOrIdx a bitset or single index to check (useful for LP, DP problems)
537 | * @param {Function} func the operation to perform (and, or, xor)
538 | * @returns {BitSet} a new bitset that is the bitwise operation of the two
539 | * @private
540 | */
541 | BitSet.prototype._op = function (bsOrIdx, func) {
542 | var i, arr1, arr2, len, newBS, word;
543 | arr1 = this.arr;
544 | if (typeof bsOrIdx === 'number') {
545 | word = this._getWord(bsOrIdx);
546 | newBS = this.clone();
547 | if (word !== -1) newBS.arr[word] = func(arr1[word], 1 << (bsOrIdx % BITS_PER_INT));
548 | } else {
549 | arr2 = bsOrIdx.arr;
550 | len = arr1.length;
551 | newBS = new BitSet(this.MAX_BIT + 1);
552 | for (i = 0; i < len; i++) {
553 | newBS.arr[i] = func(arr1[i], arr2[i]);
554 | }
555 | }
556 | return newBS;
557 | };
558 |
559 | /**
560 | *
561 | * Returns the least signifcant bit, or 0 if none set, so a prior check to see if the word > 0 is required
562 | * @param {number} word the current array
563 | * @returns {number} the index of the least significant bit in the current array
564 | * @private
565 | *
566 | */
567 | function _lsb(word) {
568 | return multiplyDeBruijnBitPosition[(((word & -word) * 0x077CB531)) >>> 27];
569 | }
570 |
571 | /**
572 | * Returns the least signifcant bit, or 0 if none set, so a prior check to see if the word > 0 is required
573 | * @param word the current array
574 | * @returns {number} the index of the most significant bit in the current array
575 | * @private
576 | */
577 | function _msb(word) {
578 | word |= word >> 1;
579 | word |= word >> 2;
580 | word |= word >> 4;
581 | word |= word >> 8;
582 | word |= word >> 16;
583 | word = (word >> 1) + 1;
584 | return multiplyDeBruijnBitPosition[(word * 0x077CB531) >>> 27];
585 | }
586 |
587 | function _toggleFunc(word, len, curStart) {
588 | var mask = (((1 << len) - 1) << curStart);
589 | return word ^ mask;
590 | }
591 |
592 | function _setFunc(word, len, curStart) {
593 | var mask = (((1 << len) - 1) << curStart);
594 | return word | mask;
595 | }
596 |
597 | function _unsetFunc(word, len, curStart) {
598 | var mask = 0x7fffffff ^ (((1 << len) - 1) << curStart);
599 | return word & mask;
600 | }
601 |
602 | function _and(word1, word2) {
603 | return word1 & word2;
604 | }
605 |
606 | function _or(word1, word2) {
607 | return word1 | word2;
608 | }
609 |
610 | function _xor(word1, word2) {
611 | return word1 ^ word2;
612 | }
613 |
614 | if (typeof define === 'function' && define['amd']) {
615 | define([], function () {
616 | return BitSet;
617 | });
618 | } else if (typeof exports === 'object') {
619 | module['exports'] = BitSet;
620 | }
621 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fast-bitset",
3 | "version": "1.3.2",
4 | "description": "a fast bitset with some neat methods",
5 | "main": "./app/BitSet.js",
6 | "keywords": [
7 | "bit",
8 | "bitset",
9 | "bitwise",
10 | "bit operations",
11 | "bitmap"
12 | ],
13 | "scripts": {
14 | "test": "./node_modules/.bin/jasmine-node spec",
15 | "docs": "jsdoc2md app/*.js > api.md"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/mattkrick/fast-bitset.git"
20 | },
21 | "author": "Matt Krick ",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/mattkrick/fast-bitset/issues"
25 | },
26 | "homepage": "https://github.com/mattkrick/fast-bitset#readme",
27 | "devDependencies": {
28 | "jasmine-node": "^1.14.5",
29 | "jsdoc-to-markdown": "^1.1.1"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/spec/BitsetSpec.js:
--------------------------------------------------------------------------------
1 | describe("BitSet", function () {
2 | var BitSet = require('../app/BitSet.js');
3 |
4 | it('should create a bitset from a dehydrated string', function () {
5 | var dehydratedBS = '1073741824,2147483647,15,0,99';
6 | var bs = new BitSet(dehydratedBS);
7 | expect(bs.dehydrate()).toBe(dehydratedBS);
8 | });
9 |
10 | it('should set an individual bit', function () {
11 | var bs = new BitSet(100);
12 | bs.set(31);
13 | expect(bs.get(31)).toBe(true);
14 | });
15 |
16 | it('should find first set', function () {
17 | var bs = new BitSet(100);
18 | bs.set(31);
19 | expect(bs.ffs()).toBe(31);
20 | });
21 |
22 | it('should not be able to find first set in an empty bitset', function () {
23 | var bs = new BitSet(100);
24 | expect(bs.ffs()).toBe(-1);
25 | });
26 |
27 | it('should find first zero', function () {
28 | var bs = new BitSet(100);
29 | bs.setRange(0,31);
30 | expect(bs.ffz()).toBe(32);
31 | });
32 |
33 | it('should not be able to find first zero in a full bitset', function () {
34 | var bs = new BitSet('2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,255,0,224');
35 | expect(bs.ffz()).toBe(-1);
36 | });
37 |
38 |
39 | it('should set a range of len 1', function () {
40 | var bs = new BitSet(100);
41 | bs.setRange(31,31);
42 | expect(bs.dehydrate()).toBe('1,1,99');
43 | });
44 |
45 | it('should set a range of len 31', function () {
46 | var bs = new BitSet(100);
47 | bs.setRange(0,30);
48 | expect(bs.dehydrate()).toBe('2147483647,0,99');
49 | });
50 |
51 | it('should set a range that spans 3 words', function () {
52 | var bs = new BitSet(100);
53 | bs.setRange(30,65);
54 | expect(bs.dehydrate()).toBe('1073741824,2147483647,15,0,99');
55 | });
56 |
57 | it('should AND two bitsets', function () {
58 | var bs1 = new BitSet(100);
59 | var bs2 = new BitSet(100);
60 | bs1.setRange(1,10);
61 | bs2.setRange(10,33);
62 | var bs3 = bs1.and(bs2);
63 | expect(bs3.dehydrate()).toBe('1024,0,99');
64 | });
65 |
66 | it('should AND a bitset and an index', function () {
67 | var bs1 = new BitSet(100);
68 | bs1.setRange(1,10);
69 | var bs3 = bs1.and(1);
70 | expect(bs3.dehydrate()).toBe('2,0,99');
71 | });
72 |
73 | it('should OR two bitsets', function () {
74 | var bs1 = new BitSet(100);
75 | var bs2 = new BitSet(100);
76 | bs1.setRange(1,10);
77 | bs2.setRange(10,33);
78 | var bs3 = bs1.or(bs2);
79 | expect(bs3.dehydrate()).toBe('2147483646,7,0,99');
80 | });
81 |
82 | it('should XOR two bitsets', function () {
83 | var bs1 = new BitSet(100);
84 | var bs2 = new BitSet(100);
85 | bs1.setRange(1,10);
86 | bs2.setRange(10,33);
87 | var bs3 = bs1.xor(bs2);
88 | expect(bs3.dehydrate()).toBe('2147482622,7,0,99');
89 | });
90 |
91 | it('should detect empty arrays', function () {
92 | var bs = new BitSet(100);
93 | expect(bs.isEmpty()).toBe(true);
94 | bs.set(31);
95 | expect(bs.isEmpty()).toBe(false);
96 | });
97 |
98 | it('should unset a bit', function () {
99 | var bs = new BitSet(100);
100 | bs.set(31);
101 | bs.unset(31);
102 | expect(bs.get(31)).toBe(false);
103 | });
104 |
105 | it('should toggle a bit', function () {
106 | var bs = new BitSet(100);
107 | bs.toggle(31);
108 | expect(bs.get(31)).toBe(true);
109 | bs.toggle(31);
110 | expect(bs.get(31)).toBe(false);
111 | });
112 |
113 | it('should toggle a range', function () {
114 | var bs = new BitSet(100);
115 | bs.toggleRange(31,35);
116 | bs.toggleRange(32,34);
117 | bs.toggleRange(33,33);
118 | expect(bs.dehydrate()).toBe('21,1,99');
119 | });
120 |
121 | it('should unset a range', function () {
122 | var bs = new BitSet(100);
123 | bs.setRange(29,59);
124 | bs.unsetRange(30,58);
125 | expect(bs.dehydrate()).toBe('536870912,268435456,0,99');
126 | });
127 |
128 | it('should clear a bitset', function () {
129 | var bs = new BitSet(100);
130 | bs.setRange(29,59);
131 | bs.clear();
132 | expect(bs.isEmpty()).toBe(true);
133 | });
134 |
135 | it('should check if one bitset is subset of another', function () {
136 | var bs = new BitSet(100);
137 | var bs2 = new BitSet(100);
138 |
139 | expect(bs.isSubsetOf(bs2)).toBe(true);
140 |
141 | bs.setRange(30, 60);
142 | bs2.setRange(30, 60);
143 |
144 | expect(bs2.isSubsetOf(bs)).toBe(true);
145 |
146 | bs2.clear();
147 | bs2.setRange(31, 59);
148 |
149 | expect(bs2.isSubsetOf(bs)).toBe(true);
150 | expect(bs.isSubsetOf(bs2)).toBe(false);
151 | })
152 |
153 | it('should check for equality', function () {
154 | var bs = new BitSet(100);
155 | bs.setRange(29,59);
156 | var bs2 = new BitSet(100);
157 | bs2.setRange(29,59);
158 | expect(bs.isEqual(bs2)).toBe(true);
159 | });
160 |
161 | it('should find next set bit in the same word', function () {
162 | var bs = new BitSet(100);
163 | bs.setRange(10,30);
164 | expect(bs.nextSetBit(1)).toBe(10);
165 | });
166 |
167 | it('should find next set bit the next word', function () {
168 | var bs = new BitSet(100);
169 | bs.setRange(66,99);
170 | expect(bs.nextSetBit(31)).toBe(66);
171 | });
172 |
173 | it('should find next unset bit in the same word', function () {
174 | var bs = new BitSet(100);
175 | bs.setRange(10,30);
176 | expect(bs.nextUnsetBit(1)).toBe(1);
177 | });
178 |
179 | it('should find next set bit the next word', function () {
180 | var bs = new BitSet(100);
181 | bs.setRange(10,30);
182 | expect(bs.nextUnsetBit(11)).toBe(31);
183 | });
184 |
185 | it('should find the last set bit', function () {
186 | var bs = new BitSet(100);
187 | bs.setRange(10,30);
188 | expect(bs.fls()).toBe(30);
189 | });
190 |
191 | it('should find the previous set bit', function () {
192 | var bs = new BitSet(100);
193 | bs.setRange(10,30);
194 | expect(bs.previousSetBit(90)).toBe(30);
195 | });
196 |
197 | it('should find the last unset bit', function () {
198 | var bs = new BitSet(100);
199 | bs.setRange(60,99);
200 | expect(bs.flz()).toBe(59);
201 | });
202 |
203 | it('should find the previous unset bit', function () {
204 | var bs = new BitSet(100);
205 | bs.setRange(60,99);
206 | expect(bs.previousUnsetBit(80)).toBe(59);
207 | });
208 |
209 | it('should clone a bitset with only 1 word', function () {
210 | var bs = new BitSet(10);
211 | bs.setRange(6,9);
212 | bs2 = bs.clone();
213 | expect(bs.dehydrate()).toBe(bs2.dehydrate());
214 | });
215 |
216 | it('should clone a bitset', function () {
217 | var bs = new BitSet(100);
218 | bs.setRange(60,99);
219 | bs2 = bs.clone();
220 | expect(bs.dehydrate()).toBe(bs2.dehydrate());
221 | });
222 |
223 | it('should count number of bits set', function () {
224 | var bs = new BitSet(100);
225 | bs.setRange(60,99);
226 | expect(bs.getCardinality()).toBe(40);
227 | });
228 |
229 | it('should return an array of set bits', function () {
230 | var bs = new BitSet(100);
231 | bs.set(30);
232 | bs.setRange(98,99);
233 | var range = [30,98,99];
234 | expect(bs.getIndices()).toEqual(range);
235 | });
236 |
237 | it('should set bit success which read from dehydrate string', function () {
238 |
239 | var bs = new BitSet('2147483646,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,0,9999999');
240 | expect(bs.get(899)).toBe(false);
241 | expect(bs.set(899, true)).toBe(true);
242 | expect(bs.get(899)).toBe(true);
243 | });
244 | //
245 | it('should rotate a bitset', function () {
246 |
247 | var sizes = [10,34,70,500];
248 | for(var i=0; i