FROM AtomicValue.java /** * Additional operations are suitable for out-of-order atomic summing operations since they * are associative. * <p> * TODO Support primitive numeric other than Integer through runtime generic reflection * TODO Support string accumulation but preserve initial order by creating a ordered prototype concurrent list which values can be inserted into slots in arbitrary order * * @param value * @return */ public OUT add(OUT value) { //TODO Support other primitive numeric types through runtime generic reflection //TODO More clear error handling if this is not of a supported type for addition if (!value.getClass().isInstance(Integer.class)) { throw new UnsupportedOperationException("add only works on Integers at the moment"); } final int i = (Integer) value; boolean success; OUT updatedSum; do { int sum = (Integer) this.valueAR.get(); success = compareAndSet(sum, updatedSum = (OUT) new Integer(sum + i)); } while (!success); return updatedSum; } /** * Multiplication operations are suitable for out-of-order atomic summing operations since they * are associative. * <p> * * @param value * @return */ public OUT multiply(OUT value) { final int i = (Integer) value; boolean success; OUT updatedProduct; do { int product = (Integer) this.valueAR.get(); success = compareAndSet(product, updatedProduct = (OUT) new Integer(product * i)); } while (!success); return updatedProduct; } ------------------------ FROM SettableAltFuture ---------------------------------------- /** * TODO flush() will guarantee that all actions within the Aspect, regardless of chain, that were fork()ed before this point are completed before proceeding. It is an aspect-wide explicit dependency * <p> * Proceed only after all operations {@link #fork()}ed before hitting the wall have completed. * <p> * This is a simple way to guarantee all actions within an {@link Async}, * not just actions upstream in this chain, have completed before continuing. Depending on circumstance * a concurrency wall() may have a significant negative performance impact and should be seen * as a special circumstances solution only. You have no knowledge and generally should have no * linkage between what this chain is doing and how many and how slow are the actions going on * elsewhere in your application. But so much for the ideal world- with real world testing and * side effects, you may need it or you may want to test to see if you need it. * <p> * "Jumping the wall": note that new tasks added to the aspect after the wall was created will queue * normally. Since they were forked after the wall, they may execute before the wall completes. * The wall completing only means actions forked before the wall was created will complete before * it proceeds. If jumping the wall is a real problem, does that mean you actually want a dedicated * {@link com.reactivecascade.i.IAspect} such as {@link com.reactivecascade.DefaultAspect} instead? * * @return */ public AltFuture<T> flush(IAspect aspect, String reason) { if (aspect.isInOrderExecutor()) { return aspect.then(() -> aspect.d(TAG, "Passed the wall: " + reason)); } throw new UnsupportedOperationException("Need to implement flush()"); // Probably here we want to proceed only after a snapshot of the queue and N previous tasks where N is the max concurrency of the Aspect gives a list of pending actions which we can proceed after // return aspect.subscribeTarget(this, aspect::wall()); } public AltFuture<T> flush(String reason) { return wall(aspect, reason); } /** * Execute the onFireAction after this <code>AltFuture</code> finishes. * * @param aspect * @param list * @param onFireAction * @return */ @Override public <P, N> IAltFuture<T, List<N>> then(IAspect aspect, IAltFuture<T, List<P>> list, IActionOneR<T, N> action) { assertNotNullThisAltFuture(list); assertNotNullThisAction(action); return new AltFuture<>(aspect, () -> { final ConcurrentIterator<P> iterator = new ConcurrentIterator<>(list.get()); final List<T> outputList = new ArrayList<>(iterator.size()); Pair<Integer, P> next; //TODO Spawn Aspect.maxConcurrency() - 1 additional tasks to work through the list at the same time while ((next = iterator.next()).second != null) { outputList.set(next.first, action.call(next.second)); } return outputList; }); } /** * Multiple threads may pull objects until they receive null indicating the iteration is complete * <p> * TODO ICEBOX, Disabled until list operations are finished. A bit messy, probably a cleaner formulation will be found * TODO The source array may not contain null. Use ZEN * <p> */ private static class ConcurrentIterator<I> { private final Object[] list; private final AtomicInteger iAI = new AtomicInteger(0); ConcurrentIterator(List<I> list) { this.list = list.toArray(); } Pair<Integer, I> next() { I value = null; final int i = iAI.getAndIncrement(); if (i < list.length) { value = (I) list[i]; } return new Pair<>(i, value); } int size() { return list.length; } }