Last active
December 8, 2018 01:22
-
-
Save alexsasharegan/549d942ce4e17c20eec241cdba8e5d6f to your computer and use it in GitHub Desktop.
Bitwise manipulations wrapped in a class with semantically meaningful methods.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class Bits { | |
static get Nil() { | |
return 0; | |
} | |
static get All() { | |
// Flip the sign bit out of all bits engaged. | |
return ~0 ^ (1 << 31); | |
} | |
value: number; | |
constructor(n?: number = Bits.Nil) { | |
this.value = n; | |
} | |
/** | |
* Equals | |
*/ | |
eq(n: number): boolean { | |
return this.value === n; | |
} | |
/** | |
* Not Equals | |
*/ | |
ne(n: number): boolean { | |
return this.value !== n; | |
} | |
/** | |
* Greater Than | |
*/ | |
gt(n: number): boolean { | |
return this.value > n; | |
} | |
/** | |
* Greater Than or Equal | |
*/ | |
gte(n: number): boolean { | |
return this.value >= n; | |
} | |
/** | |
* Less Than | |
*/ | |
lt(n: number): boolean { | |
return this.value < n; | |
} | |
/** | |
* Less Than or Equal | |
*/ | |
lte(n: number): boolean { | |
return this.value <= n; | |
} | |
/** | |
* Test the value of `Bits` to see if they include all the bits in `mask`. | |
*/ | |
includes(mask: number): boolean { | |
return (this.value & mask) === mask; | |
} | |
/** | |
* Test the value of `Bits` to see if they include any of the bits in `mask`. | |
*/ | |
some(mask: number): boolean { | |
return (this.value & mask) > 0; | |
} | |
/** | |
* Test the value of `Bits` to see if they include all the bits in `mask`. | |
*/ | |
every(mask: number): boolean { | |
return this.includes(mask); | |
} | |
/** | |
* Combine the value of `Bits` with all the given flags, | |
* and return a new instance. | |
*/ | |
combine(...flags: number[]) { | |
return new this.constructor( | |
flags.reduce((n, flag) => n | flag, this.value), | |
); | |
} | |
/** | |
* Combine the value of `Bits` with all the given flags, | |
* and mutate the instance. | |
*/ | |
combineMut(...flags: number[]) { | |
this.value = flags.reduce((n, flag) => n | flag, this.value); | |
return this; | |
} | |
/** | |
* Flip the bits in `mask` in the value of `Bits`, | |
* and return a new instance. | |
*/ | |
flip(mask: number) { | |
return new this.constructor(this.value ^ mask); | |
} | |
/** | |
* Flip the bits in `mask` in the value of `Bits`, | |
* and mutate the instance. | |
*/ | |
flipMut(mask: number) { | |
this.value = this.value ^ mask; | |
return this; | |
} | |
invert() { | |
return new this.constructor(~this.value); | |
} | |
invertMut() { | |
this.value = ~this.value; | |
return this; | |
} | |
/** | |
* Remove the bits in `mask` from the value of `Bits`, | |
* and return a new instance. | |
*/ | |
remove(mask: number) { | |
return new this.constructor(this.value & ~mask); | |
} | |
/** | |
* Remove the bits in `mask` from the value of `Bits`, | |
* and mutate the instance. | |
*/ | |
removeMut(mask: number) { | |
this.value = this.value & ~mask; | |
return this; | |
} | |
toString(): string { | |
return this.value.toString(2); | |
} | |
keys(): number[] { | |
return Array.from(bitKeys(this.value)); | |
} | |
values(): number[] { | |
return Array.from(bitValues(this.value)); | |
} | |
entries(): [number, number][] { | |
// $FlowIgnore | |
return Array.from(this); | |
} | |
// $FlowIgnore | |
[Symbol.iterator]() { | |
return bitEntries(this.value); | |
} | |
static fromString(s: string) { | |
return new this(atoi(s)); | |
} | |
} | |
/** | |
* ASCII to Integer (Binary) | |
*/ | |
export function atoi(a?: any): number { | |
if (!a || typeof a !== 'string') { | |
return 0; | |
} | |
let n = parseInt(a, 2); | |
if (Number.isNaN(n)) { | |
return 0; | |
} | |
return n; | |
} | |
/** | |
* Yields bit indexes for enabled bits | |
*/ | |
export function* bitKeys(n: number): Iterator<number> { | |
for (let i = 0; i < 32; i++) { | |
if ((n & (1 << i)) > 0) { | |
yield i; | |
} | |
} | |
} | |
/** | |
* Yields base 2 values for enabled bits | |
*/ | |
export function* bitValues(n: number): Iterator<number> { | |
for (let i = 0; i < 32; i++) { | |
if ((n & (1 << i)) > 0) { | |
yield 1 << i; | |
} | |
} | |
} | |
/** | |
* Yields [bit index, bit value] for enabled bits | |
*/ | |
export function* bitEntries(n: number): Iterator<[number, number]> { | |
for (let i = 0; i < 32; i++) { | |
if ((n & (1 << i)) > 0) { | |
yield [i, 1 << i]; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment