//package spimedb.util.bag; // //import org.jetbrains.annotations.Nullable; //import org.teavm.jso.core.JSFunction; //import spimedb.client.lodash.Lodash; //import spimedb.client.util.Console; // //import java.util.*; //import java.util.function.BiConsumer; //import java.util.function.IntFunction; // //import static java.lang.Boolean.FALSE; //import static java.lang.Boolean.TRUE; // ///** // * batches and notifies listeners about bag changes // * @param X the input key // * @param Y the output value, lazily constructed // */ //abstract public class ChangeBatcher<X, Y> { // // private final JSFunction onChange; // protected final Map<X, Boolean> changed = new HashMap(); // protected final Map<X, Y> built = new HashMap(); // // static final Object[] empty = new Object[0]; // // /** to obey an existing remove command when trying to add */ // private static final boolean RemoveOverrides = true; // // public ChangeBatcher(int updateMS, IntFunction<Y[]> arrayBuilder, ObservablePriBag<X> bag) { // this(updateMS, arrayBuilder); // // bag.ADD.on(this::add); // bag.REMOVE.on(this::remove); // } // // public ChangeBatcher(int updateMS, IntFunction<Y[]> arrayBuilder) { // // onChange = Lodash.debounce(() -> { // // // List<Y> ADD = new LinkedList(); // List<Y> REM = new LinkedList(); // int addC = 0, remC = 0; //since linkedlist size() is slow // // // for (Iterator<Map.Entry<X, Boolean>> iterator = changed.entrySet().iterator(); iterator.hasNext(); ) { // Map.Entry<X, Boolean> e = iterator.next(); // // X x = e.getKey(); // Boolean s = e.getValue(); // // iterator.remove(); // // if (s == TRUE) { // Y y = build(x); // if (y == null) // continue; // // Y existed = built.put(x, y); // assert (existed == null); // if (existed != null) Console.log("previous exist"); // ADD.add(y); // addC++; // } else if (s == FALSE) { // Y removed = built.remove(x); // assert (removed != null); // if (removed == null) Console.log("didnt exist"); // REM.add(removed); // remC++; // } else { // Console.log("unknown value"); // assert (false); // } // } // // if (addC > 0 || remC > 0) { // update(ADD.toArray(addC > 0 ? arrayBuilder.apply(addC) : (Y[]) empty), // REM.toArray(remC > 0 ? arrayBuilder.apply(remC) : (Y[]) empty)); // } // // }, updateMS); // } // // @Nullable abstract public Y build(X x); // // abstract public void update(Y[] added, Y[] removed); // // protected boolean setNext(X x, boolean addOrRem) { // boolean exist = built.get(x) != null; // if (addOrRem) { // //add // if (exist) { // changed.remove(x); //in case remove was pending // return false; //already exist, ignore // } // // } else { // //remove // if (!exist) { // changed.remove(x); //in case add was pending // return false; //doesnt exist, ignore // } // } // // changed.put(x, addOrRem); // onChange.call(null); // return true; // } // // public void add(X x) { // setNext(x, TRUE); // } // // public void remove(X x) { // setNext(x, FALSE); // } // // public void forEach(BiConsumer<X, Y> each) { // // //built.forEach(each); //TeaVM doesnt have it // // for (Map.Entry<X,Y> e : built.entrySet()) { // each.accept(e.getKey(), e.getValue()); // } // // } //}