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

dev.marksman.kraftwerk.frequency.FrequencyMapN Maven / Gradle / Ivy

The newest version!
package dev.marksman.kraftwerk.frequency;

import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.builtin.fn2.Map;
import dev.marksman.kraftwerk.Generator;
import dev.marksman.kraftwerk.Weighted;

import java.util.TreeMap;

import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons;
import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft;
import static dev.marksman.kraftwerk.Generators.generateLongIndex;

final class FrequencyMapN implements FrequencyMap {
    private final Iterable>> entries;
    private Generator cachedGenerator;

    @SuppressWarnings("unchecked")
    private FrequencyMapN(Iterable>> entries) {
        this.entries = (Iterable>>) entries;
    }

    static  FrequencyMapN frequencyMapN(Weighted> first,
                                              Iterable>> rest) {
        return new FrequencyMapN<>(cons(first, rest));
    }

    static  Generator addLabel(Generator gen) {
        return gen.labeled("frequency map");
    }

    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public Generator toGenerator() {
        synchronized (this) {
            if (cachedGenerator == null) cachedGenerator = buildGenerator();
        }
        return cachedGenerator;
    }

    private Generator buildGenerator() {
        long total = 0L;
        TreeMap> tree = new TreeMap<>();
        for (Weighted> entry : entries) {
            total += entry.getWeight();
            tree.put(total, entry.getValue());
        }

        return addLabel(generateLongIndex(total)
                .flatMap(n -> tree.ceilingEntry(1 + n).getValue()));
    }

    @SuppressWarnings("unchecked")
    @Override
    public FrequencyMap add(Weighted> weightedGenerator) {
        if (weightedGenerator.getWeight() < 1) {
            return this;
        } else {
            return new FrequencyMapN<>(cons((Weighted>) weightedGenerator, entries));
        }
    }

    @Override
    public FrequencyMap combine(FrequencyMap other) {
        return foldLeft(FrequencyMap::add, other, entries);
    }

    @Override
    public  FrequencyMap fmap(Fn1 fn) {
        Iterable>> mapped = Map.map(entry -> entry.fmap(gen -> gen.fmap(fn)), entries);
        return new FrequencyMapN<>(mapped);
    }

    @Override
    public FrequencyMap multiply(int positiveFactor) {
        if (positiveFactor == 1) {
            return this;
        } else {
            return new FrequencyMapN<>(Map.map(entry -> entry.multiplyBy(positiveFactor), entries));
        }
    }
}