-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
201 additions
and
91 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
export * from './feature'; | ||
export * from './mask'; | ||
export * from './mask-index'; | ||
export * from './feature'; | ||
export { maskAreEqual, maskIncludes, maskIntersection, maskNew, maskUnion } from './mask-impl'; | ||
export * from './mask-index'; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import type { Mask } from './mask'; | ||
|
||
const BIN_POW_31 = 0x8000_0000; | ||
const BIN_POW_32 = 0x1_0000_0000; | ||
const BIN_POW_51 = 0x8_0000_0000_0000; | ||
const BIT_MASK_31 = 0x7fff_ffff; | ||
|
||
const EMPTY_MASK: Mask = 0 as never; | ||
|
||
/** The maximum number of disjoint, non-empty masks supported by this implementation. */ | ||
export const MASK_MAX_SIZE = 52 as number; | ||
|
||
/** Determines whether two specified masks are equal. */ | ||
export function maskAreEqual(mask1: Mask, mask2: Mask): boolean | ||
{ | ||
return mask1 === mask2; | ||
} | ||
|
||
/** Determines whether a specified mask includes another one. */ | ||
export function maskIncludes(includingMask: Mask, includedMask: Mask): boolean | ||
{ | ||
let includedLoValue: number; | ||
let includedHiValue: number; | ||
const returnValue = | ||
( | ||
(includingMask as never) & | ||
(includedLoValue = (includedMask as never) | 0) | ||
) === | ||
includedLoValue && | ||
( | ||
includingMask as never / BIN_POW_32 & | ||
(includedHiValue = includedMask as never / BIN_POW_32 | 0) | ||
) === | ||
includedHiValue; | ||
return returnValue; | ||
} | ||
|
||
/** Returns a new mask that is the intersection of two specified masks. */ | ||
export function maskIntersection(mask1: Mask, mask2: Mask): Mask | ||
{ | ||
const intersectionMask: Mask = | ||
( | ||
((mask1 as unknown as number) & (mask2 as unknown as number) & BIT_MASK_31) + | ||
((mask1 as never) / BIN_POW_31 & (mask2 as never) / BIN_POW_31) * BIN_POW_31 | ||
) as never; | ||
return intersectionMask; | ||
} | ||
|
||
/** Returns a new empty mask. */ | ||
export function maskNew(): Mask | ||
{ | ||
return EMPTY_MASK; | ||
} | ||
|
||
/** | ||
* Returns a new non-empty mask that does not intersect the specified mask. | ||
* | ||
* @throws If the specified mask is full, a `RangeError` is thrown. | ||
*/ | ||
export function maskNext(mask: Mask): Mask | ||
{ | ||
let nextValue = 1; | ||
for (let checkValue: number = mask as never; checkValue & 1; checkValue /= 2) | ||
nextValue *= 2; | ||
if (nextValue > BIN_POW_51) | ||
throw RangeError('Mask full'); | ||
return nextValue as never; | ||
} | ||
|
||
/** Returns a new mask that is the union of two specified masks. */ | ||
export function maskUnion(mask1: Mask, mask2: Mask): Mask | ||
{ | ||
const unionMask: Mask = | ||
( | ||
(((mask1 as unknown as number) | (mask2 as unknown as number)) & BIT_MASK_31) + | ||
((mask1 as never) / BIN_POW_31 | (mask2 as never) / BIN_POW_31) * BIN_POW_31 | ||
) as never; | ||
return unionMask; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import type { Mask } from './mask'; | ||
|
||
const LO_INDEX = 0; | ||
const HI_INDEX = 1; | ||
|
||
type LoHi = readonly [number, number]; | ||
|
||
const freezeMask = (_LoHi: LoHi): Mask => Object.freeze(_LoHi) as unknown as Mask; | ||
|
||
/** The maximum number of disjoint, non-empty masks supported by this implementation. */ | ||
export const MASK_MAX_SIZE = 64 as number; | ||
|
||
/** Determines whether two specified masks are equal. */ | ||
export function maskAreEqual(mask1: Mask, mask2: Mask): boolean | ||
{ | ||
const _LoHi1 = mask1 as unknown as LoHi; | ||
const _LoHi2 = mask2 as unknown as LoHi; | ||
return _LoHi1[LO_INDEX] === _LoHi2[LO_INDEX] && _LoHi1[HI_INDEX] === _LoHi2[HI_INDEX]; | ||
} | ||
|
||
/** Determines whether a specified mask includes another one. */ | ||
export function maskIncludes(includingMask: Mask, includedMask: Mask): boolean | ||
{ | ||
const includingLoHi = includingMask as unknown as LoHi; | ||
const includedLoHi = includedMask as unknown as LoHi; | ||
let includedLoValue: number; | ||
let includedHiValue: number; | ||
const returnValue = | ||
(includedLoValue = includedLoHi[LO_INDEX]) === (includedLoValue & includingLoHi[LO_INDEX]) && | ||
(includedHiValue = includedLoHi[HI_INDEX]) === (includedHiValue & includingLoHi[HI_INDEX]); | ||
return returnValue; | ||
} | ||
|
||
/** Returns a new mask that is the intersection of two specified masks. */ | ||
export function maskIntersection(mask1: Mask, mask2: Mask): Mask | ||
{ | ||
const _LoHi1 = mask1 as unknown as LoHi; | ||
const _LoHi2 = mask2 as unknown as LoHi; | ||
const intersectionLo = _LoHi1[LO_INDEX] & _LoHi2[LO_INDEX]; | ||
const intersectionHi = _LoHi1[HI_INDEX] & _LoHi2[HI_INDEX]; | ||
const intersectionLoHi: LoHi = [intersectionLo, intersectionHi]; | ||
return freezeMask(intersectionLoHi); | ||
} | ||
|
||
/** Returns a new empty mask. */ | ||
export function maskNew(): Mask | ||
{ | ||
return freezeMask([0, 0]); | ||
} | ||
|
||
/** | ||
* Returns a new non-empty mask that does not intersect the specified mask. | ||
* | ||
* @throws If the specified mask is full, a `RangeError` is thrown. | ||
*/ | ||
export function maskNext(mask: Mask): Mask | ||
{ | ||
const _LoHi = mask as unknown as LoHi; | ||
let bitIndex = 0; | ||
for (; _LoHi[bitIndex >> 5] & 1 << (bitIndex & 0x1F); bitIndex++) | ||
{ | ||
if (bitIndex === 63) | ||
throw RangeError('Mask full'); | ||
} | ||
const nextLoHi: [number, number] = [0, 0]; | ||
nextLoHi[bitIndex >> 5] = 1 << (bitIndex & 0x1F); | ||
return freezeMask(nextLoHi); | ||
} | ||
|
||
/** Returns a new mask that is the union of two specified masks. */ | ||
export function maskUnion(mask1: Mask, mask2: Mask): Mask | ||
{ | ||
const _LoHi1 = mask1 as unknown as LoHi; | ||
const _LoHi2 = mask2 as unknown as LoHi; | ||
const unionLo = _LoHi1[LO_INDEX] | _LoHi2[LO_INDEX]; | ||
const unionHi = _LoHi1[HI_INDEX] | _LoHi2[HI_INDEX]; | ||
const unionLoHi: LoHi = [unionLo, unionHi]; | ||
return freezeMask(unionLoHi); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export type { Mask } from './mask'; | ||
export * from './mask-impl-64'; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,7 @@ | ||
const BIN_POW_31 = 0x8000_0000; | ||
const BIN_POW_32 = 0x1_0000_0000; | ||
const BIN_POW_51 = 0x8_0000_0000_0000; | ||
const BIT_MASK_31 = 0x7fff_ffff; | ||
|
||
const EMPTY_MASK: Mask = 0 as never; | ||
|
||
/** A vector of boolean elements, intended for efficient bulk operations. */ | ||
export interface Mask | ||
{ | ||
[MaskSymbol]: never; | ||
} | ||
|
||
declare const MaskSymbol: unique symbol; | ||
|
||
/** Determines whether two specified masks are equal. */ | ||
export function maskAreEqual(mask1: Mask, mask2: Mask): boolean | ||
{ | ||
return mask1 === mask2; | ||
} | ||
|
||
/** Determines whether a specified mask includes another one. */ | ||
export function maskIncludes(includingMask: Mask, includedMask: Mask): boolean | ||
{ | ||
let includedLoValue: number; | ||
let includedHiValue: number; | ||
const returnValue = | ||
( | ||
(includingMask as never) & | ||
(includedLoValue = (includedMask as never) | 0) | ||
) === | ||
includedLoValue && | ||
( | ||
includingMask as never / BIN_POW_32 & | ||
(includedHiValue = includedMask as never / BIN_POW_32 | 0) | ||
) === | ||
includedHiValue; | ||
return returnValue; | ||
} | ||
|
||
/** Returns a new mask that is the intersection of two specified masks. */ | ||
export function maskIntersection(mask1: Mask, mask2: Mask): Mask | ||
{ | ||
const intersectionMask: Mask = | ||
( | ||
((mask1 as unknown as number) & (mask2 as unknown as number) & BIT_MASK_31) + | ||
((mask1 as never) / BIN_POW_31 & (mask2 as never) / BIN_POW_31) * BIN_POW_31 | ||
) as never; | ||
return intersectionMask; | ||
} | ||
|
||
/** Returns a new empty mask. */ | ||
export function maskNew(): Mask | ||
{ | ||
return EMPTY_MASK; | ||
} | ||
|
||
/** | ||
* Returns a new non-empty mask that does not intersect the specified mask. | ||
* | ||
* @throws If the specified mask is full, a `RangeError` is thrown. | ||
*/ | ||
export function maskNext(mask: Mask): Mask | ||
{ | ||
let nextValue = 1; | ||
for (let checkValue: number = mask as never; checkValue & 1; checkValue /= 2) | ||
nextValue *= 2; | ||
if (nextValue > BIN_POW_51) | ||
throw RangeError('Mask full'); | ||
return nextValue as never; | ||
} | ||
|
||
/** Returns a new mask that is the union of two specified masks. */ | ||
export function maskUnion(mask1: Mask, mask2: Mask): Mask | ||
{ | ||
const unionMask: Mask = | ||
( | ||
(((mask1 as unknown as number) | (mask2 as unknown as number)) & BIT_MASK_31) + | ||
((mask1 as never) / BIN_POW_31 | (mask2 as never) / BIN_POW_31) * BIN_POW_31 | ||
) as never; | ||
return unionMask; | ||
} |
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
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
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
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