├── .gitignore ├── .jshintrc ├── .travis.yml ├── Makefile ├── index.js ├── license ├── package.json ├── readme.md └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Numerous always-ignore extensions 2 | *.diff 3 | *.err 4 | *.orig 5 | *.log 6 | *.rej 7 | *.swo 8 | *.swp 9 | *.vi 10 | *~ 11 | 12 | # OS or Editor folders 13 | .DS_Store 14 | .cache 15 | .project 16 | .settings 17 | nbproject 18 | thumbs.db 19 | 20 | # Logs 21 | .log 22 | .pid 23 | .sock 24 | 25 | # Folders to ignore 26 | node_modules 27 | .hg 28 | .svn 29 | publish 30 | .idea 31 | _dev 32 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true 3 | , "asi": true 4 | , "nonstandard": true 5 | , "es5": true 6 | , "expr": true 7 | , "strict": false 8 | , "loopfunc": true 9 | , "smarttabs": true 10 | , "maxlen": 90 11 | , "newcap": false 12 | , "undef": true 13 | , "unused": false 14 | , "onecase": true 15 | , "indent": 2 16 | , "laxcomma": true 17 | , "laxbreak": true 18 | , "white": false 19 | , "shadow": true 20 | , "proto": true 21 | , "globals": { 22 | "describe": false 23 | , "it": false 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash 2 | 3 | # Mocha v1.9.0 4 | test: 5 | mocha -R spec test.js 6 | 7 | # JSHint v1.1.0 8 | hint: 9 | @jshint index.js test.js lib/*.js 10 | 11 | .PHONY: test hint min -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*! 4 | * Module dependencies. 5 | */ 6 | 7 | var slice = Array.prototype.slice 8 | 9 | /*! 10 | * Array proxy methods. 11 | */ 12 | 13 | var methods = ['concat', 'every', 'filter', 'forEach', 'indexOf', 14 | , 'join', 'lastIndexOf', 'map', 'pop', 'push', 'reduce', 'reduceRight' 15 | , 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'unshift' 16 | ] 17 | 18 | /** 19 | * Utility: Find the longest array or string in argument list 20 | * 21 | * @param {...} arrays or strings to check 22 | * @return {Array} longest array 23 | * @api private 24 | */ 25 | 26 | function longest() { 27 | var args = slice.call(arguments) 28 | , len = 0, resp, arg 29 | for (var i = 0; i < args.length; i++) { 30 | arg = args[i] 31 | if (arg.length >= len) { 32 | len = arg.length 33 | resp = arg 34 | } 35 | } 36 | return resp 37 | } 38 | 39 | /** 40 | * BitArray constructor 41 | * 42 | * @param {Buffer} buffer of 32bit integers 43 | * @param {Number} set length of bits 44 | * @return {BitArray} new BitArray instance 45 | */ 46 | 47 | function BitArray(x, len, oct) { 48 | this.__bits = BitArray.parse(x, oct) 49 | this.__defineGetter__('length', function() { 50 | return this.__bits.length 51 | }) 52 | len && this.fill(len) 53 | this.__len = len 54 | } 55 | 56 | /*! 57 | * Max length or size for a bit array (2^32 - 1) 58 | */ 59 | 60 | BitArray.max = Math.pow(2, 32) - 1 61 | 62 | /*! 63 | * Utilities. 64 | */ 65 | 66 | /** 67 | * Factory method for help with Array.map calls 68 | * 69 | * @param {Buffer} buffer of 32bit integers 70 | * @param {Number} set length of bits 71 | * @return {BitArray} new BitArray instance 72 | */ 73 | 74 | BitArray.factory = function(x, len, oct) { 75 | return new BitArray(x, len, oct) 76 | } 77 | 78 | /** 79 | * Ensure the given array is in the form of an octet, or, has 80 | * a length with a multiple of 8, zero fill missing indexes 81 | * 82 | * @param {Array} target 83 | * @return {Array} zero filled octet array 84 | */ 85 | 86 | BitArray.octet = function(arr) { 87 | var len = arr.length 88 | , fill = len + (8 - len % 8) 89 | 90 | if (len !== 0 && len % 8 === 0) { 91 | return arr 92 | } 93 | for (var i = len; i < fill; i++) { 94 | arr[i] = 0 95 | } 96 | return arr 97 | } 98 | 99 | /** 100 | * Cast a 32bit integer or an array or buffer of 32bit integers into a bitmap 101 | * array, ensuring that they are a full octet length if specified 102 | * 103 | * @param {Number|Array|Buffer} 32bit integer or array or buffer of 32bit ints 104 | * @param {Boolean} ensure octet 105 | * @return {Array} bitmap array 106 | */ 107 | 108 | BitArray.parse = function(x, oct) { 109 | var bits = [] 110 | , tmp = x 111 | 112 | if (typeof x === 'undefined') { 113 | return bits 114 | } 115 | // Check for binary string 116 | if (typeof x === 'string') { 117 | for (var i = 0; i < x.length; i++) { 118 | bits.push(+x[i]) 119 | } 120 | return bits.reverse() 121 | } 122 | // Check for single 32bit integer 123 | if (typeof x === 'number') { 124 | while (tmp > 0) { 125 | bits.push(tmp % 2) 126 | tmp = Math.floor(tmp / 2) 127 | } 128 | oct && (bits = BitArray.octet(bits)) 129 | return bits.reverse() 130 | } 131 | // Check for direct bit array 132 | if (Array.isArray(x)) { 133 | return x 134 | } 135 | // Assumed to be array / buffer of 32bit integers 136 | for (var i = 0; i < x.length; i++) { 137 | bits = bits.concat(BitArray.parse(x[i], true)) 138 | } 139 | return bits 140 | } 141 | 142 | /** 143 | * Perform an equality check on two bit arrays, they are equal if 144 | * all bits are the same 145 | * 146 | * @param {BitArray} first 147 | * @param {BitArray} second 148 | * @return {Boolean} equal 149 | */ 150 | 151 | BitArray.equals = function(a, b) { 152 | if (a.__bits.length !== b.__bits.length) return false 153 | for (var i = 0; i < a.__bits.length; i++) { 154 | if (a.__bits[i] !== b.__bits[i]) return false 155 | } 156 | return true 157 | } 158 | 159 | /*! 160 | * Instantiation methods. 161 | */ 162 | 163 | /** 164 | * Create a new BitArray instance from a binary string 165 | * 166 | * @param {String} binary data 167 | * @return {BitArray} new instance 168 | */ 169 | 170 | BitArray.fromBinary = function(str) { 171 | var bits = [] 172 | for (var i = 0; i < str.length; i++) { 173 | bits.push(+str[i]) 174 | } 175 | return new BitArray().set(bits.reverse()) 176 | } 177 | 178 | /** 179 | * Create a new BitArray instance setting values from offsets 180 | * 181 | * @param {Array} offset positions 182 | * @return {BitArray} new instance 183 | */ 184 | 185 | BitArray.fromOffsets = function(offs) { 186 | var bits = new BitArray() 187 | for (var i = 0; i < offs.length; i++) { 188 | bits.set(offs[i], 1) 189 | } 190 | return bits 191 | } 192 | 193 | /** 194 | * Create a new BitArray instance converting from a base 10 number 195 | * 196 | * @param {Number|String} number value 197 | * @return {BitArray} new instance 198 | */ 199 | 200 | BitArray.fromDecimal = 201 | BitArray.fromNumber = function(num) { 202 | var bits = [], tmp = +num 203 | while (tmp > 0) { 204 | bits.push(tmp % 2) 205 | tmp = Math.floor(tmp / 2) 206 | } 207 | return new BitArray().set(bits) 208 | } 209 | 210 | /** 211 | * Create a new BitArray instance converting from a base 16 number 212 | * 213 | * @param {Number|String} hexidecimal value 214 | * @return {BitArray} new instance 215 | */ 216 | 217 | BitArray.fromHex = 218 | BitArray.fromHexadecimal = function(hex) { 219 | hex = ('' + hex).toLowerCase() 220 | if (!~(hex).indexOf('0x')) hex = '0x' + hex 221 | return BitArray.fromDecimal(+hex) 222 | } 223 | 224 | /** 225 | * Create a new BitArray instance from a 32bit integer 226 | * 227 | * @param {Number} 32bit integer 228 | * @return {BitArray} new instance 229 | */ 230 | 231 | BitArray.from32Integer = function(num) { 232 | var bits = [] 233 | , tmp = num 234 | 235 | while (tmp > 0) { 236 | bits.push(tmp % 2) 237 | tmp = Math.floor(tmp / 2) 238 | } 239 | bits = BitArray.octet(bits) 240 | return new BitArray().set(bits.reverse()) 241 | } 242 | 243 | /** 244 | * Create a new BitArray instance from a node Buffer 245 | * 246 | * @param {Buffer} buffer of 32bit integers 247 | * @return {BitArray} new instance 248 | */ 249 | 250 | BitArray.fromRedis = 251 | BitArray.fromBuffer = function(buf) { 252 | var bits = '' 253 | for (var i = 0; i < buf.length; i++) { 254 | bits += BitArray.from32Integer(buf[i]).__bits.join('') 255 | } 256 | return new BitArray().set(bits.split('').map(function (i) { 257 | return parseInt(i) 258 | })) 259 | } 260 | 261 | /** 262 | * Find the offsets of all flipped bits 263 | * 264 | * @param {Array} bit array 265 | * @return {Array} list of offsets 266 | */ 267 | 268 | BitArray.toOffsets = function(bits) { 269 | var offs = [] 270 | for (var i = 0; i < bits.length; i++) { 271 | bits[i] === 1 && offs.push(i) 272 | } 273 | return offs 274 | } 275 | 276 | /*! 277 | * Output methods. 278 | */ 279 | 280 | /** 281 | * Convert a bit array to a node Buffer object 282 | * 283 | * @param {Array} bit array 284 | * @return {Buffer} buffer of 32bit integers 285 | */ 286 | 287 | BitArray.toBuffer = function(bits) { 288 | var buf = [], int32, tmp 289 | for (var i = 0; i < bits.length; i += 8) { 290 | int32 = 0 291 | tmp = bits.slice(i, i + 8) 292 | for (var k = 0; k < tmp.length; k++) { 293 | int32 = (int32 * 2) + tmp[k] 294 | } 295 | buf.push(int32) 296 | } 297 | return new Buffer(buf) 298 | } 299 | 300 | /** 301 | * Convert a bit array into a base 10 number 302 | * 303 | * @param {Array} bit array 304 | * @return {Number} base 10 conversion 305 | */ 306 | 307 | BitArray.toNumber = function(bits) { 308 | var num = 0 309 | for (var i = 0; i < bits.length; i++) { 310 | if (bits[i]) num += Math.pow(2, i) 311 | } 312 | return num 313 | } 314 | 315 | /** 316 | * Convert a bit array into hexadecimal 317 | * 318 | * @param {Array} bit array 319 | * @return {String} hexadecimal conversion 320 | */ 321 | 322 | BitArray.toHex = 323 | BitArray.toHexadecimal = function(bits) { 324 | return BitArray.toNumber(bits).toString(16) 325 | } 326 | 327 | /*! 328 | * Bitwise operations. 329 | */ 330 | 331 | /** 332 | * Perform a bitwise intersection, `AND` of bit arrays 333 | * 334 | * @param {...} any number of bit arrays 335 | * @return {Array} intersected bit array 336 | */ 337 | 338 | BitArray.and = 339 | BitArray.intersect = function() { 340 | var args = slice.call(arguments) 341 | , src = longest.apply(null, arguments) 342 | , len = args.length 343 | , bits = [], aLen 344 | 345 | for (var i = 0; i < src.length; i++) { 346 | aLen = args.filter(function(x) { 347 | return x[i] === 1 348 | }).length 349 | bits.push(aLen === len ? 1 : 0) 350 | } 351 | return bits 352 | } 353 | 354 | /** 355 | * Perform a bitwise union, `OR` of bit arrays 356 | * 357 | * @param {...} any number of bit arrays 358 | * @return {Array} unioned bit array 359 | */ 360 | 361 | BitArray.or = 362 | BitArray.union = function() { 363 | var args = slice.call(arguments) 364 | , src = longest.apply(null, args) 365 | , bits = [], aLen 366 | 367 | for (var i = 0; i < src.length; i++) { 368 | aLen = args.filter(function(x) { 369 | return x[i] === 1 370 | }).length 371 | bits.push(aLen ? 1 : 0) 372 | } 373 | return bits 374 | } 375 | 376 | /** 377 | * Perform a bitwise difference, `XOR` of two bit arrays 378 | * 379 | * @param {...} any number of bit arrays 380 | * @return {Array} difference array 381 | */ 382 | 383 | BitArray.xor = 384 | BitArray.difference = function() { 385 | var args = slice.call(arguments) 386 | , aLen = args.length 387 | , src = longest.apply(null, args) 388 | , bits = [], bLen 389 | 390 | for (var i = 0; i < src.length; i++) { 391 | var bit = src[i] 392 | bLen = args.filter(function(x) { 393 | return x[i] === 1 394 | }).length 395 | bits.push(bLen === 1 || bLen === aLen ? 1 : 0) 396 | } 397 | return bits 398 | } 399 | 400 | /** 401 | * Perform a bitwise `NOT` operation on a single bit array 402 | * 403 | * @param {Array} bit array 404 | * @return {Array} bit array 405 | */ 406 | 407 | BitArray.not = 408 | BitArray.reverse = function(arr) { 409 | var bits = [] 410 | for (var i = 0; i < arr.length; i++) { 411 | bits.push(arr[i] === 1 ? 0 : 1) 412 | } 413 | return bits 414 | } 415 | 416 | /** 417 | * Find cardinality from a 32bit integer, a bit array, or a node buffer of 32bit 418 | * integers, which will buffer 4 octects at a time for performance increase. 419 | * 420 | * @param {Number|Array|Buffer} 32bit integer, bitarray, buffered 32bit integers 421 | * @return {Number} cardinality 422 | */ 423 | 424 | BitArray.count = 425 | BitArray.population = 426 | BitArray.bitcount = 427 | BitArray.cardinality = function(x) { 428 | var val = 0 429 | , tmp = 0 430 | // Check for 32bit integer 431 | if (typeof x === 'number') { 432 | x -= ((x >> 1) & 0x55555555) 433 | x = (((x >> 2) & 0x33333333) + (x & 0x33333333)) 434 | x = (((x >> 4) + x) & 0x0f0f0f0f) 435 | x += (x >> 8) 436 | x += (x >> 16) 437 | return(x & 0x0000003f) 438 | } 439 | // Check for array of bits 440 | if (Array.isArray(x)) { 441 | for (var i = 0; i < x.length; i++) { 442 | if (x[i]) val += 1 443 | } 444 | return val 445 | } 446 | // Assumed to be a buffer 447 | for (var i = 0; i < x.length ; i+=4) { 448 | tmp = x[i]; 449 | tmp += x[i + 1] << 8 450 | tmp += x[i + 2] << 16 451 | tmp += x[i + 3] << 24 452 | val += BitArray.cardinality(tmp) 453 | } 454 | return val 455 | } 456 | 457 | /*! 458 | * Instance methods. 459 | */ 460 | 461 | /** 462 | * Zerofill the current bit array to a given offset 463 | * 464 | * @param {Number} offset index 465 | */ 466 | 467 | BitArray.prototype.fill = function(idx) { 468 | while (idx > this.__bits.length) { 469 | this.__bits.push(0) 470 | } 471 | return this 472 | } 473 | 474 | /** 475 | * Copy the current bits into a new BitArray instance 476 | * 477 | * @return {BitArray} cloned instance 478 | */ 479 | 480 | BitArray.prototype.clone = 481 | BitArray.prototype.copy = function() { 482 | return new BitArray().set(this.toBits()) 483 | } 484 | 485 | /** 486 | * Reset to factory defaults 487 | */ 488 | 489 | BitArray.prototype.clear = 490 | BitArray.prototype.reset = function() { 491 | this.__bits = [] 492 | this.__len && this.fill(this.__len) 493 | return this 494 | } 495 | 496 | /** 497 | * Perform an equality check against another bit array 498 | * 499 | * @param {BitArray} compare 500 | * @return {Boolean} equal 501 | */ 502 | 503 | BitArray.prototype.equals = function(b) { 504 | return BitArray.equals(this, b) 505 | } 506 | 507 | /** 508 | * Set the bit for a given offset 509 | * 510 | * @param {Number} offset index 511 | * @param {Number} bit value 512 | */ 513 | 514 | BitArray.prototype.set = function(idx, val) { 515 | if (Array.isArray(idx)) { 516 | this.__bits = idx 517 | this.__len && this.fill(this.__len) 518 | return this 519 | } 520 | this.fill(idx) 521 | this.__bits[idx] = val ? 1 : 0 522 | return this 523 | } 524 | 525 | /** 526 | * Get the bit at a given offset 527 | * 528 | * @param {Number} offset index 529 | * @param {Number} bit value 530 | */ 531 | 532 | BitArray.prototype.get = function(idx, val) { 533 | this.fill(idx) 534 | return this.__bits[idx] 535 | } 536 | 537 | /** 538 | * Find the cardinality of the current bit array 539 | * 540 | * @return {Number} cardinality 541 | */ 542 | 543 | BitArray.prototype.count = 544 | BitArray.prototype.population = 545 | BitArray.prototype.bitcount = 546 | BitArray.prototype.cardinality = function() { 547 | return BitArray.cardinality(this.__bits) 548 | } 549 | 550 | /** 551 | * Find the offsets of all flipped bits 552 | * 553 | * @return {Array} list of offsets 554 | */ 555 | 556 | BitArray.prototype.toOffsets = function() { 557 | return BitArray.toOffsets(this.__bits) 558 | } 559 | 560 | /** 561 | * Get the binary value of the current bits 562 | * 563 | * @return {String} binary conversion 564 | */ 565 | 566 | BitArray.prototype.toString = function() { 567 | return this.__bits.slice().reverse().join('') 568 | } 569 | 570 | /** 571 | * Get the bitmap array of the current bits 572 | * 573 | * @return {Array} bit array 574 | */ 575 | 576 | BitArray.prototype.toBits = 577 | BitArray.prototype.toArray = 578 | BitArray.prototype.toJSON = function() { 579 | return this.__bits.slice() 580 | } 581 | 582 | /** 583 | * Convert the current bit array into a base 10 number 584 | * 585 | * @return {Number} base 10 conversion 586 | */ 587 | 588 | BitArray.prototype.valueOf = 589 | BitArray.prototype.toNumber = function() { 590 | return BitArray.toNumber(this.__bits) 591 | } 592 | 593 | /** 594 | * Convert the current bit array into hexadecimal 595 | * 596 | * @return {String} hexadecimal conversion 597 | */ 598 | 599 | BitArray.prototype.toHex = function() { 600 | return BitArray.toHex(this.__bits) 601 | } 602 | 603 | /** 604 | * Convert the current bits into a node Buffer 605 | * 606 | * @return {Buffer} buffer of 32bit integers 607 | */ 608 | 609 | BitArray.prototype.toBuffer = function() { 610 | return BitArray.toBuffer(this.__bits) 611 | } 612 | 613 | /*! 614 | * Proxy all Array methods to the current bits 615 | */ 616 | 617 | methods.forEach(function(method) { 618 | BitArray.prototype[method] = function() { 619 | return Array.prototype[method].apply(this.__bits, arguments) 620 | } 621 | }) 622 | 623 | /*! 624 | * Module exports. 625 | */ 626 | 627 | module.exports = BitArray 628 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2013 Beau Sorensen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Beau Sorensen (http://github.com/sorensen)", 3 | "name": "node-bitarray", 4 | "description": "Node buffer and bitarray / bytearray utility", 5 | "version": "0.1.0", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/sorensen/node-bitarray.git" 10 | }, 11 | "engines": { 12 | "node": "0.x" 13 | }, 14 | "main": "index.js", 15 | "scripts": { 16 | "test": "make test" 17 | }, 18 | "dependencies": {}, 19 | "devDependencies": { 20 | "mocha": "1.9.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | BitArray 3 | ======== 4 | 5 | [![Build Status](https://secure.travis-ci.org/sorensen/node-bitarray.png)](http://travis-ci.org/sorensen/node-bitarray) 6 | 7 | Utility library for dealing with bit / byte arrays and converting between node 8 | Buffers and bitarrays. 9 | 10 | Usage 11 | ----- 12 | 13 | ```js 14 | var BitArray = require('node-bitarray') 15 | ``` 16 | 17 | 18 | Methods 19 | ------- 20 | 21 | ### BitArray 22 | 23 | See: `BitArray.factory` for details on instantiation 24 | 25 | 26 | ### BitArray.factory([bits], [length], [asOctet]) 27 | 28 | Return a new BitArray instance. Added for use in Array.map(), if a buffer is passed 29 | in, the `asOctet` will always be set to `true`. 30 | 31 | * `bits` - 32bit integer, or buffer/array of 32bit integers (optional) 32 | * `length` - zero fill the bitarray to the set length 33 | * `asOctet` - ensure resulting array length is a multiple of 8 (optional, default `false`) 34 | 35 | ```js 36 | [255, 128].map(BitArray.factory).map(String) // [ '11111111', '00000001' ] 37 | ``` 38 | 39 | ### BitArray.parse([bits], [asOctet]) 40 | 41 | Convert a 32bit integer into a bit array, the `asOctet` will always be set to `true` 42 | if a Buffer is passed in. 43 | 44 | * `bits` - 32bit integer, or buffer/array of 32bit integers (optional) 45 | * `asOctet` - ensure resulting array length is a multiple of 8 (optional, default `false`) 46 | 47 | ```js 48 | BitArray.parse(255) // [1, 1, 1, 1, 1, 1, 1, 1] 49 | ``` 50 | 51 | 52 | ### BitArray.octet(array) 53 | 54 | Zero fill an array until it represents an octet 55 | 56 | * `array` - bit array 57 | 58 | ```js 59 | BitArray.octet([1, 0, 0]) // [1, 0, 0, 0, 0, 0, 0, 0] 60 | ``` 61 | 62 | 63 | ### BitArray.equals(bitarray, bitarray) 64 | 65 | Perform an equality check on two BitArray instances 66 | 67 | * `bitarray` - bit array to compare 68 | * `bitarray` - bit array to compare 69 | 70 | ```js 71 | var a = new BitArray('0101') 72 | , b = new BitArray('0101') 73 | , c = new BitArray('10') 74 | 75 | BitArray.equals(a, b) // true 76 | BitArray.equals(b, c) // false 77 | ``` 78 | 79 | 80 | ### BitArray.fromBinary(string) 81 | 82 | Create a new instance from a binary string 83 | 84 | * `string` - binary string 85 | 86 | ```js 87 | var bits = BitArray.fromBinary('1001101') 88 | bits.toJSON() // [1, 0, 1, 1, 0, 0, 1] 89 | ``` 90 | 91 | 92 | ### BitArray.fromOffsets(array) 93 | 94 | Create a new instance from a offset positions of set bits 95 | 96 | * `string` - binary string 97 | 98 | ```js 99 | var bits = BitArray.fromOffsets([0, 4, 2, 9]) 100 | bits.toJSON() // [1, 0, 1, 0, 1, 0, 0, 0, 0, 1] 101 | ``` 102 | 103 | 104 | ### BitArray.fromNumber(number) 105 | 106 | Create a new instance from a base 10 number 107 | 108 | * `number` - base 10 number 109 | 110 | **Aliases**: [`fromDecimal`] 111 | 112 | ```js 113 | var bits = BitArray.fromNumber(15) 114 | bits.toJSON() // [1, 1, 1, 1] 115 | ``` 116 | 117 | 118 | ### BitArray.fromHexadecimal(string) 119 | 120 | Create a new instance from a hexadecimal string, case insensitive. 121 | 122 | * `string` - hexadecimal string 123 | 124 | **Aliases**: [`fromHex`] 125 | 126 | ```js 127 | var bits = BitArray.fromHex('Fa') 128 | bits.toJSON() // [0, 1, 0, 1, 1, 1, 1, 1] 129 | ``` 130 | 131 | 132 | ### BitArray.from32Integer(number) 133 | 134 | Create a new instance from a 32bit integer 135 | 136 | * `number` - 32bit integer 137 | 138 | ```js 139 | var bits = BitArray.from32Integer(144) 140 | bits.toJSON() // [1, 0, 0, 1, 0, 0, 0, 0] 141 | ``` 142 | 143 | 144 | ### BitArray.fromBuffer(buffer) 145 | 146 | Create a new instance from a node buffer instance 147 | 148 | * `buffer` - node buffer instance 149 | 150 | **Aliases**: [`fromRedis`] 151 | 152 | ```js 153 | var buf = new Buffer([128, 144, 255]) 154 | , bits = BitArray.fromBuffer(buf) 155 | 156 | bits.toJSON() // [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1] 157 | ``` 158 | 159 | 160 | ### BitArray.and(array1, [array2], [...]) 161 | 162 | Perform a bitwise `AND` operation on any number of bit arrays 163 | 164 | * `...` - any number of bit arrays 165 | 166 | **Alias**: [`intersect`] 167 | 168 | ```js 169 | BitArray.and( 170 | [ 1, 0, 0, 1, 0, 0, 0, 1 ] 171 | , [ 1, 0, 0, 0, 1, 0, 0, 1 ] 172 | , [ 0, 1, 0, 0, 0, 1, 0, 1 ] 173 | ) 174 | //[ 0, 0, 0, 0, 0, 0, 0, 1 ] 175 | ``` 176 | 177 | 178 | ### BitArray.toOffsets(array) 179 | 180 | Find the offset indexes of all set bits 181 | 182 | * `array` - bit array 183 | 184 | ```js 185 | BitArray.toOffsets([0, 0, 1, 0, 1]) // [2, 4] 186 | new BitArray(144).toOffsets() // [0, 3] 187 | ``` 188 | 189 | 190 | ### BitArray.toBuffer(bits) 191 | 192 | ```js 193 | ``` 194 | 195 | 196 | ### BitArray.toNumber(bits) 197 | 198 | Convert an array of bits to a base 10 number 199 | 200 | **Alias**: [`toDecimal`] 201 | 202 | ```js 203 | BitArray.toNumber([1, 0, 1, 1, 0, 1]) // 45 204 | ``` 205 | 206 | 207 | ### BitArray.toHexadecimal(bits) 208 | 209 | Convert an array of bits to a hex string. Results are lowercased. 210 | 211 | **Alias**: [`toHex`] 212 | 213 | ```js 214 | BitArray.toHex([1, 0, 1, 1, 0, 1]) // '2d' 215 | ``` 216 | 217 | 218 | ### BitArray.or(array1, [array2], [...]) 219 | 220 | Perform a bitwise `OR` operation on any number of bit arrays 221 | 222 | * `...` - any number of bit arrays 223 | 224 | **Alias**: [`union`] 225 | 226 | ```js 227 | BitArray.and( 228 | [ 1, 0, 0, 1, 0, 0, 0, 1 ] 229 | , [ 1, 0, 0, 0, 1, 0, 0, 1 ] 230 | , [ 0, 1, 0, 0, 0, 1, 0, 1 ] 231 | ) 232 | //[ 1, 1, 0, 1, 1, 1, 0, 1 ] 233 | ``` 234 | 235 | 236 | ### BitArray.xor(array1, [array2], [...]) 237 | 238 | Perform a bitwise `XOR` operation on any number of bit arrays 239 | 240 | * `...` - any number of bit arrays 241 | 242 | **Alias**: [`difference`] 243 | 244 | ```js 245 | BitArray.xor( 246 | [ 1, 0, 0, 1, 0, 0, 0, 1 ] 247 | , [ 1, 0, 0, 0, 1, 0, 0, 1 ] 248 | , [ 0, 1, 0, 0, 0, 1, 0, 1 ] 249 | ) 250 | //[ 0, 1, 0, 1, 1, 1, 0, 1 ] 251 | ``` 252 | 253 | 254 | ### BitArray.not(array) 255 | 256 | Perform a bitwise `NOT` operation on a single array 257 | 258 | * `array` - single bit array to flip 259 | 260 | **Alias**: [`reverse`] 261 | 262 | ```js 263 | BitArray.not( 264 | [ 1, 0, 0, 1, 0, 0, 0, 1 ] 265 | ) 266 | //[ 0, 1, 1, 0, 1, 1, 1, 0 ] 267 | ``` 268 | 269 | 270 | ### BitArray.bitcount(32bit) 271 | 272 | Find the cardinality of a bit array, 32bit integer, or buffer of 32bit ints 273 | 274 | * `bits` - 32bit integer, buffer of 32bit integers, or bit array 275 | 276 | **Alias**: [`count`, `cardinality`, `population`] 277 | 278 | ```js 279 | BitArray.cardinality(144) // 2 280 | BitArray.population(128) // 1 281 | BitArray.count(new Buffer([255, 128])) // 9 282 | BitArray.bitcount([0,1,1,0,1]) // 3 283 | ``` 284 | 285 | 286 | ### instance.set(index, value) 287 | 288 | Set the value of the bit array at the given index / offset 289 | 290 | * `index` - offset position to set value 291 | * `value` - bit val (1 / 0) 292 | 293 | ```js 294 | new BitArray().set(2, 1) // bits: [0, 0, 1] 295 | ``` 296 | 297 | 298 | ### instance.get(index) 299 | 300 | Get the value of the bit array at the given index / offset 301 | 302 | * `index` - offset position to get 303 | 304 | ```js 305 | new BitArray(144).get(3) // 1 306 | ``` 307 | 308 | 309 | ### instance.fill(offset) 310 | 311 | Zero fill the current bits to the given offset 312 | 313 | * `offset` - zero fill the current bits to the given offset 314 | 315 | ```js 316 | new BitArray().fill(5) // bits: [0, 0, 0, 0, 0, 0] 317 | ``` 318 | 319 | 320 | ### instance.bitcount() 321 | 322 | Get the bitcount of the current bits 323 | 324 | **Alias**: [`count`, `cardinality`, `population`] 325 | 326 | ```js 327 | new BitArray(255).cardinality() // 8 328 | ``` 329 | 330 | 331 | ### instance.toString() 332 | 333 | Get the binary representation of the current bits, can also be used in 334 | string coercion. 335 | 336 | ```js 337 | new BitArray(128).toString() // '00000001' 338 | [new BitArray(255)].join('') // '11111111' 339 | ``` 340 | 341 | 342 | ### instance.valueOf() 343 | 344 | Get the base 10 number representing the current bits, can also be used 345 | in number coercion. 346 | 347 | **Alias**: [`toNumber`, `toDecimal`] 348 | 349 | ```js 350 | new BitArray(144).valueOf() // 9 351 | 1 + new BitArray(255) // 256 352 | ``` 353 | 354 | 355 | ### instance.toJSON() 356 | 357 | Get a copy of the current bit array 358 | 359 | **Alias**: [`toArray`, `toBits`] 360 | 361 | ```js 362 | new BitArray(128).toJSON() // [1,0,0,0,0,0,0,0] 363 | ``` 364 | 365 | 366 | ### instance.toBuffer() 367 | 368 | Convert the current bit array to a node Buffer 369 | 370 | ```js 371 | new BitArray(new Buffer([128, 255])).toBuffer() // 372 | ``` 373 | 374 | 375 | ### instance.toOffsets() 376 | 377 | Convert the current bit array to an offset array 378 | 379 | ```js 380 | new BitArray(new Buffer([128, 255])).toOffsets() // [0, 8, 9, 10, 11, 12, 13, 14, 15] 381 | ``` 382 | 383 | 384 | ### instance.copy() 385 | 386 | Create and return a copy of the current BitArray 387 | 388 | **Aliases**: [`clone`] 389 | 390 | ```js 391 | var bits = new BitArray(255) 392 | , bits2 = bits.clone() 393 | 394 | BitArray.equals(bits, bits2) // true 395 | bits === bits2 // false 396 | ``` 397 | 398 | 399 | ### instance.reset() 400 | 401 | Reset the current bits, if a length was supplied to the constructor it will be used. 402 | 403 | **Aliases**: [`clear`] 404 | 405 | ```js 406 | var bits = new BitArray(144, 16) 407 | bits.toString() // '000000000001001' 408 | 409 | ``` 410 | 411 | 412 | ### instance.equals(bitarray) 413 | 414 | Determine if the instance is equal to another instance 415 | 416 | * `bitarray` - instance to compare 417 | 418 | ```js 419 | var a = new BitArray(1) // [1] 420 | , b = new BitArray(2) // [1, 0] 421 | , c = new BitArray().set(0, 1) // [1] 422 | 423 | a.equals(b) // false 424 | a.equals(c) // true 425 | ``` 426 | 427 | 428 | ### instance.length 429 | 430 | Get the length of the current bit array 431 | 432 | ```js 433 | new BitArray().length // 0 434 | new BitArray([128, 255]).length // 16 435 | ``` 436 | 437 | 438 | Install 439 | ------- 440 | 441 | With [npm](https://npmjs.org) 442 | 443 | ``` 444 | npm install node-bitarray 445 | ``` 446 | 447 | 448 | License 449 | ------- 450 | 451 | (The MIT License) 452 | 453 | Copyright (c) 2013 Beau Sorensen 454 | 455 | Permission is hereby granted, free of charge, to any person obtaining 456 | a copy of this software and associated documentation files (the 457 | 'Software'), to deal in the Software without restriction, including 458 | without limitation the rights to use, copy, modify, merge, publish, 459 | distribute, sublicense, and/or sell copies of the Software, and to 460 | permit persons to whom the Software is furnished to do so, subject to 461 | the following conditions: 462 | 463 | The above copyright notice and this permission notice shall be 464 | included in all copies or substantial portions of the Software. 465 | 466 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 467 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 468 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 469 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 470 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 471 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 472 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 473 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert') 4 | , ase = assert.strictEqual 5 | , ade = assert.deepEqual 6 | , BitArray = require('./index') 7 | , info = require('./package.json') 8 | 9 | describe('BitArray v' + info.version, function() { 10 | 11 | describe('Static methods', function() { 12 | 13 | it('#factory()', function() { 14 | var a = [255, 128].map(BitArray.factory).map(String) 15 | ase(a[0], '11111111') 16 | ase(a[1], '00000001') 17 | }) 18 | 19 | it('#octet()', function() { 20 | var oct = BitArray.octet([]) 21 | ase(oct.length, 8) 22 | oct.push(1) 23 | var oct2 = BitArray.octet(oct) 24 | ase(oct2.length, 16) 25 | }) 26 | 27 | it('#parse()', function() { 28 | ade(BitArray.parse('100101'), [1,0,1,0,0,1]) 29 | ase(new BitArray(new BitArray(128).toString()).toString(), '00000001') 30 | ade(BitArray.parse(), []) 31 | ade(BitArray.parse([1,0]), [1,0]) 32 | ade(BitArray.parse(144), [1,0,0,1,0,0,0,0]) 33 | ade(BitArray.parse(), []) 34 | ade(BitArray.parse(0), []) 35 | ade(BitArray.parse(0, true), [0,0,0,0,0,0,0,0]) 36 | }) 37 | 38 | it('#equals()', function() { 39 | var a = new BitArray('00001001') 40 | , b = new BitArray(144) 41 | , c = new BitArray([ 1, 0, 0, 1, 0, 0, 0, 0 ]) 42 | , d = new BitArray([ 1, 1, 1, 1, 1, 1, 1, 1 ]) 43 | , e = new BitArray(255) 44 | 45 | ase(BitArray.equals(a, b), true) 46 | ase(BitArray.equals(a, c), true) 47 | ase(BitArray.equals(b, c), true) 48 | ase(BitArray.equals(a, d), false) 49 | ase(BitArray.equals(b, d), false) 50 | ase(BitArray.equals(c, e), false) 51 | ase(BitArray.equals(d, e), true) 52 | }) 53 | 54 | it('#push()', function() { 55 | var bits = new BitArray() 56 | bits.push(1) 57 | bits.push(0) 58 | bits.push(1) 59 | ase(bits.pop(), 1) 60 | ase(bits.pop(), 0) 61 | }) 62 | 63 | it('#fromBinary()', function() { 64 | ade(BitArray.fromBinary('1010').toJSON(), [0,1,0,1]) 65 | }) 66 | 67 | it('#fromOffsets()', function() { 68 | var offs = [1, 5, 10] 69 | , ba = BitArray.fromOffsets(offs) 70 | ase(ba.length, 11) 71 | ase(ba.toString(), '10000100010') 72 | }) 73 | 74 | it('#fromNumber()', function() { 75 | var bits = BitArray.fromDecimal(12) 76 | ase(bits.length, 4) 77 | ase(bits.toString(), (12).toString(2)) 78 | ade(bits.toJSON(), [0, 0, 1, 1]) 79 | var bits = BitArray.fromNumber(15) 80 | ade(bits.toJSON(), [1,1,1,1]) 81 | }) 82 | 83 | it('#fromHex()', function() { 84 | var bits = BitArray.fromHex('f0') 85 | ase(bits.toString(), '11110000') 86 | var bits = BitArray.fromHex(10) 87 | ase(bits.toString(), '10000') 88 | var bits = BitArray.fromHex('Fa') 89 | ade(bits.toJSON(), [0, 1, 0, 1, 1, 1, 1, 1]) 90 | }) 91 | 92 | it('#from32Integer()', function() { 93 | var bits = BitArray.from32Integer(144) 94 | ade(bits.toJSON(), [1,0,0,1,0,0,0,0]) 95 | bits.set() 96 | }) 97 | 98 | it('#fromBuffer()', function() { 99 | var buf = new Buffer([128, 144, 255]) 100 | , bits = BitArray.fromBuffer(buf) 101 | ade(bits.toJSON(), [1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1]) 102 | }) 103 | 104 | it('#toOffsets()', function() { 105 | var offs = BitArray.toOffsets([1, 0, 0, 1]) 106 | ade(offs, [0, 3]) 107 | }) 108 | 109 | it('#toBuffer()', function() { 110 | var buf = BitArray.toBuffer([1,1,1,1,1,1,1,1]) 111 | ase(buf instanceof Buffer, true) 112 | ase(buf[0], 255) 113 | }) 114 | 115 | it('#toNumber()', function() { 116 | ase(BitArray.toNumber([1, 0, 1, 1, 0, 1]), 45) 117 | }) 118 | 119 | it('#toHex()', function() { 120 | ase(BitArray.toHex([1, 0, 1, 1, 0, 1]), '2d') 121 | }) 122 | 123 | it('#and()', function() { 124 | var a = [ 1, 0, 0, 1, 0, 0, 0, 1 ] 125 | var b = [ 1, 0, 0, 0, 1, 0, 0, 1 ] 126 | var c = [ 0, 1, 0, 0, 0, 1, 0, 1 ] 127 | var d = BitArray.and(a, b, c) 128 | ade(d, [ 0, 0, 0, 0, 0, 0, 0, 1 ]) 129 | }) 130 | 131 | it('#or()', function() { 132 | var a = [ 1, 0, 0, 1, 0, 0, 0, 1 ] 133 | var b = [ 1, 0, 0, 0, 1, 0, 0, 1 ] 134 | var c = [ 0, 1, 0, 0, 0, 1, 0, 1 ] 135 | var d = BitArray.or(a, b, c) 136 | ade(d, [ 1, 1, 0, 1, 1, 1, 0, 1 ]) 137 | }) 138 | 139 | it('#xor()', function() { 140 | var a = [ 1, 0, 0, 1, 0, 0, 0, 1 ] 141 | var b = [ 1, 0, 0, 0, 1, 0, 0, 1 ] 142 | var c = [ 0, 1, 0, 0, 0, 1, 0, 1 ] 143 | var d = BitArray.xor(a, b, c) 144 | ade(d, [ 0, 1, 0, 1, 1, 1, 0, 1 ]) 145 | }) 146 | 147 | it('#not()', function() { 148 | var a = [ 1, 0, 0, 1, 0, 0, 0, 1 ] 149 | var b = BitArray.not(a) 150 | ade(b, [ 0, 1, 1, 0, 1, 1, 1, 0]) 151 | }) 152 | 153 | it('#bitcount()', function() { 154 | ase(BitArray.cardinality(144), 2) 155 | ase(BitArray.count(128), 1) 156 | ase(BitArray.bitcount(new Buffer([255, 128])), 9) 157 | ase(BitArray.population([0,1,1,0,1,0]), 3) 158 | }) 159 | }) 160 | 161 | describe('Instance methods', function() { 162 | 163 | it('#fill()', function() { 164 | var bits = new BitArray() 165 | ase(bits.length, 0) 166 | bits.fill(24) 167 | ase(bits.length, 24) 168 | var bits = new BitArray(0, 3) 169 | ase(bits.length, 3) 170 | }) 171 | 172 | it('#clone()', function() { 173 | var bits = new BitArray().set([1,0,1]) 174 | , bit2 = bits.clone() 175 | 176 | ade(bit2.toJSON(), bits.toJSON()) 177 | ase(BitArray.equals(bits, bit2), true) 178 | ase(bits == bit2, false) 179 | }) 180 | 181 | it('#clear()', function() { 182 | var bits = new BitArray(255) 183 | ase(bits.length, 8) 184 | bits.clear() 185 | ase(bits.length, 0) 186 | 187 | var bits = new BitArray(0, 10) 188 | bits.set(4, 1) 189 | ase(bits.length, 10) 190 | bits.reset() 191 | ase(bits.length, 10) 192 | }) 193 | 194 | it('#equals()', function() { 195 | var a = new BitArray(1) 196 | , b = new BitArray(2) 197 | , c = new BitArray().set(0, 1) 198 | 199 | ase(a.equals(b), false) 200 | ase(a.equals(c), true) 201 | }) 202 | 203 | it('#set()', function() { 204 | var bits = new BitArray() 205 | bits.set(0, 1) 206 | ase(bits.get(0), 1) 207 | bits.set(7, 1) 208 | ase(bits.get(6), 0) 209 | ase(bits.get(7), 1) 210 | ade(bits.toJSON(), [1,0,0,0,0,0,0,1]) 211 | ase(bits.length, 8) 212 | }) 213 | 214 | it('#get()', function() { 215 | var bits = new BitArray(144) 216 | ase(bits.get(0), 1) 217 | ase(bits.get(1), 0) 218 | ase(bits.get(3), 1) 219 | }) 220 | 221 | it('#bitcount()', function() { 222 | var bits = new BitArray() 223 | bits.set(0, 1) 224 | bits.set(3, 0) 225 | bits.set(200, 1) 226 | ase(bits.cardinality(), 2) 227 | }) 228 | 229 | it('#toOffsets()', function() { 230 | var bits = new BitArray(144) 231 | ade(bits.toOffsets(), [0, 3]) 232 | }) 233 | 234 | it('#toString()', function() { 235 | var bit = new BitArray(new Buffer([128, 144])) 236 | ase(bit.toString(), '0000100100000001') 237 | var bit2 = new BitArray(255) 238 | ase([bit2].join(''), '11111111') 239 | var bits = new BitArray('0011') 240 | ase([bits].join(''), '0011') 241 | }) 242 | 243 | it('#toJSON()', function() { 244 | var bit = new BitArray(new Buffer([128, 144])) 245 | ade(bit.toJSON(), [1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0]) 246 | ase(JSON.stringify(bit), '[1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0]') 247 | var bit2 = new BitArray(255) 248 | ade(bit2.toArray(), [1,1,1,1,1,1,1,1]) 249 | }) 250 | 251 | it('#valueOf()', function() { 252 | var bits = new BitArray('1001') 253 | ase(+bits, 9) 254 | ase(new BitArray('011001') + new BitArray(new Buffer([255])), 280) 255 | 256 | var bits = new BitArray().set([1, 0, 1, 1]) 257 | ase(bits.toNumber(), 13) 258 | }) 259 | 260 | it('#toHex()', function() { 261 | var bits = new BitArray(255) 262 | ase(bits.toHex(), 'ff') 263 | 264 | var bits = new BitArray().set([1, 0, 1, 1]) 265 | ase(bits.toHex(), 'd') 266 | }) 267 | 268 | it('#toBuffer()', function() { 269 | var bits = new BitArray([0], 8).set([1, 0, 0, 1]) 270 | , buf = bits.toBuffer() 271 | , bits2 = new BitArray(buf) 272 | 273 | ase(buf instanceof Buffer, true) 274 | ase(BitArray.equals(bits, bits2), true) 275 | ase(buf[0], 144) 276 | }) 277 | 278 | it('#length', function() { 279 | var bits = new BitArray(0, 16) 280 | ase(bits.__bits[15], 0) 281 | ase(bits.length, 16) 282 | ase(bits.toString().length, 16) 283 | ase(bits.reset().length, 16) 284 | }) 285 | }) 286 | }) 287 | --------------------------------------------------------------------------------