From 9d83255a6be245260da58fdcfcfd95e8fd00cb05 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 22 Aug 2018 23:22:35 +0100 Subject: [PATCH] perf(transducers): add IReducible, update reduce() - add IReducible interface for custom/optimized iteration and source value provision for reduce() - add array-like check to reduce() and switch to version without forcing array iterator (`for..of..`) --- packages/transducers/src/api.ts | 4 ++++ packages/transducers/src/iterator.ts | 3 ++- packages/transducers/src/reduce.ts | 30 +++++++++++++++++++++------- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/transducers/src/api.ts b/packages/transducers/src/api.ts index 819fa24302..83fed71217 100644 --- a/packages/transducers/src/api.ts +++ b/packages/transducers/src/api.ts @@ -12,6 +12,10 @@ export interface Reducer extends Array { [2]: ReductionFn; }; +export interface IReducible { + $reduce(rfn: ReductionFn, acc: A): A | Reduced; +} + export type TransformFn = (x: any) => any; export type TransformSubSpec = IObjectOf; export interface TransformSpec extends Array { diff --git a/packages/transducers/src/iterator.ts b/packages/transducers/src/iterator.ts index 50b0aaac59..7768f05830 100644 --- a/packages/transducers/src/iterator.ts +++ b/packages/transducers/src/iterator.ts @@ -28,7 +28,8 @@ export function* iterator(xform: Transducer, xs: Iterable): Itera } /** - * Optimized version of `iterator()` for transducers which are guaranteed to: + * Optimized version of `iterator()` for transducers which are + * guaranteed to: * * 1) Only produce none or a single result per input * 2) Do not require a `completion` reduction step diff --git a/packages/transducers/src/reduce.ts b/packages/transducers/src/reduce.ts index a20795bfa3..dc5999beb5 100644 --- a/packages/transducers/src/reduce.ts +++ b/packages/transducers/src/reduce.ts @@ -1,12 +1,16 @@ +import { implementsFunction } from "@thi.ng/checks/implements-function"; +import { isArrayLike } from "@thi.ng/checks/is-arraylike"; import { illegalArity } from "@thi.ng/errors/illegal-arity"; -import { Reducer } from "./api"; +import { Reducer, IReducible } from "./api"; import { isReduced, unreduced, Reduced } from "./reduced"; export function reduce(rfn: Reducer, xs: Iterable): A; export function reduce(rfn: Reducer, acc: A, xs: Iterable): A; +export function reduce(rfn: Reducer, xs: IReducible): A; +export function reduce(rfn: Reducer, acc: A, xs: IReducible): A; export function reduce(...args: any[]): A { - let acc: A, xs: Iterable; + let acc: A, xs: Iterable | IReducible; switch (args.length) { case 3: xs = args[2]; @@ -20,11 +24,23 @@ export function reduce(...args: any[]): A { } const [init, complete, reduce] = args[0]; acc = acc == null ? init() : acc; - for (let x of xs) { - acc = reduce(acc, x); - if (isReduced(acc)) { - acc = (acc).deref(); - break; + if (implementsFunction(xs, "$reduce")) { + acc = (>xs).$reduce(reduce, acc); + } else if (isArrayLike(xs)) { + for (let i = 0, n = xs.length; i < n; i++) { + acc = reduce(acc, xs[i]); + if (isReduced(acc)) { + acc = (acc).deref(); + break; + } + } + } else { + for (let x of >xs) { + acc = reduce(acc, x); + if (isReduced(acc)) { + acc = (acc).deref(); + break; + } } } return unreduced(complete(acc));