All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.reactfx.OnRecurseAccumulateStream Maven / Gradle / Ivy

There is a newer version: 2.0-M5
Show newest version
package org.reactfx;

import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.ToIntFunction;

import org.reactfx.util.MapHelper;

class OnRecurseAccumulateStream extends LazilyBoundStream {
    private final EventStream source;
    private final Function initialTransformation;
    private final BiFunction reduction;
    private final ToIntFunction size;
    private final Function head;
    private final Function tail;

    private MapHelper, A> pendingEvents = null;

    public OnRecurseAccumulateStream(
            EventStream source,
            Function initialTransformation,
            BiFunction reduction,
            ToIntFunction size,
            Function head,
            Function tail) {
        this.source = source;
        this.initialTransformation = initialTransformation;
        this.reduction = reduction;
        this.size = size;
        this.head = head;
        this.tail = tail;
    }

    @Override
    protected Subscription subscribeToInputs() {
        return subscribeTo(source, this::emitValue);
    }

    private void emitValue(T value) {
        if(MapHelper.isEmpty(pendingEvents) && getSubscriberCount() == 1) {
            emit(value);
        } else {
            forEachSubscriber(s -> {
                if(MapHelper.containsKey(pendingEvents, s)) {
                    A accum = MapHelper.get(pendingEvents, s);
                    accum = reduction.apply(accum, value);
                    if(size.applyAsInt(accum) > 0) {
                        pendingEvents = MapHelper.put(pendingEvents, s, accum);
                    } else {
                        pendingEvents = MapHelper.remove(pendingEvents, s);
                    }
                } else {
                    A accum = initialTransformation.apply(value);
                    if(size.applyAsInt(accum) > 0) {
                        pendingEvents = MapHelper.put(pendingEvents, s, accum);
                    }
                }
            });
            while(!MapHelper.isEmpty(pendingEvents)) {
                Consumer subscriber = MapHelper.chooseKey(pendingEvents);
                A accum = MapHelper.get(pendingEvents, subscriber);
                int n = size.applyAsInt(accum);
                assert n > 0;
                T first = head.apply(accum);
                if(n == 1) {
                    pendingEvents = MapHelper.remove(pendingEvents, subscriber);
                } else {
                    accum = tail.apply(accum);
                    if(size.applyAsInt(accum) > 0) { // always true if size() and tail() fulfill their contract
                        pendingEvents = MapHelper.put(pendingEvents, subscriber, accum);
                    }
                }
                tryRun(() -> subscriber.accept(first));
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy