1
0

Compare commits

...

2 Commits

2 changed files with 129 additions and 27 deletions

View File

@@ -1,5 +1,5 @@
import { join } from "./collector.js";
import { Enumerable, arrayLike, sequence } from "./sync.js";
import { arrayLike, sequence } from "./sync.js";
import { asArray, isDefined } from "./utils.js";
export interface BitArray extends Iterable<boolean> {
@@ -81,28 +81,6 @@ function* getBytes(bits: Iterable<boolean>) {
}
}
export namespace BitArray {
export function create(length: number): BitArray {
return new BitArrayImpl(length);
}
export function from(bits: Iterable<boolean>): BitArray {
const arr = asArray(bits);
const result = create(arr.length);
let i = 0;
for (const bit of arr) {
result.set(i++, bit);
}
return result;
}
export function of(...bits: boolean[]): BitArray {
return from(bits);
}
}
class BitArrayImpl implements BitArray {
readonly #length: number;
readonly #bits: Uint8Array;
@@ -281,6 +259,100 @@ class BitArrayImpl implements BitArray {
}
}
class EmptyBitArray implements BitArray {
[Symbol.iterator](): Iterator<boolean, any, undefined> {
return {
next: () => ({ done: true, value: undefined })
};
}
get length() {
return 0;
}
isFull() {
return false;
}
isEmpty() {
return false;
}
get(index: number): boolean {
throw new Error("BitArray has zero length");
}
set(index: number, value: boolean) {
throw new Error("BitArray has zero length");
}
fill(value: boolean) { }
and(other: BitArray) {
if (other.length !== 0) {
throw new Error("The other BitArray does not have zero length");
}
return this;
}
or(other: BitArray) {
if (other.length !== 0) {
throw new Error("The other BitArray does not have zero length");
}
return this;
}
xor(other: BitArray) {
if (other.length !== 0) {
throw new Error("The other BitArray does not have zero length");
}
return this;
}
not() {
return this;
}
contains(other: BitArray) {
return false;
}
intersects(other: BitArray) {
return false;
}
slice(offset: number, length: number) {
if (offset > 0) {
throw new Error("offset > 0");
}
if (length > 0) {
throw new Error("length > 0");
}
return this;
}
copy() {
return this;
}
toArray(): boolean[] {
return [];
}
equals(other: BitArray) {
return other === this || other && other.length === 0;
}
toString() {
return "";
}
}
class BitArraySlice implements BitArray {
readonly #parent: BitArray;
readonly #offset: number;
@@ -428,3 +500,32 @@ class BitArraySlice implements BitArray {
return sequence(this).select(bit => bit ? '1' : '0').collect(join());
}
}
const emptyBitArray = new EmptyBitArray();
export namespace BitArray {
export const EMPTY = emptyBitArray;
export function create(length: number): BitArray {
if (length < 0) {
throw new Error("length < 0");
}
return length === 0 ? EMPTY : new BitArrayImpl(length);
}
export function from(bits: Iterable<boolean>): BitArray {
const arr = asArray(bits);
const result = create(arr.length);
for (let i = 0; i < arr.length; i++) {
result.set(i, arr[i]);
}
return result;
}
export function of(...bits: boolean[]): BitArray {
return from(bits);
}
}

View File

@@ -91,20 +91,21 @@ export class RandomPicker<T> {
readonly #flags: BitArray;
readonly #options: Required<RandomOptions<T>>;
public constructor(elements: T[], options?: RandomOptions<T>) {
public constructor(elements: Iterable<T>, length: number, options?: RandomOptions<T>) {
this.#elements = elements;
this.#flags = BitArray.create(elements.length);
this.#flags = BitArray.create(length);
this.#options = withDefaultOptions(mergeOptions({ predicate: i => this.#flags.get(i) }, options));
this.reset();
}
public static from<T>(iterable: Iterable<T>, options?: RandomOptions<T>) {
return new this<T>(asArray(iterable), options);
const arr = asArray(iterable);
return new this<T>(arr, arr.length, options);
}
public static of<T>(options?: RandomOptions<T>, ...values: T[]) {
return new this<T>(values, options);
return new this<T>(values, values.length, options);
}
public get state() {