Files
native-monad/benchmarks/query/collection.bench.ts
2026-03-30 08:34:35 +02:00

145 lines
5.0 KiB
TypeScript

import { bench, describe } from 'vitest';
import { STANDARD, EXTENDED } from '../helpers/bench-options.js';
import { SIZES, errorIndices } from '../helpers/data-generators.js';
import {
okSome,
okNone,
errNone,
Query,
E,
O,
pipe,
} from '../helpers/imports.js';
import * as RA from 'fp-ts/ReadonlyArray';
// ---------------------------------------------------------------------------
// Query.all — all OkSome
// ---------------------------------------------------------------------------
for (const size of SIZES) {
const opts = size >= 10_000 ? EXTENDED : STANDARD;
const nmAll = Array.from({ length: size }, (_, i) => okSome(i));
const fpAll = Array.from({ length: size }, (_, i) =>
E.right(O.some(i)) as E.Either<string, O.Option<number>>,
);
describe(`Query.all — ${size} items, all OkSome`, () => {
bench('native-monad', () => { Query.all(nmAll); }, opts);
bench('fp-ts (nested, manual)', () => {
const values: number[] = [];
for (const item of fpAll) {
if (E.isLeft(item)) return item;
if (O.isNone(item.right)) continue;
values.push(item.right.value);
}
return E.right(O.some(values));
}, opts);
});
}
// ---------------------------------------------------------------------------
// Query.all — mixed (OkSome + OkNone + ErrNone)
// ---------------------------------------------------------------------------
for (const size of SIZES) {
const opts = size >= 10_000 ? EXTENDED : STANDARD;
const errIdx = errorIndices(size, 0.1);
const noneIdx = errorIndices(size, 0.15);
const nmMixed = Array.from({ length: size }, (_, i) => {
if (errIdx.has(i)) return errNone('fail');
if (noneIdx.has(i)) return okNone();
return okSome(i);
});
const fpMixed = Array.from({ length: size }, (_, i) => {
if (errIdx.has(i)) return E.left('fail') as E.Either<string, O.Option<number>>;
if (noneIdx.has(i)) return E.right(O.none) as E.Either<string, O.Option<number>>;
return E.right(O.some(i)) as E.Either<string, O.Option<number>>;
});
describe(`Query.all — ${size} items, mixed (short-circuit)`, () => {
bench('native-monad', () => { Query.all(nmMixed); }, opts);
bench('fp-ts (nested, manual)', () => {
const values: number[] = [];
for (const item of fpMixed) {
if (E.isLeft(item)) return item;
if (O.isNone(item.right)) continue;
values.push(item.right.value);
}
return E.right(O.some(values));
}, opts);
});
}
// ---------------------------------------------------------------------------
// Query.partition
// ---------------------------------------------------------------------------
for (const size of SIZES) {
const opts = size >= 10_000 ? EXTENDED : STANDARD;
const errIdx = errorIndices(size, 0.1);
const noneIdx = errorIndices(size, 0.15);
const nmMixed = Array.from({ length: size }, (_, i) => {
if (errIdx.has(i)) return errNone('fail');
if (noneIdx.has(i)) return okNone();
return okSome(i);
});
const fpMixed = Array.from({ length: size }, (_, i) => {
if (errIdx.has(i)) return E.left('fail') as E.Either<string, O.Option<number>>;
if (noneIdx.has(i)) return E.right(O.none) as E.Either<string, O.Option<number>>;
return E.right(O.some(i)) as E.Either<string, O.Option<number>>;
});
describe(`Query.partition — ${size} items`, () => {
bench('native-monad', () => { Query.partition(nmMixed); }, opts);
bench('fp-ts (nested, manual)', () => {
const values: number[] = [];
const errors: string[] = [];
let noneCount = 0;
for (const item of fpMixed) {
if (E.isLeft(item)) { errors.push(item.left); continue; }
if (O.isNone(item.right)) { noneCount++; continue; }
values.push(item.right.value);
}
return { values, noneCount, errors };
}, opts);
});
}
// ---------------------------------------------------------------------------
// Query.compact
// ---------------------------------------------------------------------------
for (const size of SIZES) {
const opts = size >= 10_000 ? EXTENDED : STANDARD;
const errIdx = errorIndices(size, 0.1);
const noneIdx = errorIndices(size, 0.15);
const nmMixed = Array.from({ length: size }, (_, i) => {
if (errIdx.has(i)) return errNone('fail');
if (noneIdx.has(i)) return okNone();
return okSome(i);
});
const fpMixed = Array.from({ length: size }, (_, i) => {
if (errIdx.has(i)) return E.left('fail') as E.Either<string, O.Option<number>>;
if (noneIdx.has(i)) return E.right(O.none) as E.Either<string, O.Option<number>>;
return E.right(O.some(i)) as E.Either<string, O.Option<number>>;
});
describe(`Query.compact — ${size} items`, () => {
bench('native-monad', () => { Query.compact(nmMixed); }, opts);
bench('fp-ts (nested, manual)', () => {
const values: number[] = [];
for (const item of fpMixed) {
if (E.isRight(item) && O.isSome(item.right)) values.push(item.right.value);
}
return values;
}, opts);
});
}