1
0

Compare commits

...

2 Commits

Author SHA1 Message Date
afa56b7adf improve typing of element finding utils 2025-05-24 13:22:09 +02:00
1f7c246faf move BitArray in its namerspace 2025-05-24 13:21:23 +02:00
5 changed files with 83 additions and 66 deletions

View File

@@ -11,7 +11,7 @@ import { AsyncRandomOptions } from "../random/types.js";
import { selectionSorter } from "../sorting.js"; import { selectionSorter } from "../sorting.js";
import { Sequence } from "../sync/types.js"; import { Sequence } from "../sync/types.js";
import { MaybeAsyncAnyPredicate, MaybeAsyncConverter, MaybeAsyncBiConverter, MaybeAsyncAccumulator, MaybeAsyncAction, MaybePromiseLike, MaybeAsyncGenerator, MaybePromise, MaybeAsyncIterable, MaybeAsyncTypePredicate } from "../types.js"; import { MaybeAsyncAnyPredicate, MaybeAsyncConverter, MaybeAsyncBiConverter, MaybeAsyncAccumulator, MaybeAsyncAction, MaybePromiseLike, MaybeAsyncGenerator, MaybePromise, MaybeAsyncIterable, MaybeAsyncTypePredicate } from "../types.js";
import { asAsyncIterable } from "../utils.js"; import { asAsyncIterable, FindElementResult } from "../utils.js";
import { array, empty, wrap } from "./index.js"; import { array, empty, wrap } from "./index.js";
import { AsyncSequence, AsyncSequencePipeline, GroupedAsyncSequence, OrderedAsyncSequence } from "./types.js"; import { AsyncSequence, AsyncSequencePipeline, GroupedAsyncSequence, OrderedAsyncSequence } from "./types.js";
@@ -173,14 +173,14 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return n >= 0 ? n : Infinity; return n >= 0 ? n : Infinity;
} }
async #tryGetFirst(predicate?: MaybeAsyncAnyPredicate<TElement>) { async #tryGetFirst(predicate?: MaybeAsyncAnyPredicate<TElement>): Promise<FindElementResult<TElement>> {
if (predicate) { if (predicate) {
for await (const element of this) { for await (const element of this) {
if (await predicate(element)) { if (await predicate(element)) {
return { return {
found: true, found: true,
element element
} as const; };
} }
} }
} else { } else {
@@ -190,13 +190,13 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return { return {
found: true, found: true,
element: next.value element: next.value
} as const; };
} }
} }
return { return {
found: false found: false
} as const; };
} }
async first(predicate?: MaybeAsyncAnyPredicate<TElement>) { async first(predicate?: MaybeAsyncAnyPredicate<TElement>) {
@@ -215,7 +215,7 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return result.found ? result.element : def; return result.found ? result.element : def;
} }
async #tryGetLast(predicate?: MaybeAsyncAnyPredicate<TElement>) { async #tryGetLast(predicate?: MaybeAsyncAnyPredicate<TElement>): Promise<FindElementResult<TElement>> {
let found = false; let found = false;
let result: TElement | undefined = undefined; let result: TElement | undefined = undefined;
@@ -236,7 +236,7 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return { return {
found, found,
element: result element: result
}; } as FindElementResult<TElement>;
} }
async last(predicate?: MaybeAsyncAnyPredicate<TElement>) { async last(predicate?: MaybeAsyncAnyPredicate<TElement>) {
@@ -255,9 +255,9 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return result.found ? result.element : def; return result.found ? result.element : def;
} }
async #tryGetSingle(predicate?: MaybeAsyncAnyPredicate<TElement>) { async #tryGetSingle(predicate?: MaybeAsyncAnyPredicate<TElement>): Promise<FindElementResult<TElement>> {
if (predicate) { if (predicate) {
let result: { found: true; element: TElement; } | undefined = undefined; let result: FindElementResult<TElement> | undefined = undefined;
for await (const element of this) { for await (const element of this) {
if (await predicate(element)) { if (await predicate(element)) {
@@ -265,13 +265,13 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return { return {
found: false, found: false,
reason: 2 reason: 2
} as const; };
} }
result = { result = {
found: true, found: true,
element element
} as const; };
} }
} }
} else { } else {
@@ -279,10 +279,10 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
let next = await iterator.next(); let next = await iterator.next();
if (!next.done) { if (!next.done) {
const result = { const result: FindElementResult<TElement> = {
found: true, found: true,
element: next.value element: next.value
} as const; };
next = await iterator.next(); next = await iterator.next();
@@ -293,14 +293,14 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return { return {
found: false, found: false,
reason: 2 reason: 2
} as const; };
} }
} }
return { return {
found: false, found: false,
reason: 1 reason: 1
} as const; };
} }
async single(predicate?: MaybeAsyncAnyPredicate<TElement>) { async single(predicate?: MaybeAsyncAnyPredicate<TElement>) {
@@ -330,7 +330,7 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return result.found ? result.element : def; return result.found ? result.element : def;
} }
async #tryElementAt(index: number) { async #tryElementAt(index: number): Promise<FindElementResult<TElement>> {
let i = index; let i = index;
for await (const element of this) { for await (const element of this) {
@@ -338,7 +338,7 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return { return {
found: true, found: true,
element element
} as const; };
} }
i--; i--;
@@ -346,7 +346,7 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return { return {
found: false found: false
} as const; };
} }
async elementAt(index: number) { async elementAt(index: number) {
@@ -693,18 +693,12 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return new CacheAsyncSequence<TElement>(this); return new CacheAsyncSequence<TElement>(this);
} }
async asArray(): Promise<TElement[]> { async asArray() {
return await this.toArray(); return await Array.fromAsync(this);
} }
async toArray() { async toArray() {
const array: TElement[] = []; return await Array.fromAsync(this);
for await (const element of this) {
array.push(element);
}
return array;
} }
toMap<TKey>(keySelector: MaybeAsyncConverter<TElement, TKey>): Promise<Map<TKey, TElement>>; toMap<TKey>(keySelector: MaybeAsyncConverter<TElement, TKey>): Promise<Map<TKey, TElement>>;
@@ -1137,13 +1131,9 @@ abstract class BaseOrderedAsyncSequence<TElement> extends BaseAsyncSequence<TEle
} }
override async *iterator() { override async *iterator() {
const arr: TElement[] = []; const arr = await Array.fromAsync(this.#sequence);
for await (const obj of this.#sequence) { await selectionSorter.sort(arr, this.#descending, this.#sorter);
arr.push(obj);
}
await selectionSorter.sort(arr, this.#descending, this.#sorter.comparison());
yield* arr; yield* arr;
} }

View File

@@ -2,27 +2,47 @@ import { asArray } from "../utils.js";
import { EmptyBitArray, BitArrayImpl } from "./impl.js"; import { EmptyBitArray, BitArrayImpl } from "./impl.js";
import { BitArray } from "./types.js"; import { BitArray } from "./types.js";
export const EMPTY = new EmptyBitArray(); namespace BitArray {
export const EMPTY: BitArray = new EmptyBitArray();
export function create(length: number): BitArray { export function create(length: number): BitArray {
if (length < 0) { if (length < 0) {
throw new Error("length < 0"); throw new Error("length < 0");
}
return length === 0 ? EMPTY : new BitArrayImpl(length);
} }
return length === 0 ? EMPTY : new BitArrayImpl(length); export function from(bits: Iterable<boolean>) {
} const arr = asArray(bits);
const result = create(arr.length);
export function from(bits: Iterable<boolean>): BitArray { for (let i = 0; i < arr.length; i++) {
const arr = asArray(bits); result.set(i, arr[i]);
const result = create(arr.length); }
for (let i = 0; i < arr.length; i++) { return result;
result.set(i, arr[i]);
} }
return result; export function of(...bits: boolean[]) {
return from(bits);
}
export function and(a: BitArray, b: BitArray) {
return a.copy().and(b);
}
export function or(a: BitArray, b: BitArray) {
return a.copy().or(b);
}
export function xor(a: BitArray, b: BitArray) {
return a.copy().xor(b);
}
export function not(a: BitArray) {
return a.copy().not();
}
} }
export function of(...bits: boolean[]): BitArray { export { BitArray };
return from(bits);
}

View File

@@ -1,5 +1,4 @@
import { create as createBitArray } from "../bitarray/index.js"; import { BitArray } from "../bitarray/index.js";
import { BitArray } from "../bitarray/types.js";
import { asArray } from "../utils.js"; import { asArray } from "../utils.js";
import { AsyncRandomOptions, ElementPredicate, ElementWeight, RandomGenerator, RandomOptions } from "./types.js"; import { AsyncRandomOptions, ElementPredicate, ElementWeight, RandomGenerator, RandomOptions } from "./types.js";
@@ -121,7 +120,7 @@ export class RandomPicker<T> {
public constructor(elements: Iterable<T>, length: number, options?: RandomOptions<T>) { public constructor(elements: Iterable<T>, length: number, options?: RandomOptions<T>) {
this.#elements = elements; this.#elements = elements;
this.#flags = createBitArray(length); this.#flags = BitArray.create(length);
this.#options = withDefaultOptions(mergeOptions({ predicate: i => this.#flags.get(i) }, options)); this.#options = withDefaultOptions(mergeOptions({ predicate: i => this.#flags.get(i) }, options));
this.reset(); this.reset();

View File

@@ -11,6 +11,7 @@ import { createQueue } from "../queue.js";
import { getRandomElement } from "../random/index.js"; import { getRandomElement } from "../random/index.js";
import { RandomOptions } from "../random/types.js"; import { RandomOptions } from "../random/types.js";
import { AnyPredicate, Converter, TypePredicate, BiConverter, Accumulator, Action } from "../types.js"; import { AnyPredicate, Converter, TypePredicate, BiConverter, Accumulator, Action } from "../types.js";
import { FindElementResult } from "../utils.js";
import { array, empty, wrap } from "./index.js"; import { array, empty, wrap } from "./index.js";
import { Sequence, GroupedSequence, OrderedSequence, SequencePipeline } from "./types.js"; import { Sequence, GroupedSequence, OrderedSequence, SequencePipeline } from "./types.js";
@@ -181,7 +182,7 @@ export abstract class BaseSequence<TElement> extends SequenceMarker implements S
return n >= 0 ? n : Infinity; return n >= 0 ? n : Infinity;
} }
#tryGetFirst(predicate?: AnyPredicate<TElement>): { found: boolean, element?: TElement | undefined; } { #tryGetFirst(predicate?: AnyPredicate<TElement>): FindElementResult<TElement> {
if (predicate) { if (predicate) {
for (const element of this) { for (const element of this) {
if (predicate(element)) { if (predicate(element)) {
@@ -223,7 +224,7 @@ export abstract class BaseSequence<TElement> extends SequenceMarker implements S
return result.found ? result.element : def; return result.found ? result.element : def;
} }
#tryGetLast(predicate?: AnyPredicate<TElement>): { found: boolean, element?: TElement; } { #tryGetLast(predicate?: AnyPredicate<TElement>): FindElementResult<TElement> {
let found = false; let found = false;
let result: TElement | undefined = undefined; let result: TElement | undefined = undefined;
@@ -244,7 +245,7 @@ export abstract class BaseSequence<TElement> extends SequenceMarker implements S
return { return {
found, found,
element: result element: result
}; } as FindElementResult<TElement>;
} }
last(predicate?: AnyPredicate<TElement>) { last(predicate?: AnyPredicate<TElement>) {
@@ -263,9 +264,9 @@ export abstract class BaseSequence<TElement> extends SequenceMarker implements S
return result.found ? result.element : def; return result.found ? result.element : def;
} }
#tryGetSingle(predicate?: AnyPredicate<TElement>): { found: boolean, element?: TElement, reason?: number; } { #tryGetSingle(predicate?: AnyPredicate<TElement>): FindElementResult<TElement> {
if (predicate) { if (predicate) {
let result: { found: boolean; element: TElement; } | undefined = undefined; let result: FindElementResult<TElement> | undefined = undefined;
for (const element of this) { for (const element of this) {
if (predicate(element)) { if (predicate(element)) {
@@ -287,7 +288,7 @@ export abstract class BaseSequence<TElement> extends SequenceMarker implements S
let next = iterator.next(); let next = iterator.next();
if (!next.done) { if (!next.done) {
const result = { const result: FindElementResult<TElement> = {
found: true, found: true,
element: next.value element: next.value
}; };
@@ -319,7 +320,7 @@ export abstract class BaseSequence<TElement> extends SequenceMarker implements S
} }
let reason: string; let reason: string;
switch (result.reason!) { switch (result.reason) {
case 1: case 1:
reason = "No element was found."; reason = "No element was found.";
break; break;
@@ -338,7 +339,7 @@ export abstract class BaseSequence<TElement> extends SequenceMarker implements S
return result.found ? result.element : def; return result.found ? result.element : def;
} }
#tryElementAt(index: number) { #tryElementAt(index: number): FindElementResult<TElement> {
let i = index; let i = index;
for (const element of this) { for (const element of this) {
@@ -346,7 +347,7 @@ export abstract class BaseSequence<TElement> extends SequenceMarker implements S
return { return {
found: true, found: true,
element element
} as const; };
} }
i--; i--;
@@ -354,7 +355,7 @@ export abstract class BaseSequence<TElement> extends SequenceMarker implements S
return { return {
found: false found: false
} as const; };
} }
elementAt(index: number) { elementAt(index: number) {
@@ -1164,11 +1165,7 @@ export abstract class BaseOrderedSequence<TElement> extends BaseSequence<TElemen
} }
override *iterator() { override *iterator() {
const arr: TElement[] = []; const arr = Array.from(this.#sequence);
for (const obj of this.#sequence) {
arr.push(obj);
}
if (this.#sorter) { if (this.#sorter) {
arr.sort((this.#descending ? this.#sorter.reverse() : this.#sorter).comparison()); arr.sort((this.#descending ? this.#sorter.reverse() : this.#sorter).comparison());

View File

@@ -49,3 +49,14 @@ const _emptyIterableIterator = new class EmptyIterableIterator implements Iterab
export function emptyIterableIterator<T>(): IterableIterator<T> { export function emptyIterableIterator<T>(): IterableIterator<T> {
return _emptyIterableIterator; return _emptyIterableIterator;
} }
type FindElementSuccess<T> = {
found: true;
element: T;
};
type FindElementFail = {
found: false;
element?: never;
reason?: number;
};
export type FindElementResult<T> = FindElementSuccess<T> | FindElementFail;