initial commit
This commit is contained in:
42
benchmarks/option/async.bench.ts
Normal file
42
benchmarks/option/async.bench.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { EXTENDED } from '../helpers/bench-options.js';
|
||||
import {
|
||||
some,
|
||||
none,
|
||||
OptionPromise,
|
||||
} from '../helpers/imports.js';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// OptionPromise.from — returns value
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('OptionPromise.from — returns value', () => {
|
||||
bench('native-monad', async () => {
|
||||
await OptionPromise.from(() => Promise.resolve(42));
|
||||
}, EXTENDED);
|
||||
// No other library has an async Option wrapper
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// OptionPromise.from — returns null
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('OptionPromise.from — returns null', () => {
|
||||
bench('native-monad', async () => {
|
||||
await OptionPromise.from(() => Promise.resolve(null));
|
||||
}, EXTENDED);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// OptionPromise.all — all Some
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
for (const size of [10, 100] as const) {
|
||||
describe(`OptionPromise.all — ${size} items, all Some`, () => {
|
||||
const promises = () => Array.from({ length: size }, (_, i) => Promise.resolve(some(i)));
|
||||
|
||||
bench('native-monad', async () => {
|
||||
await OptionPromise.all(promises());
|
||||
}, EXTENDED);
|
||||
});
|
||||
}
|
||||
132
benchmarks/option/chaining.bench.ts
Normal file
132
benchmarks/option/chaining.bench.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { STANDARD } from '../helpers/bench-options.js';
|
||||
import {
|
||||
some,
|
||||
none,
|
||||
TsSome,
|
||||
TsNone,
|
||||
OxSome,
|
||||
OxNone,
|
||||
O,
|
||||
pipe,
|
||||
TmMaybe,
|
||||
} from '../helpers/imports.js';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 5-step pipeline — Some path
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option chaining — 5-step pipeline (all Some)', () => {
|
||||
bench('native-monad', () => {
|
||||
some(42)
|
||||
.map(x => x * 2)
|
||||
.flatMap(x => (x > 0 ? some(x) : none()))
|
||||
.map(x => ({ value: x }))
|
||||
.flatMap(x => some({ ...x, label: 'result' }))
|
||||
.map(x => JSON.stringify(x));
|
||||
}, STANDARD);
|
||||
|
||||
bench('ts-results-es', () => {
|
||||
TsSome(42)
|
||||
.map(x => x * 2)
|
||||
.andThen(x => (x > 0 ? TsSome(x) : TsNone))
|
||||
.map(x => ({ value: x }))
|
||||
.andThen(x => TsSome({ ...x, label: 'result' }))
|
||||
.map(x => JSON.stringify(x));
|
||||
}, STANDARD);
|
||||
|
||||
bench('oxide.ts', () => {
|
||||
OxSome(42)
|
||||
.map(x => x * 2)
|
||||
.andThen(x => (x > 0 ? OxSome(x) : OxNone))
|
||||
.map(x => ({ value: x }))
|
||||
.andThen(x => OxSome({ ...x, label: 'result' }))
|
||||
.map(x => JSON.stringify(x));
|
||||
}, STANDARD);
|
||||
|
||||
bench('fp-ts', () => {
|
||||
pipe(
|
||||
O.some(42),
|
||||
O.map(x => x * 2),
|
||||
O.flatMap(x => (x > 0 ? O.some(x) : O.none)),
|
||||
O.map(x => ({ value: x })),
|
||||
O.flatMap(x => O.some({ ...x, label: 'result' })),
|
||||
O.map(x => JSON.stringify(x)),
|
||||
);
|
||||
}, STANDARD);
|
||||
|
||||
bench('true-myth', () => {
|
||||
TmMaybe.just(42)
|
||||
.map(x => x * 2)
|
||||
.andThen(x => (x > 0 ? TmMaybe.just(x) : TmMaybe.nothing()))
|
||||
.map(x => ({ value: x }))
|
||||
.andThen(x => TmMaybe.just({ ...x, label: 'result' }))
|
||||
.map(x => JSON.stringify(x));
|
||||
}, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// None short-circuit — 9 no-op maps
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option chaining — None at step 1, 9 no-op maps', () => {
|
||||
const nmNone = none();
|
||||
const tsNone = TsNone;
|
||||
const oxNone = OxNone;
|
||||
const fpNone = O.none;
|
||||
const tmNone = TmMaybe.nothing<number>();
|
||||
const fn = (x: number) => x + 1;
|
||||
|
||||
bench('native-monad', () => {
|
||||
nmNone.map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn);
|
||||
}, STANDARD);
|
||||
|
||||
bench('ts-results-es', () => {
|
||||
tsNone.map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn);
|
||||
}, STANDARD);
|
||||
|
||||
bench('oxide.ts', () => {
|
||||
oxNone.map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn);
|
||||
}, STANDARD);
|
||||
|
||||
bench('fp-ts', () => {
|
||||
pipe(fpNone, O.map(fn), O.map(fn), O.map(fn), O.map(fn), O.map(fn), O.map(fn), O.map(fn), O.map(fn), O.map(fn));
|
||||
}, STANDARD);
|
||||
|
||||
bench('true-myth', () => {
|
||||
tmNone.map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn);
|
||||
}, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 20-step deep map chain — Some path
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option chaining — 20 maps on Some', () => {
|
||||
const fn = (x: number) => x + 1;
|
||||
|
||||
bench('native-monad', () => {
|
||||
let r = some(0);
|
||||
for (let i = 0; i < 20; i++) r = r.map(fn);
|
||||
}, STANDARD);
|
||||
|
||||
bench('ts-results-es', () => {
|
||||
let r = TsSome(0);
|
||||
for (let i = 0; i < 20; i++) r = r.map(fn) as any;
|
||||
}, STANDARD);
|
||||
|
||||
bench('oxide.ts', () => {
|
||||
let r = OxSome(0);
|
||||
for (let i = 0; i < 20; i++) r = r.map(fn) as any;
|
||||
}, STANDARD);
|
||||
|
||||
bench('fp-ts', () => {
|
||||
let r = O.some(0) as O.Option<number>;
|
||||
for (let i = 0; i < 20; i++) r = pipe(r, O.map(fn));
|
||||
}, STANDARD);
|
||||
|
||||
bench('true-myth', () => {
|
||||
let r = TmMaybe.just(0);
|
||||
for (let i = 0; i < 20; i++) r = r.map(fn) as any;
|
||||
}, STANDARD);
|
||||
});
|
||||
144
benchmarks/option/collection.bench.ts
Normal file
144
benchmarks/option/collection.bench.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { STANDARD, EXTENDED } from '../helpers/bench-options.js';
|
||||
import { SIZES, errorIndices } from '../helpers/data-generators.js';
|
||||
import {
|
||||
some,
|
||||
none,
|
||||
Option,
|
||||
TsSome,
|
||||
TsNone,
|
||||
TsOption,
|
||||
OxSome,
|
||||
OxNone,
|
||||
O,
|
||||
pipe,
|
||||
TmMaybe,
|
||||
} from '../helpers/imports.js';
|
||||
import * as RA from 'fp-ts/ReadonlyArray';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Option.all — all Some
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
for (const size of SIZES) {
|
||||
const opts = size >= 10_000 ? EXTENDED : STANDARD;
|
||||
|
||||
const nmAll = Array.from({ length: size }, (_, i) => some(i));
|
||||
const tsAll = Array.from({ length: size }, (_, i) => TsSome(i));
|
||||
const fpAll = Array.from({ length: size }, (_, i) => O.some(i));
|
||||
const tmAll = Array.from({ length: size }, (_, i) => TmMaybe.just(i));
|
||||
|
||||
describe(`Option.all — ${size} items, all Some`, () => {
|
||||
bench('native-monad', () => { Option.all(nmAll); }, opts);
|
||||
bench('ts-results-es', () => { TsOption.all(...tsAll); }, opts);
|
||||
bench('fp-ts', () => { pipe(fpAll, RA.sequence(O.Applicative)); }, opts);
|
||||
bench('true-myth (manual)', () => {
|
||||
const values: number[] = [];
|
||||
for (const m of tmAll) {
|
||||
if (m.isNothing) return TmMaybe.nothing();
|
||||
values.push((m as { value: number }).value);
|
||||
}
|
||||
return TmMaybe.just(values);
|
||||
}, opts);
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Option.all — 20% None (short-circuit)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
for (const size of SIZES) {
|
||||
const opts = size >= 10_000 ? EXTENDED : STANDARD;
|
||||
const noneIdx = errorIndices(size, 0.2);
|
||||
|
||||
const nmMixed = Array.from({ length: size }, (_, i) =>
|
||||
noneIdx.has(i) ? none() : some(i),
|
||||
);
|
||||
const tsMixed = Array.from({ length: size }, (_, i) =>
|
||||
noneIdx.has(i) ? TsNone : TsSome(i),
|
||||
);
|
||||
const fpMixed = Array.from({ length: size }, (_, i) =>
|
||||
noneIdx.has(i) ? O.none : O.some(i),
|
||||
);
|
||||
|
||||
describe(`Option.all — ${size} items, 20% None (short-circuit)`, () => {
|
||||
bench('native-monad', () => { Option.all(nmMixed); }, opts);
|
||||
bench('ts-results-es', () => { TsOption.all(...tsMixed); }, opts);
|
||||
bench('fp-ts', () => { pipe(fpMixed, RA.sequence(O.Applicative)); }, opts);
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Option.partition
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
for (const size of SIZES) {
|
||||
const opts = size >= 10_000 ? EXTENDED : STANDARD;
|
||||
const noneIdx = errorIndices(size, 0.2);
|
||||
|
||||
const nmMixed = Array.from({ length: size }, (_, i) =>
|
||||
noneIdx.has(i) ? none() : some(i),
|
||||
);
|
||||
const fpMixed = Array.from({ length: size }, (_, i) =>
|
||||
noneIdx.has(i) ? O.none : O.some(i),
|
||||
);
|
||||
|
||||
describe(`Option.partition — ${size} items`, () => {
|
||||
bench('native-monad', () => { Option.partition(nmMixed); }, opts);
|
||||
bench('fp-ts (manual)', () => {
|
||||
const values: number[] = [];
|
||||
let noneCount = 0;
|
||||
for (const o of fpMixed) {
|
||||
if (O.isSome(o)) values.push(o.value);
|
||||
else noneCount++;
|
||||
}
|
||||
return { values, noneCount };
|
||||
}, opts);
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Option.compact
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
for (const size of SIZES) {
|
||||
const opts = size >= 10_000 ? EXTENDED : STANDARD;
|
||||
const noneIdx = errorIndices(size, 0.2);
|
||||
|
||||
const nmMixed = Array.from({ length: size }, (_, i) =>
|
||||
noneIdx.has(i) ? none() : some(i),
|
||||
);
|
||||
const fpMixed = Array.from({ length: size }, (_, i) =>
|
||||
noneIdx.has(i) ? O.none : O.some(i),
|
||||
);
|
||||
|
||||
describe(`Option.compact — ${size} items`, () => {
|
||||
bench('native-monad', () => { Option.compact(nmMixed); }, opts);
|
||||
bench('fp-ts', () => { pipe(fpMixed, RA.compact); }, opts);
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Option.some / Option.every
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
for (const size of [100, 1_000] as const) {
|
||||
const noneIdx = errorIndices(size, 0.2);
|
||||
|
||||
const nmMixed = Array.from({ length: size }, (_, i) =>
|
||||
noneIdx.has(i) ? none() : some(i),
|
||||
);
|
||||
const fpMixed = Array.from({ length: size }, (_, i) =>
|
||||
noneIdx.has(i) ? O.none : O.some(i),
|
||||
);
|
||||
|
||||
describe(`Option.some — ${size} items`, () => {
|
||||
bench('native-monad', () => { Option.some(nmMixed); }, STANDARD);
|
||||
bench('fp-ts (manual)', () => { fpMixed.some(O.isSome); }, STANDARD);
|
||||
});
|
||||
|
||||
describe(`Option.every — ${size} items`, () => {
|
||||
bench('native-monad', () => { Option.every(nmMixed); }, STANDARD);
|
||||
bench('fp-ts (manual)', () => { fpMixed.every(O.isSome); }, STANDARD);
|
||||
});
|
||||
}
|
||||
47
benchmarks/option/construction.bench.ts
Normal file
47
benchmarks/option/construction.bench.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { STANDARD } from '../helpers/bench-options.js';
|
||||
import {
|
||||
some,
|
||||
none,
|
||||
TsSome,
|
||||
TsNone,
|
||||
OxSome,
|
||||
OxNone,
|
||||
O,
|
||||
TmMaybe,
|
||||
} from '../helpers/imports.js';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Some construction
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option construction — Some (primitive)', () => {
|
||||
bench('native-monad', () => { some(42); }, STANDARD);
|
||||
// neverthrow: no Option type
|
||||
bench('ts-results-es', () => { TsSome(42); }, STANDARD);
|
||||
bench('oxide.ts', () => { OxSome(42); }, STANDARD);
|
||||
bench('fp-ts', () => { O.some(42); }, STANDARD);
|
||||
bench('true-myth', () => { TmMaybe.just(42); }, STANDARD);
|
||||
});
|
||||
|
||||
describe('Option construction — Some (object payload)', () => {
|
||||
const value = { id: 1, name: 'Alice', roles: ['admin', 'user'] };
|
||||
|
||||
bench('native-monad', () => { some(value); }, STANDARD);
|
||||
bench('ts-results-es', () => { TsSome(value); }, STANDARD);
|
||||
bench('oxide.ts', () => { OxSome(value); }, STANDARD);
|
||||
bench('fp-ts', () => { O.some(value); }, STANDARD);
|
||||
bench('true-myth', () => { TmMaybe.just(value); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// None construction / access
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option construction — None', () => {
|
||||
bench('native-monad', () => { none(); }, STANDARD);
|
||||
bench('ts-results-es', () => { TsNone; }, STANDARD);
|
||||
bench('oxide.ts', () => { OxNone; }, STANDARD);
|
||||
bench('fp-ts', () => { O.none; }, STANDARD);
|
||||
bench('true-myth', () => { TmMaybe.nothing(); }, STANDARD);
|
||||
});
|
||||
55
benchmarks/option/conversion.bench.ts
Normal file
55
benchmarks/option/conversion.bench.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { STANDARD } from '../helpers/bench-options.js';
|
||||
import {
|
||||
some,
|
||||
none,
|
||||
OxSome,
|
||||
OxNone,
|
||||
O,
|
||||
pipe,
|
||||
} from '../helpers/imports.js';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// toNullable — Some path
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.toNullable — Some', () => {
|
||||
const nm = some(42);
|
||||
const ox = OxSome(42);
|
||||
const fp = O.some(42);
|
||||
|
||||
bench('native-monad', () => { nm.toNullable(); }, STANDARD);
|
||||
bench('oxide.ts', () => { ox.into(); }, STANDARD);
|
||||
bench('fp-ts', () => { pipe(fp, O.toNullable); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// toNullable — None path
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.toNullable — None', () => {
|
||||
const nm = none();
|
||||
const ox = OxNone;
|
||||
const fp = O.none;
|
||||
|
||||
bench('native-monad', () => { nm.toNullable(); }, STANDARD);
|
||||
bench('oxide.ts', () => { ox.into(); }, STANDARD);
|
||||
bench('fp-ts', () => { pipe(fp, O.toNullable); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// toString
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.toString — Some', () => {
|
||||
const nm = some(42);
|
||||
|
||||
bench('native-monad', () => { nm.toString(); }, STANDARD);
|
||||
// Most other libraries don't have toString
|
||||
});
|
||||
|
||||
describe('Option.toString — None', () => {
|
||||
const nm = none();
|
||||
|
||||
bench('native-monad', () => { nm.toString(); }, STANDARD);
|
||||
});
|
||||
59
benchmarks/option/from-wrapping.bench.ts
Normal file
59
benchmarks/option/from-wrapping.bench.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { STANDARD } from '../helpers/bench-options.js';
|
||||
import {
|
||||
Option,
|
||||
O,
|
||||
TmMaybe,
|
||||
} from '../helpers/imports.js';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Option.from — non-nullish value
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.from — non-nullish value', () => {
|
||||
bench('native-monad', () => { Option.from(42); }, STANDARD);
|
||||
bench('fp-ts', () => { O.fromNullable(42); }, STANDARD);
|
||||
bench('true-myth', () => { TmMaybe.of(42); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Option.from — null value
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.from — null', () => {
|
||||
bench('native-monad', () => { Option.from(null); }, STANDARD);
|
||||
bench('fp-ts', () => { O.fromNullable(null); }, STANDARD);
|
||||
bench('true-myth', () => { TmMaybe.of(null); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Option.from — undefined value
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.from — undefined', () => {
|
||||
bench('native-monad', () => { Option.from(undefined); }, STANDARD);
|
||||
bench('fp-ts', () => { O.fromNullable(undefined); }, STANDARD);
|
||||
bench('true-myth', () => { TmMaybe.of(undefined); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Option.from — function that returns value
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.from — function returning value', () => {
|
||||
const fn = () => 42;
|
||||
|
||||
bench('native-monad', () => { Option.from(fn); }, STANDARD);
|
||||
// fp-ts: no function overload for fromNullable
|
||||
// true-myth: no function overload for of
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Option.from — function that returns null
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.from — function returning null', () => {
|
||||
const fn = () => null;
|
||||
|
||||
bench('native-monad', () => { Option.from(fn); }, STANDARD);
|
||||
});
|
||||
151
benchmarks/option/instance-methods.bench.ts
Normal file
151
benchmarks/option/instance-methods.bench.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { STANDARD } from '../helpers/bench-options.js';
|
||||
import {
|
||||
some,
|
||||
none,
|
||||
TsSome,
|
||||
TsNone,
|
||||
OxSome,
|
||||
OxNone,
|
||||
oxMatch,
|
||||
O,
|
||||
pipe,
|
||||
TmMaybe,
|
||||
} from '../helpers/imports.js';
|
||||
|
||||
const double = (x: number) => x * 2;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// map — Some path
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.map — Some path', () => {
|
||||
const nm = some(42);
|
||||
const ts = TsSome(42);
|
||||
const ox = OxSome(42);
|
||||
const fp = O.some(42);
|
||||
const tm = TmMaybe.just(42);
|
||||
|
||||
bench('native-monad', () => { nm.map(double); }, STANDARD);
|
||||
bench('ts-results-es', () => { ts.map(double); }, STANDARD);
|
||||
bench('oxide.ts', () => { ox.map(double); }, STANDARD);
|
||||
bench('fp-ts', () => { pipe(fp, O.map(double)); }, STANDARD);
|
||||
bench('true-myth', () => { tm.map(double); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// map — None path (no-op)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.map — None path (no-op)', () => {
|
||||
const nm = none();
|
||||
const ts = TsNone;
|
||||
const ox = OxNone;
|
||||
const fp = O.none;
|
||||
const tm = TmMaybe.nothing<number>();
|
||||
|
||||
bench('native-monad', () => { nm.map(double); }, STANDARD);
|
||||
bench('ts-results-es', () => { ts.map(double); }, STANDARD);
|
||||
bench('oxide.ts', () => { ox.map(double); }, STANDARD);
|
||||
bench('fp-ts', () => { pipe(fp, O.map(double)); }, STANDARD);
|
||||
bench('true-myth', () => { tm.map(double); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// flatMap — Some path
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.flatMap — Some path', () => {
|
||||
const nm = some(42);
|
||||
const ts = TsSome(42);
|
||||
const ox = OxSome(42);
|
||||
const fp = O.some(42);
|
||||
const tm = TmMaybe.just(42);
|
||||
|
||||
bench('native-monad', () => { nm.flatMap(x => some(x * 2)); }, STANDARD);
|
||||
bench('ts-results-es', () => { ts.andThen(x => TsSome(x * 2)); }, STANDARD);
|
||||
bench('oxide.ts', () => { ox.andThen(x => OxSome(x * 2)); }, STANDARD);
|
||||
bench('fp-ts', () => { pipe(fp, O.flatMap(x => O.some(x * 2))); }, STANDARD);
|
||||
bench('true-myth', () => { tm.andThen(x => TmMaybe.just(x * 2)); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// flatMap — None path (no-op)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.flatMap — None path (no-op)', () => {
|
||||
const nm = none();
|
||||
const ts = TsNone;
|
||||
const ox = OxNone;
|
||||
const fp = O.none;
|
||||
const tm = TmMaybe.nothing<number>();
|
||||
|
||||
bench('native-monad', () => { nm.flatMap(x => some(x * 2)); }, STANDARD);
|
||||
bench('ts-results-es', () => { ts.andThen(x => TsSome(x * 2)); }, STANDARD);
|
||||
bench('oxide.ts', () => { ox.andThen(x => OxSome(x * 2)); }, STANDARD);
|
||||
bench('fp-ts', () => { pipe(fp, O.flatMap(x => O.some(x * 2))); }, STANDARD);
|
||||
bench('true-myth', () => { tm.andThen(x => TmMaybe.just(x * 2)); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// match — Some path
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.match — Some path', () => {
|
||||
const nm = some(42);
|
||||
const ox = OxSome(42);
|
||||
const fp = O.some(42);
|
||||
const tm = TmMaybe.just(42);
|
||||
|
||||
bench('native-monad', () => { nm.match(x => x * 2, () => 0); }, STANDARD);
|
||||
// ts-results-es: no match
|
||||
bench('oxide.ts', () => { oxMatch(ox, { Some: (x: number) => x * 2, None: () => 0 }); }, STANDARD);
|
||||
bench('fp-ts', () => { pipe(fp, O.match(() => 0, x => x * 2)); }, STANDARD);
|
||||
bench('true-myth', () => { tm.match({ Just: x => x * 2, Nothing: () => 0 }); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// match — None path
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.match — None path', () => {
|
||||
const nm = none();
|
||||
const ox = OxNone;
|
||||
const fp = O.none;
|
||||
const tm = TmMaybe.nothing<number>();
|
||||
|
||||
bench('native-monad', () => { nm.match(x => x * 2, () => 0); }, STANDARD);
|
||||
bench('oxide.ts', () => { oxMatch(ox, { Some: (x: number) => x * 2, None: () => 0 }); }, STANDARD);
|
||||
bench('fp-ts', () => { pipe(fp, O.match(() => 0, x => x * 2)); }, STANDARD);
|
||||
bench('true-myth', () => { tm.match({ Just: x => x * 2, Nothing: () => 0 }); }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// filter — Some path (predicate passes)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.filter — predicate passes', () => {
|
||||
const nm = some(42);
|
||||
const ox = OxSome(42);
|
||||
const fp = O.some(42);
|
||||
|
||||
bench('native-monad', () => { nm.filter(x => x > 0); }, STANDARD);
|
||||
// ts-results-es: no filter
|
||||
bench('oxide.ts', () => { ox.filter(x => x > 0); }, STANDARD);
|
||||
bench('fp-ts', () => { pipe(fp, O.filter(x => x > 0)); }, STANDARD);
|
||||
// true-myth: no filter on Maybe
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// filter — predicate fails
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.filter — predicate fails', () => {
|
||||
const nm = some(-1);
|
||||
const ox = OxSome(-1);
|
||||
const fp = O.some(-1);
|
||||
|
||||
bench('native-monad', () => { nm.filter(x => x > 0); }, STANDARD);
|
||||
bench('oxide.ts', () => { ox.filter(x => x > 0); }, STANDARD);
|
||||
bench('fp-ts', () => { pipe(fp, O.filter(x => x > 0)); }, STANDARD);
|
||||
});
|
||||
66
benchmarks/option/type-guards.bench.ts
Normal file
66
benchmarks/option/type-guards.bench.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { STANDARD } from '../helpers/bench-options.js';
|
||||
import {
|
||||
some,
|
||||
none,
|
||||
TsSome,
|
||||
TsNone,
|
||||
OxSome,
|
||||
OxNone,
|
||||
O,
|
||||
TmMaybe,
|
||||
} from '../helpers/imports.js';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// isSome — on Some
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.isSome — on Some', () => {
|
||||
const nm = some(42);
|
||||
const ts = TsSome(42);
|
||||
const ox = OxSome(42);
|
||||
const fp = O.some(42);
|
||||
const tm = TmMaybe.just(42);
|
||||
|
||||
bench('native-monad', () => { nm.isSome(); }, STANDARD);
|
||||
bench('ts-results-es', () => { ts.isSome(); }, STANDARD);
|
||||
bench('oxide.ts', () => { ox.isSome(); }, STANDARD);
|
||||
bench('fp-ts', () => { O.isSome(fp); }, STANDARD);
|
||||
bench('true-myth', () => { tm.isJust; }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// isSome — on None
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.isSome — on None', () => {
|
||||
const nm = none();
|
||||
const ts = TsNone;
|
||||
const ox = OxNone;
|
||||
const fp = O.none;
|
||||
const tm = TmMaybe.nothing<number>();
|
||||
|
||||
bench('native-monad', () => { nm.isSome(); }, STANDARD);
|
||||
bench('ts-results-es', () => { ts.isSome(); }, STANDARD);
|
||||
bench('oxide.ts', () => { ox.isSome(); }, STANDARD);
|
||||
bench('fp-ts', () => { O.isSome(fp); }, STANDARD);
|
||||
bench('true-myth', () => { tm.isJust; }, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// isNone — on None
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Option.isNone — on None', () => {
|
||||
const nm = none();
|
||||
const ts = TsNone;
|
||||
const ox = OxNone;
|
||||
const fp = O.none;
|
||||
const tm = TmMaybe.nothing<number>();
|
||||
|
||||
bench('native-monad', () => { nm.isNone(); }, STANDARD);
|
||||
bench('ts-results-es', () => { ts.isNone(); }, STANDARD);
|
||||
bench('oxide.ts', () => { ox.isNone(); }, STANDARD);
|
||||
bench('fp-ts', () => { O.isNone(fp); }, STANDARD);
|
||||
bench('true-myth', () => { tm.isNothing; }, STANDARD);
|
||||
});
|
||||
Reference in New Issue
Block a user