libjsr166y-java-0.1.20080107.orig/0000755000000000000000000000000011412734661012736 5ustar libjsr166y-java-0.1.20080107.orig/src/0000755000000000000000000000000011412734657013532 5ustar libjsr166y-java-0.1.20080107.orig/src/main/0000755000000000000000000000000011412734657014456 5ustar libjsr166y-java-0.1.20080107.orig/src/main/java/0000755000000000000000000000000011412734657015377 5ustar libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/0000755000000000000000000000000011412734661016616 5ustar libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/package-info.java0000644000000000000000000000043410735315511022002 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ /** * Preview versions of classes targetted for Java 7. */ package jsr166y; libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/TransferQueue.java0000644000000000000000000001253110735315511022250 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y; import java.util.concurrent.*; /** * A {@link BlockingQueue} in which producers may wait for consumers * to receive elements. A TransferQueue may be useful for * example in message passing applications in which producers * sometimes (using method transfer) await receipt of * elements by consumers invoking take or poll, * while at other times enqueue elements (via method put) * without waiting for receipt. Non-blocking and time-out versions of * tryTransfer are also available. A TransferQueue may also * be queried via hasWaitingConsumer whether there are any * threads waiting for items, which is a converse analogy to a * peek operation * *

Like any BlockingQueue, a TransferQueue may be * capacity bounded. If so, an attempted transfer operation * may initially block waiting for available space, and/or * subsequently block waiting for reception by a consumer. Note that * in a queue with zero capacity, such as {@link SynchronousQueue}, * put and transfer are effectively synonymous. * *

This interface is a member of the * * Java Collections Framework. * * @since 1.7 * @author Doug Lea * @param the type of elements held in this collection */ public interface TransferQueue extends BlockingQueue { /** * Transfers the specified element if there exists a consumer * already waiting to receive it, otherwise returning false * without enqueuing the element. * * @param e the element to transfer * @return true if the element was transferred, else * false * @throws ClassCastException if the class of the specified element * prevents it from being added to this queue * @throws NullPointerException if the specified element is null * @throws IllegalArgumentException if some property of the specified * element prevents it from being added to this queue */ boolean tryTransfer(E e); /** * Inserts the specified element into this queue, waiting if * necessary for space to become available and the element to be * dequeued by a consumer invoking take or poll. * * @param e the element to transfer * @throws InterruptedException if interrupted while waiting, * in which case the element is not enqueued. * @throws ClassCastException if the class of the specified element * prevents it from being added to this queue * @throws NullPointerException if the specified element is null * @throws IllegalArgumentException if some property of the specified * element prevents it from being added to this queue */ void transfer(E e) throws InterruptedException; /** * Inserts the specified element into this queue, waiting up to * the specified wait time if necessary for space to become * available and the element to be dequeued by a consumer invoking * take or poll. * * @param e the element to transfer * @param timeout how long to wait before giving up, in units of * unit * @param unit a TimeUnit determining how to interpret the * timeout parameter * @return true if successful, or false if * the specified waiting time elapses before completion, * in which case the element is not enqueued. * @throws InterruptedException if interrupted while waiting, * in which case the element is not enqueued. * @throws ClassCastException if the class of the specified element * prevents it from being added to this queue * @throws NullPointerException if the specified element is null * @throws IllegalArgumentException if some property of the specified * element prevents it from being added to this queue */ boolean tryTransfer(E e, long timeout, TimeUnit unit) throws InterruptedException; /** * Returns true if there is at least one consumer waiting to * dequeue an element via take or poll. The * return value represents a momentary state of affairs. * @return true if there is at least one waiting consumer. */ boolean hasWaitingConsumer(); /** * Returns an estimate of the number of consumers waiting to * dequeue elements via take or poll. The return * value is an approximation of a momentary state of affairs, that * may be inaccurate if consumers have completed or given up * waiting. The value may be useful for monitoring and heuristics, * but not for synchronization control. Implementations of this * method are likely to be noticeably slower than those for * hasWaitingConsumer. * @return the number of consumers waiting to dequeue elements */ int getWaitingConsumerCount(); } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/0000755000000000000000000000000011412734661020437 5ustar libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/RecursiveAction.java0000644000000000000000000002175610735315511024416 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; /** * Recursive resultless ForkJoinTasks. To maintain conformance with * other classes in this framework, RecursiveActions are parameterized * as Void ForkJoinTasks, and return null as * results. But for simplicity and efficiency, the compute * method and related methods use void. RecursiveActions * normally proceed via parallel divide and conquer; very often using * the convenient (and typically more efficient) combined method * forkJoin. Here is a sketch of a ForkJoin sort that sorts * a given long[] array: * * *

 * class SortTask extends RecursiveAction {
 *   final long[] array; final int lo; final int hi;
 *   SortTask(long[] array, int lo, int hi) {
 *     this.array = array; this.lo = lo; this.hi = hi;
 *   }
 *   protected void compute() {
 *     if (hi - lo < THRESHOLD)
 *       sequentiallySort(array, lo, hi);
 *     else {
 *       int mid = (lo + hi) >>> 1;
 *       forkJoin(new SortTask(array, lo, mid),
 *                new SortTask(array, mid, hi));
 *       merge(array, lo, hi);
 *     }
 *   }
 * }
 * 
* * You could then sort anArray by creating new SortTask(anArray, 0, * anArray.length-1) and invoking it in a ForkJoinPool. * As a more concrete simple example, the following task increments * each element of an array: *
 * class IncrementTask extends RecursiveAction {
 *   final long[] array; final int lo; final int hi;
 *   IncrementTask(long[] array, int lo, int hi) {
 *     this.array = array; this.lo = lo; this.hi = hi;
 *   }
 *   protected void compute() {
 *     if (hi - lo < THRESHOLD) {
 *       for (int i = lo; i < hi; ++i)
 *         array[i]++;
 *     }
 *     else {
 *       int mid = (lo + hi) >>> 1;
 *       forkJoin(new IncrementTask(array, lo, mid),
 *                new IncrementTask(array, mid, hi));
 *     }
 *   }
 * }
 * 
* * *

RecursiveActions need not be fully recursive, so long as they * maintain the basic divide-and-conquer approach. For example, here * is a class that sums the squares of each element of a double array, * by subdividing out only the right-hand-sides of repeated divisions * by two, and keeping track of them with a chain of next * references. It uses a common rule of thumb for granularity * settings, corresponding to about eight times as many base tasks as * there are threads in the pool. * *

 * double sumOfSquares(ForkJoinPool pool, double[] array) {
 *   int n = array.length;
 *   int seqSize = 1 + n / (8 * pool.getParallelismLevel());
 *   Applyer a = new Applyer(array, 0, n-1, seqSize, null);
 *   pool.invoke(a);
 *   return a.result;
 * }
 *
 * class Applyer extends RecursiveAction {
 *   final double[] array;
 *   final int lo, hi, seqSize;
 *   int result;
 *   Applyer next; // keeps track of right-hand-side tasks
 *   Applyer(double[] array, int lo, int hi, int seqSize, Applyer next) {
 *     this.array = array; this.lo = lo; this.hi = hi;
 *     this.seqSize = seqSize; this.next = next;
 *   }
 *
 *   protected void compute() {
 *     int l = lo;
 *     int h = hi;
 *     Applyer right = null;
 *     while (h - l > seqSize) { // fork right-hand sides
 *        int mid = (l + h) >>> 1;
 *        right = new Applyer(array, mid, h, seqSize, right);
 *        right.fork();
 *        h = mid;
 *     }
 *     double sum = 0;
 *     for (int i = l; i < h; ++i) // perform leftmost base step
 *       sum += array[i] * array[i];
 *     while (right != null) {  // join right-hand sides
 *       right.join();
 *       sum += right.result;
 *       right = right.next;
 *     }
 *     result = sum;
 *   }
 * }
 * 
*/ public abstract class RecursiveAction extends ForkJoinTask { /** * The main computation performed by this task. While you must * define this method, you should not in general call it directly. * To immediately perform the computation, use forkJoin. */ protected abstract void compute(); /** * Forks both tasks and returns when isDone holds for * both.. If both tasks encounter exceptions, only one of them * (arbitrarily chosen) is thrown from this method. You can check * individual status using method getException. This * method may be invoked only from within other ForkJoinTask * computations. Attempts to invoke in other contexts result in * exceptions or errors including ClassCastException. * @throws NullPointerException if t1 or t2 are null. */ public static void forkJoin(RecursiveAction t1, RecursiveAction t2) { ((ForkJoinWorkerThread)(Thread.currentThread())).doForkJoin(t1, t2); } /** * Forks all tasks in the array, returning when isDone * holds for all of them. If any task encounters an exception, * others are cancelled. This method may be invoked only from * within other ForkJoinTask computations. Attempts to invoke in * other contexts result in exceptions or errors including * ClassCastException. * @throws NullPointerException if array or any element of array are null */ public static void forkJoin(RecursiveAction[] tasks) { int last = tasks.length - 1; Throwable ex = null; for (int i = last; i >= 0; --i) { RecursiveAction t = tasks[i]; if (t == null) { if (ex == null) ex = new NullPointerException(); } else if (ex != null) t.cancel(); else if (i != 0) t.fork(); else ex = t.exec(); } for (int i = 1; i <= last; ++i) { RecursiveAction t = tasks[i]; if (t != null) { boolean pop = ForkJoinWorkerThread.removeIfNextLocalTask(t); if (ex != null) t.cancel(); else if (!pop) ex = t.quietlyJoin(); else ex = t.exec(); } } if (ex != null) rethrowException(ex); } /** * Forks all tasks in the list, returning when isDone * holds for all of them. If any task encounters an exception, * others are cancelled. * This method may be invoked only from within other ForkJoinTask * computations. Attempts to invoke in other contexts result * in exceptions or errors including ClassCastException. * @throws NullPointerException if list or any element of list are null. */ public static void forkJoin(List tasks) { int last = tasks.size() - 1; Throwable ex = null; for (int i = last; i >= 0; --i) { RecursiveAction t = tasks.get(i); if (t == null) { if (ex == null) ex = new NullPointerException(); } else if (i != 0) t.fork(); else if (ex != null) t.cancel(); else ex = t.exec(); } for (int i = 1; i <= last; ++i) { RecursiveAction t = tasks.get(i); if (t != null) { boolean pop = ForkJoinWorkerThread.removeIfNextLocalTask(t); if (ex != null) t.cancel(); else if (!pop) ex = t.quietlyJoin(); else ex = t.exec(); } } if (ex != null) rethrowException(ex); } /** * Always returns null. * @return null */ public final Void rawResult() { return null; } public final Void forkJoin() { try { if (exception == null) compute(); } catch(Throwable rex) { setDoneExceptionally(rex); } Throwable ex = setDone(); if (ex != null) rethrowException(ex); return null; } public final Throwable exec() { try { if (exception == null) compute(); } catch(Throwable rex) { return setDoneExceptionally(rex); } return setDone(); } /** * Equivalent to finish(null). */ public final void finish() { setDone(); } public final void finish(Void result) { setDone(); } public final void finishExceptionally(Throwable ex) { setDoneExceptionally(ex); } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/PAS.java0000644000000000000000000035506010740452246021735 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import static jsr166y.forkjoin.Ops.*; import java.util.*; import java.util.concurrent.atomic.*; import java.lang.reflect.Array; /** * Shared internal support for ParallelArray and specializations. * * The majority of operations take a similar form: Class Prefix serves * as the base of prefix classes, also serving as parameters for * single-step fork+join parallel tasks using subclasses of FJBase and * FJSearchBase. Prefix instances hold the non-operation-specific * control and data accessors needed for a task as a whole (as opposed * to subtasks), and also house leaf methods that perform the actual * array processing. The leaf methods are for the most part just plain * array operations. They are boringly repetitive in order to flatten * out and minimize inner-loop overhead, as well as to minimized * call-chain depth. This makes it more likely that dynamic compilers * can go the rest of the way, and hoist per-element method call * dispatch, so we have a good chance to speed up processing via * parallelism rather than lose due to dispatch and indirection * overhead. The dispatching from Prefix to FJ and back is otherwise * Visitor-pattern-like, allowing the basic parallelism control for * most FJ tasks to be centralized. * * Operations taking forms other than single-step fork/join * (SelectAll, sort, scan, etc) are organized in basically similar * ways, but don't always follow as regular patterns. * * Note the extensive use of raw types. Arrays and generics do not * work together very well. It is more manageable to avoid them here, * and let the public classes perform casts in and out to the * processing here. */ class PAS { private PAS() {} // all-static, non-instantiable /** Global default executor */ private static ForkJoinPool defaultExecutor; /** Lock for on-demand initialization of defaultExecutor */ private static final Object poolLock = new Object(); static ForkJoinExecutor defaultExecutor() { synchronized(poolLock) { ForkJoinPool p = defaultExecutor; if (p == null) { // use ceil(7/8 * ncpus) int nprocs = Runtime.getRuntime().availableProcessors(); int nthreads = nprocs - (nprocs >>> 3); defaultExecutor = p = new ForkJoinPool(nthreads); } return p; } } /** * Base of prefix classes. */ static abstract class Prefix { final ForkJoinExecutor ex; final int firstIndex; final int upperBound; final int threshold; // subtask split control Prefix(ForkJoinExecutor ex, int firstIndex, int upperBound) { this.ex = ex; this.firstIndex = firstIndex; this.upperBound = upperBound; int n = upperBound - firstIndex; int p = ex.getParallelismLevel(); this.threshold = defaultSequentialThreshold(n, p); } /** * Returns size threshold for splitting into subtask. By * default, uses about 8 times as many tasks as threads */ static int defaultSequentialThreshold(int size, int procs) { return (procs > 1) ? (1 + size / (procs << 3)) : size; } /** * Divide-and conquer split control. Returns true if subtask * of size n should be split in half. */ final boolean shouldSplit(int n) { return n > threshold; } /** * Array access methods for ref, double, long. Checking * for null return is used as a sort of type test. */ abstract Object[] rgetArray(); abstract double[] dgetArray(); abstract long[] lgetArray(); /* * Inner leaf methods. Most are no-ops overriddden in concrete * classes. Some of them can never be called from some * contexts and so are never overridden in the associated leaf * classes. For example the double version of leafApply can't * be called from any ParallelArray.WithBounds method, but can * be in ParallelArray.WithBoundedDoubleMapping, Introducing * them all here, regardless, simplifies usage in the FJ* and * prefix classes. */ void leafApply(int lo, int hi, Procedure procedure) {} void leafApply(int lo, int hi, DoubleProcedure procedure) {} void leafApply(int lo, int hi, LongProcedure procedure) {} Object leafReduce(int lo, int hi, Reducer reducer, Object base) { return null; } double leafReduce(int lo, int hi, DoubleReducer reducer, double base) { return 0.0; } long leafReduce(int lo, int hi, LongReducer reducer, long base) { return 0L; } void leafStats(int lo, int hi, FJRStats task) {} void leafStats(int lo, int hi, FJDStats task) {} void leafStats(int lo, int hi, FJLStats task) {} // copy elements, ignoring selector, but applying mapping void leafTransfer(int lo, int hi, Object[] dest, int offset) {} void leafTransfer(int lo, int hi, double[] dest, int offset) {} void leafTransfer(int lo, int hi, long[] dest, int offset) {} // copy elements indexed in indices[loIdx..hiIdx], ignoring // selector, but applying mapping void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, Object[] dest, int offset) {} void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, double[] dest, int offset) {} void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, long[] dest, int offset) {} void leafCombineInPlace(int lo, int hi, Object[] other, int otherOffset, Reducer combiner) {} void leafCombineInPlace(int lo, int hi, double[] other, int otherOffset, DoubleReducer combiner) {} void leafCombineInPlace(int lo, int hi, long[] other, int otherOffset, LongReducer combiner) {} void leafCombine(int lo, int hi, Object[] other, int otherOffset, Object[] dest, Combiner combiner) {} void leafCombine(int lo, int hi, long[] other, int otherOffset, long[] dest, LongReducer combiner) {} void leafCombine(int lo, int hi, double[] other, int otherOffset, double[] dest, DoubleReducer combiner) {} void leafTransform(int lo, int hi, Mapper mapper) {} void leafTransform(int lo, int hi, DoubleMapper mapper) {} void leafTransform(int lo, int hi, LongMapper mapper) {} void leafIndexMap(int lo, int hi, MapperFromInt mapper) {} void leafIndexMap(int lo, int hi, MapperFromIntToDouble mapper) {} void leafIndexMap(int lo, int hi, MapperFromIntToLong mapper) {} void leafGenerate(int lo, int hi, Generator generator) {} void leafGenerate(int lo, int hi, DoubleGenerator generator) {} void leafGenerate(int lo, int hi, LongGenerator generator) {} void leafFillValue(int lo, int hi, Object value) {} void leafFillValue(int lo, int hi, double value) {} void leafFillValue(int lo, int hi, long value) {} // add indices of selected elements to index array; return #added int leafIndexSelected(int lo, int hi, boolean positive, int[] indices) { return 0; } // move selected elements to indices starting at offset, // return final offset int leafMoveSelected(int lo, int hi, int offset, boolean positive) { return 0; } // move elements indexed by indices[loIdx...hiIdx] starting // at given offset abstract void leafMoveByIndex(int[] indices, int loIdx, int hiIdx, int offset); } /** * Base of ref array prefix classes */ static abstract class RPrefix extends PAS.Prefix { final ParallelArray pa; RPrefix(ParallelArray pa, int firstIndex, int upperBound) { super(pa.ex, firstIndex, upperBound); this.pa = pa; } final Object[] rgetArray() { return pa.array; } final double[] dgetArray() { return null; } final long[] lgetArray() { return null; } final void leafMoveByIndex(int[] indices, int loIdx, int hiIdx, int offset) { final Object[] array = pa.array; for (int i = loIdx; i < hiIdx; ++i) array[offset++] = array[indices[i]]; } } /** * Base of double array prefix classes */ static abstract class DPrefix extends PAS.Prefix { final ParallelDoubleArray pa; DPrefix(ParallelDoubleArray pa, int firstIndex, int upperBound) { super(pa.ex, firstIndex, upperBound); this.pa = pa; } final Object[] rgetArray() { return null; } final double[] dgetArray() { return pa.array; } final long[] lgetArray() { return null; } final void leafMoveByIndex(int[] indices, int loIdx, int hiIdx, int offset) { final double[] array = pa.array; for (int i = loIdx; i < hiIdx; ++i) array[offset++] = array[indices[i]]; } } /** * Base of long array prefix classes */ static abstract class LPrefix extends PAS.Prefix { final ParallelLongArray pa; LPrefix(ParallelLongArray pa, int firstIndex, int upperBound) { super(pa.ex, firstIndex, upperBound); this.pa = pa; } final Object[] rgetArray() { return null; } final double[] dgetArray() { return null; } final long[] lgetArray() { return pa.array; } final void leafMoveByIndex(int[] indices, int loIdx, int hiIdx, int offset) { final long[] array = pa.array; for (int i = loIdx; i < hiIdx; ++i) array[offset++] = array[indices[i]]; } } /** * Base for most divide-and-conquer tasks used for computing * ParallelArray operations. Rather than pure recursion, it links * right-hand-sides and then joins up the tree, exploiting cases * where tasks aren't stolen. This generates and joins tasks with * a bit less overhead than pure recursive style -- there are only * as many tasks as leaves (no strictly internal nodes). * * Split control relies on prefix.shouldSplit, which is expected * to err on the side of generating too many tasks. To * counterblance, if a task pops off its smallest subtask, it * directly runs its leaf action rather than possibly replitting. * * There are, with a few exceptions, three flavors of each FJBase * subclass, prefixed FJR (reference), FJD (double) and FJL * (long). These in turn normally dispatch to the ref-based, * double-based, or long-based leaf* methods. */ static abstract class FJBase extends RecursiveAction { final Prefix prefix; final int lo; final int hi; final FJBase next; // the next task that creator should join FJBase(Prefix prefix, int lo, int hi, FJBase next) { this.prefix = prefix; this.lo = lo; this.hi = hi; this.next = next; } public final void compute() { FJBase r = null; int l = lo; int h = hi; while (prefix.shouldSplit(h - l)) { int rh = h; h = (l + h) >>> 1; (r = newSubtask(h, rh, r)).fork(); } atLeaf(l, h); while (r != null) { if (ForkJoinWorkerThread.removeIfNextLocalTask(r)) r.atLeaf(r.lo, r.hi); else r.join(); onReduce(r); r = r.next; } } /** Leaf computation */ abstract void atLeaf(int l, int h); /** Operation performed after joining right subtask -- default noop */ void onReduce(FJBase right) {} /** Factory method to create new subtask, normally of current type */ abstract FJBase newSubtask(int l, int h, FJBase r); } // apply static final class FJRApply extends FJBase { final Procedure procedure; FJRApply(Prefix prefix, int lo, int hi, FJBase next, Procedure procedure) { super(prefix, lo, hi, next); this.procedure = procedure; } FJBase newSubtask(int l, int h, FJBase r) { return new FJRApply(prefix, l, h, r, procedure); } void atLeaf(int l, int h) { prefix.leafApply(l, h, procedure); } } static final class FJDApply extends FJBase { final DoubleProcedure procedure; FJDApply(Prefix prefix, int lo, int hi, FJBase next, DoubleProcedure procedure) { super(prefix, lo, hi, next); this.procedure = procedure; } FJBase newSubtask(int l, int h, FJBase r) { return new FJDApply(prefix, l, h, r, procedure); } void atLeaf(int l, int h) { prefix.leafApply(l, h, procedure); } } static final class FJLApply extends FJBase { final LongProcedure procedure; FJLApply(Prefix prefix, int lo, int hi, FJBase next, LongProcedure procedure) { super(prefix, lo, hi, next); this.procedure = procedure; } FJBase newSubtask(int l, int h, FJBase r) { return new FJLApply(prefix, l, h, r, procedure); } void atLeaf(int l, int h) { prefix.leafApply(l, h, procedure); } } // reduce static final class FJRReduce extends FJBase { final Reducer reducer; Object result; FJRReduce(Prefix prefix, int lo, int hi, FJBase next, Reducer reducer, Object base) { super(prefix, lo, hi, next); this.reducer = reducer; this.result = base; } FJBase newSubtask(int l, int h, FJBase r) { return new FJRReduce(prefix, l, h, r, reducer, result); } void atLeaf(int l, int h) { result = prefix.leafReduce(l, h, reducer, result); } void onReduce(FJBase right) { result = reducer.combine(result, ((FJRReduce)right).result); } } static final class FJDReduce extends FJBase { final DoubleReducer reducer; double result; FJDReduce(Prefix prefix, int lo, int hi, FJBase next, DoubleReducer reducer, double base) { super(prefix, lo, hi, next); this.reducer = reducer; this.result = base; } FJBase newSubtask(int l, int h, FJBase r) { return new FJDReduce(prefix, l, h, r, reducer, result); } void atLeaf(int l, int h) { result = prefix.leafReduce(l, h, reducer, result); } void onReduce(FJBase right) { result = reducer.combine(result, ((FJDReduce)right).result); } } static final class FJLReduce extends FJBase { final LongReducer reducer; long result; FJLReduce(Prefix prefix, int lo, int hi, FJBase next, LongReducer reducer, long base) { super(prefix, lo, hi, next); this.reducer = reducer; this.result = base; } FJBase newSubtask(int l, int h, FJBase r) { return new FJLReduce(prefix, l, h, r, reducer, result); } void atLeaf(int l, int h) { result = prefix.leafReduce(l, h, reducer, result); } void onReduce(FJBase right) { result = reducer.combine(result, ((FJLReduce)right).result); } } // map static final class FJRMap extends FJBase { final Object[] dest; final int offset; FJRMap(Prefix prefix, int lo, int hi, FJBase next, Object[] dest, int offset) { super(prefix, lo, hi, next); this.dest = dest; this.offset = offset; } FJBase newSubtask(int l, int h, FJBase r) { return new FJRMap(prefix, l, h, r, dest, offset); } void atLeaf(int l, int h) { prefix.leafTransfer(l, h, dest, l - offset); } } static final class FJDMap extends FJBase { final double[] dest; final int offset; FJDMap(Prefix prefix, int lo, int hi, FJBase next, double[] dest, int offset) { super(prefix, lo, hi, next); this.dest = dest; this.offset = offset; } FJBase newSubtask(int l, int h, FJBase r) { return new FJDMap(prefix, l, h, r, dest, offset); } void atLeaf(int l, int h) { prefix.leafTransfer(l, h, dest, l - offset); } } static final class FJLMap extends FJBase { final long[] dest; final int offset; FJLMap(Prefix prefix, int lo, int hi, FJBase next, long[] dest, int offset) { super(prefix, lo, hi, next); this.dest = dest; this.offset = offset; } FJBase newSubtask(int l, int h, FJBase r) { return new FJLMap(prefix, l, h, r, dest, offset); } void atLeaf(int l, int h) { prefix.leafTransfer(l, h, dest, l - offset); } } // transform static final class FJRTransform extends FJBase { final Mapper mapper; FJRTransform(Prefix prefix, int lo, int hi, FJBase next, Mapper mapper) { super(prefix, lo, hi, next); this.mapper = mapper; } FJBase newSubtask(int l, int h, FJBase r) { return new FJRTransform(prefix, l, h, r, mapper); } void atLeaf(int l, int h) { prefix.leafTransform(l, h, mapper); } } static final class FJDTransform extends FJBase { final DoubleMapper mapper; FJDTransform(Prefix prefix, int lo, int hi, FJBase next, DoubleMapper mapper) { super(prefix, lo, hi, next); this.mapper = mapper; } FJBase newSubtask(int l, int h, FJBase r) { return new FJDTransform(prefix, l, h, r, mapper); } void atLeaf(int l, int h) { prefix.leafTransform(l, h, mapper); } } static final class FJLTransform extends FJBase { final LongMapper mapper; FJLTransform(Prefix prefix, int lo, int hi, FJBase next, LongMapper mapper) { super(prefix, lo, hi, next); this.mapper = mapper; } FJBase newSubtask(int l, int h, FJBase r) { return new FJLTransform(prefix, l, h, r, mapper); } void atLeaf(int l, int h) { prefix.leafTransform(l, h, mapper); } } // index map static final class FJRIndexMap extends FJBase { final MapperFromInt mapper; FJRIndexMap(Prefix prefix, int lo, int hi, FJBase next, MapperFromInt mapper) { super(prefix, lo, hi, next); this.mapper = mapper; } FJBase newSubtask(int l, int h, FJBase r) { return new FJRIndexMap(prefix, l, h, r, mapper); } void atLeaf(int l, int h) { prefix.leafIndexMap(l, h, mapper); } } static final class FJDIndexMap extends FJBase { final MapperFromIntToDouble mapper; FJDIndexMap(Prefix prefix, int lo, int hi, FJBase next, MapperFromIntToDouble mapper) { super(prefix, lo, hi, next); this.mapper = mapper; } FJBase newSubtask(int l, int h, FJBase r) { return new FJDIndexMap(prefix, l, h, r, mapper); } void atLeaf(int l, int h) { prefix.leafIndexMap(l, h, mapper); } } static final class FJLIndexMap extends FJBase { final MapperFromIntToLong mapper; FJLIndexMap(Prefix prefix, int lo, int hi, FJBase next, MapperFromIntToLong mapper) { super(prefix, lo, hi, next); this.mapper = mapper; } FJBase newSubtask(int l, int h, FJBase r) { return new FJLIndexMap(prefix, l, h, r, mapper); } void atLeaf(int l, int h) { prefix.leafIndexMap(l, h, mapper); } } // generate static final class FJRGenerate extends FJBase { final Generator generator; FJRGenerate(Prefix prefix, int lo, int hi, FJBase next, Generator generator) { super(prefix, lo, hi, next); this.generator = generator; } FJBase newSubtask(int l, int h, FJBase r) { return new FJRGenerate(prefix, l, h, r, generator); } void atLeaf(int l, int h) { prefix.leafGenerate(l, h, generator); } } static final class FJDGenerate extends FJBase { final DoubleGenerator generator; FJDGenerate(Prefix prefix, int lo, int hi, FJBase next, DoubleGenerator generator) { super(prefix, lo, hi, next); this.generator = generator; } FJBase newSubtask(int l, int h, FJBase r) { return new FJDGenerate(prefix, l, h, r, generator); } void atLeaf(int l, int h) { prefix.leafGenerate(l, h, generator); } } static final class FJLGenerate extends FJBase { final LongGenerator generator; FJLGenerate(Prefix prefix, int lo, int hi, FJBase next, LongGenerator generator) { super(prefix, lo, hi, next); this.generator = generator; } FJBase newSubtask(int l, int h, FJBase r) { return new FJLGenerate(prefix, l, h, r, generator); } void atLeaf(int l, int h) { prefix.leafGenerate(l, h, generator); } } // fill static final class FJRFill extends FJBase { final Object value; FJRFill(Prefix prefix, int lo, int hi, FJBase next, Object value) { super(prefix, lo, hi, next); this.value = value; } FJBase newSubtask(int l, int h, FJBase r) { return new FJRFill(prefix, l, h, r, value); } void atLeaf(int l, int h) { prefix.leafFillValue(l, h, value); } } static final class FJDFill extends FJBase { final double value; FJDFill(Prefix prefix, int lo, int hi, FJBase next, double value) { super(prefix, lo, hi, next); this.value = value; } FJBase newSubtask(int l, int h, FJBase r) { return new FJDFill(prefix, l, h, r, value); } void atLeaf(int l, int h) { prefix.leafFillValue(l, h, value); } } static final class FJLFill extends FJBase { final long value; FJLFill(Prefix prefix, int lo, int hi, FJBase next, long value) { super(prefix, lo, hi, next); this.value = value; } FJBase newSubtask(int l, int h, FJBase r) { return new FJLFill(prefix, l, h, r, value); } void atLeaf(int l, int h) { prefix.leafFillValue(l, h, value); } } // combine in place static final class FJRCombineInPlace extends FJBase { final Object[] other; final int otherOffset; final Reducer combiner; FJRCombineInPlace(Prefix prefix, int lo, int hi, FJBase next, Object[] other, int otherOffset, Reducer combiner) { super(prefix, lo, hi, next); this.other = other; this.otherOffset = otherOffset; this.combiner = combiner; } FJBase newSubtask(int l, int h, FJBase r) { return new FJRCombineInPlace (prefix, l, h, r, other, otherOffset, combiner); } void atLeaf(int l, int h) { prefix.leafCombineInPlace(l, h, other, otherOffset, combiner); } } static final class FJDCombineInPlace extends FJBase { final double[] other; final int otherOffset; final DoubleReducer combiner; FJDCombineInPlace(Prefix prefix, int lo, int hi, FJBase next, double[] other, int otherOffset, DoubleReducer combiner) { super(prefix, lo, hi, next); this.other = other; this.otherOffset = otherOffset; this.combiner = combiner; } FJBase newSubtask(int l, int h, FJBase r) { return new FJDCombineInPlace (prefix, l, h, r, other, otherOffset, combiner); } void atLeaf(int l, int h) { prefix.leafCombineInPlace(l, h, other, otherOffset, combiner); } } static final class FJLCombineInPlace extends FJBase { final long[] other; final int otherOffset; final LongReducer combiner; FJLCombineInPlace(Prefix prefix, int lo, int hi, FJBase next, long[] other, int otherOffset, LongReducer combiner) { super(prefix, lo, hi, next); this.other = other; this.otherOffset = otherOffset; this.combiner = combiner; } FJBase newSubtask(int l, int h, FJBase r) { return new FJLCombineInPlace (prefix, l, h, r, other, otherOffset, combiner); } void atLeaf(int l, int h) { prefix.leafCombineInPlace(l, h, other, otherOffset, combiner); } } // combine static final class FJRCombine extends FJBase { final Object[] other; final Object[] dest; final int otherOffset; final Combiner combiner; FJRCombine(Prefix prefix, int lo, int hi, FJBase next, Object[] other, int otherOffset, Object[] dest, Combiner combiner) { super(prefix, lo, hi, next); this.other = other; this.otherOffset = otherOffset; this.dest = dest; this.combiner = combiner; } FJBase newSubtask(int l, int h, FJBase r) { return new FJRCombine(prefix, l, h, r, other, otherOffset, dest, combiner); } void atLeaf(int l, int h) { prefix.leafCombine(l, h, other, otherOffset, dest, combiner); } } static final class FJDCombine extends FJBase { final double[] other; final double[] dest; final int otherOffset; final DoubleReducer combiner; FJDCombine(Prefix prefix, int lo, int hi, FJBase next, double[] other, int otherOffset, double[] dest, DoubleReducer combiner) { super(prefix, lo, hi, next); this.other = other; this.otherOffset = otherOffset; this.dest = dest; this.combiner = combiner; } FJBase newSubtask(int l, int h, FJBase r) { return new FJDCombine(prefix, l, h, r, other, otherOffset, dest, combiner); } void atLeaf(int l, int h) { prefix.leafCombine(l, h, other, otherOffset, dest, combiner); } } static final class FJLCombine extends FJBase { final long[] other; final long[] dest; final int otherOffset; final LongReducer combiner; FJLCombine(Prefix prefix, int lo, int hi, FJBase next, long[] other, int otherOffset, long[] dest, LongReducer combiner) { super(prefix, lo, hi, next); this.other = other; this.otherOffset = otherOffset; this.dest = dest; this.combiner = combiner; } FJBase newSubtask(int l, int h, FJBase r) { return new FJLCombine(prefix, l, h, r, other, otherOffset, dest, combiner); } void atLeaf(int l, int h) { prefix.leafCombine(l, h, other, otherOffset, dest, combiner); } } // stats static final class FJRStats extends FJBase implements ParallelArray.SummaryStatistics { final Comparator comparator; public int size() { return size; } public Object min() { return min; } public Object max() { return max; } public int indexOfMin() { return indexOfMin; } public int indexOfMax() { return indexOfMax; } int size; Object min; Object max; int indexOfMin; int indexOfMax; FJRStats(Prefix prefix, int lo, int hi, FJBase next, Comparator comparator) { super(prefix, lo, hi, next); this.comparator = comparator; this.indexOfMin = -1; this.indexOfMax = -1; } FJBase newSubtask(int l, int h, FJBase r) { return new FJRStats(prefix, l, h, r, comparator); } void atLeaf(int l, int h) { prefix.leafStats(l, h, this); } void onReduce(FJBase right) { FJRStats r = (FJRStats)right; size += r.size; updateMin(r.indexOfMin, r.min); updateMax(r.indexOfMax, r.max); } void updateMin(int i, Object x) { if (i >= 0 && (indexOfMin < 0 || comparator.compare(min, x) > 0)) { min = x; indexOfMin = i; } } void updateMax(int i, Object x) { if (i >= 0 && (indexOfMax < 0 || comparator.compare(max, x) < 0)) { max = x; indexOfMax = i; } } public String toString() { return "size: " + size + " min: " + min + " (index " + indexOfMin + ") max: " + max + " (index " + indexOfMax + ")"; } } static final class FJDStats extends FJBase implements ParallelDoubleArray.SummaryStatistics { final DoubleComparator comparator; public int size() { return size; } public double min() { return min; } public double max() { return max; } public double sum() { return sum; } public double average() { return sum / size; } public int indexOfMin() { return indexOfMin; } public int indexOfMax() { return indexOfMax; } int size; double min; double max; double sum; int indexOfMin; int indexOfMax; FJDStats(Prefix prefix, int lo, int hi, FJBase next, DoubleComparator comparator) { super(prefix, lo, hi, next); this.comparator = comparator; this.indexOfMin = -1; this.indexOfMax = -1; this.min = Double.MAX_VALUE; this.max = -Double.MAX_VALUE; } FJBase newSubtask(int l, int h, FJBase r) { return new FJDStats(prefix, l, h, r, comparator); } void atLeaf(int l, int h) { prefix.leafStats(l, h, this); } void onReduce(FJBase right) { FJDStats r = (FJDStats)right; size += r.size; sum += r.sum; updateMin(r.indexOfMin, r.min); updateMax(r.indexOfMax, r.max); } void updateMin(int i, double x) { if (i >= 0 && (indexOfMin < 0 || comparator.compare(min, x) > 0)) { min = x; indexOfMin = i; } } void updateMax(int i, double x) { if (i >= 0 && (indexOfMax < 0 || comparator.compare(max, x) < 0)) { max = x; indexOfMax = i; } } public String toString() { return "size: " + size + " min: " + min + " (index " + indexOfMin + ") max: " + max + " (index " + indexOfMax + ") sum: " + sum; } } static final class FJLStats extends FJBase implements ParallelLongArray.SummaryStatistics { final LongComparator comparator; public int size() { return size; } public long min() { return min; } public long max() { return max; } public long sum() { return sum; } public double average() { return (double)sum / size; } public int indexOfMin() { return indexOfMin; } public int indexOfMax() { return indexOfMax; } int size; long min; long max; long sum; int indexOfMin; int indexOfMax; FJLStats(Prefix prefix, int lo, int hi, FJBase next, LongComparator comparator) { super(prefix, lo, hi, next); this.comparator = comparator; this.indexOfMin = -1; this.indexOfMax = -1; this.min = Long.MAX_VALUE; this.max = Long.MIN_VALUE; } FJBase newSubtask(int l, int h, FJBase r) { return new FJLStats(prefix, l, h, r, comparator); } void atLeaf(int l, int h) { prefix.leafStats(l, h, this); } void onReduce(FJBase right) { FJLStats r = (FJLStats)right; size += r.size; sum += r.sum; updateMin(r.indexOfMin, r.min); updateMax(r.indexOfMax, r.max); } void updateMin(int i, long x) { if (i >= 0 && (indexOfMin < 0 || comparator.compare(min, x) > 0)) { min = x; indexOfMin = i; } } void updateMax(int i, long x) { if (i >= 0 && (indexOfMax < 0 || comparator.compare(max, x) < 0)) { max = x; indexOfMax = i; } } public String toString() { return "size: " + size + " min: " + min + " (index " + indexOfMin + ") max: " + max + " (index " + indexOfMax + ") sum: " + sum; } } // count static final class FJRCountSelected extends FJBase { final Predicate selector; int count; FJRCountSelected(Prefix prefix, int lo, int hi, FJBase next, Predicate selector) { super(prefix, lo, hi, next); this.selector = selector; } FJBase newSubtask(int l, int h, FJBase r) { return new FJRCountSelected(prefix, l, h, r, selector); } void onReduce(FJBase right) { count += ((FJRCountSelected)right).count; } void atLeaf(int l, int h) { final Object[] array = prefix.rgetArray(); if (array == null) return; final Predicate sel = this.selector; int n = 0; for (int i = l; i < h; ++i) { if (sel.evaluate(array[i])) ++n; } count = n; } } static final class FJDCountSelected extends FJBase { final DoublePredicate selector; int count; FJDCountSelected(Prefix prefix, int lo, int hi, FJBase next, DoublePredicate selector) { super(prefix, lo, hi, next); this.selector = selector; } FJBase newSubtask(int l, int h, FJBase r) { return new FJDCountSelected(prefix, l, h, r, selector); } void onReduce(FJBase right) { count += ((FJDCountSelected)right).count; } void atLeaf(int l, int h) { final double[] array = prefix.dgetArray(); if (array == null) return; final DoublePredicate sel = this.selector; int n = 0; for (int i = l; i < h; ++i) { if (sel.evaluate(array[i])) ++n; } count = n; } } static final class FJLCountSelected extends FJBase { final LongPredicate selector; int count; FJLCountSelected(Prefix prefix, int lo, int hi, FJBase next, LongPredicate selector) { super(prefix, lo, hi, next); this.selector = selector; } FJBase newSubtask(int l, int h, FJBase r) { return new FJLCountSelected(prefix, l, h, r, selector); } void onReduce(FJBase right) { count += ((FJLCountSelected)right).count; } void atLeaf(int l, int h) { final long[] array = prefix.lgetArray(); if (array == null) return; final LongPredicate sel = this.selector; int n = 0; for (int i = l; i < h; ++i) { if (sel.evaluate(array[i])) ++n; } count = n; } } /** * Base for cancellable search tasks. Same idea as FJBase * but cancels tasks when result nonnegative. */ static abstract class FJSearchBase extends RecursiveAction { final Prefix prefix; final int lo; final int hi; final FJSearchBase next; final AtomicInteger result; FJSearchBase(Prefix prefix, int lo, int hi, FJSearchBase next, AtomicInteger result) { this.prefix = prefix; this.lo = lo; this.hi = hi; this.next = next; this.result = result; } public void compute() { if (result.get() >= 0) return; FJSearchBase r = null; int l = lo; int h = hi; while (prefix.shouldSplit(h - l)) { int rh = h; h = (l + h) >>> 1; (r = newSubtask(h, rh, r)).fork(); } atLeaf(l, h); boolean stopping = false; while (r != null) { stopping |= result.get() >= 0; if (ForkJoinWorkerThread.removeIfNextLocalTask(r)) { if (!stopping) r.atLeaf(r.lo, r.hi); } else if (stopping) r.cancel(); else r.join(); r = r.next; } } abstract FJSearchBase newSubtask(int l, int h, FJSearchBase r); abstract void atLeaf(int l, int h); } // select any static final class FJRSelectAny extends FJSearchBase { final Predicate selector; FJRSelectAny(Prefix prefix, int lo, int hi, FJSearchBase next, AtomicInteger result, Predicate selector) { super(prefix, lo, hi, next, result); this.selector = selector; } FJSearchBase newSubtask(int l, int h, FJSearchBase r) { return new FJRSelectAny(prefix, l, h, r, result, selector); } void atLeaf(int l, int h) { final Object[] array = prefix.rgetArray(); if (array == null) return; for (int i = l; i < h; ++i) { if (selector.evaluate(array[i])) { result.compareAndSet(-1, i); break; } else if (result.get() >= 0) break; } } } static final class FJDSelectAny extends FJSearchBase { final DoublePredicate selector; FJDSelectAny(Prefix prefix, int lo, int hi, FJSearchBase next, AtomicInteger result, DoublePredicate selector) { super(prefix, lo, hi, next, result); this.selector = selector; } FJSearchBase newSubtask(int l, int h, FJSearchBase r) { return new FJDSelectAny(prefix, l, h, r, result, selector); } void atLeaf(int l, int h) { final double[] array = prefix.dgetArray(); if (array == null) return; for (int i = l; i < h; ++i) { if (selector.evaluate(array[i])) { result.compareAndSet(-1, i); break; } else if (result.get() >= 0) break; } } } static final class FJLSelectAny extends FJSearchBase { final LongPredicate selector; FJLSelectAny(Prefix prefix, int lo, int hi, FJSearchBase next, AtomicInteger result, LongPredicate selector) { super(prefix, lo, hi, next, result); this.selector = selector; } FJSearchBase newSubtask(int l, int h, FJSearchBase r) { return new FJLSelectAny(prefix, l, h, r, result, selector); } void atLeaf(int l, int h) { final long[] array = prefix.lgetArray(); if (array == null) return; for (int i = l; i < h; ++i) { if (selector.evaluate(array[i])) { result.compareAndSet(-1, i); break; } else if (result.get() >= 0) break; } } } // index of static final class FJRIndexOf extends FJSearchBase { final Object target; FJRIndexOf(Prefix prefix, int lo, int hi, FJSearchBase next, AtomicInteger result, Object target) { super(prefix, lo, hi, next, result); this.target = target; } FJSearchBase newSubtask(int l, int h, FJSearchBase r) { return new FJRIndexOf(prefix, l, h, r, result, target); } void atLeaf(int l, int h) { final Object[] array = prefix.rgetArray(); if (array == null) return; for (int i = l; i < h; ++i) { if (target.equals(array[i])) { result.compareAndSet(-1, i); break; } else if (result.get() >= 0) break; } } } static final class FJDIndexOf extends FJSearchBase { final double target; FJDIndexOf(Prefix prefix, int lo, int hi, FJSearchBase next, AtomicInteger result, double target) { super(prefix, lo, hi, next, result); this.target = target; } FJSearchBase newSubtask(int l, int h, FJSearchBase r) { return new FJDIndexOf(prefix, l, h, r, result, target); } void atLeaf(int l, int h) { final double[] array = prefix.dgetArray(); if (array == null) return; for (int i = l; i < h; ++i) { if (target == (array[i])) { result.compareAndSet(-1, i); break; } else if (result.get() >= 0) break; } } } static final class FJLIndexOf extends FJSearchBase { final long target; FJLIndexOf(Prefix prefix, int lo, int hi, FJSearchBase next, AtomicInteger result, long target) { super(prefix, lo, hi, next, result); this.target = target; } FJSearchBase newSubtask(int l, int h, FJSearchBase r) { return new FJLIndexOf(prefix, l, h, r, result, target); } void atLeaf(int l, int h) { final long[] array = prefix.lgetArray(); if (array == null) return; for (int i = l; i < h; ++i) { if (target == (array[i])) { result.compareAndSet(-1, i); break; } else if (result.get() >= 0) break; } } } // select all /** * SelectAll proceeds in two passes. In the first pass, indices of * matching elements are recorded in indices array. In second pass, * once the size of results is known and result array is * constructed in driver, the matching elements are placed into * corresponding result positions. */ static final class FJSelectAll extends RecursiveAction { final FJSelectAllDriver driver; FJSelectAll left, right; final int lo; final int hi; int count; // number of matching elements int offset; boolean isInternal; // true if this is a non-leaf node FJSelectAll(FJSelectAllDriver driver, int lo, int hi) { this.driver = driver; this.lo = lo; this.hi = hi; } public void compute() { FJSelectAllDriver d = driver; if (d.phase == 0) { Prefix p = d.prefix; if (isInternal = p.shouldSplit(hi - lo)) internalPhase0(); else count = p.leafIndexSelected(lo, hi, true, d.indices); } else if (count != 0) { if (isInternal) internalPhase1(); else d.leafPhase1(lo, lo+count, offset); } } void internalPhase0() { int mid = (lo + hi) >>> 1; FJSelectAll l = new FJSelectAll(driver, lo, mid); FJSelectAll r = new FJSelectAll(driver, mid, hi); forkJoin(l, r); int ln = l.count; if (ln != 0) left = l; int rn = r.count; if (rn != 0) right = r; count = ln + rn; } void internalPhase1() { int k = offset; if (left != null) { int ln = left.count; left.offset = k; left.reinitialize(); if (right != null) { right.offset = k + ln; right.reinitialize(); forkJoin(left, right); } else left.compute(); } else if (right != null) { right.offset = k; right.compute(); } } } static abstract class FJSelectAllDriver extends RecursiveAction { final int[] indices; final Prefix prefix; int phase; FJSelectAllDriver(Prefix prefix) { this.prefix = prefix; int n = prefix.upperBound - prefix.firstIndex; indices = new int[n]; } public final void compute() { FJSelectAll r = new FJSelectAll (this, prefix.firstIndex, prefix.upperBound); r.compute(); createResults(r.count); phase = 1; r.compute(); } abstract void createResults(int size); abstract void leafPhase1(int loIdx, int hiIdx, int offset); } static final class FJRSelectAllDriver extends FJSelectAllDriver { final Class elementType; Object[] results; FJRSelectAllDriver(Prefix prefix, Class elementType) { super(prefix); this.elementType = elementType; } void createResults(int size) { results = (Object[])Array.newInstance(elementType, size); } void leafPhase1(int loIdx, int hiIdx, int offset) { prefix.leafTransferByIndex(indices, loIdx, hiIdx, results, offset); } } static final class FJDSelectAllDriver extends FJSelectAllDriver { double[] results; FJDSelectAllDriver(Prefix prefix) { super(prefix); } void createResults(int size) { results = new double[size]; } void leafPhase1(int loIdx, int hiIdx, int offset) { prefix.leafTransferByIndex(indices, loIdx, hiIdx, results, offset); } } static final class FJLSelectAllDriver extends FJSelectAllDriver { long[] results; FJLSelectAllDriver(Prefix prefix) { super(prefix); } void createResults(int size) { results = new long[size]; } void leafPhase1(int loIdx, int hiIdx, int offset) { prefix.leafTransferByIndex(indices, loIdx, hiIdx, results, offset); } } /** * Root node for FJRemoveAll. Spawns subtasks and shifts elements * as indices become available, bypassing index array creation * when offsets are known. This differs from SelectAll mainly in * that data movement is all done by the driver rather than in a * second parallel pass. */ static final class FJRemoveAllDriver extends RecursiveAction { final Prefix prefix; final int lo; final int hi; final int[] indices; int offset; FJRemoveAllDriver(Prefix prefix, int lo, int hi) { this.prefix = prefix; this.lo = lo; this.hi = hi; this.indices = new int[hi - lo]; } public void compute() { FJRemoveAll r = null; int l = lo; int h = hi; while (prefix.shouldSplit(h - l)) { int rh = h; h = (l + h) >>> 1; (r = new FJRemoveAll(prefix, h, rh, r, indices)).fork(); } int k = prefix.leafMoveSelected(l, h, l, false); while (r != null) { if (ForkJoinWorkerThread.removeIfNextLocalTask(r)) k = prefix.leafMoveSelected(r.lo, r.hi, k, false); else { r.join(); int n = r.count; if (n != 0) prefix.leafMoveByIndex(indices, r.lo, r.lo+n, k); k += n; FJRemoveAll rr = r.right; if (rr != null) k = inorderMove(rr, k); } r = r.next; } offset = k; } /** * Inorder traversal to move indexed elements across reachable * nodes. This guarantees that element shifts don't overwrite * those still being used by active subtasks. */ static int inorderMove(FJRemoveAll t, int index) { while (t != null) { int n = t.count; if (n != 0) t.prefix.leafMoveByIndex(t.indices, t.lo, t.lo+n, index); index += n; FJRemoveAll p = t.next; if (p != null) index = inorderMove(p, index); t = t.right; } return index; } } /** * Basic FJ tssk for non-root FJRemoveAll nodes */ static final class FJRemoveAll extends RecursiveAction { final Prefix prefix; final int lo; final int hi; final FJRemoveAll next; final int[] indices; int count; FJRemoveAll right; FJRemoveAll(Prefix prefix, int lo, int hi, FJRemoveAll next, int[] indices) { this.prefix = prefix; this.lo = lo; this.hi = hi; this.next = next; this.indices = indices; } public void compute() { FJRemoveAll r = null; int l = lo; int h = hi; while (prefix.shouldSplit(h - l)) { int rh = h; h = (l + h) >>> 1; (r = new FJRemoveAll(prefix, h, rh, r, indices)).fork(); } right = r; count = prefix.leafIndexSelected(l, h, false, indices); while (r != null) { if (ForkJoinWorkerThread.removeIfNextLocalTask(r)) r.count = prefix.leafIndexSelected (r.lo, r.hi, false, indices); else r.join(); r = r.next; } } } // unique elements static final class FJUniquifier extends FJBase { final UniquifierTable table; int count; FJUniquifier(Prefix prefix, int lo, int hi, FJBase next, UniquifierTable table) { super(prefix, lo, hi, next); this.table = table; } FJBase newSubtask(int l, int h, FJBase r) { return new FJUniquifier(prefix, l, h, r, table); } void atLeaf(int l, int h) { count = table.addElements(l, h); } void onReduce(FJBase right) { count += ((FJUniquifier)right).count; } } /** * Base class of fixed-size hash tables for * uniquification. Opportunistically subclasses * AtomicLongArray. The high word of each slot is the cached * massaged hash of an element, and the low word contains its * index, plus one, to ensure that a zero tab entry means * empty. The mechanics for this are just folded into the * main addElements method. * Each leaf step places source array elements into table, * Even though this table undergoes a lot of contention when * elements are concurrently inserted by parallel threads, it is * generally faster to do this than to have separate tables and * then merge them. */ static abstract class UniquifierTable extends AtomicLongArray { UniquifierTable(int size) { super(tableSizeFor(size)); } /** Returns a good size for table */ static int tableSizeFor(int n) { int padded = n + (n >>> 1) + 1; if (padded < n) // int overflow throw new OutOfMemoryError(); int s = 8; while (s < padded) s <<= 1; return s; } // Same hashcode conditioning as HashMap static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } /** * Add source elements from lo to hi; return count * of number of unique elements inserted */ abstract int addElements(int lo, int hi); } static final class RUniquifierTable extends UniquifierTable { final Object[] source; final Predicate selector; final boolean byIdentity; RUniquifierTable(int size, Object[] array, Predicate selector, boolean byIdentity) { super(size); this.source = array; this.selector = selector; this.byIdentity = byIdentity; } int addElements(int lo, int hi) { final Predicate selector = this.selector; final Object[] src = source; final int mask = length() - 1; int count = 0; for (int k = lo; k < hi; ++k) { Object x = src[k]; if (x == null || (selector != null && !selector.evaluate(x))) continue; int hc = byIdentity? System.identityHashCode(x): x.hashCode(); int hash = hash(hc); long entry = (((long)hash) << 32) + (k + 1); int idx = hash & mask; for (;;) { long d = get(idx); if (d != 0) { if ((int)(d >>> 32) == hash) { Object y = src[(int)((d - 1) & 0x7fffffffL)]; if (byIdentity? (x == y) : x.equals(y)) break; } idx = (idx + 1) & mask; } else if (compareAndSet(idx, 0, entry)) { ++count; break; } } } return count; } /** * Return new array holding all elements. */ Object[] uniqueElements(int size) { Object[] src = source; Class sclass = src.getClass().getComponentType(); Object[] res = (Object[])Array.newInstance(sclass, size); int k = 0; int n = length(); for (int i = 0; i < n && k < size; ++i) { long d = get(i); if (d != 0) res[k++] = src[((int)((d - 1) & 0x7fffffffL))]; } return res; } } static final class DUniquifierTable extends UniquifierTable { final double[] source; final DoublePredicate selector; DUniquifierTable(int size, double[] array, DoublePredicate selector) { super(size); this.source = array; this.selector = selector; } int addElements(int lo, int hi) { final DoublePredicate selector = this.selector; final double[] src = source; final int mask = length() - 1; int count = 0; for (int k = lo; k < hi; ++k) { double x = src[k]; if (selector != null && !selector.evaluate(x)) continue; long bits = Double.doubleToLongBits(x); int hash = hash((int)(bits ^ (bits >>> 32)));; long entry = (((long)hash) << 32) + (k + 1); int idx = hash & mask; for (;;) { long d = get(idx); if (d != 0) { if ((int)(d >>> 32) == hash && x == (src[(int)((d - 1) & 0x7fffffffL)])) break; idx = (idx + 1) & mask; } else if (compareAndSet(idx, 0, entry)) { ++count; break; } } } return count; } double[] uniqueElements(int size) { double[] res = new double[size]; double[] src = source; int k = 0; int n = length(); for (int i = 0; i < n && k < size; ++i) { long d = get(i); if (d != 0) res[k++] = src[((int)((d - 1) & 0x7fffffffL))]; } return res; } } static final class LUniquifierTable extends UniquifierTable { final long[] source; final LongPredicate selector; LUniquifierTable(int size, long[] array, LongPredicate selector) { super(size); this.source = array; this.selector = selector; } int addElements(int lo, int hi) { final LongPredicate selector = this.selector; final long[] src = source; final int mask = length() - 1; int count = 0; for (int k = lo; k < hi; ++k) { long x = src[k]; if (selector != null && !selector.evaluate(x)) continue; int hash = hash((int)(x ^ (x >>> 32))); long entry = (((long)hash) << 32) + (k + 1); int idx = hash & mask; for (;;) { long d = get(idx); if (d != 0) { if ((int)(d >>> 32) == hash && x == (src[(int)((d - 1) & 0x7fffffffL)])) break; idx = (idx + 1) & mask; } else if (compareAndSet(idx, 0, entry)) { ++count; break; } } } return count; } long[] uniqueElements(int size) { long[] res = new long[size]; long[] src = source; int k = 0; int n = length(); for (int i = 0; i < n && k < size; ++i) { long d = get(i); if (d != 0) res[k++] = src[((int)((d - 1) & 0x7fffffffL))]; } return res; } } /** * Sorter classes based mainly on CilkSort * Cilk: * Basic algorithm: * if array size is small, just use a sequential quicksort * Otherwise: * 1. Break array in half. * 2. For each half, * a. break the half in half (i.e., quarters), * b. sort the quarters * c. merge them together * 3. merge together the two halves. * * One reason for splitting in quarters is that this guarantees * that the final sort is in the main array, not the workspace * array. (workspace and main swap roles on each subsort step.) * Leaf-level sorts use a Sequential quicksort, that in turn uses * insertion sort if under threshold. Otherwise it uses median of * three to pick pivot, and loops rather than recurses along left * path. * * It is sad but true that sort and merge performance are * sensitive enough to inner comparison overhead to warrant * creating 6 versions (not just 3) -- one each for natural * comparisons vs supplied comparators. */ static final class FJRSorter extends RecursiveAction { final Comparator cmp; final Object[] a; // array to be sorted. final Object[] w; // workspace for merge final int origin; // origin of the part of array we deal with final int n; // Number of elements in (sub)arrays. final int gran; // split control FJRSorter(Comparator cmp, Object[] a, Object[] w, int origin, int n, int gran) { this.cmp = cmp; this.a = a; this.w = w; this.origin = origin; this.n = n; this.gran = gran; } public void compute() { int l = origin; int g = gran; if (n > g) { int h = n >>> 1; // half int q = n >>> 2; // lower quarter index int u = h + q; // upper quarter forkJoin(new FJSubSorter (new FJRSorter(cmp, a, w, l, q, g), new FJRSorter(cmp, a, w, l+q, h-q, g), new FJRMerger(cmp, a, w, l, q, l+q, h-q, l, g, null)), new FJSubSorter (new FJRSorter(cmp, a, w, l+h, q, g), new FJRSorter(cmp, a, w, l+u, n-u, g), new FJRMerger(cmp, a, w, l+h, q, l+u, n-u, l+h, g, null))); new FJRMerger(cmp, w, a, l, h, l+h, n-h, l, g, null).compute(); } else rquickSort(a, cmp, l, l+n-1); } } static final class FJRCSorter extends RecursiveAction { final Comparable[] a; final Comparable[] w; final int origin; final int n; final int gran; FJRCSorter(Comparable[] a, Comparable[] w, int origin, int n, int gran) { this.a = a; this.w = w; this.origin = origin; this.n = n; this.gran = gran; } public void compute() { int l = origin; int g = gran; if (n > g) { int h = n >>> 1; int q = n >>> 2; int u = h + q; forkJoin(new FJSubSorter (new FJRCSorter(a, w, l, q, g), new FJRCSorter(a, w, l+q, h-q, g), new FJRCMerger(a, w, l, q, l+q, h-q, l, g, null)), new FJSubSorter (new FJRCSorter(a, w, l+h, q, g), new FJRCSorter(a, w, l+u, n-u, g), new FJRCMerger(a, w, l+h, q, l+u, n-u, l+h, g, null))); new FJRCMerger(w, a, l, h, l+h, n-h, l, g, null).compute(); } else rcquickSort(a, l, l+n-1); } } static final class FJDSorter extends RecursiveAction { final DoubleComparator cmp; final double[] a; final double[] w; final int origin; final int n; final int gran; FJDSorter(DoubleComparator cmp, double[] a, double[] w, int origin, int n, int gran) { this.cmp = cmp; this.a = a; this.w = w; this.origin = origin; this.n = n; this.gran = gran; } public void compute() { int l = origin; int g = gran; if (n > g) { int h = n >>> 1; int q = n >>> 2; int u = h + q; forkJoin(new FJSubSorter (new FJDSorter(cmp, a, w, l, q, g), new FJDSorter(cmp, a, w, l+q, h-q, g), new FJDMerger(cmp, a, w, l, q, l+q, h-q, l, g, null)), new FJSubSorter (new FJDSorter(cmp, a, w, l+h, q, g), new FJDSorter(cmp, a, w, l+u, n-u, g), new FJDMerger(cmp, a, w, l+h, q, l+u, n-u, l+h, g, null))); new FJDMerger(cmp, w, a, l, h, l+h, n-h, l, g, null).compute(); } else dquickSort(a, cmp, l, l+n-1); } } static final class FJDCSorter extends RecursiveAction { final double[] a; final double[] w; final int origin; final int n; final int gran; FJDCSorter(double[] a, double[] w, int origin, int n, int gran) { this.a = a; this.w = w; this.origin = origin; this.n = n; this.gran = gran; } public void compute() { int l = origin; int g = gran; if (n > g) { int h = n >>> 1; int q = n >>> 2; int u = h + q; forkJoin(new FJSubSorter (new FJDCSorter(a, w, l, q, g), new FJDCSorter(a, w, l+q, h-q, g), new FJDCMerger(a, w, l, q, l+q, h-q, l, g, null)), new FJSubSorter (new FJDCSorter(a, w, l+h, q, g), new FJDCSorter(a, w, l+u, n-u, g), new FJDCMerger(a, w, l+h, q, l+u, n-u, l+h, g, null))); new FJDCMerger(w, a, l, h, l+h, n-h, l, g, null).compute(); } else dcquickSort(a, l, l+n-1); } } static final class FJLSorter extends RecursiveAction { final LongComparator cmp; final long[] a; final long[] w; final int origin; final int n; final int gran; FJLSorter(LongComparator cmp, long[] a, long[] w, int origin, int n, int gran) { this.cmp = cmp; this.a = a; this.w = w; this.origin = origin; this.n = n; this.gran = gran; } public void compute() { int l = origin; int g = gran; if (n > g) { int h = n >>> 1; int q = n >>> 2; int u = h + q; forkJoin(new FJSubSorter (new FJLSorter(cmp, a, w, l, q, g), new FJLSorter(cmp, a, w, l+q, h-q, g), new FJLMerger(cmp, a, w, l, q, l+q, h-q, l, g, null)), new FJSubSorter (new FJLSorter(cmp, a, w, l+h, q, g), new FJLSorter(cmp, a, w, l+u, n-u, g), new FJLMerger(cmp, a, w, l+h, q, l+u, n-u, l+h, g, null))); new FJLMerger(cmp, w, a, l, h, l+h, n-h, l, g, null).compute(); } else lquickSort(a, cmp, l, l+n-1); } } static final class FJLCSorter extends RecursiveAction { final long[] a; final long[] w; final int origin; final int n; final int gran; FJLCSorter(long[] a, long[] w, int origin, int n, int gran) { this.a = a; this.w = w; this.origin = origin; this.n = n; this.gran = gran; } public void compute() { int l = origin; int g = gran; if (n > g) { int h = n >>> 1; int q = n >>> 2; int u = h + q; forkJoin(new FJSubSorter (new FJLCSorter(a, w, l, q, g), new FJLCSorter(a, w, l+q, h-q, g), new FJLCMerger(a, w, l, q, l+q, h-q, l, g, null)), new FJSubSorter (new FJLCSorter(a, w, l+h, q, g), new FJLCSorter(a, w, l+u, n-u, g), new FJLCMerger(a, w, l+h, q, l+u, n-u, l+h, g, null))); new FJLCMerger(w, a, l, h, l+h, n-h, l, g, null).compute(); } else lcquickSort(a, l, l+n-1); } } /** Utility class to sort half a partitioned array */ static final class FJSubSorter extends RecursiveAction { final RecursiveAction left; final RecursiveAction right; final RecursiveAction merger; FJSubSorter(RecursiveAction left, RecursiveAction right, RecursiveAction merger){ this.left = left; this.right = right; this.merger = merger; } public void compute() { forkJoin(left, right); merger.compute(); } } /** * Perform merging for FJSorter. If big enough, splits Left * partition in half; finds the greatest point in Right partition * less than the beginning of the second half of Left via binary * search; and then, in parallel, merges left half of Left with * elements of Right up to split point, and merges right half of * Left with elements of R past split point. At leaf, it just * sequentially merges. This is all messy to code; sadly we need * six versions. */ static final class FJRMerger extends RecursiveAction { final Comparator cmp; final Object[] a; // partitioned array. final Object[] w; // Output array. final int lo; // relative origin of left side of a final int ln; // number of elements on left of a final int ro; // relative origin of right side of a final int rn; // number of elements on right of a final int wo; // origin for output final int gran; final FJRMerger next; FJRMerger(Comparator cmp, Object[] a, Object[] w, int lo, int ln, int ro, int rn, int wo, int gran, FJRMerger next) { this.cmp = cmp; this.a = a; this.w = w; this.lo = lo; this.ln = ln; this.ro = ro; this.rn = rn; this.wo = wo; this.gran = gran; this.next = next; } public void compute() { // spawn right subtasks FJRMerger rights = null; int nleft = ln; int nright = rn; while (nleft > gran) { int lh = nleft >>> 1; int splitIndex = lo + lh; Object split = a[splitIndex]; // binary search r for split int rl = 0; int rh = nright; while (rl < rh) { int mid = (rl + rh) >>> 1; if (cmp.compare(split, a[ro + mid]) <= 0) rh = mid; else rl = mid + 1; } (rights = new FJRMerger (cmp, a, w, splitIndex, nleft-lh, ro+rh, nright-rh, wo+lh+rh, gran, rights)).fork(); nleft = lh; nright = rh; } // sequentially merge int l = lo; int lFence = lo + nleft; int r = ro; int rFence = ro + nright; int k = wo; while (l < lFence && r < rFence) { Object al = a[l]; Object ar = a[r]; Object t; if (cmp.compare(al, ar) <= 0) {++l; t=al;} else {++r; t=ar;} w[k++] = t; } while (l < lFence) w[k++] = a[l++]; while (r < rFence) w[k++] = a[r++]; // join subtasks while (rights != null) { if (ForkJoinWorkerThread.removeIfNextLocalTask(rights)) rights.compute(); else rights.join(); rights = rights.next; } } } static final class FJRCMerger extends RecursiveAction { final Comparable[] a; final Comparable[] w; final int lo; final int ln; final int ro; final int rn; final int wo; final int gran; final FJRCMerger next; FJRCMerger(Comparable[] a, Comparable[] w, int lo, int ln, int ro, int rn, int wo, int gran, FJRCMerger next) { this.a = a; this.w = w; this.lo = lo; this.ln = ln; this.ro = ro; this.rn = rn; this.wo = wo; this.gran = gran; this.next = next; } public void compute() { FJRCMerger rights = null; int nleft = ln; int nright = rn; while (nleft > gran) { int lh = nleft >>> 1; int splitIndex = lo + lh; Comparable split = a[splitIndex]; int rl = 0; int rh = nright; while (rl < rh) { int mid = (rl + rh) >>> 1; if (split.compareTo(a[ro + mid]) <= 0) rh = mid; else rl = mid + 1; } (rights = new FJRCMerger (a, w, splitIndex, nleft-lh, ro+rh, nright-rh, wo+lh+rh, gran, rights)).fork(); nleft = lh; nright = rh; } int l = lo; int lFence = lo + nleft; int r = ro; int rFence = ro + nright; int k = wo; while (l < lFence && r < rFence) { Comparable al = a[l]; Comparable ar = a[r]; Comparable t; if (al.compareTo(ar) <= 0) {++l; t=al;} else {++r; t=ar; } w[k++] = t; } while (l < lFence) w[k++] = a[l++]; while (r < rFence) w[k++] = a[r++]; while (rights != null) { if (ForkJoinWorkerThread.removeIfNextLocalTask(rights)) rights.compute(); else rights.join(); rights = rights.next; } } } static final class FJDMerger extends RecursiveAction { final DoubleComparator cmp; final double[] a; final double[] w; final int lo; final int ln; final int ro; final int rn; final int wo; final int gran; final FJDMerger next; FJDMerger(DoubleComparator cmp, double[] a, double[] w, int lo, int ln, int ro, int rn, int wo, int gran, FJDMerger next) { this.cmp = cmp; this.a = a; this.w = w; this.lo = lo; this.ln = ln; this.ro = ro; this.rn = rn; this.wo = wo; this.gran = gran; this.next = next; } public void compute() { FJDMerger rights = null; int nleft = ln; int nright = rn; while (nleft > gran) { int lh = nleft >>> 1; int splitIndex = lo + lh; double split = a[splitIndex]; int rl = 0; int rh = nright; while (rl < rh) { int mid = (rl + rh) >>> 1; if (cmp.compare(split, a[ro + mid]) <= 0) rh = mid; else rl = mid + 1; } (rights = new FJDMerger (cmp, a, w, splitIndex, nleft-lh, ro+rh, nright-rh, wo+lh+rh, gran, rights)).fork(); nleft = lh; nright = rh; } int l = lo; int lFence = lo + nleft; int r = ro; int rFence = ro + nright; int k = wo; while (l < lFence && r < rFence) { double al = a[l]; double ar = a[r]; double t; if (cmp.compare(al, ar) <= 0) {++l; t=al;} else {++r; t=ar; } w[k++] = t; } while (l < lFence) w[k++] = a[l++]; while (r < rFence) w[k++] = a[r++]; while (rights != null) { if (ForkJoinWorkerThread.removeIfNextLocalTask(rights)) rights.compute(); else rights.join(); rights = rights.next; } } } static final class FJDCMerger extends RecursiveAction { final double[] a; final double[] w; final int lo; final int ln; final int ro; final int rn; final int wo; final int gran; final FJDCMerger next; FJDCMerger(double[] a, double[] w, int lo, int ln, int ro, int rn, int wo, int gran, FJDCMerger next) { this.a = a; this.w = w; this.lo = lo; this.ln = ln; this.ro = ro; this.rn = rn; this.wo = wo; this.gran = gran; this.next = next; } public void compute() { FJDCMerger rights = null; int nleft = ln; int nright = rn; while (nleft > gran) { int lh = nleft >>> 1; int splitIndex = lo + lh; double split = a[splitIndex]; int rl = 0; int rh = nright; while (rl < rh) { int mid = (rl + rh) >>> 1; if (split <= a[ro + mid]) rh = mid; else rl = mid + 1; } (rights = new FJDCMerger (a, w, splitIndex, nleft-lh, ro+rh, nright-rh, wo+lh+rh, gran, rights)).fork(); nleft = lh; nright = rh; } int l = lo; int lFence = lo + nleft; int r = ro; int rFence = ro + nright; int k = wo; while (l < lFence && r < rFence) { double al = a[l]; double ar = a[r]; double t; if (al <= ar) {++l; t=al;} else {++r; t=ar; } w[k++] = t; } while (l < lFence) w[k++] = a[l++]; while (r < rFence) w[k++] = a[r++]; while (rights != null) { if (ForkJoinWorkerThread.removeIfNextLocalTask(rights)) rights.compute(); else rights.join(); rights = rights.next; } } } static final class FJLMerger extends RecursiveAction { final LongComparator cmp; final long[] a; final long[] w; final int lo; final int ln; final int ro; final int rn; final int wo; final int gran; final FJLMerger next; FJLMerger(LongComparator cmp, long[] a, long[] w, int lo, int ln, int ro, int rn, int wo, int gran, FJLMerger next) { this.cmp = cmp; this.a = a; this.w = w; this.lo = lo; this.ln = ln; this.ro = ro; this.rn = rn; this.wo = wo; this.gran = gran; this.next = next; } public void compute() { FJLMerger rights = null; int nleft = ln; int nright = rn; while (nleft > gran) { int lh = nleft >>> 1; int splitIndex = lo + lh; long split = a[splitIndex]; int rl = 0; int rh = nright; while (rl < rh) { int mid = (rl + rh) >>> 1; if (cmp.compare(split, a[ro + mid]) <= 0) rh = mid; else rl = mid + 1; } (rights = new FJLMerger (cmp, a, w, splitIndex, nleft-lh, ro+rh, nright-rh, wo+lh+rh, gran, rights)).fork(); nleft = lh; nright = rh; } int l = lo; int lFence = lo + nleft; int r = ro; int rFence = ro + nright; int k = wo; while (l < lFence && r < rFence) { long al = a[l]; long ar = a[r]; long t; if (cmp.compare(al, ar) <= 0) {++l; t=al;} else {++r; t=ar;} w[k++] = t; } while (l < lFence) w[k++] = a[l++]; while (r < rFence) w[k++] = a[r++]; while (rights != null) { if (ForkJoinWorkerThread.removeIfNextLocalTask(rights)) rights.compute(); else rights.join(); rights = rights.next; } } } static final class FJLCMerger extends RecursiveAction { final long[] a; final long[] w; final int lo; final int ln; final int ro; final int rn; final int wo; final int gran; final FJLCMerger next; FJLCMerger(long[] a, long[] w, int lo, int ln, int ro, int rn, int wo, int gran, FJLCMerger next) { this.a = a; this.w = w; this.lo = lo; this.ln = ln; this.ro = ro; this.rn = rn; this.wo = wo; this.gran = gran; this.next = next; } public void compute() { FJLCMerger rights = null; int nleft = ln; int nright = rn; while (nleft > gran) { int lh = nleft >>> 1; int splitIndex = lo + lh; long split = a[splitIndex]; int rl = 0; int rh = nright; while (rl < rh) { int mid = (rl + rh) >>> 1; if (split <= a[ro + mid]) rh = mid; else rl = mid + 1; } (rights = new FJLCMerger (a, w, splitIndex, nleft-lh, ro+rh, nright-rh, wo+lh+rh, gran, rights)).fork(); nleft = lh; nright = rh; } int l = lo; int lFence = lo + nleft; int r = ro; int rFence = ro + nright; int k = wo; while (l < lFence && r < rFence) { long al = a[l]; long ar = a[r]; long t; if (al <= ar) {++l; t=al;} else {++r; t = ar;} w[k++] = t; } while (l < lFence) w[k++] = a[l++]; while (r < rFence) w[k++] = a[r++]; while (rights != null) { if (ForkJoinWorkerThread.removeIfNextLocalTask(rights)) rights.compute(); else rights.join(); rights = rights.next; } } } /** Cutoff for when to use insertion-sort instead of quicksort */ static final int INSERTION_SORT_THRESHOLD = 8; // Six nearly identical versions of quicksort static void rquickSort(Object[] a, Comparator cmp, int lo, int hi) { for (;;) { if (hi - lo <= INSERTION_SORT_THRESHOLD) { for (int i = lo + 1; i <= hi; i++) { Object t = a[i]; int j = i - 1; while (j >= lo && cmp.compare(t, a[j]) < 0) { a[j+1] = a[j]; --j; } a[j+1] = t; } return; } int mid = (lo + hi) >>> 1; if (cmp.compare(a[lo], a[mid]) > 0) { Object t = a[lo]; a[lo] = a[mid]; a[mid] = t; } if (cmp.compare(a[mid], a[hi]) > 0) { Object t = a[mid]; a[mid] = a[hi]; a[hi] = t; if (cmp.compare(a[lo], a[mid]) > 0) { Object u = a[lo]; a[lo] = a[mid]; a[mid] = u; } } Object pivot = a[mid]; int left = lo+1; int right = hi-1; for (;;) { while (cmp.compare(pivot, a[right]) < 0) --right; while (left < right && cmp.compare(pivot, a[left]) >= 0) ++left; if (left < right) { Object t = a[left]; a[left] = a[right]; a[right] = t; --right; } else break; } rquickSort(a, cmp, lo, left); lo = left + 1; } } static void rcquickSort(Comparable[] a, int lo, int hi) { for (;;) { if (hi - lo <= INSERTION_SORT_THRESHOLD) { for (int i = lo + 1; i <= hi; i++) { Comparable t = a[i]; int j = i - 1; while (j >= lo && t.compareTo(a[j]) < 0) { a[j+1] = a[j]; --j; } a[j+1] = t; } return; } int mid = (lo + hi) >>> 1; if (a[lo].compareTo(a[mid]) > 0) { Comparable t = a[lo]; a[lo] = a[mid]; a[mid] = t; } if (a[mid].compareTo(a[hi]) > 0) { Comparable t = a[mid]; a[mid] = a[hi]; a[hi] = t; if (a[lo].compareTo(a[mid]) > 0) { Comparable u = a[lo]; a[lo] = a[mid]; a[mid] = u; } } Comparable pivot = a[mid]; int left = lo+1; int right = hi-1; for (;;) { while (pivot.compareTo(a[right]) < 0) --right; while (left < right && pivot.compareTo(a[left]) >= 0) ++left; if (left < right) { Comparable t = a[left]; a[left] = a[right]; a[right] = t; --right; } else break; } rcquickSort(a, lo, left); lo = left + 1; } } static void dquickSort(double[] a, DoubleComparator cmp, int lo, int hi) { for (;;) { if (hi - lo <= INSERTION_SORT_THRESHOLD) { for (int i = lo + 1; i <= hi; i++) { double t = a[i]; int j = i - 1; while (j >= lo && cmp.compare(t, a[j]) < 0) { a[j+1] = a[j]; --j; } a[j+1] = t; } return; } int mid = (lo + hi) >>> 1; if (cmp.compare(a[lo], a[mid]) > 0) { double t = a[lo]; a[lo] = a[mid]; a[mid] = t; } if (cmp.compare(a[mid], a[hi]) > 0) { double t = a[mid]; a[mid] = a[hi]; a[hi] = t; if (cmp.compare(a[lo], a[mid]) > 0) { double u = a[lo]; a[lo] = a[mid]; a[mid] = u; } } double pivot = a[mid]; int left = lo+1; int right = hi-1; for (;;) { while (cmp.compare(pivot, a[right]) < 0) --right; while (left < right && cmp.compare(pivot, a[left]) >= 0) ++left; if (left < right) { double t = a[left]; a[left] = a[right]; a[right] = t; --right; } else break; } dquickSort(a, cmp, lo, left); lo = left + 1; } } static void dcquickSort(double[] a, int lo, int hi) { for (;;) { if (hi - lo <= INSERTION_SORT_THRESHOLD) { for (int i = lo + 1; i <= hi; i++) { double t = a[i]; int j = i - 1; while (j >= lo && t < a[j]) { a[j+1] = a[j]; --j; } a[j+1] = t; } return; } int mid = (lo + hi) >>> 1; if (a[lo] > a[mid]) { double t = a[lo]; a[lo] = a[mid]; a[mid] = t; } if (a[mid] > a[hi]) { double t = a[mid]; a[mid] = a[hi]; a[hi] = t; if (a[lo] > a[mid]) { double u = a[lo]; a[lo] = a[mid]; a[mid] = u; } } double pivot = a[mid]; int left = lo+1; int right = hi-1; for (;;) { while (pivot < a[right]) --right; while (left < right && pivot >= a[left]) ++left; if (left < right) { double t = a[left]; a[left] = a[right]; a[right] = t; --right; } else break; } dcquickSort(a, lo, left); lo = left + 1; } } static void lquickSort(long[] a, LongComparator cmp, int lo, int hi) { for (;;) { if (hi - lo <= INSERTION_SORT_THRESHOLD) { for (int i = lo + 1; i <= hi; i++) { long t = a[i]; int j = i - 1; while (j >= lo && cmp.compare(t, a[j]) < 0) { a[j+1] = a[j]; --j; } a[j+1] = t; } return; } int mid = (lo + hi) >>> 1; if (cmp.compare(a[lo], a[mid]) > 0) { long t = a[lo]; a[lo] = a[mid]; a[mid] = t; } if (cmp.compare(a[mid], a[hi]) > 0) { long t = a[mid]; a[mid] = a[hi]; a[hi] = t; if (cmp.compare(a[lo], a[mid]) > 0) { long u = a[lo]; a[lo] = a[mid]; a[mid] = u; } } long pivot = a[mid]; int left = lo+1; int right = hi-1; for (;;) { while (cmp.compare(pivot, a[right]) < 0) --right; while (left < right && cmp.compare(pivot, a[left]) >= 0) ++left; if (left < right) { long t = a[left]; a[left] = a[right]; a[right] = t; --right; } else break; } lquickSort(a, cmp, lo, left); lo = left + 1; } } static void lcquickSort(long[] a, int lo, int hi) { for (;;) { if (hi - lo <= INSERTION_SORT_THRESHOLD) { for (int i = lo + 1; i <= hi; i++) { long t = a[i]; int j = i - 1; while (j >= lo && t < a[j]) { a[j+1] = a[j]; --j; } a[j+1] = t; } return; } int mid = (lo + hi) >>> 1; if (a[lo] > a[mid]) { long t = a[lo]; a[lo] = a[mid]; a[mid] = t; } if (a[mid] > a[hi]) { long t = a[mid]; a[mid] = a[hi]; a[hi] = t; if (a[lo] > a[mid]) { long u = a[lo]; a[lo] = a[mid]; a[mid] = u; } } long pivot = a[mid]; int left = lo+1; int right = hi-1; for (;;) { while (pivot < a[right]) --right; while (left < right && pivot >= a[left]) ++left; if (left < right) { long t = a[left]; a[left] = a[right]; a[right] = t; --right; } else break; } lcquickSort(a, lo, left); lo = left + 1; } } /** * Cumulative scan * * A basic version of scan is straightforward. * Keep dividing by two to threshold segment size, and then: * Pass 1: Create tree of partial sums for each segment * Pass 2: For each segment, cumulate with offset of left sibling * See G. Blelloch's http://www.cs.cmu.edu/~scandal/alg/scan.html * * This version improves performance within FJ framework mainly by * allowing second pass of ready left-hand sides to proceed even * if some right-hand side first passes are still executing. It * also combines first and second pass for leftmost segment, and * for cumulate (not precumulate) also skips first pass for * rightmost segment (whose result is not needed for second pass). * * To manage this, it relies on "phase" phase/state control field * maintaining bits CUMULATE, SUMMED, and FINISHED. CUMULATE is * main phase bit. When false, segments compute only their sum. * When true, they cumulate array elements. CUMULATE is set at * root at beginning of second pass and then propagated down. But * it may also be set earlier for subtrees with lo==firstIndex (the * left spine of tree). SUMMED is a one bit join count. For leafs, * set when summed. For internal nodes, becomes true when one * child is summed. When second child finishes summing, it then * moves up tree to trigger cumulate phase. FINISHED is also a one * bit join count. For leafs, it is set when cumulated. For * internal nodes, it becomes true when one child is cumulated. * When second child finishes cumulating, it then moves up tree, * excecuting finish() at the root. * * This class maintains only the basic control logic. Subclasses * maintain the "in" and "out" fields, and *Ops classes perform * computations */ static abstract class FJScan extends AsyncAction { static final int CUMULATE = 1; static final int SUMMED = 2; static final int FINISHED = 4; final FJScan parent; final FJScanOp op; FJScan left, right; volatile int phase; // phase/state final int lo; final int hi; static final AtomicIntegerFieldUpdater phaseUpdater = AtomicIntegerFieldUpdater.newUpdater(FJScan.class, "phase"); FJScan(FJScan parent, FJScanOp op, int lo, int hi) { this.parent = parent; this.op = op; this.lo = lo; this.hi = hi; } /** Returns true if can CAS CUMULATE bit true */ final boolean transitionToCumulate() { int c; while (((c = phase) & CUMULATE) == 0) if (phaseUpdater.compareAndSet(this, c, c | CUMULATE)) return true; return false; } public final void compute() { if (hi - lo > op.threshold) { if (left == null) { // first pass int mid = (lo + hi) >>> 1; left = op.newSubtask(this, lo, mid); right = op.newSubtask(this, mid, hi); } boolean cumulate = (phase & CUMULATE) != 0; if (cumulate) op.pushDown(this, left, right); if (!cumulate || right.transitionToCumulate()) right.fork(); if (!cumulate || left.transitionToCumulate()) left.compute(); } else { int cb; for (;;) { // Establish action: sum, cumulate, or both int b = phase; if ((b & FINISHED) != 0) // already done return; if ((b & CUMULATE) != 0) cb = FINISHED; else if (lo == op.firstIndex) // combine leftmost cb = (SUMMED|FINISHED); else cb = SUMMED; if (phaseUpdater.compareAndSet(this, b, b|cb)) break; } if (cb == SUMMED) op.sumLeaf(lo, hi, this); else if (cb == FINISHED) op.cumulateLeaf(lo, hi, this); else if (cb == (SUMMED|FINISHED)) op.sumAndCumulateLeaf(lo, hi, this); // propagate up FJScan ch = this; FJScan par = parent; for (;;) { if (par == null) { if ((cb & FINISHED) != 0) ch.finish(); break; } int pb = par.phase; if ((pb & cb & FINISHED) != 0) { // both finished ch = par; par = par.parent; } else if ((pb & cb & SUMMED) != 0) { // both summed op.pushUp(par, par.left, par.right); int refork = ((pb & CUMULATE) == 0 && par.lo == op.firstIndex)? CUMULATE : 0; int nextPhase = pb|cb|refork; if (pb == nextPhase || phaseUpdater.compareAndSet(par, pb, nextPhase)) { if (refork != 0) par.fork(); cb = SUMMED; // drop finished bit ch = par; par = par.parent; } } else if (phaseUpdater.compareAndSet(par, pb, pb|cb)) break; } } } // no-op versions of methods to get/set in/out, overridden as // appropriate in subclasses Object rgetIn() { return null; } Object rgetOut() { return null; } void rsetIn(Object x) { } void rsetOut(Object x) { } double dgetIn() { return 0; } double dgetOut() { return 0; } void dsetIn(double x) { } void dsetOut(double x) { } long lgetIn() { return 0; } long lgetOut() { return 0; } void lsetIn(long x) { } void lsetOut(long x) { } } // Subclasses adding in/out fields of the appropriate type static final class FJRScan extends FJScan { Object in; Object out; FJRScan(FJScan parent, FJScanOp op, int lo, int hi) { super(parent, op, lo, hi); } Object rgetIn() { return in; } Object rgetOut() { return out; } void rsetIn(Object x) { in = x; } void rsetOut(Object x) { out = x; } } static final class FJDScan extends FJScan { double in; double out; FJDScan(FJScan parent, FJScanOp op, int lo, int hi) { super(parent, op, lo, hi); } double dgetIn() { return in; } double dgetOut() { return out; } void dsetIn(double x) { in = x; } void dsetOut(double x) { out = x; } } static final class FJLScan extends FJScan { long in; long out; FJLScan(FJScan parent, FJScanOp op, int lo, int hi) { super(parent, op, lo, hi); } long lgetIn() { return in; } long lgetOut() { return out; } void lsetIn(long x) { in = x; } void lsetOut(long x) { out = x; } } /** * Computational operations for FJSCan */ static abstract class FJScanOp { final int threshold; final int firstIndex; final int upperBound; FJScanOp(Prefix prefix) { this.firstIndex = prefix.firstIndex; this.upperBound = prefix.upperBound; this.threshold = prefix.threshold; } abstract void pushDown(FJScan parent, FJScan left, FJScan right); abstract void pushUp(FJScan parent, FJScan left, FJScan right); abstract void sumLeaf(int lo, int hi, FJScan f); abstract void cumulateLeaf(int lo, int hi, FJScan f); abstract void sumAndCumulateLeaf(int lo, int hi, FJScan f); abstract FJScan newSubtask(FJScan parent, int lo, int hi); } static abstract class FJRScanOp extends FJScanOp { final Object[] array; final Reducer reducer; final Object base; FJRScanOp(RPrefix prefix, Reducer reducer, Object base) { super(prefix); this.array = prefix.pa.array; this.reducer = reducer; this.base = base; } final void pushDown(FJScan parent, FJScan left, FJScan right) { Object pin = parent.rgetIn(); left.rsetIn(pin); right.rsetIn(reducer.combine(pin, left.rgetOut())); } final void pushUp(FJScan parent, FJScan left, FJScan right) { parent.rsetOut(reducer.combine(left.rgetOut(), right.rgetOut())); } final FJScan newSubtask(FJScan parent, int lo, int hi) { FJRScan f = new FJRScan(parent, this, lo, hi); f.in = base; f.out = base; return f; } } static final class FJRCumulateOp extends FJRScanOp { FJRCumulateOp(RPrefix prefix, Reducer reducer, Object base) { super(prefix, reducer, base); } void sumLeaf(int lo, int hi, FJScan f) { Object sum = base; if (hi != upperBound) { Object[] arr = array; for (int i = lo; i < hi; ++i) sum = reducer.combine(sum, arr[i]); } f.rsetOut(sum); } void cumulateLeaf(int lo, int hi, FJScan f) { Object[] arr = array; Object sum = f.rgetIn(); for (int i = lo; i < hi; ++i) arr[i] = sum = reducer.combine(sum, arr[i]); } void sumAndCumulateLeaf(int lo, int hi, FJScan f) { Object[] arr = array; Object sum = base; for (int i = lo; i < hi; ++i) arr[i] = sum = reducer.combine(sum, arr[i]); f.rsetOut(sum); } } static final class FJRPrecumulateOp extends FJRScanOp { FJRPrecumulateOp(RPrefix prefix, Reducer reducer, Object base) { super(prefix, reducer, base); } void sumLeaf(int lo, int hi, FJScan f) { Object[] arr = array; Object sum = base; for (int i = lo; i < hi; ++i) sum = reducer.combine(sum, arr[i]); f.rsetOut(sum); } void cumulateLeaf(int lo, int hi, FJScan f) { Object[] arr = array; Object sum = f.rgetIn(); for (int i = lo; i < hi; ++i) { Object x = arr[i]; arr[i] = sum; sum = reducer.combine(sum, x); } } void sumAndCumulateLeaf(int lo, int hi, FJScan f) { Object[] arr = array; Object sum = base; for (int i = lo; i < hi; ++i) { Object x = arr[i]; arr[i] = sum; sum = reducer.combine(sum, x); } f.rsetOut(sum); } } static abstract class FJDScanOp extends FJScanOp { final double[] array; final DoubleReducer reducer; final double base; FJDScanOp(DPrefix prefix, DoubleReducer reducer, double base) { super(prefix); this.array = prefix.pa.array; this.reducer = reducer; this.base = base; } final void pushDown(FJScan parent, FJScan left, FJScan right) { double pin = parent.dgetIn(); left.dsetIn(pin); right.dsetIn(reducer.combine(pin, left.dgetOut())); } final void pushUp(FJScan parent, FJScan left, FJScan right) { parent.dsetOut(reducer.combine(left.dgetOut(), right.dgetOut())); } final FJScan newSubtask(FJScan parent, int lo, int hi) { FJDScan f = new FJDScan(parent, this, lo, hi); f.in = base; f.out = base; return f; } } static final class FJDCumulateOp extends FJDScanOp { FJDCumulateOp(DPrefix prefix, DoubleReducer reducer, double base) { super(prefix, reducer, base); } void sumLeaf(int lo, int hi, FJScan f) { double sum = base; if (hi != upperBound) { double[] arr = array; for (int i = lo; i < hi; ++i) sum = reducer.combine(sum, arr[i]); } f.dsetOut(sum); } void cumulateLeaf(int lo, int hi, FJScan f) { double[] arr = array; double sum = f.dgetIn(); for (int i = lo; i < hi; ++i) arr[i] = sum = reducer.combine(sum, arr[i]); } void sumAndCumulateLeaf(int lo, int hi, FJScan f) { double[] arr = array; double sum = base; for (int i = lo; i < hi; ++i) arr[i] = sum = reducer.combine(sum, arr[i]); f.dsetOut(sum); } } static final class FJDPrecumulateOp extends FJDScanOp { FJDPrecumulateOp(DPrefix prefix, DoubleReducer reducer, double base) { super(prefix, reducer, base); } void sumLeaf(int lo, int hi, FJScan f) { double[] arr = array; double sum = base; for (int i = lo; i < hi; ++i) sum = reducer.combine(sum, arr[i]); f.dsetOut(sum); } void cumulateLeaf(int lo, int hi, FJScan f) { double[] arr = array; double sum = f.dgetIn(); for (int i = lo; i < hi; ++i) { double x = arr[i]; arr[i] = sum; sum = reducer.combine(sum, x); } } void sumAndCumulateLeaf(int lo, int hi, FJScan f) { double[] arr = array; double sum = base; for (int i = lo; i < hi; ++i) { double x = arr[i]; arr[i] = sum; sum = reducer.combine(sum, x); } f.dsetOut(sum); } } static abstract class FJLScanOp extends FJScanOp { final long[] array; final LongReducer reducer; final long base; FJLScanOp(LPrefix prefix, LongReducer reducer, long base) { super(prefix); this.array = prefix.pa.array; this.reducer = reducer; this.base = base; } final void pushDown(FJScan parent, FJScan left, FJScan right) { long pin = parent.lgetIn(); left.lsetIn(pin); right.lsetIn(reducer.combine(pin, left.lgetOut())); } final void pushUp(FJScan parent, FJScan left, FJScan right) { parent.lsetOut(reducer.combine(left.lgetOut(), right.lgetOut())); } final FJScan newSubtask(FJScan parent, int lo, int hi) { FJLScan f = new FJLScan(parent, this, lo, hi); f.in = base; f.out = base; return f; } } static final class FJLCumulateOp extends FJLScanOp { FJLCumulateOp(LPrefix prefix, LongReducer reducer, long base) { super(prefix, reducer, base); } void sumLeaf(int lo, int hi, FJScan f) { long sum = base; if (hi != upperBound) { long[] arr = array; for (int i = lo; i < hi; ++i) sum = reducer.combine(sum, arr[i]); } f.lsetOut(sum); } void cumulateLeaf(int lo, int hi, FJScan f) { long[] arr = array; long sum = f.lgetIn(); for (int i = lo; i < hi; ++i) arr[i] = sum = reducer.combine(sum, arr[i]); } void sumAndCumulateLeaf(int lo, int hi, FJScan f) { long[] arr = array; long sum = base; for (int i = lo; i < hi; ++i) arr[i] = sum = reducer.combine(sum, arr[i]); f.lsetOut(sum); } } static final class FJLPrecumulateOp extends FJLScanOp { FJLPrecumulateOp(LPrefix prefix, LongReducer reducer, long base) { super(prefix, reducer, base); } void sumLeaf(int lo, int hi, FJScan f) { long[] arr = array; long sum = base; for (int i = lo; i < hi; ++i) sum = reducer.combine(sum, arr[i]); f.lsetOut(sum); } void cumulateLeaf(int lo, int hi, FJScan f) { long[] arr = array; long sum = f.lgetIn(); for (int i = lo; i < hi; ++i) { long x = arr[i]; arr[i] = sum; sum = reducer.combine(sum, x); } } void sumAndCumulateLeaf(int lo, int hi, FJScan f) { long[] arr = array; long sum = base; for (int i = lo; i < hi; ++i) { long x = arr[i]; arr[i] = sum; sum = reducer.combine(sum, x); } f.lsetOut(sum); } } // specialized versions for plus static abstract class FJDScanPlusOp extends FJScanOp { final double[] array; FJDScanPlusOp(DPrefix prefix) { super(prefix); this.array = prefix.pa.array; } final void pushDown(FJScan parent, FJScan left, FJScan right) { double pin = parent.dgetIn(); left.dsetIn(pin); right.dsetIn(pin + left.dgetOut()); } final void pushUp(FJScan parent, FJScan left, FJScan right) { parent.dsetOut(left.dgetOut() + right.dgetOut()); } final FJScan newSubtask(FJScan parent, int lo, int hi) { FJDScan f = new FJDScan(parent, this, lo, hi); f.in = 0.0; f.out = 0.0; return f; } } static final class FJDCumulatePlusOp extends FJDScanPlusOp { FJDCumulatePlusOp(DPrefix prefix) { super(prefix); } void sumLeaf(int lo, int hi, FJScan f) { double sum = 0.0; if (hi != upperBound) { double[] arr = array; for (int i = lo; i < hi; ++i) sum += arr[i]; } f.dsetOut(sum); } void cumulateLeaf(int lo, int hi, FJScan f) { double[] arr = array; double sum = f.dgetIn(); for (int i = lo; i < hi; ++i) arr[i] = sum += arr[i]; } void sumAndCumulateLeaf(int lo, int hi, FJScan f) { double[] arr = array; double sum = 0.0; for (int i = lo; i < hi; ++i) arr[i] = sum += arr[i]; f.dsetOut(sum); } } static final class FJDPrecumulatePlusOp extends FJDScanPlusOp { FJDPrecumulatePlusOp(DPrefix prefix) { super(prefix); } void sumLeaf(int lo, int hi, FJScan f) { double[] arr = array; double sum = 0.0; for (int i = lo; i < hi; ++i) sum += arr[i]; f.dsetOut(sum); } void cumulateLeaf(int lo, int hi, FJScan f) { double[] arr = array; double sum = f.dgetIn(); for (int i = lo; i < hi; ++i) { double x = arr[i]; arr[i] = sum; sum += x; } } void sumAndCumulateLeaf(int lo, int hi, FJScan f) { double[] arr = array; double sum = 0.0; for (int i = lo; i < hi; ++i) { double x = arr[i]; arr[i] = sum; sum += x; } f.dsetOut(sum); } } static abstract class FJLScanPlusOp extends FJScanOp { final long[] array; FJLScanPlusOp(LPrefix prefix) { super(prefix); this.array = prefix.pa.array; } final void pushDown(FJScan parent, FJScan left, FJScan right) { long pin = parent.lgetIn(); left.lsetIn(pin); right.lsetIn(pin + left.lgetOut()); } final void pushUp(FJScan parent, FJScan left, FJScan right) { parent.lsetOut(left.lgetOut() + right.lgetOut()); } final FJScan newSubtask(FJScan parent, int lo, int hi) { FJLScan f = new FJLScan(parent, this, lo, hi); f.in = 0L; f.out = 0L; return f; } } static final class FJLCumulatePlusOp extends FJLScanPlusOp { FJLCumulatePlusOp(LPrefix prefix) { super(prefix); } void sumLeaf(int lo, int hi, FJScan f) { long sum = 0L; if (hi != upperBound) { long[] arr = array; for (int i = lo; i < hi; ++i) sum += arr[i]; } f.lsetOut(sum); } void cumulateLeaf(int lo, int hi, FJScan f) { long[] arr = array; long sum = f.lgetIn(); for (int i = lo; i < hi; ++i) arr[i] = sum += arr[i]; } void sumAndCumulateLeaf(int lo, int hi, FJScan f) { long[] arr = array; long sum = 0L; for (int i = lo; i < hi; ++i) arr[i] = sum += arr[i]; f.lsetOut(sum); } } static final class FJLPrecumulatePlusOp extends FJLScanPlusOp { FJLPrecumulatePlusOp(LPrefix prefix) { super(prefix); } void sumLeaf(int lo, int hi, FJScan f) { long[] arr = array; long sum = 0L; for (int i = lo; i < hi; ++i) sum += arr[i]; f.lsetOut(sum); } void cumulateLeaf(int lo, int hi, FJScan f) { long[] arr = array; long sum = f.lgetIn(); for (int i = lo; i < hi; ++i) { long x = arr[i]; arr[i] = sum; sum += x; } } void sumAndCumulateLeaf(int lo, int hi, FJScan f) { long[] arr = array; long sum = 0L; for (int i = lo; i < hi; ++i) { long x = arr[i]; arr[i] = sum; sum += x; } f.lsetOut(sum); } } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/ParallelDoubleArray.java0000644000000000000000000031744710740452246025207 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import static jsr166y.forkjoin.Ops.*; import java.util.*; import java.util.concurrent.atomic.*; import java.lang.reflect.Array; /** * An array of doubles supporting parallel operations. This class * provides methods supporting the same operations as {@link * ParallelArray}, but specialized for scalar doubles. It additionally * provides a few methods specific to numerical values. */ public class ParallelDoubleArray { // Same internals as ParallelArray, but specialized for doubles double[] array; final ForkJoinExecutor ex; int limit; AsList listView; // lazily constructed /** * Returns a common default executor for use in ParallelArrays. * This executor arranges enough parallelism to use most, but not * necessarily all, of the avaliable processors on this system. * @return the executor */ public static ForkJoinExecutor defaultExecutor() { return PAS.defaultExecutor(); } /** * Constructor for use by subclasses to create a new ParallelDoubleArray * using the given executor, and initially using the supplied * array, with effective size bound by the given limit. This * constructor is designed to enable extensions via * subclassing. To create a ParallelDoubleArray, use {@link #create}, * {@link #createEmpty}, {@link #createUsingHandoff} or {@link * #createFromCopy}. * @param executor the executor * @param array the array * @param limit the upper bound limit */ protected ParallelDoubleArray(ForkJoinExecutor executor, double[] array, int limit) { if (executor == null || array == null) throw new NullPointerException(); if (limit < 0 || limit > array.length) throw new IllegalArgumentException(); this.ex = executor; this.array = array; this.limit = limit; } /** * Trusted internal version of protected constructor. */ ParallelDoubleArray(ForkJoinExecutor executor, double[] array) { this.ex = executor; this.array = array; this.limit = array.length; } /** * Creates a new ParallelDoubleArray using the given executor and * an array of the given size * @param size the array size * @param executor the executor */ public static ParallelDoubleArray create (int size, ForkJoinExecutor executor) { double[] array = new double[size]; return new ParallelDoubleArray(executor, array, size); } /** * Creates a new ParallelDoubleArray initially using the given array and * executor. In general, the handed off array should not be used * for other purposes once constructing this ParallelDoubleArray. The * given array may be internally replaced by another array in the * course of methods that add or remove elements. * @param handoff the array * @param executor the executor */ public static ParallelDoubleArray createUsingHandoff (double[] handoff, ForkJoinExecutor executor) { return new ParallelDoubleArray(executor, handoff, handoff.length); } /** * Creates a new ParallelDoubleArray using the given executor and * initially holding copies of the given * source elements. * @param source the source of initial elements * @param executor the executor */ public static ParallelDoubleArray createFromCopy (double[] source, ForkJoinExecutor executor) { // For now, avoid copyOf so people can compile with Java5 int size = source.length; double[] array = new double[size]; System.arraycopy(source, 0, array, 0, size); return new ParallelDoubleArray(executor, array, size); } /** * Creates a new ParallelDoubleArray using an array of the given size, * initially holding copies of the given source truncated or * padded with zeros to obtain the specified length. * @param source the source of initial elements * @param size the array size * @param executor the executor */ public static ParallelDoubleArray createFromCopy (int size, double[] source, ForkJoinExecutor executor) { // For now, avoid copyOf so people can compile with Java5 double[] array = new double[size]; System.arraycopy(source, 0, array, 0, Math.min(source.length, size)); return new ParallelDoubleArray(executor, array, size); } /** * Creates a new ParallelDoubleArray using the given executor and * an array of the given size, but with an initial effective size * of zero, enabling incremental insertion via {@link * ParallelDoubleArray#asList} operations. * @param size the array size * @param executor the executor */ public static ParallelDoubleArray createEmpty (int size, ForkJoinExecutor executor) { double[] array = new double[size]; return new ParallelDoubleArray(executor, array, 0); } /** * Summary statistics for a possibly bounded, filtered, and/or * mapped ParallelDoubleArray. */ public static interface SummaryStatistics { /** Return the number of elements */ public int size(); /** Return the minimum element, or Double.MAX_VALUE if empty */ public double min(); /** Return the maximum element, or -Double.MAX_VALUE if empty */ public double max(); /** Return the index of the minimum element, or -1 if empty */ public int indexOfMin(); /** Return the index of the maximum element, or -1 if empty */ public int indexOfMax(); /** Return the sum of all elements */ public double sum(); /** Return the arithmetic average of all elements */ public double average(); } /** * Returns the executor used for computations * @return the executor */ public ForkJoinExecutor getExecutor() { return ex; } /** * Applies the given procedure to elements * @param procedure the procedure */ public void apply(DoubleProcedure procedure) { new WithBounds(this).apply(procedure); } /** * Returns reduction of elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public double reduce(DoubleReducer reducer, double base) { return new WithBounds(this).reduce(reducer, base); } /** * Returns a new ParallelDoubleArray holding all elements * @return a new ParallelDoubleArray holding all elements */ public ParallelDoubleArray all() { return new WithBounds(this).all(); } /** * Returns a ParallelDoubleArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelDoubleArray combine (double[] other, DoubleReducer combiner) { return new WithBounds(this).combine(other, combiner); } /** * Returns a ParallelDoubleArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is not * the same length as this array. */ public ParallelDoubleArray combine (ParallelDoubleArray other, DoubleReducer combiner) { return new WithBounds(this).combine(other, combiner); } /** * Returns a ParallelDoubleArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array segment * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other segment is * shorter than this array. */ public ParallelDoubleArray combine (ParallelDoubleArray.WithBounds other, DoubleReducer combiner) { return new WithBounds(this).combine(other, combiner); } /** * Replaces elements with the results of applying the given mapper * to their current values. * @param mapper the mapper */ public void replaceWithTransform(DoubleMapper mapper) { new WithBounds(this).replaceWithTransform(mapper); } /** * Replaces elements with the results of applying the given * mapper to their indices. * @param mapper the mapper */ public void replaceWithMappedIndex(MapperFromIntToDouble mapper) { new WithBounds(this).replaceWithMappedIndex(mapper); } /** * Replaces elements with the results of applying the given * generator. For example, to fill the array with uniform random * values, use * replaceWithGeneratedValue(Ops.doubleRandom()) * @param generator the generator */ public void replaceWithGeneratedValue(DoubleGenerator generator) { new WithBounds(this).replaceWithGeneratedValue(generator); } /** * Replaces elements with the given value. * @param value the value */ public void replaceWithValue(double value) { new WithBounds(this).replaceWithValue(value); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer elements than this array. */ public void replaceWithCombination (ParallelDoubleArray other, DoubleReducer combiner) { new WithBounds(this).replaceWithCombination(other.array, combiner); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer elements than this array. */ public void replaceWithCombination(double[] other, DoubleReducer combiner) { new WithBounds(this).replaceWithCombination(other, combiner); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array segment * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other segment has * fewer elements.than this array, */ public void replaceWithCombination (ParallelDoubleArray.WithBounds other, DoubleReducer combiner) { new WithBounds(this).replaceWithCombination(other, combiner); } /** * Returns the index of some element equal to given target, or -1 * if not present * @param target the element to search for * @return the index or -1 if not present */ public int indexOf(double target) { return new WithBounds(this).indexOf(target); } /** * Assuming this array is sorted, returns the index of an element * equal to given target, or -1 if not present. If the array * is not sorted, the results are undefined. * @param target the element to search for * @return the index or -1 if not present */ public int binarySearch(double target) { int lo = 0; int hi = limit - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; double m = array[mid]; if (target == m) return mid; else if (target < m) hi = mid - 1; else lo = mid + 1; } return -1; } /** * Assuming this array is sorted with respect to the given * comparator, returns the index of an element equal to given * target, or -1 if not present. If the array is not sorted, the * results are undefined. * @param target the element to search for * @param comparator the comparator * @return the index or -1 if not present */ public int binarySearch(double target, DoubleComparator comparator) { int lo = 0; int hi = limit - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; int c = comparator.compare(target, array[mid]); if (c == 0) return mid; else if (c < 0) hi = mid - 1; else lo = mid + 1; } return -1; } /** * Returns summary statistics, using the given comparator * to locate minimum and maximum elements. * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelDoubleArray.SummaryStatistics summary (DoubleComparator comparator) { return new WithBounds(this).summary(comparator); } /** * Returns summary statistics, using natural comparator * @return the summary. */ public ParallelDoubleArray.SummaryStatistics summary() { return new WithBounds(this).summary(); } /** * Returns the minimum element, or Double.MAX_VALUE if empty * @param comparator the comparator * @return minimum element, or Double.MAX_VALUE if empty */ public double min(DoubleComparator comparator) { return new WithBounds(this).min(comparator); } /** * Returns the minimum element, or Double.MAX_VALUE if empty, * @return minimum element, or Double.MAX_VALUE if empty */ public double min() { return new WithBounds(this).min(); } /** * Returns the maximum element, or -Double.MAX_VALUE if empty * @param comparator the comparator * @return maximum element, or -Double.MAX_VALUE if empty */ public double max(DoubleComparator comparator) { return new WithBounds(this).max(comparator); } /** * Returns the maximum element, or -Double.MAX_VALUE if empty * @return maximum element, or -Double.MAX_VALUE if empty */ public double max() { return new WithBounds(this).max(); } /** * Replaces each element with the running cumulation of applying * the given reducer. For example, if the contents are the numbers * 1, 2, 3, and the reducer operation adds numbers, then * after invocation of this method, the contents would be 1, * 3, 6 (that is, 1, 1+2, 1+2+3); * @param reducer the reducer * @param base the result for an empty array */ public void cumulate(DoubleReducer reducer, double base) { new WithBounds(this).cumulate(reducer, base); } /** * Replaces each element with the cumulation of applying the given * reducer to all previous values, and returns the total * reduction. For example, if the contents are the numbers 1, * 2, 3, and the reducer operation adds numbers, then after * invocation of this method, the contents would be 0, 1, * 3 (that is, 0, 0+1, 0+1+2, and the return value * would be 6 (that is, 1+2+3); * @param reducer the reducer * @param base the result for an empty array * @return the total reduction */ public double precumulate(DoubleReducer reducer, double base) { return new WithBounds(this).precumulate(reducer, base); } /** * Sorts the array. Unlike Arrays.sort, this sort does * not guarantee that elements with equal keys maintain their * relative position in the array. * @param comparator the comparator to use */ public void sort(DoubleComparator comparator) { new WithBounds(this).sort(comparator); } /** * Sorts the array, assuming all elements are Comparable. Unlike * Arrays.sort, this sort does not guarantee that elements * with equal keys maintain their relative position in the array. * @throws ClassCastException if any element is not Comparable. */ public void sort() { new WithBounds(this).sort(); } /** * Removes consecutive elements that are equal, * shifting others leftward, and possibly decreasing size. This * method may be used after sorting to ensure that this * ParallelDoubleArray contains a set of unique elements. */ public void removeConsecutiveDuplicates() { new WithBounds(this).removeConsecutiveDuplicates(); } /** * Returns a new ParallelDoubleArray containing only the unique * elements of this array (that is, without any duplicates). * @return the new ParallelDoubleArray */ public ParallelDoubleArray allUniqueElements() { return new WithBounds(this).allUniqueElements(); } /** * Returns the sum of elements * @return the sum of elements */ public double sum() { return new WithBounds(this).sum(); } /** * Replaces each element with the running sum */ public void cumulateSum() { new WithBounds(this).cumulateSum(); } /** * Replaces each element with its prefix sum * @return the total sum */ public double precumulateSum() { return new WithBounds(this).precumulateSum(); } /** * Returns an operation prefix that causes a method to * operate only on the elements of the array between * firstIndex (inclusive) and upperBound (exclusive). * @param firstIndex the lower bound (inclusive) * @param upperBound the upper bound (exclusive) * @return operation prefix */ public WithBounds withBounds(int firstIndex, int upperBound) { if (firstIndex > upperBound) throw new IllegalArgumentException ("firstIndex(" + firstIndex + ") > upperBound(" + upperBound+")"); if (firstIndex < 0) throw new ArrayIndexOutOfBoundsException(firstIndex); if (upperBound > this.limit) throw new ArrayIndexOutOfBoundsException(upperBound); return new WithBounds(this, firstIndex, upperBound); } /** * Returns an operation prefix that causes a method to operate * only on the elements of the array for which the given selector * returns true * @param selector the selector * @return operation prefix */ public WithFilter withFilter(DoublePredicate selector) { return new WithBoundedFilter(this, 0, limit, selector); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithMapping withMapping (MapperFromDouble mapper) { return new WithBoundedMapping(this, 0, limit, mapper); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithDoubleMapping withMapping(DoubleMapper mapper) { return new WithBoundedDoubleMapping(this, 0, limit, mapper); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithLongMapping withMapping(MapperFromDoubleToLong mapper) { return new WithBoundedLongMapping(this, 0, limit, mapper); } /** * A modifier for parallel array operations to apply to mappings * of elements, not to the elements themselves */ public static abstract class WithMapping extends PAS.DPrefix { final MapperFromDouble mapper; WithMapping(ParallelDoubleArray pa, int firstIndex, int upperBound, MapperFromDouble mapper) { super(pa, firstIndex, upperBound); this.mapper = mapper; } /** * Applies the given procedure to mapped elements * @param procedure the procedure */ public void apply(Procedure procedure) { ex.invoke(new PAS.FJRApply(this, firstIndex, upperBound, null, procedure)); } /** * Returns reduction of mapped elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public U reduce(Reducer reducer, U base) { PAS.FJRReduce f = new PAS.FJRReduce (this, firstIndex, upperBound, null, reducer, base); ex.invoke(f); return (U)(f.result); } /** * Returns the index of some element matching bound and filter * constraints, or -1 if none. * @return index of matching element, or -1 if none. */ public abstract int anyIndex(); /** * Returns mapping of some element matching bound and filter * constraints, or null if none. * @return mapping of matching element, or null if none. */ public abstract U any(); /** * Returns the minimum mapped element, or null if empty * @param comparator the comparator * @return minimum mapped element, or null if empty */ public U min(Comparator comparator) { return reduce(Ops.minReducer(comparator), null); } /** * Returns the minimum mapped element, or null if empty, * assuming that all elements are Comparables * @return minimum mapped element, or null if empty * @throws ClassCastException if any element is not Comparable. */ public U min() { return reduce((Reducer)(Ops.castedMinReducer()), null); } /** * Returns the maximum mapped element, or null if empty * @param comparator the comparator * @return maximum mapped element, or null if empty */ public U max(Comparator comparator) { return reduce(Ops.maxReducer(comparator), null); } /** * Returns the maximum mapped element, or null if empty * assuming that all elements are Comparables * @return maximum mapped element, or null if empty * @throws ClassCastException if any element is not Comparable. */ public U max() { return reduce((Reducer)(Ops.castedMaxReducer()), null); } /** * Returns summary statistics, using the given comparator * to locate minimum and maximum elements. * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelArray.SummaryStatistics summary (Comparator comparator) { PAS.FJRStats f = new PAS.FJRStats (this, firstIndex, upperBound, null, comparator); ex.invoke(f); return (ParallelArray.SummaryStatistics)f; } /** * Returns summary statistics, assuming that all elements are * Comparables * @return the summary. */ public ParallelArray.SummaryStatistics summary() { PAS.FJRStats f = new PAS.FJRStats (this, firstIndex, upperBound, null, (Comparator)(Ops.castedComparator())); ex.invoke(f); return (ParallelArray.SummaryStatistics)f; } /** * Returns a new ParallelArray holding elements * @return a new ParallelArray holding elements */ public abstract ParallelArray all(); /** * Returns a new ParallelArray with the given element type holding * elements * @param elementType the type of the elements * @return a new ParallelArray holding elements */ public abstract ParallelArray all(Class elementType); /** * Return the number of elements selected using bound or * filter restrictions. Note that this method must evaluate * all selectors to return its result. * @return the number of elements */ public abstract int size(); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper * applied to current mapper's results * @param mapper the mapper * @return operation prefix */ public abstract WithMapping withMapping (Mapper mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper * applied to current mapper's results * @param mapper the mapper * @return operation prefix */ public abstract WithDoubleMapping withMapping (MapperToDouble mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper * applied to current mapper's results * @param mapper the mapper * @return operation prefix */ public abstract WithLongMapping withMapping (MapperToLong mapper); final void leafTransfer(int lo, int hi, Object[] dest, int offset) { final double[] array = pa.array; final MapperFromDouble mpr = mapper; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, Object[] dest, int offset) { final double[] array = pa.array; final MapperFromDouble mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = mpr.map(array[indices[i]]); } } static final class WithBoundedMapping extends WithMapping { WithBoundedMapping(ParallelDoubleArray pa, int firstIndex, int upperBound, MapperFromDouble mapper) { super(pa, firstIndex, upperBound, mapper); } public ParallelArray all() { int n = upperBound - firstIndex; U[] dest = (U[])new Object[n]; PAS.FJRMap f = new PAS.FJRMap (this, firstIndex, upperBound, null, dest, firstIndex); ex.invoke(f); return new ParallelArray(ex, dest); } public ParallelArray all(Class elementType) { int n = upperBound - firstIndex; U[] dest = (U[])Array.newInstance(elementType, n); PAS.FJRMap f = new PAS.FJRMap (this, firstIndex, upperBound, null, dest, firstIndex); ex.invoke(f); return new ParallelArray(ex, dest); } public int size() { return upperBound - firstIndex; } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } public U any() { final double[] array = pa.array; final MapperFromDouble mpr = mapper; return (firstIndex < upperBound)? (U)(mpr.map(array[firstIndex])) : null; } public WithMapping withMapping (Mapper mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithDoubleMapping withMapping(MapperToDouble mapper){ return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping(MapperToLong mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, Procedure procedure) { final double[] array = pa.array; final MapperFromDouble mpr = mapper; for (int i = lo; i < hi; ++i) procedure.apply(mpr.map(array[i])); } Object leafReduce(int lo, int hi, Reducer reducer, Object base) { if (lo >= hi) return base; final double[] array = pa.array; final MapperFromDouble mpr = mapper; Object r = mpr.map(array[lo]); for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, mpr.map(array[i])); return r; } void leafStats(int lo, int hi, PAS.FJRStats task) { final double[] array = pa.array; final MapperFromDouble mpr = mapper; task.size = hi - lo; for (int i = lo; i < hi; ++i) { Object x = mpr.map(array[i]); task.updateMin(i, x); task.updateMax(i, x); } } } static final class WithBoundedFilteredMapping extends WithMapping { final DoublePredicate selector; WithBoundedFilteredMapping(ParallelDoubleArray pa, int firstIndex, int upperBound, DoublePredicate selector, MapperFromDouble mapper) { super(pa, firstIndex, upperBound, mapper); this.selector = selector; } public ParallelArray all() { PAS.FJRSelectAllDriver r = new PAS.FJRSelectAllDriver (this, Object.class); ex.invoke(r); return new ParallelArray(ex, (U[])(r.results)); } public ParallelArray all(Class elementType) { PAS.FJRSelectAllDriver r = new PAS.FJRSelectAllDriver (this, elementType); ex.invoke(r); return new ParallelArray(ex, (U[])(r.results)); } public int size() { PAS.FJDCountSelected f = new PAS.FJDCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJDSelectAny f = new PAS.FJDSelectAny (this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public U any() { int idx = anyIndex(); final double[] array = pa.array; final MapperFromDouble mpr = mapper; return (idx < 0)? null : (U)(mpr.map(array[idx])); } public WithMapping withMapping (Mapper mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithDoubleMapping withMapping (MapperToDouble mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping (MapperToLong mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, Procedure procedure) { final DoublePredicate sel = selector; final MapperFromDouble mpr = mapper; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) procedure.apply(mpr.map(x)); } } Object leafReduce(int lo, int hi, Reducer reducer, Object base) { boolean gotFirst = false; Object r = base; final DoublePredicate sel = selector; final MapperFromDouble mpr = mapper; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) { Object y = mpr.map(x); if (!gotFirst) { gotFirst = true; r = y; } else r = reducer.combine(r, y); } } return r; } void leafStats(int lo, int hi, PAS.FJRStats task) { final double[] array = pa.array; final DoublePredicate sel = selector; final MapperFromDouble mpr = mapper; int count = 0; for (int i = lo; i < hi; ++i) { double t = array[i]; if (sel.evaluate(t)) { Object x = mpr.map(t); ++count; task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final DoublePredicate sel = selector; final double[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final DoublePredicate sel = selector; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } /** * A modifier for parallel array operations to apply to mappings * of elements to doubles, not to the elements themselves */ public static abstract class WithDoubleMapping extends PAS.DPrefix { WithDoubleMapping(ParallelDoubleArray pa, int firstIndex, int upperBound) { super(pa, firstIndex, upperBound); } /** * Applies the given procedure to elements * @param procedure the procedure */ public void apply(DoubleProcedure procedure) { ex.invoke(new PAS.FJDApply (this, firstIndex, upperBound, null, procedure)); } /** * Returns reduction of elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public double reduce(DoubleReducer reducer, double base) { PAS.FJDReduce f = new PAS.FJDReduce (this, firstIndex, upperBound, null, reducer, base); ex.invoke(f); return f.result; } /** * Returns the minimum element, or Double.MAX_VALUE if empty * @return minimum element, or Double.MAX_VALUE if empty */ public double min() { return reduce(naturalDoubleMinReducer(), Double.MAX_VALUE); } /** * Returns the minimum element, or Double.MAX_VALUE if empty * @param comparator the comparator * @return minimum element, or Double.MAX_VALUE if empty */ public double min(DoubleComparator comparator) { return reduce(doubleMinReducer(comparator), Double.MAX_VALUE); } /** * Returns the maximum element, or -Double.MAX_VALUE if empty * @return maximum element, or -Double.MAX_VALUE if empty */ public double max() { return reduce(naturalDoubleMaxReducer(), -Double.MAX_VALUE); } /** * Returns the maximum element, or -Double.MAX_VALUE if empty * @param comparator the comparator * @return maximum element, or -Double.MAX_VALUE if empty */ public double max(DoubleComparator comparator) { return reduce(doubleMaxReducer(comparator), -Double.MAX_VALUE); } /** * Returns the sum of elements * @return the sum of elements */ public double sum() { return reduce(Ops.doubleAdder(), 0); } /** * Returns summary statistics * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelDoubleArray.SummaryStatistics summary (DoubleComparator comparator) { PAS.FJDStats f = new PAS.FJDStats (this, firstIndex, upperBound, null, comparator); ex.invoke(f); return f; } /** * Returns summary statistics, using natural comparator * @return the summary. */ public ParallelDoubleArray.SummaryStatistics summary() { PAS.FJDStats f = new PAS.FJDStats (this, firstIndex, upperBound, null,naturalDoubleComparator()); ex.invoke(f); return f; } /** * Returns a new ParallelDoubleArray holding elements * @return a new ParallelDoubleArray holding elements */ public abstract ParallelDoubleArray all(); /** * Return the number of elements selected using bound or * filter restrictions. Note that this method must evaluate * all selectors to return its result. * @return the number of elements */ public abstract int size(); /** * Returns the index of some element matching bound and filter * constraints, or -1 if none. * @return index of matching element, or -1 if none. */ public abstract int anyIndex(); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithDoubleMapping withMapping(DoubleMapper mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithLongMapping withMapping (MapperFromDoubleToLong mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithMapping withMapping (MapperFromDouble mapper); } /** * A restriction of parallel array operations to apply only to * elements for which a selector returns true */ public static abstract class WithFilter extends WithDoubleMapping { WithFilter(ParallelDoubleArray pa, int firstIndex, int upperBound) { super(pa, firstIndex, upperBound); } /** * Replaces elements with the results of applying the given * mapper to their current values. * @param mapper the mapper */ public void replaceWithTransform (DoubleMapper mapper) { ex.invoke(new PAS.FJDTransform(this, firstIndex, upperBound, null, mapper)); } /** * Replaces elements with the results of applying the given * mapper to their indices * @param mapper the mapper */ public void replaceWithMappedIndex(MapperFromIntToDouble mapper) { ex.invoke(new PAS.FJDIndexMap(this, firstIndex, upperBound, null, mapper)); } /** * Replaces elements with results of applying the given * generator. * @param generator the generator */ public void replaceWithGeneratedValue(DoubleGenerator generator) { ex.invoke(new PAS.FJDGenerate (this, firstIndex, upperBound, null, generator)); } /** * Replaces elements with the given value. * @param value the value */ public void replaceWithValue(double value) { ex.invoke(new PAS.FJDFill(this, firstIndex, upperBound, null, value)); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer than upperBound elements. */ public void replaceWithCombination(ParallelDoubleArray other, DoubleReducer combiner) { if (other.size() < size()) throw new ArrayIndexOutOfBoundsException(); ex.invoke(new PAS.FJDCombineInPlace (this, firstIndex, upperBound, null, other.array, 0, combiner)); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array segment * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer than upperBound elements. */ public void replaceWithCombination (ParallelDoubleArray.WithBounds other, DoubleReducer combiner) { if (other.size() < size()) throw new ArrayIndexOutOfBoundsException(); ex.invoke(new PAS.FJDCombineInPlace (this, firstIndex, upperBound, null, other.pa.array, other.firstIndex - firstIndex, combiner)); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer than upperBound elements. */ public void replaceWithCombination(double[] other, DoubleReducer combiner) { if (other.length < size()) throw new ArrayIndexOutOfBoundsException(); ex.invoke(new PAS.FJDCombineInPlace (this, firstIndex, upperBound, null, other, -firstIndex, combiner)); } /** * Removes from the array all elements matching bound and/or * filter constraints. */ public abstract void removeAll(); /** * Returns a new ParallelDoubleArray containing only unique * elements (that is, without any duplicates). * @return the new ParallelDoubleArray */ public abstract ParallelDoubleArray allUniqueElements(); /** * Returns an operation prefix that causes a method to operate * only on elements for which the current selector (if * present) and the given selector returns true * @param selector the selector * @return operation prefix */ public abstract WithFilter withFilter(DoublePredicate selector); /** * Returns an operation prefix that causes a method to operate * only on elements for which the current selector (if * present) or the given selector returns true * @param selector the selector * @return operation prefix */ public abstract WithFilter orFilter(DoublePredicate selector); final void leafTransfer(int lo, int hi, double[] dest, int offset) { final double[] array = pa.array; for (int i = lo; i < hi; ++i) dest[offset++] = (array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, double[] dest, int offset) { final double[] array = pa.array; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = (array[indices[i]]); } } /** * A restriction of parallel array operations to apply only within * a given range of indices. */ public static final class WithBounds extends WithFilter { WithBounds(ParallelDoubleArray pa, int firstIndex, int upperBound) { super(pa, firstIndex, upperBound); } WithBounds(ParallelDoubleArray pa) { super(pa, 0, pa.limit); } /** * Returns an operation prefix that causes a method to operate * only on the elements of the array between firstIndex * (inclusive) and upperBound (exclusive). The bound * arguments are relative to the current bounds. For example * pa.withBounds(2, 8).withBounds(3, 5) indexes the * 5th (= 2+3) and 6th elements of pa. However, indices * returned by methods such as indexOf are * with respect to the underlying ParallelDoubleArray. * @param firstIndex the lower bound (inclusive) * @param upperBound the upper bound (exclusive) * @return operation prefix */ public WithBounds withBounds(int firstIndex, int upperBound) { if (firstIndex > upperBound) throw new IllegalArgumentException ("firstIndex(" + firstIndex + ") > upperBound(" + upperBound+")"); if (firstIndex < 0) throw new ArrayIndexOutOfBoundsException(firstIndex); if (upperBound - firstIndex > this.upperBound - this.firstIndex) throw new ArrayIndexOutOfBoundsException(upperBound); return new WithBounds(pa, this.firstIndex + firstIndex, this.firstIndex + upperBound); } /** * Returns an operation prefix that causes a method to operate * only on the elements of the array for which the given selector * returns true * @param selector the selector * @return operation prefix */ public WithFilter withFilter(DoublePredicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, selector); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithMapping withMapping (MapperFromDouble mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, mapper); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithDoubleMapping withMapping(DoubleMapper mapper) { return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, mapper); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithLongMapping withMapping(MapperFromDoubleToLong mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, mapper); } public WithFilter orFilter(DoublePredicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, selector); } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } /** * Returns a ParallelDoubleArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelDoubleArray combine(double[] other, DoubleReducer combiner) { int size = upperBound - firstIndex; if (other.length < size) throw new ArrayIndexOutOfBoundsException(); double[] dest = new double[size]; ex.invoke(new PAS.FJDCombine (this, firstIndex, upperBound, null, other, -firstIndex, dest, combiner)); return new ParallelDoubleArray(ex, dest); } /** * Returns a ParallelDoubleArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelDoubleArray combine(ParallelDoubleArray other, DoubleReducer combiner) { int size = upperBound - firstIndex; if (other.size() < size) throw new ArrayIndexOutOfBoundsException(); double[] dest = new double[size]; ex.invoke(new PAS.FJDCombine (this, firstIndex, upperBound, null, other.array, -firstIndex, dest, combiner)); return new ParallelDoubleArray(ex, dest); } /** * Returns a ParallelDoubleArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array segment * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other segment is * shorter than this array. */ public ParallelDoubleArray combine (ParallelDoubleArray.WithBounds other, DoubleReducer combiner) { int size = upperBound - firstIndex; if (other.size() < size) throw new ArrayIndexOutOfBoundsException(); double[] dest = new double[size]; ex.invoke(new PAS.FJDCombine (this, firstIndex, upperBound, null, other.pa.array, other.firstIndex - firstIndex, dest, combiner)); return new ParallelDoubleArray(ex, dest); } public ParallelDoubleArray all() { final double[] array = pa.array; // For now, avoid copyOf so people can compile with Java5 int size = upperBound - firstIndex; double[] dest = new double[size]; System.arraycopy(array, firstIndex, dest, 0, size); return new ParallelDoubleArray(ex, dest); } public ParallelDoubleArray allUniqueElements() { PAS.DUniquifierTable tab = new PAS.DUniquifierTable (upperBound - firstIndex, pa.array, null); PAS.FJUniquifier f = new PAS.FJUniquifier (this, firstIndex, upperBound, null, tab); ex.invoke(f); double[] res = tab.uniqueElements(f.count); return new ParallelDoubleArray(ex, res); } /** * Returns the index of some element equal to given target, * or -1 if not present * @param target the element to search for * @return the index or -1 if not present */ public int indexOf(double target) { AtomicInteger result = new AtomicInteger(-1); PAS.FJDIndexOf f = new PAS.FJDIndexOf (this, firstIndex, upperBound, null, result, target); ex.invoke(f); return result.get(); } /** * Assuming this array is sorted, returns the index of an * element equal to given target, or -1 if not present. If the * array is not sorted, the results are undefined. * @param target the element to search for * @return the index or -1 if not present */ public int binarySearch(double target) { final double[] array = pa.array; int lo = firstIndex; int hi = upperBound - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; double m = array[mid]; if (target == m) return mid; else if (target < m) hi = mid - 1; else lo = mid + 1; } return -1; } /** * Assuming this array is sorted with respect to the given * comparator, returns the index of an element equal to given * target, or -1 if not present. If the array is not sorted, * the results are undefined. * @param target the element to search for * @param comparator the comparator * @return the index or -1 if not present */ public int binarySearch(double target, DoubleComparator comparator) { final double[] array = pa.array; int lo = firstIndex; int hi = upperBound - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; int c = comparator.compare(target, array[mid]); if (c == 0) return mid; else if (c < 0) hi = mid - 1; else lo = mid + 1; } return -1; } /** * Returns the number of elements within bounds * @return the number of elements within bounds */ public int size() { return upperBound - firstIndex; } /** * Replaces each element with the running cumulation of applying * the given reducer. * @param reducer the reducer * @param base the result for an empty array */ public void cumulate(DoubleReducer reducer, double base) { PAS.FJDCumulateOp op = new PAS.FJDCumulateOp(this, reducer, base); PAS.FJDScan r = new PAS.FJDScan(null, op, firstIndex, upperBound); ex.invoke(r); } /** * Replaces each element with the running sum */ public void cumulateSum() { PAS.FJDCumulatePlusOp op = new PAS.FJDCumulatePlusOp(this); PAS.FJDScan r = new PAS.FJDScan(null, op, firstIndex, upperBound); ex.invoke(r); } /** * Replaces each element with the cumulation of applying the given * reducer to all previous values, and returns the total * reduction. * @param reducer the reducer * @param base the result for an empty array * @return the total reduction */ public double precumulate(DoubleReducer reducer, double base) { PAS.FJDPrecumulateOp op = new PAS.FJDPrecumulateOp (this, reducer, base); PAS.FJDScan r = new PAS.FJDScan(null, op, firstIndex, upperBound); ex.invoke(r); return r.out; } /** * Replaces each element with its prefix sum * @return the total sum */ public double precumulateSum() { PAS.FJDPrecumulatePlusOp op = new PAS.FJDPrecumulatePlusOp(this); PAS.FJDScan r = new PAS.FJDScan(null, op, firstIndex, upperBound); ex.invoke(r); return r.out; } /** * Sorts the elements. * Unlike Arrays.sort, this sort does * not guarantee that elements with equal keys maintain their * relative position in the array. * @param cmp the comparator to use */ public void sort(DoubleComparator cmp) { ex.invoke(new PAS.FJDSorter (cmp, pa.array, new double[upperBound], firstIndex, upperBound - firstIndex, threshold)); } /** * Sorts the elements, assuming all elements are * Comparable. Unlike Arrays.sort, this sort does not * guarantee that elements with equal keys maintain their relative * position in the array. * @throws ClassCastException if any element is not Comparable. */ public void sort() { ex.invoke(new PAS.FJDCSorter (pa.array, new double[upperBound], firstIndex, upperBound - firstIndex, threshold)); } public void removeAll() { pa.removeSlotsAt(firstIndex, upperBound); } /** * Removes consecutive elements that are equal (or null), * shifting others leftward, and possibly decreasing size. This * method may be used after sorting to ensure that this * ParallelDoubleArray contains a set of unique elements. */ public void removeConsecutiveDuplicates() { // Sequential implementation for now int k = firstIndex; int n = upperBound; if (k < n) { double[] arr = pa.array; double last = arr[k++]; for (int i = k; i < n; ++i) { double x = arr[i]; if (last != x) arr[k++] = last = x; } pa.removeSlotsAt(k, n); } } void leafApply(int lo, int hi, DoubleProcedure procedure) { final double[] array = pa.array; for (int i = lo; i < hi; ++i) procedure.apply(array[i]); } double leafReduce(int lo, int hi, DoubleReducer reducer, double base) { if (lo >= hi) return base; final double[] array = pa.array; double r = array[lo]; for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, array[i]); return r; } void leafStats(int lo, int hi, PAS.FJDStats task) { final double[] array = pa.array; task.size = hi - lo; for (int i = lo; i < hi; ++i) { double x = array[i]; task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } void leafTransform(int lo, int hi, DoubleMapper mapper) { final double[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = mapper.map(array[i]); } void leafIndexMap(int lo, int hi, MapperFromIntToDouble mapper) { final double[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = mapper.map(i); } void leafGenerate(int lo, int hi, DoubleGenerator generator) { final double[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = generator.generate(); } void leafFillValue(int lo, int hi, double value) { final double[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = value; } void leafCombineInPlace(int lo, int hi, double[] other, int otherOffset, DoubleReducer combiner) { final double[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = combiner.combine(array[i], other[i+otherOffset]); } void leafCombine(int lo, int hi, double[] other, int otherOffset, double[] dest, DoubleReducer combiner) { final double[] array = pa.array; int k = lo - firstIndex; for (int i = lo; i < hi; ++i) { dest[k] = combiner.combine(array[i], other[i + otherOffset]); ++k; } } } static final class WithBoundedFilter extends WithFilter { final DoublePredicate selector; WithBoundedFilter(ParallelDoubleArray pa, int firstIndex, int upperBound, DoublePredicate selector) { super(pa, firstIndex, upperBound); this.selector = selector; } public WithFilter withFilter(DoublePredicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, Ops.andPredicate(this.selector, selector)); } public WithFilter orFilter(DoublePredicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, Ops.orPredicate(this.selector, selector)); } public WithMapping withMapping (MapperFromDouble mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, mapper); } public WithDoubleMapping withMapping(DoubleMapper mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, mapper); } public WithLongMapping withMapping(MapperFromDoubleToLong mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, mapper); } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJDSelectAny f = new PAS.FJDSelectAny(this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public ParallelDoubleArray all() { PAS.FJDSelectAllDriver r = new PAS.FJDSelectAllDriver(this); ex.invoke(r); return new ParallelDoubleArray(ex, r.results); } public int size() { PAS.FJDCountSelected f = new PAS.FJDCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public ParallelDoubleArray allUniqueElements() { PAS.DUniquifierTable tab = new PAS.DUniquifierTable (upperBound - firstIndex, pa.array, selector); PAS.FJUniquifier f = new PAS.FJUniquifier (this, firstIndex, upperBound, null, tab); ex.invoke(f); double[] res = tab.uniqueElements(f.count); return new ParallelDoubleArray(ex, res); } public void removeAll() { PAS.FJRemoveAllDriver f = new PAS.FJRemoveAllDriver (this, firstIndex, upperBound); ex.invoke(f); pa.removeSlotsAt(f.offset, upperBound); } void leafApply(int lo, int hi, DoubleProcedure procedure) { final DoublePredicate sel = selector; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) procedure.apply(x); } } double leafReduce(int lo, int hi, DoubleReducer reducer, double base) { final DoublePredicate sel = selector; boolean gotFirst = false; double r = base; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) { if (!gotFirst) { gotFirst = true; r = x; } else r = reducer.combine(r, x); } } return r; } void leafStats(int lo, int hi, PAS.FJDStats task) { final DoublePredicate sel = selector; final double[] array = pa.array; int count = 0; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) { ++count; task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } void leafTransform(int lo, int hi, DoubleMapper mapper) { final DoublePredicate sel = selector; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) array[i] = mapper.map(x); } } void leafIndexMap(int lo, int hi, MapperFromIntToDouble mapper) { final DoublePredicate sel = selector; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) array[i] = mapper.map(i); } } void leafGenerate(int lo, int hi, DoubleGenerator generator) { final DoublePredicate sel = selector; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) array[i] = generator.generate(); } } void leafFillValue(int lo, int hi, double value) { final DoublePredicate sel = selector; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) array[i] = value; } } void leafCombineInPlace(int lo, int hi, double[] other, int otherOffset, DoubleReducer combiner) { final DoublePredicate sel = selector; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) array[i] = combiner.combine(x, other[i+otherOffset]); } } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final DoublePredicate sel = selector; final double[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final DoublePredicate sel = selector; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } static final class WithBoundedDoubleMapping extends WithDoubleMapping { final DoubleMapper mapper; WithBoundedDoubleMapping(ParallelDoubleArray pa, int firstIndex, int upperBound, DoubleMapper mapper) { super(pa, firstIndex, upperBound); this.mapper = mapper; } public ParallelDoubleArray all() { double[] dest = new double[upperBound - firstIndex]; PAS.FJDMap f = new PAS.FJDMap (this, firstIndex, upperBound, null, dest, firstIndex); ex.invoke(f); return new ParallelDoubleArray(ex, dest); } public int size() { return upperBound - firstIndex; } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } public WithDoubleMapping withMapping(DoubleMapper mapper) { return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping(MapperFromDoubleToLong mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromDouble mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, DoubleProcedure procedure) { final double[] array = pa.array; final DoubleMapper mpr = mapper; for (int i = lo; i < hi; ++i) procedure.apply(mpr.map(array[i])); } double leafReduce(int lo, int hi, DoubleReducer reducer, double base) { if (lo >= hi) return base; final double[] array = pa.array; final DoubleMapper mpr = mapper; double r = mpr.map(array[lo]); for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, mpr.map(array[i])); return r; } void leafStats(int lo, int hi, PAS.FJDStats task) { task.size = hi - lo; final double[] array = pa.array; final DoubleMapper mpr = mapper; for (int i = lo; i < hi; ++i) { double x = mpr.map(array[i]); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } void leafTransfer(int lo, int hi, double[] dest, int offset) { final double[] array = pa.array; final DoubleMapper mpr = mapper; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, double[] dest, int offset) { final double[] array = pa.array; final DoubleMapper mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = (array[indices[i]]); } } static final class WithBoundedFilteredDoubleMapping extends WithDoubleMapping { final DoublePredicate selector; final DoubleMapper mapper; WithBoundedFilteredDoubleMapping (ParallelDoubleArray pa, int firstIndex, int upperBound, DoublePredicate selector, DoubleMapper mapper) { super(pa, firstIndex, upperBound); this.selector = selector; this.mapper = mapper; } public ParallelDoubleArray all() { PAS.FJDSelectAllDriver r = new PAS.FJDSelectAllDriver(this); ex.invoke(r); return new ParallelDoubleArray(ex, r.results); } public int size() { PAS.FJDCountSelected f = new PAS.FJDCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJDSelectAny f = new PAS.FJDSelectAny (this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public WithDoubleMapping withMapping(DoubleMapper mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping(MapperFromDoubleToLong mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromDouble mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, DoubleProcedure procedure) { final DoublePredicate sel = selector; final DoubleMapper mpr = mapper; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) procedure.apply(mpr.map(x)); } } double leafReduce(int lo, int hi, DoubleReducer reducer, double base) { final DoublePredicate sel = selector; boolean gotFirst = false; double r = base; final double[] array = pa.array; final DoubleMapper mpr = mapper; for (int i = lo; i < hi; ++i) { double t = array[i]; if (sel.evaluate(t)) { double y = mpr.map(t); if (!gotFirst) { gotFirst = true; r = y; } else r = reducer.combine(r, y); } } return r; } void leafStats(int lo, int hi, PAS.FJDStats task) { final DoublePredicate sel = selector; final double[] array = pa.array; final DoubleMapper mpr = mapper; int count = 0; for (int i = lo; i < hi; ++i) { double t = array[i]; if (sel.evaluate(t)) { ++count; double x = mpr.map(t); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } void leafTransfer(int lo, int hi, double[] dest, int offset) { final double[] array = pa.array; final DoubleMapper mpr = mapper; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, double[] dest, int offset) { final double[] array = pa.array; final DoubleMapper mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = (array[indices[i]]); } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final DoublePredicate sel = selector; final double[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final DoublePredicate sel = selector; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } /** * A modifier for parallel array operations to apply to mappings * of elements to longs, not to the elements themselves */ public static abstract class WithLongMapping extends PAS.DPrefix { final MapperFromDoubleToLong mapper; WithLongMapping(ParallelDoubleArray pa, int firstIndex, int upperBound, MapperFromDoubleToLong mapper) { super(pa, firstIndex, upperBound); this.mapper = mapper; } /** * Applies the given procedure * @param procedure the procedure */ public void apply(LongProcedure procedure) { ex.invoke(new PAS.FJLApply (this, firstIndex, upperBound, null, procedure)); } /** * Returns reduction of mapped elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public long reduce(LongReducer reducer, long base) { PAS.FJLReduce f = new PAS.FJLReduce (this, firstIndex, upperBound, null, reducer, base); ex.invoke(f); return f.result; } /** * Returns the minimum element, or Long.MAX_VALUE if empty * @return minimum element, or Long.MAX_VALUE if empty */ public long min() { return reduce(naturalLongMinReducer(), Long.MAX_VALUE); } /** * Returns the minimum element, or Long.MAX_VALUE if empty * @param comparator the comparator * @return minimum element, or Long.MAX_VALUE if empty */ public long min(LongComparator comparator) { return reduce(longMinReducer(comparator), Long.MAX_VALUE); } /** * Returns the maximum element, or Long.MIN_VALUE if empty * @return maximum element, or Long.MIN_VALUE if empty */ public long max() { return reduce(naturalLongMaxReducer(), Long.MIN_VALUE); } /** * Returns the maximum element, or Long.MIN_VALUE if empty * @param comparator the comparator * @return maximum element, or Long.MIN_VALUE if empty */ public long max(LongComparator comparator) { return reduce(longMaxReducer(comparator), Long.MIN_VALUE); } /** * Returns the sum of elements * @return the sum of elements */ public long sum() { return reduce(Ops.longAdder(), 0); } /** * Returns summary statistics * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelLongArray.SummaryStatistics summary (LongComparator comparator) { PAS.FJLStats f = new PAS.FJLStats (this, firstIndex, upperBound, null, comparator); ex.invoke(f); return f; } /** * Returns summary statistics, using natural comparator * @return the summary. */ public ParallelLongArray.SummaryStatistics summary() { PAS.FJLStats f = new PAS.FJLStats (this, firstIndex, upperBound, null, naturalLongComparator()); ex.invoke(f); return f; } /** * Returns a new ParallelLongArray holding mappings * @return a new ParallelLongArray holding mappings */ public abstract ParallelLongArray all(); /** * Return the number of elements selected using bound or * filter restrictions. Note that this method must evaluate * all selectors to return its result. * @return the number of elements */ public abstract int size(); /** * Returns the index of some element matching bound and filter * constraints, or -1 if none. * @return index of matching element, or -1 if none. */ public abstract int anyIndex(); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithDoubleMapping withMapping (MapperFromLongToDouble mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithLongMapping withMapping (LongMapper mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithMapping withMapping (MapperFromLong mapper); final void leafTransfer(int lo, int hi, long[] dest, int offset) { final double[] array = pa.array; final MapperFromDoubleToLong mpr = mapper; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, long[] dest, int offset) { final double[] array = pa.array; final MapperFromDoubleToLong mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = mpr.map(array[indices[i]]); } } static final class WithBoundedLongMapping extends WithLongMapping { WithBoundedLongMapping(ParallelDoubleArray pa, int firstIndex, int upperBound, MapperFromDoubleToLong mapper) { super(pa, firstIndex, upperBound, mapper); } public ParallelLongArray all() { long[] dest = new long[upperBound - firstIndex]; PAS.FJLMap f = new PAS.FJLMap (this, firstIndex, upperBound, null, dest, firstIndex); ex.invoke(f); return new ParallelLongArray(ex, dest); } public int size() { return upperBound - firstIndex; } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } public WithDoubleMapping withMapping (MapperFromLongToDouble mapper) { return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping (LongMapper mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromLong mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, LongProcedure procedure) { final double[] array = pa.array; final MapperFromDoubleToLong mpr = mapper; for (int i = lo; i < hi; ++i) procedure.apply(mpr.map(array[i])); } long leafReduce(int lo, int hi, LongReducer reducer, long base) { if (lo >= hi) return base; final double[] array = pa.array; final MapperFromDoubleToLong mpr = mapper; long r = mpr.map(array[lo]); for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, mpr.map(array[i])); return r; } void leafStats(int lo, int hi, PAS.FJLStats task) { final double[] array = pa.array; final MapperFromDoubleToLong mpr = mapper; task.size = hi - lo; for (int i = lo; i < hi; ++i) { long x = mpr.map(array[i]); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } } static final class WithBoundedFilteredLongMapping extends WithLongMapping { final DoublePredicate selector; WithBoundedFilteredLongMapping (ParallelDoubleArray pa, int firstIndex, int upperBound, DoublePredicate selector, MapperFromDoubleToLong mapper) { super(pa, firstIndex, upperBound, mapper); this.selector = selector; } public ParallelLongArray all() { PAS.FJLSelectAllDriver r = new PAS.FJLSelectAllDriver(this); ex.invoke(r); return new ParallelLongArray(ex, r.results); } public int size() { PAS.FJDCountSelected f = new PAS.FJDCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJDSelectAny f = new PAS.FJDSelectAny (this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public WithDoubleMapping withMapping (MapperFromLongToDouble mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping (LongMapper mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromLong mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, LongProcedure procedure) { final DoublePredicate sel = selector; final MapperFromDoubleToLong mpr = mapper; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double x = array[i]; if (sel.evaluate(x)) procedure.apply(mpr.map(x)); } } long leafReduce(int lo, int hi, LongReducer reducer, long base) { boolean gotFirst = false; long r = base; final double[] array = pa.array; final DoublePredicate sel = selector; final MapperFromDoubleToLong mpr = mapper; for (int i = lo; i < hi; ++i) { double t = array[i]; if (sel.evaluate(t)) { long y = mpr.map(t); if (!gotFirst) { gotFirst = true; r = y; } else r = reducer.combine(r, y); } } return r; } void leafStats(int lo, int hi, PAS.FJLStats task) { final double[] array = pa.array; final DoublePredicate sel = selector; final MapperFromDoubleToLong mpr = mapper; int count = 0; for (int i = lo; i < hi; ++i) { double t = array[i]; if (sel.evaluate(t)) { ++count; long x = mpr.map(t); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final DoublePredicate sel = selector; final double[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final DoublePredicate sel = selector; final double[] array = pa.array; for (int i = lo; i < hi; ++i) { double t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } /** * Returns an iterator stepping through each element of the array * up to the current limit. This iterator does not * support the remove operation. However, a full * ListIterator supporting add, remove, and set * operations is available via {@link #asList}. * @return an iterator stepping through each element. */ public Iterator iterator() { return new ParallelDoubleArrayIterator(array, limit); } static final class ParallelDoubleArrayIterator implements Iterator { int cursor; final double[] arr; final int hi; ParallelDoubleArrayIterator(double[] a, int limit) { arr = a; hi = limit; } public boolean hasNext() { return cursor < hi; } public Double next() { if (cursor >= hi) throw new NoSuchElementException(); return Double.valueOf(arr[cursor++]); } public void remove() { throw new UnsupportedOperationException(); } } // List support /** * Returns a view of this ParallelDoubleArray as a List. This List * has the same structural and performance characteristics as * {@link ArrayList}, and may be used to modify, replace or extend * the bounds of the array underlying this ParallelDoubleArray. * The methods supported by this list view are not in * general implemented as parallel operations. This list is also * not itself thread-safe. In particular, performing list updates * while other parallel operations are in progress has undefined * (and surely undesired) effects. * @return a list view */ public List asList() { AsList lv = listView; if (lv == null) listView = lv = new AsList(); return lv; } /** * Returns the effective size of the underlying array. The * effective size is the current limit, if used (see {@link * #setLimit}), or the length of the array otherwise. * @return the effective size of array */ public int size() { return limit; } /** * Returns the underlying array used for computations * @return the array */ public double[] getArray() { return array; } /** * Returns the element of the array at the given index * @param i the index * @return the element of the array at the given index */ public double get(int i) { return array[i]; } /** * Sets the element of the array at the given index to the given value * @param i the index * @param x the value */ public void set(int i, double x) { array[i] = x; } /** * Equivalent to asList().toString() * @return a string representation */ public String toString() { return asList().toString(); } /** * Equivalent to AsList.addAll but specialized for array * arguments and likely to be more efficient. * @param other the elements to add */ public void addAll(double[] other) { int csize = other.length; int end = limit; insertSlotsAt(end, csize); System.arraycopy(other, 0, array, end, csize); } /** * Equivalent to AsList.addAll but specialized for * ParallelDoubleArray arguments and likely to be more efficient. * @param other the elements to add */ public void addAll(ParallelDoubleArray other) { int csize = other.size(); int end = limit; insertSlotsAt(end, csize); System.arraycopy(other.array, 0, array, end, csize); } /** * Equivalent to AsList.addAll but specialized for * ParallelDoubleArray arguments and likely to be more efficient. * @param other the elements to add */ public void addAll(ParallelDoubleArray.WithBounds other) { int csize = other.size(); int end = limit; insertSlotsAt(end, csize); System.arraycopy(other.pa.array, other.firstIndex, array, end, csize); } /** * Ensures that the underlying array can be accessed up to the * given upper bound, reallocating and copying the underlying * array to expand if necessary. Or, if the given limit is less * than the length of the underlying array, causes computations to * ignore elements past the given limit. * @param newLimit the new upper bound * @throws IllegalArgumentException if newLimit less than zero. */ public final void setLimit(int newLimit) { if (newLimit < 0) throw new IllegalArgumentException(); int cap = array.length; if (newLimit > cap) resizeArray(newLimit); limit = newLimit; } final void replaceElementsWith(double[] a) { System.arraycopy(a, 0, array, 0, a.length); limit = a.length; } final void resizeArray(int newCap) { int cap = array.length; if (newCap > cap) { double[] a = new double[newCap]; System.arraycopy(array, 0, a, 0, cap); array = a; } } final void insertElementAt(int index, double e) { int hi = limit++; if (hi >= array.length) resizeArray((hi * 3)/2 + 1); if (hi > index) System.arraycopy(array, index, array, index+1, hi - index); array[index] = e; } final void appendElement(double e) { int hi = limit++; if (hi >= array.length) resizeArray((hi * 3)/2 + 1); array[hi] = e; } /** * Make len slots available at index */ final void insertSlotsAt(int index, int len) { if (len <= 0) return; int cap = array.length; int newSize = limit + len; if (cap < newSize) { cap = (cap * 3)/2 + 1; if (cap < newSize) cap = newSize; resizeArray(cap); } if (index < limit) System.arraycopy(array, index, array, index + len, limit - index); limit = newSize; } final void removeSlotAt(int index) { System.arraycopy(array, index + 1, array, index, limit - index - 1); --limit; } final void removeSlotsAt(int fromIndex, int toIndex) { if (fromIndex < toIndex) { int size = limit; System.arraycopy(array, toIndex, array, fromIndex, size - toIndex); int newSize = size - (toIndex - fromIndex); limit = newSize; } } final int seqIndexOf(double target) { double[] arr = array; int fence = limit; for (int i = 0; i < fence; i++) if (target == arr[i]) return i; return -1; } final int seqLastIndexOf(double target) { double[] arr = array; for (int i = limit - 1; i >= 0; i--) if (target == arr[i]) return i; return -1; } final class ListIter implements ListIterator { int cursor; int lastRet; double[] arr; // cache array and bound int hi; ListIter(int lo) { this.cursor = lo; this.lastRet = -1; this.arr = ParallelDoubleArray.this.array; this.hi = ParallelDoubleArray.this.limit; } public boolean hasNext() { return cursor < hi; } public Double next() { int i = cursor; if (i < 0 || i >= hi) throw new NoSuchElementException(); double next = arr[i]; lastRet = i; cursor = i + 1; return Double.valueOf(next); } public void remove() { int k = lastRet; if (k < 0) throw new IllegalStateException(); ParallelDoubleArray.this.removeSlotAt(k); hi = ParallelDoubleArray.this.limit; if (lastRet < cursor) cursor--; lastRet = -1; } public boolean hasPrevious() { return cursor > 0; } public Double previous() { int i = cursor - 1; if (i < 0 || i >= hi) throw new NoSuchElementException(); double previous = arr[i]; lastRet = cursor = i; return Double.valueOf(previous); } public int nextIndex() { return cursor; } public int previousIndex() { return cursor - 1; } public void set(Double e) { int i = lastRet; if (i < 0 || i >= hi) throw new NoSuchElementException(); arr[i] = e.doubleValue(); } public void add(Double e) { int i = cursor; ParallelDoubleArray.this.insertElementAt(i, e.doubleValue()); arr = ParallelDoubleArray.this.array; hi = ParallelDoubleArray.this.limit; lastRet = -1; cursor = i + 1; } } final class AsList extends AbstractList implements RandomAccess { public Double get(int i) { if (i >= limit) throw new IndexOutOfBoundsException(); return Double.valueOf(array[i]); } public Double set(int i, Double x) { if (i >= limit) throw new IndexOutOfBoundsException(); double[] arr = array; Double t = Double.valueOf(arr[i]); arr[i] = x.doubleValue(); return t; } public boolean isEmpty() { return limit == 0; } public int size() { return limit; } public Iterator iterator() { return new ListIter(0); } public ListIterator listIterator() { return new ListIter(0); } public ListIterator listIterator(int index) { if (index < 0 || index > limit) throw new IndexOutOfBoundsException(); return new ListIter(index); } public boolean add(Double e) { appendElement(e.doubleValue()); return true; } public void add(int index, Double e) { if (index < 0 || index > limit) throw new IndexOutOfBoundsException(); insertElementAt(index, e.doubleValue()); } public boolean addAll(Collection c) { int csize = c.size(); if (csize == 0) return false; int hi = limit; setLimit(hi + csize); double[] arr = array; for (Double e : c) arr[hi++] = e.doubleValue(); return true; } public boolean addAll(int index, Collection c) { if (index < 0 || index > limit) throw new IndexOutOfBoundsException(); int csize = c.size(); if (csize == 0) return false; insertSlotsAt(index, csize); double[] arr = array; for (Double e : c) arr[index++] = e.doubleValue(); return true; } public void clear() { limit = 0; } public boolean remove(Object o) { if (!(o instanceof Double)) return false; int idx = seqIndexOf(((Double)o).doubleValue()); if (idx < 0) return false; removeSlotAt(idx); return true; } public Double remove(int index) { Double oldValue = get(index); removeSlotAt(index); return oldValue; } protected void removeRange(int fromIndex, int toIndex) { removeSlotsAt(fromIndex, toIndex); } public boolean contains(Object o) { if (!(o instanceof Double)) return false; return seqIndexOf(((Double)o).doubleValue()) >= 0; } public int indexOf(Object o) { if (!(o instanceof Double)) return -1; return seqIndexOf(((Double)o).doubleValue()); } public int lastIndexOf(Object o) { if (!(o instanceof Double)) return -1; return seqLastIndexOf(((Double)o).doubleValue()); } } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/TaskBarrier.java0000644000000000000000000003134310735315511023513 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import java.util.concurrent.atomic.*; /** * A synchronization barrier for ForkJoinTasks. A TaskBarrier is * similar in functionality to a {@link * java.util.concurrent.CyclicBarrier}, but differs in the following * ways. * *
    * *
  1. The number of parties may vary over time. A task may register * to be a party in a barrier at any time (but almost always before * being forked), and may deregister upon arriving at the barrier. As * is the case with most other basic synchronization constructs, * registration and deregistration affect only internal counts; they * do not establish any further internal bookkeeping. * *
  2. TaskBarriers support split-phase operation: The two aspects of * coordination, arriving at a barrier (arrive) and awaiting * others (awaitCycleAdvance) are independently supported. * Like a CyclicBarrier, A TaskBarrier may be * repeatedly awaited. Each cycle has an associated value, returned * from arrive, that be used as an argument to * awaitCycleAdvance. Method arriveAndAwait * conveniently combines these. (In descriptions below, a task is * termed "active" unless it has arrived at a barrier but has not * advanced via awaitCycleAdvance, or has deregistered.) * *
  3. TaskBarriers may enter a termination state in which * all await actions immediately return, indicating (via a negative * cycle value) that execution is complete. Termination is triggered * by executing the overridable terminate method that is * executed each time the barrier is tripped. * *
  4. TaskBarriers may be used only by ForkJoinTasks. Coordination * operations (arriveAndAwait and awaitCycleAdvance) * need not block, but instead help other tasks make progress. While * not dynamically enforced, only registered tasks may invoke methods * arrive, arriveAndAwait, and * arriveAndDeregister. However any ForkJoinTask may invoke * awaitCycleAdvance. And any caller may invoke status * methods such as getParties for the sake of monitoring and * debugging. * *
* *

A TaskBarrier may be used to support a style of programming in * which a task waits for others to complete, without otherwise * needing to keep track of which tasks it is waiting for. This is * similar to the "sync" construct in Cilk and "clocks" in X10. * Special constructions based on such barriers are available using * the LinkedAsyncAction and CyclicAction classes, but * they can be useful in other contexts as well. For a simple (but * not very useful) example, here is a variant of Fibonacci: * *

 * class BarrierFibonacci extends RecursiveAction {
 *   int argument, result;
 *   final TaskBarrier parentBarrier;
 *   BarrierFibonacci(int n, TaskBarrier parentBarrier) {
 *     this.argument = n;
 *     this.parentBarrier = parentBarrier;
 *     parentBarrier.register();
 *   }
 *   protected void compute() {
 *     int n = argument;
 *     if (n <= 1)
 *        result = n;
 *     else {
 *        TaskBarrier childBarrier = new TaskBarrier(1);
 *        BarrierFibonacci f1 = new BarrierFibonacci(n - 1, childBarrier);
 *        BarrierFibonacci f2 = new BarrierFibonacci(n - 2, childBarrier);
 *        f1.fork();
 *        f2.fork();
 *        childBarrier.arriveAndAwait();
 *        result = f1.result + f2.result;
 *     }
 *     parentBarrier.arriveAndDeregister();
 *   }
 * }
 * 
* *

Implementation notes: This implementation restricts the * maximum number of registered parties to 65535. Attempts to register * additional parties result in IllegalStateExceptions. */ public class TaskBarrier { /* * This class implements a form of X10 "clocks". Thanks to Vijay * Saraswat for the idea of applying it to ForkJoinTasks. * * Conceptually, a barrier contains three values: * nParties -- the number of parties to wait (16 bits) * nActive -- the number of parties yet to hit barrier (16 bits) * cycle -- the generation of the barrier (32 bits) * However, to efficiently maintain atomicity, these values * are packed into a single AtomicLong. */ private final AtomicLong state; private static final int ushortBits = 16; private static final int ushortMask = (1 << ushortBits) - 1; private static int nActiveOf(long s) { return (int)(s & ushortMask); } private static int nPartiesOf(long s) { return (int)(s & (ushortMask << 16)) >>> 16; } private static int cycleOf(long s) { return (int)(s >>> 32); } private static long stateFor(int cycle, int nParties, int nActive) { return (((long)cycle) << 32) | ((nParties << 16) | nActive); } private static final int TERMINATED = -1; /** * Trip the barrier, checking for termination */ private void trip(int cycle, int nParties) { if (cycle >= 0) { if (terminate(cycle, nParties)) cycle = TERMINATED; else if (++cycle < 0) cycle = 0; // wrap back positive } state.set(stateFor(cycle, nParties, nParties)); } /** * Creates a new barrier without any initially registered parties. */ public TaskBarrier() { this(0); } /** * Creates a new barrier with the given numbers of registered * active parties. * @param parties the number of parties required to trip barrier. * @throws IllegalArgumentException if parties less than zero * or greater than the maximum number of parties supported. */ public TaskBarrier(int parties) { if (parties < 0 || parties > ushortMask) throw new IllegalArgumentException("Too many parties"); state = new AtomicLong(stateFor(0, parties, parties)); } /** * Adds a new active party to the barrier. * @return the current barrier cycle number upon registration */ public int register() { // increment both parties and active for (;;) { long s = state.get(); int nParties = nPartiesOf(s) + 1; if (nParties > ushortMask) throw new IllegalStateException("Too many parties"); int nActive = nActiveOf(s) + 1; int cycle = cycleOf(s); long next = stateFor(cycle, nParties, nActive); if (state.compareAndSet(s, next)) return cycle; } } /** * Arrives at the barrier, but does not wait for others. (You can * in turn wait for others via {@link #awaitCycleAdvance}). * * @return the current barrier cycle number upon entry to * this method, or a negative value if terminated; */ public int arrive() { // decrement active. If zero, increment cycle and reset active for (;;) { long s = state.get(); int cycle = cycleOf(s); int nParties = nPartiesOf(s); int nActive = nActiveOf(s) - 1; if (nActive > 0) { long next = stateFor(cycle, nParties, nActive); if (state.compareAndSet(s, next)) return cycle; } else { trip(cycle, nParties); return cycle; } } } /** * Arrives at the barrier, and deregisters from it. * * @return the current barrier cycle number upon entry to * this method, or a negative value if terminated; */ public int arriveAndDeregister() { // Same as arrive except also decrement parties for (;;) { long s = state.get(); int cycle = cycleOf(s); int nParties = nPartiesOf(s) - 1; if (nParties < 0) throw new IllegalStateException("Unregistered deregistration"); int nActive = nActiveOf(s) - 1; if (nActive > 0) { long next = stateFor(cycle, nParties, nActive); if (state.compareAndSet(s, next)) return cycle; } else { trip(cycle, nParties); return cycle; } } } /** * Awaits the cycle of the barrier to advance from the given * value, by helping other tasks. * @param cycle the cycle on entry to this method * @return the cycle on exit from this method */ public int awaitCycleAdvance(int cycle) { for (;;) { int p = getCycle(); if (p != cycle || p < 0) return p; ForkJoinTask t = ForkJoinWorkerThread.pollTask(); if (t != null) { p = getCycle(); if (p != cycle) { // if barrier advanced t.fork(); // push task and exit return p; } else t.exec(); } } } /** * Arrives at the barrier and awaits others. Unlike other * arrival methods, this method returns the arrival * index of the caller. The caller tripping the barrier * returns zero, the previous caller 1, and so on. * This enables creation of barrier actions by the task * tripping the barrier using constructions of the form: * if (b.arriveAndAwait()== 0) action(); b.arriveAndAwait(); * @return the arrival index */ public int arriveAndAwait() { for (;;) { long s = state.get(); int cycle = cycleOf(s); int nParties = nPartiesOf(s); int nActive = nActiveOf(s) - 1; if (nActive > 0) { long next = stateFor(cycle, nParties, nActive); if (state.compareAndSet(s, next)) { awaitCycleAdvance(cycle); return nActive; } } else { trip(cycle, nParties); return 0; } } } /** * Returns the current cycle number. The maximum cycle number is * Integer.MAX_VALUE, after which it restarts at * zero. Upon termination, the cycle number is negative. * @return the cycle number, or a negative value if terminated */ public int getCycle() { return cycleOf(state.get()); } /** * Returns the number of parties registered at this barrier. * @return the number of parties */ public int getRegisteredParties() { return nPartiesOf(state.get()); } /** * Returns the number of parties that have not yet arrived at the * current cycle of this barrier. * @return the number of active parties */ public int getActiveParties() { return nActiveOf(state.get()); } /** * Returns true if this barrier has been terminated * @return true if this barrier has been terminated */ public boolean isTerminated() { return cycleOf(state.get()) < 0; } /** * Overridable method to control termination. This method is * invoked whenever the barrier is tripped. If it returns true, * then this barrier is set to a final termination state, and * subsequent calls to getCycle and related methods * return negative values. * *

The default version returns true only when the number * of registered parties is zero. * @param cycle the cycle count on entering the barrier * @param registeredParties the current number of registered * parties. */ protected boolean terminate(int cycle, int registeredParties) { return registeredParties <= 0; } /** * Returns a string identifying this barrier, as well as its * state. The state, in brackets, includes the String {@code * "Cycle ="} followed by the cycle number, {@code "parties ="} * followed by the number of registered parties, and {@code * "acivie ="} followed by the number of active parties * * @return a string identifying this barrier, as well as its state */ public String toString() { long s = state.get(); return super.toString() + "[Cycle = " + cycleOf(s) + " parties = " + nPartiesOf(s) + " active = " + nActiveOf(s) + "]"; } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/LinkedAsyncAction.java0000644000000000000000000002746510735315511024656 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * */ package jsr166y.forkjoin; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; /** * Resultless ForkJoinTasks with explicit completions, that may be * linked in parent-child relationships. Unlike other kinds of tasks, * LinkedAsyncActions do not intrinisically complete upon exit from * their compute methods, but instead require explicit * invocation of their finish methods and completion of * subtasks. * *

Upon construction, an LinkedAsyncAction may register as a * subtask of a given parent task. In this case, completion of this * task will propagate to its parent. If the parent's pending subtask * completion count becomes zero, it too will finish. * LinkedAsyncActions rarely use methods join or * invoke but instead propagate completion to parents * implicitly via finish. While typical, it is not necessary * for each task to finish itself. For example, it is * possible to treat one subtask as a continuation of the current task * by not registering it on construction. In this case, a * finish of the subtask will trigger finish of the * parent without the parent explicitly doing so. * *

In addition to supporting these different computation styles * compared to Recursive tasks, LinkedAsyncActions may have smaller * stack space footprints while executing, but may have greater * per-task overhead. * *

Sample Usage. Here is a sketch of an LinkedAsyncAction * that visits all of the nodes of a graph. The details of the graph's * Node and Edge classes are omitted, but we assume each node contains * an AtomicBoolean mark that starts out false. To execute * this, you would create a GraphVisitor for the root node with null * parent, and invoke in a ForkJoinPool. Upon return, all * reachable nodes will have been visited. * *

 * class GraphVisitor extends LinkedAsyncAction {
 *    final Node node;
 *    GraphVisitor(GraphVistor parent, Node node) {
 *      super(parent); this.node = node;
 *    }
 *    protected void compute() {
 *      if (node.mark.compareAndSet(false, true)) {
 *         for (Edge e : node.edges()) {
 *            Node dest = e.getDestination();
 *            if (!dest.mark.get())
 *               new GraphVisitor(this, dest).fork();
 *         }
 *         visit(node);
 *      }
 *      finish();
 *   }
 * }
 * 
* */ public abstract class LinkedAsyncAction extends ForkJoinTask { /** * Parent to notify on completion */ private LinkedAsyncAction parent; /** * Count of outstanding subtask joins */ private volatile int pendingCount; private static final AtomicIntegerFieldUpdater pendingCountUpdater = AtomicIntegerFieldUpdater.newUpdater(LinkedAsyncAction.class, "pendingCount"); /** * Creates a new action with no parent. (You can add a parent * later (but before forking) via reinitialize). */ protected LinkedAsyncAction() { } /** * Creates a new action with the given parent. If the parent is * non-null, this tasks registers with the parent, in which case, * the parent task cannot complete until this task completes. * @param parent the parent task, or null if none */ protected LinkedAsyncAction(LinkedAsyncAction parent) { this.parent = parent; if (parent != null) pendingCountUpdater.incrementAndGet(parent); } /** * Creates a new action with the given parent, optionally * registering with the parent. If the parent is non-null and * register is true, this tasks registers with the * parent, in which case, the parent task cannot complete until * this task completes. * @param parent the parent task, or null if none * @param register true if parent must wait for this task * to complete before it completes */ protected LinkedAsyncAction(LinkedAsyncAction parent, boolean register) { this.parent = parent; if (parent != null && register) pendingCountUpdater.incrementAndGet(parent); } /** * Creates a new action with the given parent, optionally * registering with the parent, and setting the pending join count * to the given value. If the parent is non-null and * register is true, this tasks registers with the * parent, in which case, the parent task cannot complete until * this task completes. Setting the pending join count requires * care -- it is correct only if child tasks do not themselves * register. * @param parent the parent task, or null if none * @param register true if parent must wait for this task * to complete before it completes * @param pending the pending join count */ protected LinkedAsyncAction(LinkedAsyncAction parent, boolean register, int pending) { this.parent = parent; pendingCount = pending; if (parent != null && register) pendingCountUpdater.incrementAndGet(parent); } /** * The asynchronous part of the computation performed by this * task. While you must define this method, you should not in * general call it directly (although you can invoke immediately * via exec.) If this method throws a Throwable, * finishExceptionally is immediately invoked. */ protected abstract void compute(); /** * Overridable callback action triggered by finish. Upon * invocation, all subtasks have completed. After return, this * task isDone and is joinable by other tasks. The * default version of this method does nothing. But it may may be * overridden in subclasses to perform some action when this task * is about to complete. */ protected void onCompletion() { } /** * Overridable callback action triggered by * finishExceptionally. Upon invocation, this task has * aborted due to an exception (accessible via * getException). If this method returns true, * the exception propagates to the current task's * parent. Otherwise, normal completion is propagated. The * default version of this method does nothing and returns * true. * @return true if this task's exception should be propagated to * this tasks parent. */ protected boolean onException() { return true; } /** * Equivalent to finish(null). */ public final void finish() { finish(null); } /** * Completes this task. If the pending subtask completion count is * zero, invokes onCompletion, then causes this task to * be joinable (isDone becomes true), and then * recursively applies to this tasks's parent, if it exists. If an * exception is encountered in any onCompletion * invocation, that task and its ancestors * finishExceptionally. * * @param result must be null. */ public final void finish(Void result) { LinkedAsyncAction a = this; while (a != null && !a.isDone()) { int c = a.pendingCount; if (c == 0) { try { a.onCompletion(); } catch (Throwable rex) { a.finishExceptionally(rex); return; } a.setDone(); a = a.parent; } else if (pendingCountUpdater.compareAndSet(a, c, c-1)) return; } } /** * Completes this task abnormally. Unless this task already * cancelled or aborted, upon invocation, this method invokes * onException, and then, depending on its return value, * finishes parent (if one exists) exceptionally or normally. To * avoid unbounded exception loops, this method aborts if an * exception is encountered in any onException * invocation. * @param ex the exception to throw when joining this task * @throws NullPointerException if ex is null * @throws Throwable if any invocation of * onException does so. */ public final void finishExceptionally(Throwable ex) { if (ex == null) throw new NullPointerException(); LinkedAsyncAction a = this; while (a.setDoneExceptionally(ex) == ex) { boolean up = a.onException(); // abort if this throws a = a.parent; if (a == null) return; if (!up) { a.finish(); return; } } } /** * Returns this task's parent, or null if none. * @return this task's parent, or null if none. */ public final LinkedAsyncAction getParent() { return parent; } /** * Returns the number of subtasks that have not yet completed. * @return the number of subtasks that have not yet completed. */ public final int getPendingSubtaskCount() { return pendingCount; } /** * Always returns null. * @return null */ public final Void rawResult() { return null; } /** * Resets the internal bookkeeping state of this task, maintaining * the current parent but clearing pending joins. */ public void reinitialize() { super.reinitialize(); if (pendingCount != 0) pendingCount = 0; } /** * Resets the internal bookkeeping state of this task, maintaining * the current parent and setting pending joins to the given value. * @param pending the number of pending joins */ public void reinitialize(int pending) { super.reinitialize(); pendingCount = pending; } /** * Reinitialize with the given parent, optionally registering. * @param parent the parent task, or null if none * @param register true if parent must wait for this task * to complete before it completes */ public void reinitialize(LinkedAsyncAction parent, boolean register) { super.reinitialize(); if (pendingCount != 0) pendingCount = 0; this.parent = parent; if (parent != null && register) pendingCountUpdater.incrementAndGet(parent); } /** * Reinitialize with the given parent, optionally registering * and setting pending join count. * @param parent the parent task, or null if none * @param register true if parent must wait for this task * to complete before it completes * @param pending the pending join count */ public void reinitialize(LinkedAsyncAction parent, boolean register, int pending) { super.reinitialize(); pendingCount = pending; this.parent = parent; if (parent != null && register) pendingCountUpdater.incrementAndGet(parent); } public final Void forkJoin() { exec(); return join(); } public final Throwable exec() { if (exception == null) { try { compute(); } catch(Throwable rex) { finishExceptionally(rex); } } return exception; } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/ForkJoinTask.java0000644000000000000000000003634610735315511023656 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import sun.misc.Unsafe; import java.lang.reflect.*; /** * Abstract base class for tasks that run within a ForkJoinPool. A * ForkJoinTask is a thread-like entity that is much lighter weight * than a normal thread. Huge numbers of tasks and subtasks may be * hosted by a small number of actual threads in a ForkJoinPool, * at the price of some usage limitations. * *

The ForkJoinTask class is not directly subclassable * outside of this package. Instead, you can subclass one of the * supplied abstract classes that support the various styles of * fork/join processing. Normally, a concrete ForkJoinTask subclass * declares fields comprising its parameters, established in a * constructor, and then defines a protected compute method * that somehow uses the control methods supplied by this base * class. While these methods have public access, most may * only be called from within other ForkJoinTasks. Attempts to invoke * them in other contexts result in exceptions or errors including * ClassCastException. The only generally accessible methods are * those for cancellation and status checking. The only way to invoke * a "main" driver task is to submit it to a ForkJoinPool. Normally, * once started, this will in turn start other subtasks. Nearly all * of these base support methods are final because their * implementations are intrinsically tied to the underlying * lightweight task scheduling framework, and so cannot in general be * overridden. * *

ForkJoinTasks play similar roles as Futures but * support a more limited range of use. The "lightness" of * ForkJoinTasks is due to a set of restrictions (that are only * partially statically enforceable) reflecting their intended use as * purely computational tasks -- calculating pure functions or * operating on purely isolated objects. The only coordination * mechanisms supported for ForkJoinTasks are fork, that * arranges asynchronous execution, and join, that doesn't * proceed until the task's result has been computed. (A simple form * of cancellation is also supported). The computation defined in the * compute method should not in general perform any other * form of blocking synchronization, should not perform IO, and should * be independent of other tasks. Minor breaches of these * restrictions, for example using shared output streams, may be * tolerable in practice, but frequent use will result in poor * performance, and the potential to indefinitely stall if the number * of threads not waiting for external synchronization becomes * exhausted. This usage restriction is in part enforced by not * permitting checked exceptions to be thrown. However, computations * may still encounter unchecked exceptions, that are rethrown to * callers attempting join them. These exceptions may additionally * include RejectedExecutionExceptions stemming from internal resource * exhaustion such as failure to allocate internal task queues. * */ public abstract class ForkJoinTask { /* * The main implementations of execution methods are provided by * ForkJoinWorkerThread, so internals are package protected. This * class is mainly responsible for maintaining its exception and * status fields. */ /** * Disallow direct construction outside this package. */ ForkJoinTask() { } /** * The exception thrown within compute method, or via cancellation. * Updated only via CAS, to arbitrate cancellations vs normal * exceptions. */ volatile Throwable exception; /** * Updater to enable CAS of exception field */ static final AtomicReferenceFieldUpdater exceptionUpdater = AtomicReferenceFieldUpdater.newUpdater (ForkJoinTask.class, Throwable.class, "exception"); /** * Status, taking values: * 0: initial * -1: completed * >0: stolen (or external) * * Status is set negative when task completes normally. A task is * considered completed if the exception is non-null or status is * negative (or both); and must always be checked accordingly. The * status field need not be volatile so long as it is written in * correct order. Even though according to the JMM, writes to * status (or other per-task fields) need not be immediately * visible to other threads, they must eventually be so here: They * will always be visible to any stealing thread, since these * reads will be fresh. In other situations, in the worst case of * not being seen earlier, since Worker threads eventually scan * all other threads looking for work, any subsequent read must * see any writes occuring before last volatile bookkeeping * operation, which all workers must eventually perform. And on * the issuing side, status is set after rechecking exception * field which prevents premature writes. * * The positive range could hold the pool index of the origin of * non-complete stolen tasks but isn't currently done. */ int status; // within-package utilities /** * Sets status to stolen (or an external submission). Called only * by task-stealing and submission code. */ final void setStolen() { status = 1; } /** * Sets status to indicate this task is done. */ final Throwable setDone() { Throwable ex = exception; int s = status; status = -1; if (s != 0) // conservatively signal on any nonzero ForkJoinWorkerThread.signalTaskCompletion(); return ex; } /** * setDone for exceptional termination */ final Throwable setDoneExceptionally(Throwable rex) { exceptionUpdater.compareAndSet(this, null, rex); ForkJoinWorkerThread.signalTaskCompletion(); return exception; } /** * Returns result or throws exception. * Only call when isDone known to be true. */ final V reportAsForkJoinResult() { Throwable ex = getException(); if (ex != null) rethrowException(ex); return rawResult(); } /** * Returns result or throws exception using j.u.c.Future conventions * Only call when isDone known to be true. */ final V reportAsFutureResult() throws ExecutionException { Throwable ex = getException(); if (ex != null) { if (ex instanceof CancellationException) throw (CancellationException)ex; else throw new ExecutionException(ex); } return rawResult(); } /** * Arranges to asynchronously execute this task, which will later * be directly or indirectly joined by the caller of this method. * While it is not necessarily enforced, it is a usage error to * fork a task more than once unless it has completed and been * reinitialized. This method may be invoked only from within * other ForkJoinTask computations. Attempts to invoke in other * contexts result in exceptions or errors including * ClassCastException. */ public final void fork() { ((ForkJoinWorkerThread)(Thread.currentThread())).pushTask(this); } /** * Returns the result of the computation when it is ready. * Monitoring note: Callers of this method need not block, but may * instead assist in performing computations that may directly or * indirectly cause the result to be ready. * This method may be invoked only from within other ForkJoinTask * computations. Attempts to invoke in other contexts result * in exceptions or errors including ClassCastException. * * @return the computed result * @throws Throwable (a RuntimeException, Error, or unchecked * exception) if the underlying computation did so. */ public final V join() { return ((ForkJoinWorkerThread)(Thread.currentThread())).doJoinTask(this); } /** * Equivalent in effect to the sequence fork(); join(); * but may be more efficient. * @throws Throwable (a RuntimeException, Error, or unchecked * exception) if the underlying computation did so. * @return the computed result */ public abstract V forkJoin(); /** * Returns true if the computation performed by this task has * completed (or has been cancelled). This method will eventually * return true upon task completion, but return values are not * otherwise guaranteed to be uniform across observers. Thus, * when task t finishes, concurrent invocations of * t.isDone() from other tasks or threads on may * transiently return different results, but on repeated * invocation, will eventually agree that t.isDone(). * @return true if this computation has completed */ public final boolean isDone() { return exception != null || status < 0; } /** * Returns true if this task was cancelled. * @return true if this task was cancelled */ public final boolean isCancelled() { return exception instanceof CancellationException; } /** * Asserts that the results of this task's computation will not be * used. If a cancellation occurs before this task is processed, * then its compute method will not be executed, * isCancelled will report true, and join will * result in a CancellationException being thrown. Otherwise, * there are no guarantees about whether isCancelled will * report true, whether join will return normally or via * an exception, or whether these behaviors will remain consistent * upon repeated invocation. This method may be overridden in * subclasses, but if so, must still ensure that these minimal * properties hold. */ public void cancel() { setDoneExceptionally(new CancellationException()); } /** * Returns the exception thrown by method compute, or a * CancellationException if cancelled, or null if none or if the * method has not yet completed. * @return the exception, or null if none */ public final Throwable getException() { return exception; } /** * Returns the result that would be returned by join, or * null if this task is not known to have been completed. This * method is designed to aid debugging, as well as to support * extensions. Its use in any other context is strongly * discouraged. * @return the result, or null if not completed. */ public abstract V rawResult(); /** * Resets the internal bookkeeping state of this task, allowing a * subsequent fork. This method allows repeated reuse of * this task, but only if reuse occurs when this task has either * never been forked, or has been forked, then completed and all * outstanding joins of this task have also completed. Effects * under any other usage conditions are not guaranteed, and are * almost surely wrong. This method may be useful when repeatedly * executing pre-constructed trees of subtasks. */ public void reinitialize() { if (exception != null) exception = null; status = 0; } /** * Returns true if this task was stolen from some other worker in the * pool and has not yet completed. This method should be called * only by the thread currently executing this task. The results * of calling this method in any other context are undefined. * @return true is this task is stolen */ public final boolean isStolen() { return status > 0; } /** * Joins this task, without returning its result or throwing an * exception, but returning the exception that join would * throw. This method may be useful when processing collections of * tasks when some have been cancelled or otherwise known to have * aborted. This method may be invoked only from within other * ForkJoinTask computations. Attempts to invoke in other contexts * result in exceptions or errors including ClassCastException. * @return the exception that would be thrown by join, or * null if this task completed normally. */ public final Throwable quietlyJoin() { return ((ForkJoinWorkerThread)(Thread.currentThread())).doQuietlyJoinTask(this); } /** * Immediately commences execution of this task by the current * worker thread unless already cancelled, returning any exception * thrown by its compute method. * @return exception thrown by compute (or via cancellation), or * null if none */ public abstract Throwable exec(); /** * Completes this task, and if not already aborted or cancelled, * returning the given result upon join and related * operations. This method may be invoked only from within other * ForkJoinTask computations. This method may be used to provide * results, mainly for asynchronous tasks. Upon invocation, the * task itself, if running, must exit (return) in a small finite * number of steps. * @param result the result to return */ public abstract void finish(V result); /** * Completes this task abnormally, and if not already aborted or * cancelled, causes it to throw the given exception upon * join and related operations. Upon invocation, the task * itself, if running, must exit (return) in a small finite number * of steps. * @param ex the exception to throw. While not necessarily * statically enforced, this must be a RuntimeException or Error. */ public abstract void finishExceptionally(Throwable ex); // Temporary Unsafe mechanics for preliminary release private static Unsafe getUnsafe() { try { if (ForkJoinTask.class.getClassLoader() != null) { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); return (Unsafe)f.get(null); } else return Unsafe.getUnsafe(); } catch (Exception e) { throw new RuntimeException("Could not initialize intrinsics", e); } } private static final Unsafe _unsafe = getUnsafe(); /** * Workaround for not being able to rethrow unchecked exceptions. */ static final void rethrowException(Throwable ex) { if (ex != null) _unsafe.throwException(ex); } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/package-info.java0000644000000000000000000000361110735315511023623 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ /** * A fine-grained parallel computation framework. ForkJoinTasks and * their related support classes provide a very efficient basis for * obtaining platform-independent parallel speed-ups of * computation-intensive operations. They are not a full substitute * for the kinds of arbitrary processing supported by Executors or * Threads. However, when applicable, they typically provide * significantly greater performance on multiprocessor platforms. * *

Candidates for fork/join processing mainly include those that * can be expressed using parallel divide-and-conquer techniques: To * solve a problem, break it in two (or more) parts, and then solve * those parts in parallel, continuing on in this way until the * problem is too small to be broken up, so is solved directly. The * underlying work-stealing framework makes subtasks * available to other threads (normally one per CPU), that help * complete the tasks. In general, the most efficient ForkJoinTasks * are those that directly implement this algorithmic design pattern. * *

While direct implementation of parallel divide-and-conquer * algorithms is often straightforward, it can also be tedious and * code-intensive. For this reason, a number of solution "templates" * are available for common kinds of operations on lists and arrays: * applying some operation to all elements, combining elements * according to some function, and so on. In this preliminary * release, these are presented via some interfaces describing the * associated code bodies in TaskTypes, along with an evolving set of * implementations for lists and arrays of objects and scalars. */ package jsr166y.forkjoin; libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/ParallelLongArray.java0000644000000000000000000031310010740452246024652 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import static jsr166y.forkjoin.Ops.*; import java.util.*; import java.util.concurrent.atomic.*; import java.lang.reflect.Array; /** * An array of longs supporting parallel operations. This class * provides methods supporting the same operations as {@link * ParallelArray}, but specialized for scalar longs. It additionally * provides a few methods specific to numerical values. */ public class ParallelLongArray { // Same internals as ParallelArray, but specialized for longs long[] array; final ForkJoinExecutor ex; int limit; AsList listView; /** * Returns a common default executor for use in ParallelArrays. * This executor arranges enough parallelism to use most, but not * necessarily all, of the avaliable processors on this system. * @return the executor */ public static ForkJoinExecutor defaultExecutor() { return PAS.defaultExecutor(); } /** * Constructor for use by subclasses to create a new ParallelLongArray * using the given executor, and initially using the supplied * array, with effective size bound by the given limit. This * constructor is designed to enable extensions via * subclassing. To create a ParallelLongArray, use {@link #create}, * {@link #createEmpty}, {@link #createUsingHandoff} or {@link * #createFromCopy}. * @param executor the executor * @param array the array * @param limit the upper bound limit */ protected ParallelLongArray(ForkJoinExecutor executor, long[] array, int limit) { if (executor == null || array == null) throw new NullPointerException(); if (limit < 0 || limit > array.length) throw new IllegalArgumentException(); this.ex = executor; this.array = array; this.limit = limit; } /** * Trusted internal version of protected constructor. */ ParallelLongArray(ForkJoinExecutor executor, long[] array) { this.ex = executor; this.array = array; this.limit = array.length; } /** * Creates a new ParallelLongArray using the given executor and * an array of the given size * @param size the array size * @param executor the executor */ public static ParallelLongArray create (int size, ForkJoinExecutor executor) { long[] array = new long[size]; return new ParallelLongArray(executor, array, size); } /** * Creates a new ParallelLongArray initially using the given array and * executor. In general, the handed off array should not be used * for other purposes once constructing this ParallelLongArray. The * given array may be internally replaced by another array in the * course of methods that add or remove elements. * @param handoff the array * @param executor the executor */ public static ParallelLongArray createUsingHandoff (long[] handoff, ForkJoinExecutor executor) { return new ParallelLongArray(executor, handoff, handoff.length); } /** * Creates a new ParallelLongArray using the given executor and * initially holding copies of the given * source elements. * @param source the source of initial elements * @param executor the executor */ public static ParallelLongArray createFromCopy (long[] source, ForkJoinExecutor executor) { // For now, avoid copyOf so people can compile with Java5 int size = source.length; long[] array = new long[size]; System.arraycopy(source, 0, array, 0, size); return new ParallelLongArray(executor, array, size); } /** * Creates a new ParallelLongArray using an array of the given size, * initially holding copies of the given source truncated or * padded with zeros to obtain the specified length. * @param source the source of initial elements * @param size the array size * @param executor the executor */ public static ParallelLongArray createFromCopy (int size, long[] source, ForkJoinExecutor executor) { // For now, avoid copyOf so people can compile with Java5 long[] array = new long[size]; System.arraycopy(source, 0, array, 0, Math.min(source.length, size)); return new ParallelLongArray(executor, array, size); } /** * Creates a new ParallelLongArray using the given executor and * an array of the given size, but with an initial effective size * of zero, enabling incremental insertion via {@link * ParallelLongArray#asList} operations. * @param size the array size * @param executor the executor */ public static ParallelLongArray createEmpty (int size, ForkJoinExecutor executor) { long[] array = new long[size]; return new ParallelLongArray(executor, array, 0); } /** * Summary statistics for a possibly bounded, filtered, and/or * mapped ParallelLongArray. */ public static interface SummaryStatistics { /** Return the number of elements */ public int size(); /** Return the minimum element, or Long.MAX_VALUE if empty */ public long min(); /** Return the maximum element, or Long.MIN_VALUE if empty */ public long max(); /** Return the index of the minimum element, or -1 if empty */ public int indexOfMin(); /** Return the index of the maximum element, or -1 if empty */ public int indexOfMax(); /** Return the sum of all elements */ public long sum(); /** Return the arithmetic average of all elements */ public double average(); } /** * Returns the executor used for computations * @return the executor */ public ForkJoinExecutor getExecutor() { return ex; } /** * Applies the given procedure to elements * @param procedure the procedure */ public void apply(LongProcedure procedure) { new WithBounds(this).apply(procedure); } /** * Returns reduction of elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public long reduce(LongReducer reducer, long base) { return new WithBounds(this).reduce(reducer, base); } /** * Returns a new ParallelLongArray holding all elements * @return a new ParallelLongArray holding all elements */ public ParallelLongArray all() { return new WithBounds(this).all(); } /** * Returns a ParallelLongArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelLongArray combine(long[] other, LongReducer combiner) { return new WithBounds(this).combine(other, combiner); } /** * Returns a ParallelLongArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is not * the same length as this array. */ public ParallelLongArray combine(ParallelLongArray other, LongReducer combiner) { return new WithBounds(this).combine(other, combiner); } /** * Returns a ParallelLongArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array segment * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other segment is * shorter than this array. */ public ParallelLongArray combine(ParallelLongArray.WithBounds other, LongReducer combiner) { return new WithBounds(this).combine(other, combiner); } /** * Replaces elements with the results of applying the given mapper * to their current values. * @param mapper the mapper */ public void replaceWithTransform(LongMapper mapper) { new WithBounds(this).replaceWithTransform(mapper); } /** * Replaces elements with the results of applying the given * mapper to their indices. * @param mapper the mapper */ public void replaceWithMappedIndex(MapperFromIntToLong mapper) { new WithBounds(this).replaceWithMappedIndex(mapper); } /** * Replaces elements with the results of applying the given * generator. For example, to fill the array with uniform random * values, use * replaceWithGeneratedValue(Ops.longRandom()) * @param generator the generator */ public void replaceWithGeneratedValue(LongGenerator generator) { new WithBounds(this).replaceWithGeneratedValue(generator); } /** * Replaces elements with the given value. * @param value the value */ public void replaceWithValue(long value) { new WithBounds(this).replaceWithValue(value); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer elements than this array. */ public void replaceWithCombination (ParallelLongArray other, LongReducer combiner) { new WithBounds(this).replaceWithCombination(other.array, combiner); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer elements than this array. */ public void replaceWithCombination(long[] other, LongReducer combiner) { new WithBounds(this).replaceWithCombination(other, combiner); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array segment * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other segment has * fewer elements.than this array, */ public void replaceWithCombination (ParallelLongArray.WithBounds other, LongReducer combiner) { new WithBounds(this).replaceWithCombination(other, combiner); } /** * Returns the index of some element equal to given target, or -1 * if not present * @param target the element to search for * @return the index or -1 if not present */ public int indexOf(long target) { return new WithBounds(this).indexOf(target); } /** * Assuming this array is sorted, returns the index of an element * equal to given target, or -1 if not present. If the array * is not sorted, the results are undefined. * @param target the element to search for * @return the index or -1 if not present */ public int binarySearch(long target) { int lo = 0; int hi = limit - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; long m = array[mid]; if (target == m) return mid; else if (target < m) hi = mid - 1; else lo = mid + 1; } return -1; } /** * Assuming this array is sorted with respect to the given * comparator, returns the index of an element equal to given * target, or -1 if not present. If the array is not sorted, the * results are undefined. * @param target the element to search for * @param comparator the comparator * @return the index or -1 if not present */ public int binarySearch(long target, LongComparator comparator) { int lo = 0; int hi = limit - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; int c = comparator.compare(target, array[mid]); if (c == 0) return mid; else if (c < 0) hi = mid - 1; else lo = mid + 1; } return -1; } /** * Returns summary statistics, using the given comparator * to locate minimum and maximum elements. * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelLongArray.SummaryStatistics summary (LongComparator comparator) { return new WithBounds(this).summary(comparator); } /** * Returns summary statistics, using natural comparator * @return the summary. */ public ParallelLongArray.SummaryStatistics summary() { return new WithBounds(this).summary(); } /** * Returns the minimum element, or Long.MAX_VALUE if empty * @param comparator the comparator * @return minimum element, or Long.MAX_VALUE if empty */ public long min(LongComparator comparator) { return new WithBounds(this).min(comparator); } /** * Returns the minimum element, or Long.MAX_VALUE if empty, * @return minimum element, or Long.MAX_VALUE if empty */ public long min() { return new WithBounds(this).min(); } /** * Returns the maximum element, or Long.MIN_VALUE if empty * @param comparator the comparator * @return maximum element, or Long.MIN_VALUE if empty */ public long max(LongComparator comparator) { return new WithBounds(this).max(comparator); } /** * Returns the maximum element, or Long.MIN_VALUE if empty * @return maximum element, or Long.MIN_VALUE if empty */ public long max() { return new WithBounds(this).max(); } /** * Replaces each element with the running cumulation of applying * the given reducer. For example, if the contents are the numbers * 1, 2, 3, and the reducer operation adds numbers, then * after invocation of this method, the contents would be 1, * 3, 6 (that is, 1, 1+2, 1+2+3); * @param reducer the reducer * @param base the result for an empty array */ public void cumulate(LongReducer reducer, long base) { new WithBounds(this).cumulate(reducer, base); } /** * Replaces each element with the cumulation of applying the given * reducer to all previous values, and returns the total * reduction. For example, if the contents are the numbers 1, * 2, 3, and the reducer operation adds numbers, then after * invocation of this method, the contents would be 0, 1, * 3 (that is, 0, 0+1, 0+1+2, and the return value * would be 6 (that is, 1+2+3); * @param reducer the reducer * @param base the result for an empty array * @return the total reduction */ public long precumulate(LongReducer reducer, long base) { return new WithBounds(this).precumulate(reducer, base); } /** * Sorts the array. Unlike Arrays.sort, this sort does * not guarantee that elements with equal keys maintain their * relative position in the array. * @param comparator the comparator to use */ public void sort(LongComparator comparator) { new WithBounds(this).sort(comparator); } /** * Sorts the array, assuming all elements are Comparable. Unlike * Arrays.sort, this sort does not guarantee that elements * with equal keys maintain their relative position in the array. * @throws ClassCastException if any element is not Comparable. */ public void sort() { new WithBounds(this).sort(); } /** * Removes consecutive elements that are equal, * shifting others leftward, and possibly decreasing size. This * method may be used after sorting to ensure that this * ParallelLongArray contains a set of unique elements. */ public void removeConsecutiveDuplicates() { new WithBounds(this).removeConsecutiveDuplicates(); } /** * Returns a new ParallelLongArray containing only the unique * elements of this array (that is, without any duplicates). * @return the new ParallelLongArray */ public ParallelLongArray allUniqueElements() { return new WithBounds(this).allUniqueElements(); } /** * Returns the sum of elements * @return the sum of elements */ public long sum() { return new WithBounds(this).sum(); } /** * Replaces each element with the running sum */ public void cumulateSum() { new WithBounds(this).cumulateSum(); } /** * Replaces each element with its prefix sum * @return the total sum */ public long precumulateSum() { return new WithBounds(this).precumulateSum(); } /** * Returns an operation prefix that causes a method to * operate only on the elements of the array between * firstIndex (inclusive) and upperBound (exclusive). * @param firstIndex the lower bound (inclusive) * @param upperBound the upper bound (exclusive) * @return operation prefix */ public WithBounds withBounds(int firstIndex, int upperBound) { if (firstIndex > upperBound) throw new IllegalArgumentException ("firstIndex(" + firstIndex + ") > upperBound(" + upperBound+")"); if (firstIndex < 0) throw new ArrayIndexOutOfBoundsException(firstIndex); if (upperBound > this.limit) throw new ArrayIndexOutOfBoundsException(upperBound); return new WithBounds(this, firstIndex, upperBound); } /** * Returns an operation prefix that causes a method to operate * only on the elements of the array for which the given selector * returns true * @param selector the selector * @return operation prefix */ public WithFilter withFilter(LongPredicate selector) { return new WithBoundedFilter(this, 0, limit, selector); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithMapping withMapping(MapperFromLong mapper) { return new WithBoundedMapping(this, 0, limit, mapper); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithLongMapping withMapping(LongMapper mapper) { return new WithBoundedLongMapping(this, 0, limit, mapper); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithDoubleMapping withMapping(MapperFromLongToDouble mapper) { return new WithBoundedDoubleMapping(this, 0, limit, mapper); } /** * A modifier for parallel array operations to apply to mappings * of elements, not to the elements themselves */ public static abstract class WithMapping extends PAS.LPrefix { final MapperFromLong mapper; WithMapping(ParallelLongArray pa, int firstIndex, int upperBound, MapperFromLong mapper) { super(pa, firstIndex, upperBound); this.mapper = mapper; } /** * Applies the given procedure to mapped elements * @param procedure the procedure */ public void apply(Procedure procedure) { ex.invoke(new PAS.FJRApply (this, firstIndex, upperBound, null, procedure)); } /** * Returns reduction of mapped elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public U reduce(Reducer reducer, U base) { PAS.FJRReduce f = new PAS.FJRReduce (this, firstIndex, upperBound, null, reducer, base); ex.invoke(f); return (U)(f.result); } /** * Returns the index of some element matching bound and filter * constraints, or -1 if none. * @return index of matching element, or -1 if none. */ public abstract int anyIndex(); /** * Returns mapping of some element matching bound and filter * constraints, or null if none. * @return mapping of matching element, or null if none. */ public abstract U any(); /** * Returns the minimum mapped element, or null if empty * @param comparator the comparator * @return minimum mapped element, or null if empty */ public U min(Comparator comparator) { return reduce(Ops.minReducer(comparator), null); } /** * Returns the minimum mapped element, or null if empty, * assuming that all elements are Comparables * @return minimum mapped element, or null if empty * @throws ClassCastException if any element is not Comparable. */ public U min() { return reduce((Reducer)(Ops.castedMinReducer()), null); } /** * Returns the maximum mapped element, or null if empty * @param comparator the comparator * @return maximum mapped element, or null if empty */ public U max(Comparator comparator) { return reduce(Ops.maxReducer(comparator), null); } /** * Returns the maximum mapped element, or null if empty * assuming that all elements are Comparables * @return maximum mapped element, or null if empty * @throws ClassCastException if any element is not Comparable. */ public U max() { return reduce((Reducer)(Ops.castedMaxReducer()), null); } /** * Returns summary statistics, using the given comparator * to locate minimum and maximum elements. * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelArray.SummaryStatistics summary (Comparator comparator) { PAS.FJRStats f = new PAS.FJRStats (this, firstIndex, upperBound, null, comparator); ex.invoke(f); return (ParallelArray.SummaryStatistics)f; } /** * Returns summary statistics, assuming that all elements are * Comparables * @return the summary. */ public ParallelArray.SummaryStatistics summary() { PAS.FJRStats f = new PAS.FJRStats (this, firstIndex, upperBound, null, (Comparator)(Ops.castedComparator())); ex.invoke(f); return (ParallelArray.SummaryStatistics)f; } /** * Returns a new ParallelArray holding mapped elements * @return a new ParallelArray holding mapped elements */ public abstract ParallelArray all(); /** * Returns a new ParallelArray with the given element type holding * all elements * @param elementType the type of the elements * @return a new ParallelArray holding all elements */ public abstract ParallelArray all(Class elementType); /** * Return the number of elements selected using bound or * filter restrictions. Note that this method must evaluate * all selectors to return its result. * @return the number of elements */ public abstract int size(); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper * applied to current mapper's results * @param mapper the mapper * @return operation prefix */ public abstract WithMapping withMapping (Mapper mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper * applied to current mapper's results * @param mapper the mapper * @return operation prefix */ public abstract WithLongMapping withMapping (MapperToLong mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper * applied to current mapper's results * @param mapper the mapper * @return operation prefix */ public abstract WithDoubleMapping withMapping (MapperToDouble mapper); final void leafTransfer(int lo, int hi, Object[] dest, int offset) { final long[] array = pa.array; final MapperFromLong mpr = mapper; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, Object[] dest, int offset) { final long[] array = pa.array; final MapperFromLong mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = mpr.map(array[indices[i]]); } } static final class WithBoundedMapping extends WithMapping { WithBoundedMapping(ParallelLongArray pa, int firstIndex, int upperBound, MapperFromLong mapper) { super(pa, firstIndex, upperBound, mapper); } public ParallelArray all() { int n = upperBound - firstIndex; U[] dest = (U[])new Object[n]; PAS.FJRMap f = new PAS.FJRMap (this, firstIndex, upperBound, null, dest, firstIndex); ex.invoke(f); return new ParallelArray(ex, dest); } public ParallelArray all(Class elementType) { int n = upperBound - firstIndex; U[] dest = (U[])Array.newInstance(elementType, n); PAS.FJRMap f = new PAS.FJRMap (this, firstIndex, upperBound, null, dest, firstIndex); ex.invoke(f); return new ParallelArray(ex, dest); } public int size() { return upperBound - firstIndex; } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } public U any() { final MapperFromLong mpr = mapper; final long[] array = pa.array; return (firstIndex < upperBound)? (U)(mpr.map(array[firstIndex])) : null; } public WithMapping withMapping (Mapper mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping (MapperToLong mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithDoubleMapping withMapping (MapperToDouble mapper) { return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, Procedure procedure) { final long[] array = pa.array; final MapperFromLong mpr = mapper; for (int i = lo; i < hi; ++i) procedure.apply(mpr.map(array[i])); } Object leafReduce(int lo, int hi, Reducer reducer, Object base) { if (lo >= hi) return base; final long[] array = pa.array; final MapperFromLong mpr = mapper; Object r = mpr.map(array[lo]); for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, mpr.map(array[i])); return r; } void leafStats(int lo, int hi, PAS.FJRStats task) { final long[] array = pa.array; final MapperFromLong mpr = mapper; task.size = hi - lo; for (int i = lo; i < hi; ++i) { Object x = mpr.map(array[i]); task.updateMin(i, x); task.updateMax(i, x); } } } static final class WithBoundedFilteredMapping extends WithMapping { final LongPredicate selector; WithBoundedFilteredMapping(ParallelLongArray pa, int firstIndex, int upperBound, LongPredicate selector, MapperFromLong mapper) { super(pa, firstIndex, upperBound, mapper); this.selector = selector; } public ParallelArray all() { PAS.FJRSelectAllDriver r = new PAS.FJRSelectAllDriver (this, Object.class); ex.invoke(r); return new ParallelArray(ex, (U[])(r.results)); } public ParallelArray all(Class elementType) { PAS.FJRSelectAllDriver r = new PAS.FJRSelectAllDriver (this, elementType); ex.invoke(r); return new ParallelArray(ex, (U[])(r.results)); } public int size() { PAS.FJLCountSelected f = new PAS.FJLCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJLSelectAny f = new PAS.FJLSelectAny (this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public U any() { int idx = anyIndex(); final long[] array = pa.array; final MapperFromLong mpr = mapper; return (idx < 0)? null : (U)(mpr.map(array[idx])); } public WithMapping withMapping (Mapper mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping (MapperToLong mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithDoubleMapping withMapping (MapperToDouble mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, Procedure procedure) { final LongPredicate sel = selector; final MapperFromLong mpr = mapper; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) procedure.apply(mpr.map(x)); } } Object leafReduce(int lo, int hi, Reducer reducer, Object base) { final LongPredicate sel = selector; final MapperFromLong mpr = mapper; boolean gotFirst = false; Object r = base; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) { Object y = mpr.map(x); if (!gotFirst) { gotFirst = true; r = y; } else r = reducer.combine(r, y); } } return r; } void leafStats(int lo, int hi, PAS.FJRStats task) { final LongPredicate sel = selector; final MapperFromLong mpr = mapper; final long[] array = pa.array; int count = 0; for (int i = lo; i < hi; ++i) { long t = array[i]; if (sel.evaluate(t)) { Object x = mpr.map(t); ++count; task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final LongPredicate sel = selector; final long[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final LongPredicate sel = selector; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } /** * A modifier for parallel array operations to apply to mappings * of elements to longs, not to the elements themselves */ public static abstract class WithLongMapping extends PAS.LPrefix { WithLongMapping(ParallelLongArray pa, int firstIndex, int upperBound) { super(pa, firstIndex, upperBound); } /** * Applies the given procedure to elements * @param procedure the procedure */ public void apply(LongProcedure procedure) { ex.invoke(new PAS.FJLApply (this, firstIndex, upperBound, null, procedure)); } /** * Returns reduction of elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public long reduce(LongReducer reducer, long base) { PAS.FJLReduce f = new PAS.FJLReduce (this, firstIndex, upperBound, null, reducer, base); ex.invoke(f); return f.result; } /** * Returns the minimum element, or Long.MAX_VALUE if empty * @return minimum element, or Long.MAX_VALUE if empty */ public long min() { return reduce(naturalLongMinReducer(), Long.MAX_VALUE); } /** * Returns the minimum element, or Long.MAX_VALUE if empty * @param comparator the comparator * @return minimum element, or Long.MAX_VALUE if empty */ public long min(LongComparator comparator) { return reduce(longMinReducer(comparator), Long.MAX_VALUE); } /** * Returns the maximum element, or Long.MIN_VALUE if empty * @return maximum element, or Long.MIN_VALUE if empty */ public long max() { return reduce(naturalLongMaxReducer(), Long.MIN_VALUE); } /** * Returns the maximum element, or Long.MIN_VALUE if empty * @param comparator the comparator * @return maximum element, or Long.MIN_VALUE if empty */ public long max(LongComparator comparator) { return reduce(longMaxReducer(comparator), Long.MIN_VALUE); } /** * Returns the sum of elements * @return the sum of elements */ public long sum() { return reduce(Ops.longAdder(), 0L); } /** * Returns summary statistics * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelLongArray.SummaryStatistics summary (LongComparator comparator) { PAS.FJLStats f = new PAS.FJLStats (this, firstIndex, upperBound, null, comparator); ex.invoke(f); return f; } /** * Returns summary statistics, using natural comparator * @return the summary. */ public ParallelLongArray.SummaryStatistics summary() { PAS.FJLStats f = new PAS.FJLStats (this, firstIndex, upperBound, null, naturalLongComparator()); ex.invoke(f); return f; } /** * Returns a new ParallelLongArray holding elements * @return a new ParallelLongArray holding elements */ public abstract ParallelLongArray all(); /** * Return the number of elements selected using bound or * filter restrictions. Note that this method must evaluate * all selectors to return its result. * @return the number of elements */ public abstract int size(); /** * Returns the index of some element matching bound and filter * constraints, or -1 if none. * @return index of matching element, or -1 if none. */ public abstract int anyIndex(); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithLongMapping withMapping(LongMapper mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithDoubleMapping withMapping (MapperFromLongToDouble mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithMapping withMapping (MapperFromLong mapper); } /** * A restriction of parallel array operations to apply only to * elements for which a selector returns true */ public static abstract class WithFilter extends WithLongMapping { WithFilter(ParallelLongArray pa, int firstIndex, int upperBound) { super(pa, firstIndex, upperBound); } /** * Replaces elements with the results of applying the given * mapper to their current values. * @param mapper the mapper */ public void replaceWithTransform(LongMapper mapper) { ex.invoke(new PAS.FJLTransform (this, firstIndex, upperBound, null, mapper)); } /** * Replaces elements with the results of applying the given * mapper to their indices * @param mapper the mapper */ public void replaceWithMappedIndex(MapperFromIntToLong mapper) { ex.invoke(new PAS.FJLIndexMap (this, firstIndex, upperBound, null, mapper)); } /** * Replaces elements with results of applying the given * generator. * @param generator the generator */ public void replaceWithGeneratedValue(LongGenerator generator) { ex.invoke(new PAS.FJLGenerate (this, firstIndex, upperBound, null, generator)); } /** * Replaces elements with the given value. * @param value the value */ public void replaceWithValue(long value) { ex.invoke(new PAS.FJLFill (this, firstIndex, upperBound, null, value)); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer than upperBound elements. */ public void replaceWithCombination(ParallelLongArray other, LongReducer combiner) { if (other.size() < size()) throw new ArrayIndexOutOfBoundsException(); ex.invoke(new PAS.FJLCombineInPlace (this, firstIndex, upperBound, null, other.array, 0, combiner)); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array segment * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer than upperBound elements. */ public void replaceWithCombination (ParallelLongArray.WithBounds other, LongReducer combiner) { if (other.size() < size()) throw new ArrayIndexOutOfBoundsException(); ex.invoke(new PAS.FJLCombineInPlace (this, firstIndex, upperBound, null, other.pa.array, other.firstIndex-firstIndex, combiner)); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer than upperBound elements. */ public void replaceWithCombination(long[] other, LongReducer combiner) { if (other.length < size()) throw new ArrayIndexOutOfBoundsException(); ex.invoke(new PAS.FJLCombineInPlace (this, firstIndex, upperBound, null, other, -firstIndex, combiner)); } /** * Removes from the array all elements matching bound and/or * filter constraints. */ public abstract void removeAll(); /** * Returns a new ParallelLongArray containing only unique * elements (that is, without any duplicates). * @return the new ParallelLongArray */ public abstract ParallelLongArray allUniqueElements(); /** * Returns an operation prefix that causes a method to operate * only on elements for which the current selector (if * present) and the given selector returns true * @param selector the selector * @return operation prefix */ public abstract WithFilter withFilter(LongPredicate selector); /** * Returns an operation prefix that causes a method to operate * only on elements for which the current selector (if * present) or the given selector returns true * @param selector the selector * @return operation prefix */ public abstract WithFilter orFilter(LongPredicate selector); final void leafTransfer(int lo, int hi, long[] dest, int offset) { final long[] array = pa.array; for (int i = lo; i < hi; ++i) dest[offset++] = (array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, long[] dest, int offset) { final long[] array = pa.array; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = (array[indices[i]]); } } /** * A restriction of parallel array operations to apply only within * a given range of indices. */ public static final class WithBounds extends WithFilter { WithBounds(ParallelLongArray pa, int firstIndex, int upperBound) { super(pa, firstIndex, upperBound); } WithBounds(ParallelLongArray pa) { super(pa, 0, pa.limit); } /** * Returns an operation prefix that causes a method to operate * only on the elements of the array between firstIndex * (inclusive) and upperBound (exclusive). The bound * arguments are relative to the current bounds. For example * pa.withBounds(2, 8).withBounds(3, 5) indexes the * 5th (= 2+3) and 6th elements of pa. However, indices * returned by methods such as indexOf are * with respect to the underlying ParallelLongArray. * @param firstIndex the lower bound (inclusive) * @param upperBound the upper bound (exclusive) * @return operation prefix */ public WithBounds withBounds(int firstIndex, int upperBound) { if (firstIndex > upperBound) throw new IllegalArgumentException ("firstIndex(" + firstIndex + ") > upperBound(" + upperBound+")"); if (firstIndex < 0) throw new ArrayIndexOutOfBoundsException(firstIndex); if (upperBound - firstIndex > this.upperBound - this.firstIndex) throw new ArrayIndexOutOfBoundsException(upperBound); return new WithBounds(pa, this.firstIndex + firstIndex, this.firstIndex + upperBound); } public WithFilter withFilter(LongPredicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, selector); } public WithMapping withMapping (MapperFromLong mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, mapper); } public WithLongMapping withMapping(LongMapper mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, mapper); } public WithDoubleMapping withMapping(MapperFromLongToDouble mapper) { return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, mapper); } public WithFilter orFilter(LongPredicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, selector); } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } /** * Returns a ParallelLongArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelLongArray combine(long[] other, LongReducer combiner) { int size = upperBound - firstIndex; if (other.length < size) throw new ArrayIndexOutOfBoundsException(); long[] dest = new long[size]; ex.invoke(new PAS.FJLCombine (this, firstIndex, upperBound, null, other, -firstIndex, dest, combiner)); return new ParallelLongArray(ex, dest); } /** * Returns a ParallelLongArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelLongArray combine(ParallelLongArray other, LongReducer combiner) { int size = upperBound - firstIndex; if (other.size() < size) throw new ArrayIndexOutOfBoundsException(); long[] dest = new long[size]; ex.invoke(new PAS.FJLCombine (this, firstIndex, upperBound, null, other.array, -firstIndex, dest, combiner)); return new ParallelLongArray(ex, dest); } /** * Returns a ParallelLongArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array segment * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other segment is * shorter than this array. */ public ParallelLongArray combine (ParallelLongArray.WithBounds other, LongReducer combiner) { int size = upperBound - firstIndex; if (other.size() < size) throw new ArrayIndexOutOfBoundsException(); long[] dest = new long[size]; ex.invoke(new PAS.FJLCombine (this, firstIndex, upperBound, null, other.pa.array, other.firstIndex - firstIndex, dest, combiner)); return new ParallelLongArray(ex, dest); } public ParallelLongArray all() { final long[] array = pa.array; // For now, avoid copyOf so people can compile with Java5 int size = upperBound - firstIndex; long[] dest = new long[size]; System.arraycopy(array, firstIndex, dest, 0, size); return new ParallelLongArray(ex, dest); } public ParallelLongArray allUniqueElements() { PAS.LUniquifierTable tab = new PAS.LUniquifierTable (upperBound - firstIndex, pa.array, null); PAS.FJUniquifier f = new PAS.FJUniquifier (this, firstIndex, upperBound, null, tab); ex.invoke(f); long[] res = tab.uniqueElements(f.count); return new ParallelLongArray(ex, res); } /** * Returns the index of some element equal to given target, or * -1 if not present * @param target the element to search for * @return the index or -1 if not present */ public int indexOf(long target) { AtomicInteger result = new AtomicInteger(-1); PAS.FJLIndexOf f = new PAS.FJLIndexOf (this, firstIndex, upperBound, null, result, target); ex.invoke(f); return result.get(); } /** * Assuming this array is sorted, returns the index of an * element equal to given target, or -1 if not present. If the * array is not sorted, the results are undefined. * @param target the element to search for * @return the index or -1 if not present */ public int binarySearch(long target) { final long[] array = pa.array; int lo = firstIndex; int hi = upperBound - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; long m = array[mid]; if (target == m) return mid; else if (target < m) hi = mid - 1; else lo = mid + 1; } return -1; } /** * Assuming this array is sorted with respect to the given * comparator, returns the index of an element equal to given * target, or -1 if not present. If the array is not sorted, * the results are undefined. * @param target the element to search for * @param comparator the comparator * @return the index or -1 if not present */ public int binarySearch(long target, LongComparator comparator) { final long[] array = pa.array; int lo = firstIndex; int hi = upperBound - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; int c = comparator.compare(target, array[mid]); if (c == 0) return mid; else if (c < 0) hi = mid - 1; else lo = mid + 1; } return -1; } public int size() { return upperBound - firstIndex; } /** * Replaces each element with the running cumulation of applying * the given reducer. * @param reducer the reducer * @param base the result for an empty array */ public void cumulate(LongReducer reducer, long base) { PAS.FJLCumulateOp op = new PAS.FJLCumulateOp(this, reducer, base); PAS.FJLScan r = new PAS.FJLScan(null, op, firstIndex, upperBound); ex.invoke(r); } /** * Replaces each element with the running sum */ public void cumulateSum() { PAS.FJLCumulatePlusOp op = new PAS.FJLCumulatePlusOp(this); PAS.FJLScan r = new PAS.FJLScan(null, op, firstIndex, upperBound); ex.invoke(r); } /** * Replaces each element with the cumulation of applying the given * reducer to all previous values, and returns the total * reduction. * @param reducer the reducer * @param base the result for an empty array * @return the total reduction */ public long precumulate(LongReducer reducer, long base) { PAS.FJLPrecumulateOp op = new PAS.FJLPrecumulateOp (this, reducer, base); PAS.FJLScan r = new PAS.FJLScan(null, op, firstIndex, upperBound); ex.invoke(r); return r.out; } /** * Replaces each element with its prefix sum * @return the total sum */ public long precumulateSum() { PAS.FJLPrecumulatePlusOp op = new PAS.FJLPrecumulatePlusOp(this); PAS.FJLScan r = new PAS.FJLScan(null, op, firstIndex, upperBound); ex.invoke(r); return r.out; } /** * Sorts the elements. * Unlike Arrays.sort, this sort does * not guarantee that elements with equal keys maintain their * relative position in the array. * @param cmp the comparator to use */ public void sort(LongComparator cmp) { ex.invoke(new PAS.FJLSorter (cmp, pa.array, new long[upperBound], firstIndex, upperBound - firstIndex, threshold)); } /** * Sorts the elements, assuming all elements are * Comparable. Unlike Arrays.sort, this sort does not * guarantee that elements with equal keys maintain their relative * position in the array. * @throws ClassCastException if any element is not Comparable. */ public void sort() { ex.invoke(new PAS.FJLCSorter (pa.array, new long[upperBound], firstIndex, upperBound - firstIndex, threshold)); } public void removeAll() { pa.removeSlotsAt(firstIndex, upperBound); } /** * Removes consecutive elements that are equal (or null), * shifting others leftward, and possibly decreasing size. This * method may be used after sorting to ensure that this * ParallelLongArray contains a set of unique elements. */ public void removeConsecutiveDuplicates() { // Sequential implementation for now int k = firstIndex; int n = upperBound; if (k < n) { long[] arr = pa.array; long last = arr[k++]; for (int i = k; i < n; ++i) { long x = arr[i]; if (last != x) arr[k++] = last = x; } pa.removeSlotsAt(k, n); } } void leafApply(int lo, int hi, LongProcedure procedure) { final long[] array = pa.array; for (int i = lo; i < hi; ++i) procedure.apply(array[i]); } long leafReduce(int lo, int hi, LongReducer reducer, long base) { if (lo >= hi) return base; final long[] array = pa.array; long r = array[lo]; for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, array[i]); return r; } void leafStats(int lo, int hi, PAS.FJLStats task) { final long[] array = pa.array; task.size = hi - lo; for (int i = lo; i < hi; ++i) { long x = array[i]; task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } void leafTransform(int lo, int hi, LongMapper mapper) { final long[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = mapper.map(array[i]); } void leafIndexMap(int lo, int hi, MapperFromIntToLong mapper) { final long[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = mapper.map(i); } void leafGenerate(int lo, int hi, LongGenerator generator) { final long[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = generator.generate(); } void leafFillValue(int lo, int hi, long value) { final long[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = value; } void leafCombineInPlace(int lo, int hi, long[] other, int otherOffset, LongReducer combiner) { final long[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = combiner.combine(array[i], other[i+otherOffset]); } void leafCombine(int lo, int hi, long[] other, int otherOffset, long[] dest, LongReducer combiner) { final long[] array = pa.array; int k = lo - firstIndex; for (int i = lo; i < hi; ++i) { dest[k] = combiner.combine(array[i], other[i + otherOffset]); ++k; } } } static final class WithBoundedFilter extends WithFilter { final LongPredicate selector; WithBoundedFilter(ParallelLongArray pa, int firstIndex, int upperBound, LongPredicate selector) { super(pa, firstIndex, upperBound); this.selector = selector; } public WithFilter withFilter(LongPredicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, Ops.andPredicate(this.selector, selector)); } public WithFilter orFilter(LongPredicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, Ops.orPredicate(this.selector, selector)); } public WithMapping withMapping (MapperFromLong mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, mapper); } public WithLongMapping withMapping (LongMapper mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, mapper); } public WithDoubleMapping withMapping (MapperFromLongToDouble mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, mapper); } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJLSelectAny f = new PAS.FJLSelectAny (this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public ParallelLongArray all() { PAS.FJLSelectAllDriver r = new PAS.FJLSelectAllDriver(this); ex.invoke(r); return new ParallelLongArray(ex, r.results); } public int size() { PAS.FJLCountSelected f = new PAS.FJLCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public ParallelLongArray allUniqueElements() { PAS.LUniquifierTable tab = new PAS.LUniquifierTable (upperBound - firstIndex, pa.array, selector); PAS.FJUniquifier f = new PAS.FJUniquifier (this, firstIndex, upperBound, null, tab); ex.invoke(f); long[] res = tab.uniqueElements(f.count); return new ParallelLongArray(ex, res); } public void removeAll() { PAS.FJRemoveAllDriver f = new PAS.FJRemoveAllDriver (this, firstIndex, upperBound); ex.invoke(f); pa.removeSlotsAt(f.offset, upperBound); } void leafApply(int lo, int hi, LongProcedure procedure) { final LongPredicate sel = selector; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) procedure.apply(x); } } long leafReduce(int lo, int hi, LongReducer reducer, long base) { final LongPredicate sel = selector; boolean gotFirst = false; long r = base; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) { if (!gotFirst) { gotFirst = true; r = x; } else r = reducer.combine(r, x); } } return r; } void leafStats(int lo, int hi, PAS.FJLStats task) { final LongPredicate sel = selector; final long[] array = pa.array; int count = 0; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) { ++count; task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } void leafTransform(int lo, int hi, LongMapper mapper) { final LongPredicate sel = selector; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) array[i] = mapper.map(x); } } void leafIndexMap(int lo, int hi, MapperFromIntToLong mapper) { final LongPredicate sel = selector; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) array[i] = mapper.map(i); } } void leafGenerate(int lo, int hi, LongGenerator generator) { final LongPredicate sel = selector; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) array[i] = generator.generate(); } } void leafFillValue(int lo, int hi, long value) { final LongPredicate sel = selector; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) array[i] = value; } } void leafCombineInPlace(int lo, int hi, long[] other, int otherOffset, LongReducer combiner) { final LongPredicate sel = selector; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) array[i] = combiner.combine(x, other[i+otherOffset]); } } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final LongPredicate sel = selector; final long[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final LongPredicate sel = selector; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } static final class WithBoundedLongMapping extends WithLongMapping { final LongMapper mapper; WithBoundedLongMapping(ParallelLongArray pa, int firstIndex, int upperBound, LongMapper mapper) { super(pa, firstIndex, upperBound); this.mapper = mapper; } public ParallelLongArray all() { long[] dest = new long[upperBound - firstIndex]; PAS.FJLMap f = new PAS.FJLMap (this, firstIndex, upperBound, null, dest, firstIndex); ex.invoke(f); return new ParallelLongArray(ex, dest); } public int size() { return upperBound - firstIndex; } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } public WithLongMapping withMapping(LongMapper mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithDoubleMapping withMapping(MapperFromLongToDouble mapper) { return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromLong mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, LongProcedure procedure) { final LongMapper mpr = mapper; final long[] array = pa.array; for (int i = lo; i < hi; ++i) procedure.apply(mpr.map(array[i])); } long leafReduce(int lo, int hi, LongReducer reducer, long base) { if (lo >= hi) return base; final long[] array = pa.array; final LongMapper mpr = mapper; long r = mpr.map(array[lo]); for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, mpr.map(array[i])); return r; } void leafStats(int lo, int hi, PAS.FJLStats task) { task.size = hi - lo; final long[] array = pa.array; final LongMapper mpr = mapper; for (int i = lo; i < hi; ++i) { long x = mpr.map(array[i]); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } final void leafTransfer(int lo, int hi, long[] dest, int offset) { final long[] array = pa.array; final LongMapper mpr = mapper; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, long[] dest, int offset) { final long[] array = pa.array; final LongMapper mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = mpr.map(array[indices[i]]); } } static final class WithBoundedFilteredLongMapping extends WithLongMapping { final LongPredicate selector; final LongMapper mapper; WithBoundedFilteredLongMapping (ParallelLongArray pa, int firstIndex, int upperBound, LongPredicate selector, LongMapper mapper) { super(pa, firstIndex, upperBound); this.selector = selector; this.mapper = mapper; } public ParallelLongArray all() { PAS.FJLSelectAllDriver r = new PAS.FJLSelectAllDriver(this); ex.invoke(r); return new ParallelLongArray(ex, r.results); } public int size() { PAS.FJLCountSelected f = new PAS.FJLCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJLSelectAny f = new PAS.FJLSelectAny (this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public WithLongMapping withMapping(LongMapper mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithDoubleMapping withMapping(MapperFromLongToDouble mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromLong mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, LongProcedure procedure) { final LongPredicate sel = selector; final LongMapper mpr = mapper; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) procedure.apply(mpr.map(x)); } } long leafReduce(int lo, int hi, LongReducer reducer, long base) { final LongPredicate sel = selector; final LongMapper mpr = mapper; boolean gotFirst = false; long r = base; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long t = array[i]; if (sel.evaluate(t)) { long y = mpr.map(t); if (!gotFirst) { gotFirst = true; r = y; } else r = reducer.combine(r, y); } } return r; } void leafStats(int lo, int hi, PAS.FJLStats task) { final LongPredicate sel = selector; final long[] array = pa.array; final LongMapper mpr = mapper; int count = 0; for (int i = lo; i < hi; ++i) { long t = array[i]; if (sel.evaluate(t)) { ++count; long x = mpr.map(t); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } final void leafTransfer(int lo, int hi, long[] dest, int offset) { final long[] array = pa.array; final LongMapper mpr = mapper; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, long[] dest, int offset) { final long[] array = pa.array; final LongMapper mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = mpr.map(array[indices[i]]); } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final LongPredicate sel = selector; final long[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final LongPredicate sel = selector; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } /** * A modifier for parallel array operations to apply to mappings * of elements to doubles, not to the elements themselves */ public static abstract class WithDoubleMapping extends PAS.LPrefix { final MapperFromLongToDouble mapper; WithDoubleMapping(ParallelLongArray pa, int firstIndex, int upperBound, MapperFromLongToDouble mapper) { super(pa, firstIndex, upperBound); this.mapper = mapper; } /** * Applies the given procedure * @param procedure the procedure */ public void apply(DoubleProcedure procedure) { ex.invoke(new PAS.FJDApply (this, firstIndex, upperBound, null, procedure)); } /** * Returns reduction of mapped elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public double reduce(DoubleReducer reducer, double base) { PAS.FJDReduce f = new PAS.FJDReduce (this, firstIndex, upperBound, null, reducer, base); ex.invoke(f); return f.result; } /** * Returns the minimum element, or Double.MAX_VALUE if empty * @return minimum element, or Double.MAX_VALUE if empty */ public double min() { return reduce(naturalDoubleMinReducer(), Double.MAX_VALUE); } /** * Returns the minimum element, or Double.MAX_VALUE if empty * @param comparator the comparator * @return minimum element, or Double.MAX_VALUE if empty */ public double min(DoubleComparator comparator) { return reduce(doubleMinReducer(comparator), Double.MAX_VALUE); } /** * Returns the maximum element, or -Double.MAX_VALUE if empty * @return maximum element, or -Double.MAX_VALUE if empty */ public double max() { return reduce(naturalDoubleMaxReducer(), -Double.MAX_VALUE); } /** * Returns the maximum element, or -Double.MAX_VALUE if empty * @param comparator the comparator * @return maximum element, or -Double.MAX_VALUE if empty */ public double max(DoubleComparator comparator) { return reduce(doubleMaxReducer(comparator), -Double.MAX_VALUE); } /** * Returns the sum of elements * @return the sum of elements */ public double sum() { return reduce(Ops.doubleAdder(), 0); } /** * Returns summary statistics * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelDoubleArray.SummaryStatistics summary (DoubleComparator comparator) { PAS.FJDStats f = new PAS.FJDStats (this, firstIndex, upperBound, null, comparator); ex.invoke(f); return f; } /** * Returns summary statistics, using natural comparator * @return the summary. */ public ParallelDoubleArray.SummaryStatistics summary() { PAS.FJDStats f = new PAS.FJDStats (this, firstIndex, upperBound, null, naturalDoubleComparator()); ex.invoke(f); return f; } /** * Returns a new ParallelDoubleArray holding mappings * @return a new ParallelDoubleArray holding mappings */ public abstract ParallelDoubleArray all(); /** * Return the number of elements selected using bound or * filter restrictions. Note that this method must evaluate * all selectors to return its result. * @return the number of elements */ public abstract int size(); /** * Returns the index of some element matching bound and filter * constraints, or -1 if none. * @return index of matching element, or -1 if none. */ public abstract int anyIndex(); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithLongMapping withMapping (MapperFromDoubleToLong mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithDoubleMapping withMapping(DoubleMapper mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithMapping withMapping (MapperFromDouble mapper); final void leafTransfer(int lo, int hi, double[] dest, int offset) { final long[] array = pa.array; final MapperFromLongToDouble mpr = mapper; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, double[] dest, int offset) { final long[] array = pa.array; final MapperFromLongToDouble mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = mpr.map(array[indices[i]]); } } static final class WithBoundedDoubleMapping extends WithDoubleMapping { WithBoundedDoubleMapping(ParallelLongArray pa, int firstIndex, int upperBound, MapperFromLongToDouble mapper) { super(pa, firstIndex, upperBound, mapper); } public ParallelDoubleArray all() { double[] dest = new double[upperBound - firstIndex]; PAS.FJDMap f = new PAS.FJDMap (this, firstIndex, upperBound, null, dest, firstIndex); ex.invoke(f); return new ParallelDoubleArray(ex, dest); } public int size() { return upperBound - firstIndex; } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } public WithLongMapping withMapping(MapperFromDoubleToLong mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithDoubleMapping withMapping(DoubleMapper mapper) { return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromDouble mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, DoubleProcedure procedure) { final MapperFromLongToDouble mpr = mapper; final long[] array = pa.array; for (int i = lo; i < hi; ++i) procedure.apply(mpr.map(array[i])); } double leafReduce(int lo, int hi, DoubleReducer reducer, double base) { if (lo >= hi) return base; final long[] array = pa.array; final MapperFromLongToDouble mpr = mapper; double r = mpr.map(array[lo]); for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, mpr.map(array[i])); return r; } void leafStats(int lo, int hi, PAS.FJDStats task) { final long[] array = pa.array; final MapperFromLongToDouble mpr = mapper; task.size = hi - lo; for (int i = lo; i < hi; ++i) { double x = mpr.map(array[i]); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } } static final class WithBoundedFilteredDoubleMapping extends WithDoubleMapping { final LongPredicate selector; WithBoundedFilteredDoubleMapping (ParallelLongArray pa, int firstIndex, int upperBound, LongPredicate selector, MapperFromLongToDouble mapper) { super(pa, firstIndex, upperBound, mapper); this.selector = selector; } public ParallelDoubleArray all() { PAS.FJDSelectAllDriver r = new PAS.FJDSelectAllDriver(this); ex.invoke(r); return new ParallelDoubleArray(ex, r.results); } public int size() { PAS.FJLCountSelected f = new PAS.FJLCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJLSelectAny f = new PAS.FJLSelectAny (this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public WithLongMapping withMapping(MapperFromDoubleToLong mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithDoubleMapping withMapping(DoubleMapper mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromDouble mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, DoubleProcedure procedure) { final LongPredicate sel = selector; final long[] array = pa.array; final MapperFromLongToDouble mpr = mapper; for (int i = lo; i < hi; ++i) { long x = array[i]; if (sel.evaluate(x)) procedure.apply(mpr.map(x)); } } double leafReduce(int lo, int hi, DoubleReducer reducer, double base) { final LongPredicate sel = selector; final MapperFromLongToDouble mpr = mapper; boolean gotFirst = false; double r = base; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long t = array[i]; if (sel.evaluate(t)) { double y = mpr.map(t); if (!gotFirst) { gotFirst = true; r = y; } else r = reducer.combine(r, y); } } return r; } void leafStats(int lo, int hi, PAS.FJDStats task) { final LongPredicate sel = selector; final MapperFromLongToDouble mpr = mapper; final long[] array = pa.array; int count = 0; for (int i = lo; i < hi; ++i) { long t = array[i]; if (sel.evaluate(t)) { ++count; double x = mpr.map(t); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final LongPredicate sel = selector; final long[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final LongPredicate sel = selector; final long[] array = pa.array; for (int i = lo; i < hi; ++i) { long t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } /** * Returns an iterator stepping through each element of the array * up to the current limit. This iterator does not * support the remove operation. However, a full * ListIterator supporting add, remove, and set * operations is available via {@link #asList}. * @return an iterator stepping through each element. */ public Iterator iterator() { return new ParallelLongArrayIterator(array, limit); } static final class ParallelLongArrayIterator implements Iterator { int cursor; final long[] arr; final int hi; ParallelLongArrayIterator(long[] a, int limit) { arr = a; hi = limit; } public boolean hasNext() { return cursor < hi; } public Long next() { if (cursor >= hi) throw new NoSuchElementException(); return Long.valueOf(arr[cursor++]); } public void remove() { throw new UnsupportedOperationException(); } } // List support /** * Returns a view of this ParallelLongArray as a List. This List has * the same structural and performance characteristics as {@link * ArrayList}, and may be used to modify, replace or extend the * bounds of the array underlying this ParallelLongArray. The methods * supported by this list view are not in general * implemented as parallel operations. This list is also not * itself thread-safe. In particular, performing list updates * while other parallel operations are in progress has undefined * (and surely undesired) effects. * @return a list view */ public List asList() { AsList lv = listView; if (lv == null) listView = lv = new AsList(); return lv; } /** * Returns the effective size of the underlying array. The * effective size is the current limit, if used (see {@link * #setLimit}), or the length of the array otherwise. * @return the effective size of array */ public int size() { return limit; } /** * Returns the underlying array used for computations * @return the array */ public long[] getArray() { return array; } /** * Returns the element of the array at the given index * @param i the index * @return the element of the array at the given index */ public long get(int i) { return array[i]; } /** * Sets the element of the array at the given index to the given value * @param i the index * @param x the value */ public void set(int i, long x) { array[i] = x; } /** * Equivalent to asList().toString() * @return a string representation */ public String toString() { return asList().toString(); } /** * Equivalent to AsList.addAll but specialized for array * arguments and likely to be more efficient. * @param other the elements to add */ public void addAll(long[] other) { int csize = other.length; int end = limit; insertSlotsAt(end, csize); System.arraycopy(other, 0, array, end, csize); } /** * Equivalent to AsList.addAll but specialized for * ParallelLongArray arguments and likely to be more efficient. * @param other the elements to add */ public void addAll(ParallelLongArray other) { int csize = other.size(); int end = limit; insertSlotsAt(end, csize); System.arraycopy(other.array, 0, array, end, csize); } /** * Equivalent to AsList.addAll but specialized for * ParallelLongArray arguments and likely to be more efficient. * @param other the elements to add */ public void addAll(ParallelLongArray.WithBounds other) { int csize = other.size(); int end = limit; insertSlotsAt(end, csize); System.arraycopy(other.pa.array, other.firstIndex, array, end, csize); } /** * Ensures that the underlying array can be accessed up to the * given upper bound, reallocating and copying the underlying * array to expand if necessary. Or, if the given limit is less * than the length of the underlying array, causes computations to * ignore elements past the given limit. * @param newLimit the new upper bound * @throws IllegalArgumentException if newLimit less than zero. */ public final void setLimit(int newLimit) { if (newLimit < 0) throw new IllegalArgumentException(); int cap = array.length; if (newLimit > cap) resizeArray(newLimit); limit = newLimit; } final void replaceElementsWith(long[] a) { System.arraycopy(a, 0, array, 0, a.length); limit = a.length; } final void resizeArray(int newCap) { int cap = array.length; if (newCap > cap) { long[] a = new long[newCap]; System.arraycopy(array, 0, a, 0, cap); array = a; } } final void insertElementAt(int index, long e) { int hi = limit++; if (hi >= array.length) resizeArray((hi * 3)/2 + 1); if (hi > index) System.arraycopy(array, index, array, index+1, hi - index); array[index] = e; } final void appendElement(long e) { int hi = limit++; if (hi >= array.length) resizeArray((hi * 3)/2 + 1); array[hi] = e; } /** * Make len slots available at index */ final void insertSlotsAt(int index, int len) { if (len <= 0) return; int cap = array.length; int newSize = limit + len; if (cap < newSize) { cap = (cap * 3)/2 + 1; if (cap < newSize) cap = newSize; resizeArray(cap); } if (index < limit) System.arraycopy(array, index, array, index + len, limit - index); limit = newSize; } final void removeSlotAt(int index) { System.arraycopy(array, index + 1, array, index, limit - index - 1); --limit; } final void removeSlotsAt(int fromIndex, int toIndex) { if (fromIndex < toIndex) { int size = limit; System.arraycopy(array, toIndex, array, fromIndex, size - toIndex); int newSize = size - (toIndex - fromIndex); limit = newSize; } } final int seqIndexOf(long target) { long[] arr = array; int fence = limit; for (int i = 0; i < fence; i++) if (target == arr[i]) return i; return -1; } final int seqLastIndexOf(long target) { long[] arr = array; for (int i = limit - 1; i >= 0; i--) if (target == arr[i]) return i; return -1; } final class ListIter implements ListIterator { int cursor; int lastRet; long[] arr; // cache array and bound int hi; ListIter(int lo) { this.cursor = lo; this.lastRet = -1; this.arr = ParallelLongArray.this.array; this.hi = ParallelLongArray.this.limit; } public boolean hasNext() { return cursor < hi; } public Long next() { int i = cursor; if (i < 0 || i >= hi) throw new NoSuchElementException(); long next = arr[i]; lastRet = i; cursor = i + 1; return Long.valueOf(next); } public void remove() { int k = lastRet; if (k < 0) throw new IllegalStateException(); ParallelLongArray.this.removeSlotAt(k); hi = ParallelLongArray.this.limit; if (lastRet < cursor) cursor--; lastRet = -1; } public boolean hasPrevious() { return cursor > 0; } public Long previous() { int i = cursor - 1; if (i < 0 || i >= hi) throw new NoSuchElementException(); long previous = arr[i]; lastRet = cursor = i; return Long.valueOf(previous); } public int nextIndex() { return cursor; } public int previousIndex() { return cursor - 1; } public void set(Long e) { int i = lastRet; if (i < 0 || i >= hi) throw new NoSuchElementException(); arr[i] = e.longValue(); } public void add(Long e) { int i = cursor; ParallelLongArray.this.insertElementAt(i, e.longValue()); arr = ParallelLongArray.this.array; hi = ParallelLongArray.this.limit; lastRet = -1; cursor = i + 1; } } final class AsList extends AbstractList implements RandomAccess { public Long get(int i) { if (i >= limit) throw new IndexOutOfBoundsException(); return Long.valueOf(array[i]); } public Long set(int i, Long x) { if (i >= limit) throw new IndexOutOfBoundsException(); long[] arr = array; Long t = Long.valueOf(arr[i]); arr[i] = x.longValue(); return t; } public boolean isEmpty() { return limit == 0; } public int size() { return limit; } public Iterator iterator() { return new ListIter(0); } public ListIterator listIterator() { return new ListIter(0); } public ListIterator listIterator(int index) { if (index < 0 || index > limit) throw new IndexOutOfBoundsException(); return new ListIter(index); } public boolean add(Long e) { appendElement(e.longValue()); return true; } public void add(int index, Long e) { if (index < 0 || index > limit) throw new IndexOutOfBoundsException(); insertElementAt(index, e.longValue()); } public boolean addAll(Collection c) { int csize = c.size(); if (csize == 0) return false; int hi = limit; setLimit(hi + csize); long[] arr = array; for (Long e : c) arr[hi++] = e.longValue(); return true; } public boolean addAll(int index, Collection c) { if (index < 0 || index > limit) throw new IndexOutOfBoundsException(); int csize = c.size(); if (csize == 0) return false; insertSlotsAt(index, csize); long[] arr = array; for (Long e : c) arr[index++] = e.longValue(); return true; } public void clear() { limit = 0; } public boolean remove(Object o) { if (!(o instanceof Long)) return false; int idx = seqIndexOf(((Long)o).longValue()); if (idx < 0) return false; removeSlotAt(idx); return true; } public Long remove(int index) { Long oldValue = get(index); removeSlotAt(index); return oldValue; } protected void removeRange(int fromIndex, int toIndex) { removeSlotsAt(fromIndex, toIndex); } public boolean contains(Object o) { if (!(o instanceof Long)) return false; return seqIndexOf(((Long)o).longValue()) >= 0; } public int indexOf(Object o) { if (!(o instanceof Long)) return -1; return seqIndexOf(((Long)o).longValue()); } public int lastIndexOf(Object o) { if (!(o instanceof Long)) return -1; return seqLastIndexOf(((Long)o).longValue()); } } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/PoolBarrier.java0000644000000000000000000001176010735315511023523 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.*; import java.util.concurrent.atomic.*; /** * A variant of a cyclic barrier that is advanced upon explicit * signals representing event occurrences. */ final class PoolBarrier { /** * Wait nodes for Treiber stack representing wait queue. */ static final class EQNode { EQNode next; volatile ForkJoinWorkerThread thread; // nulled to cancel wait final long count; EQNode(ForkJoinWorkerThread t, long c) { thread = t; count = c; } } /** * Head of Treiber stack. Even though this variable is very * busy, it is not usually heavily contended because of * signal/wait/release policies. */ final AtomicReference head = new AtomicReference(); /** * The event count */ final AtomicLong counter = new AtomicLong(); /** * Returns the current event count */ long getCount() { return counter.get(); } /** * Waits until event count advances from count, or some * other thread arrives or is already waiting with a different * count. * @param count previous value returned by sync (or 0) * @return current event count */ long sync(ForkJoinWorkerThread thread, long count) { long current = counter.get(); if (current == count) enqAndWait(thread, count); if (head.get() != null) releaseAll(); return current; } /** * Ensures that event count on exit is greater than event * count on entry, and that at least one thread waiting for * count to change is signalled, (It will then in turn * propagate other wakeups.) This lessens stalls by signallers * when they want to be doing something more productive. * However, on contention to release, wakes up all threads to * help forestall further contention. Note that the counter * is not necessarily incremented by caller. If attempted CAS * fails, then some other thread already advanced from * incoming value; */ void signal() { final AtomicLong counter = this.counter; long c = counter.get(); counter.compareAndSet(c, c+1); final AtomicReference head = this.head; EQNode h = head.get(); if (h != null) { ForkJoinWorkerThread t; if (head.compareAndSet(h, h.next) && (t = h.thread) != null) { h.thread = null; LockSupport.unpark(t); } else if (head.get() != null) releaseAll(); } } /** * Version of signal called from pool. Forces increment and * releases all. It is OK if this is called by worker threads, * but it is heavier than necessary for them. */ void poolSignal() { counter.incrementAndGet(); releaseAll(); } /** * Enqueues node and waits unless aborted or signalled. */ private void enqAndWait(ForkJoinWorkerThread thread, long count) { EQNode node = new EQNode(thread, count); final AtomicReference head = this.head; final AtomicLong counter = this.counter; for (;;) { EQNode h = head.get(); node.next = h; if ((h != null && h.count != count) || counter.get() != count) break; if (head.compareAndSet(h, node)) { while (!thread.isInterrupted() && node.thread != null && counter.get() == count) LockSupport.park(); node.thread = null; break; } } } /** * Release all waiting threads. Called on exit from sync, as * well as on contention in signal. Regardless of why sync'ing * threads exit, other waiting threads must also recheck for * tasks or completions before resync. Release by chopping off * entire list, and then signalling. This both lessens * contention and avoids unbounded enq/deq races. */ private void releaseAll() { final AtomicReference head = this.head; EQNode p; while ( (p = head.get()) != null) { if (head.compareAndSet(p, null)) { do { ForkJoinWorkerThread t = p.thread; if (t != null) { p.thread = null; LockSupport.unpark(t); } } while ((p = p.next) != null); break; } } } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/Ops.java0000644000000000000000000012224010740452246022043 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import java.util.*; /** * Interfaces and utilities describing per-element operations used * within parallel methods on aggregates. This class provides type * names for common operation signatures accepting zero, one or two * arguments, and returning zero or one results, for parameterized * types, as well as specializations to long, and * double. (Other scalar types like short are * absent.) * *

In addition to stated signatures, implementations of these * interfaces must work safely in parallel. In general, this means * methods should operate only on their arguments, and should not rely * on ThreadLocals, unsafely published globals, or other unsafe * constructions. Additionally, they should not block waiting for * synchronization. * *

This class also provides methods returning some commonly used * implementations of some of these interfaces * *

This class is normally best used via import static. */ public class Ops { private Ops() {} // disable construction /** * A generator (builder) of objects of type T that takes no * arguments. */ public static interface Generator { public T generate(); } /** * An object with a method of one argument that does not return a * result. */ public static interface Procedure { public void apply(T t); } /** * An object with a function accepting objects of type T and * returning those of type U */ public static interface Mapper { public U map(T t); } /** * An object with a function accepting pairs of objects, one of * type T and one of type U, returning those of type V */ public static interface Combiner { public V combine(T t, U u); } /** * A specialized combiner that is associative and accepts pairs of * objects of the same type and returning one of the same * type. Like for example, an addition operation, a Reducer must * be associative: combine(a, combine(b, c)) should have * the same result as combine(combine(a, b), c). */ public static interface Reducer extends Combiner { public T combine(T t, T v); } /** * An object with boolean method of one argument */ public static interface Predicate { public boolean evaluate(T t); } /** * An object with boolean method of two arguments */ public static interface RelationalPredicate { public boolean evaluate(T t, U u); } /** * A mapper returning an int */ public static interface MapperToInt { public int map(T t); } /** * A mapper returning a double */ public static interface MapperToDouble { public double map(T t); } /** * A mapper returning a long */ public static interface MapperToLong { public long map(T t); } /** * A mapper accepting an int */ public static interface MapperFromInt { public T map(int t); } /** * A mapper accepting a double */ public static interface MapperFromDouble { public T map(double t); } /** * A mapper accepting a long argument */ public static interface MapperFromLong { public T map(long t); } /** A generator of doubles */ public static interface DoubleGenerator { public double generate(); } /** A procedure accepting a double */ public static interface DoubleProcedure { public void apply(double t); } /** * A mapper accepting a double argument and returning an int */ public static interface MapperFromDoubleToInt { public int map(double t); } /** * A mapper accepting a double argument and returning a long */ public static interface MapperFromDoubleToLong { public long map(double t); } /** * A mapper accepting a double argument and returning a double */ public static interface DoubleMapper { public double map(double t); } /** A reducer accepting and returning doubles */ public static interface DoubleReducer { public double combine(double u, double v); } /** A predicate accepting a double argument */ public static interface DoublePredicate { public boolean evaluate(double t); } /** A relationalPredicate accepting double arguments */ public static interface DoubleRelationalPredicate { public boolean evaluate(double t, double u); } /** A generator of longs */ public static interface LongGenerator { public long generate(); } /** A procedure accepting a long */ public static interface LongProcedure { public void apply(long t); } /** * A mapper accepting a long argument and returning an int */ public static interface MapperFromLongToInt { public int map(long t); } /** * A mapper accepting a long argument and returning a double */ public static interface MapperFromLongToDouble { public double map(long t); } /** * A mapper accepting a long argument and returning a long */ public static interface LongMapper { public long map(long t); } /** A reducer accepting and returning longs */ public static interface LongReducer { public long combine(long u, long v); } /** A predicate accepting a long argument */ public static interface LongPredicate { public boolean evaluate(long t); } /** A relationalPredicate accepting long arguments */ public static interface LongRelationalPredicate { public boolean evaluate(long t, long u); } /** A generator of ints */ public static interface IntGenerator { public int generate(); } /** A procedure accepting an int */ public static interface IntProcedure { public void apply(int t); } /** A map accepting an int and returning an int */ public static interface IntMapper { public int map(int u); } /** * A mapper accepting an int argument and returning a long */ public static interface MapperFromIntToLong { public long map(int t); } /** * A mapper accepting an int argument and returning a double */ public static interface MapperFromIntToDouble { public double map(int t); } /** A reducer accepting and returning ints */ public static interface IntReducer { public int combine(int u, int v); } /** A predicate accepting an int */ public static interface IntPredicate { public boolean evaluate(int t); } /** A relationalPredicate accepting int arguments */ public static interface IntRelationalPredicate { public boolean evaluate(int t, int u); } // comparators /** * A Comparator for doubles */ public static interface DoubleComparator { public int compare(double x, double y); } /** * A Comparator for longs */ public static interface LongComparator { public int compare(long x, long y); } /** * A Comparator for ints */ public static interface IntComparator { public int compare(int x, int y); } /** * Returns a Comparator for Comparable objects */ public static > Comparator naturalComparator(Class type) { return new Comparator() { public int compare(T a, T b) { return a.compareTo(b); } }; } /** * Returns a reducer returning the maximum of two Comparable * elements, treating null as less than any non-null element. */ public static > Reducer naturalMaxReducer(Class type) { return new Reducer() { public T combine(T a, T b) { return (a != null && (b == null || a.compareTo(b) >= 0))? a : b; } }; } /** * Returns a reducer returning the minimum of two Comparable * elements, treating null as greater than any non-null element. */ public static > Reducer naturalMinReducer(Class type) { return new Reducer() { public T combine(T a, T b) { return (a != null && (b == null || a.compareTo(b) <= 0))? a : b; } }; } /** * Returns a reducer returning the maximum of two elements, using * the given comparator, and treating null as less than any * non-null element. */ public static Reducer maxReducer (final Comparator comparator) { return new Reducer() { public T combine(T a, T b) { return (a != null && (b == null || comparator.compare(a, b) >= 0))? a : b; } }; } /** * Returns a reducer returning the minimum of two elements, using * the given comparator, and treating null as greater than any * non-null element. */ public static Reducer minReducer (final Comparator comparator) { return new Reducer() { public T combine(T a, T b) { return (a != null && (b == null || comparator.compare(a, b) <= 0))? a : b; } }; } /** * Returns a Comparator that casts its arguments as Comparable on * each comparison, throwing ClassCastException on failure. */ public static Comparator castedComparator() { return (Comparator)(RawComparator.cmp); } static final class RawComparator implements Comparator { static final RawComparator cmp = new RawComparator(); public int compare(Object a, Object b) { return ((Comparable)a).compareTo((Comparable)b); } } /** * Returns a reducer returning maximum of two values, or * null if both arguments are null, and that casts * its arguments as Comparable on each comparison, throwing * ClassCastException on failure. */ public static Reducer castedMaxReducer() { return (Reducer)RawMaxReducer.max; } static final class RawMaxReducer implements Reducer { static final RawMaxReducer max = new RawMaxReducer(); public Object combine(Object a, Object b) { return (a != null && (b == null || ((Comparable)a).compareTo((Comparable)b) >= 0))? a : b; } } /** * Returns a reducer returning minimum of two values, or * null if both arguments are null, and that casts * its arguments as Comparable on each comparison, throwing * ClassCastException on failure. */ public static Reducer castedMinReducer() { return (Reducer)RawMinReducer.min; } static final class RawMinReducer implements Reducer { static final RawMinReducer min = new RawMinReducer(); public Object combine(Object a, Object b) { return (a != null && (b == null || ((Comparable)a).compareTo((Comparable)b) <= 0))? a : b; } } /** * Returns a comparator for doubles relying on natural ordering */ public static DoubleComparator naturalDoubleComparator() { return NaturalDoubleComparator.comparator; } static final class NaturalDoubleComparator implements DoubleComparator { static final NaturalDoubleComparator comparator = new NaturalDoubleComparator(); public int compare(double a, double b) { return Double.compare(a, b); } } /** * Returns a reducer returning the maximum of two double elements, * using natural comparator */ public static DoubleReducer naturalDoubleMaxReducer() { return NaturalDoubleMaxReducer.max; } static final class NaturalDoubleMaxReducer implements DoubleReducer { public static final NaturalDoubleMaxReducer max = new NaturalDoubleMaxReducer(); public double combine(double a, double b) { return Math.max(a, b); } } /** * Returns a reducer returning the minimum of two double elements, * using natural comparator */ public static DoubleReducer naturalDoubleMinReducer() { return NaturalDoubleMinReducer.min; } static final class NaturalDoubleMinReducer implements DoubleReducer { public static final NaturalDoubleMinReducer min = new NaturalDoubleMinReducer(); public double combine(double a, double b) { return Math.min(a, b); } } /** * Returns a reducer returning the maximum of two double elements, * using the given comparator */ public static DoubleReducer doubleMaxReducer (final DoubleComparator comparator) { return new DoubleReducer() { public double combine(double a, double b) { return (comparator.compare(a, b) >= 0)? a : b; } }; } /** * Returns a reducer returning the minimum of two double elements, * using the given comparator */ public static DoubleReducer doubleMinReducer (final DoubleComparator comparator) { return new DoubleReducer() { public double combine(double a, double b) { return (comparator.compare(a, b) <= 0)? a : b; } }; } /** * Returns a comparator for longs relying on natural ordering */ public static LongComparator naturalLongComparator() { return NaturalLongComparator.comparator; } static final class NaturalLongComparator implements LongComparator { static final NaturalLongComparator comparator = new NaturalLongComparator(); public int compare(long a, long b) { return a < b? -1 : ((a > b)? 1 : 0); } } /** * Returns a reducer returning the maximum of two long elements, * using natural comparator */ public static LongReducer naturalLongMaxReducer() { return NaturalLongMaxReducer.max; } static final class NaturalLongMaxReducer implements LongReducer { public static final NaturalLongMaxReducer max = new NaturalLongMaxReducer(); public long combine(long a, long b) { return a >= b? a : b; } } /** * A reducer returning the minimum of two long elements, * using natural comparator */ public static LongReducer naturalLongMinReducer() { return NaturalLongMinReducer.min; } static final class NaturalLongMinReducer implements LongReducer { public static final NaturalLongMinReducer min = new NaturalLongMinReducer(); public long combine(long a, long b) { return a <= b? a : b; } } /** * Returns a reducer returning the maximum of two long elements, * using the given comparator */ public static LongReducer longMaxReducer (final LongComparator comparator) { return new LongReducer() { public long combine(long a, long b) { return (comparator.compare(a, b) >= 0)? a : b; } }; } /** * Returns a reducer returning the minimum of two long elements, * using the given comparator */ public static LongReducer longMinReducer (final LongComparator comparator) { return new LongReducer() { public long combine(long a, long b) { return (comparator.compare(a, b) <= 0)? a : b; } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static Mapper compoundMapper (final Mapper first, final Mapper second) { return new Mapper() { public final V map(T t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static Mapper compoundMapper (final MapperToDouble first, final MapperFromDouble second) { return new Mapper() { public final V map(T t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static Mapper compoundMapper (final MapperToLong first, final MapperFromLong second) { return new Mapper() { public final V map(T t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromDouble compoundMapper (final MapperFromDouble first, final Mapper second) { return new MapperFromDouble() { public final V map(double t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromLong compoundMapper (final MapperFromLong first, final Mapper second) { return new MapperFromLong() { public final V map(long t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperToDouble compoundMapper (final Mapper first, final MapperToDouble second) { return new MapperToDouble() { public final double map(T t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperToLong compoundMapper (final Mapper first, final MapperToLong second) { return new MapperToLong() { public final long map(T t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperToDouble compoundMapper (final MapperToDouble first, final DoubleMapper second) { return new MapperToDouble() { public final double map(T t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperToLong compoundMapper (final MapperToDouble first, final MapperFromDoubleToLong second) { return new MapperToLong() { public final long map(T t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperToLong compoundMapper (final MapperToLong first, final LongMapper second) { return new MapperToLong() { public final long map(T t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperToDouble compoundMapper (final MapperToLong first, final MapperFromLongToDouble second) { return new MapperToDouble() { public final double map(T t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static DoubleMapper compoundMapper (final DoubleMapper first, final DoubleMapper second) { return new DoubleMapper() { public final double map(double t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromDoubleToLong compoundMapper (final DoubleMapper first, final MapperFromDoubleToLong second) { return new MapperFromDoubleToLong() { public final long map(double t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromDoubleToLong compoundMapper (final MapperFromDoubleToLong first, final LongMapper second) { return new MapperFromDoubleToLong() { public final long map(double t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromDouble compoundMapper (final MapperFromDoubleToLong first, final MapperFromLong second) { return new MapperFromDouble() { public final T map(double t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromLong compoundMapper (final MapperFromLongToDouble first, final MapperFromDouble second) { return new MapperFromLong() { public final T map(long t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromLongToDouble compoundMapper (final LongMapper first, final MapperFromLongToDouble second) { return new MapperFromLongToDouble() { public final double map(long t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromLongToDouble compoundMapper (final MapperFromLongToDouble first, final DoubleMapper second) { return new MapperFromLongToDouble() { public final double map(long t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromDouble compoundMapper (final DoubleMapper first, final MapperFromDouble second) { return new MapperFromDouble() { public final T map(double t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromLong compoundMapper (final LongMapper first, final MapperFromLong second) { return new MapperFromLong() { public final T map(long t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static DoubleMapper compoundMapper (final MapperFromDouble first, final MapperToDouble second) { return new DoubleMapper() { public final double map(double t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromLongToDouble compoundMapper (final MapperFromLong first, final MapperToDouble second) { return new MapperFromLongToDouble() { public final double map(long t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static MapperFromDoubleToLong compoundMapper (final MapperFromDouble first, final MapperToLong second) { return new MapperFromDoubleToLong() { public final long map(double t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static LongMapper compoundMapper (final MapperFromLong first, final MapperToLong second) { return new LongMapper() { public final long map(long t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static LongMapper compoundMapper (final LongMapper first, final LongMapper second) { return new LongMapper() { public final long map(long t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static DoubleMapper compoundMapper (final MapperFromDoubleToLong first, final MapperFromLongToDouble second) { return new DoubleMapper() { public final double map(double t) { return second.map(first.map(t)); } }; } /** * Returns a composite mapper that applies a second mapper to the results * of applying the first one */ public static LongMapper compoundMapper (final MapperFromLongToDouble first, final MapperFromDoubleToLong second) { return new LongMapper() { public final long map(long t) { return second.map(first.map(t)); } }; } /** * Returns a predicate evaluating to the negation of its contained predicate */ public static Predicate notPredicate (final Predicate pred) { return new Predicate() { public final boolean evaluate(T x) { return !pred.evaluate(x); } }; } /** * Returns a predicate evaluating to the negation of its contained predicate */ public static DoublePredicate notPredicate (final DoublePredicate pred) { return new DoublePredicate() { public final boolean evaluate(double x) { return !pred.evaluate(x); } }; } /** * Returns a predicate evaluating to the negation of its contained predicate */ public static LongPredicate notPredicate (final LongPredicate pred) { return new LongPredicate() { public final boolean evaluate(long x) { return !pred.evaluate(x); } }; } /** * Returns a predicate evaluating to the conjunction of its contained predicates */ public static Predicate andPredicate (final Predicate first, final Predicate second) { return new Predicate() { public final boolean evaluate(T x) { return first.evaluate(x) && second.evaluate(x); } }; } /** * Returns a predicate evaluating to the disjuntion of its contained predicates */ public static Predicate orPredicate (final Predicate first, final Predicate second) { return new Predicate() { public final boolean evaluate(T x) { return first.evaluate(x) || second.evaluate(x); } }; } /** * Returns a predicate evaluating to the conjunction of its contained predicates */ public static DoublePredicate andPredicate (final DoublePredicate first, final DoublePredicate second) { return new DoublePredicate() { public final boolean evaluate(double x) { return first.evaluate(x) && second.evaluate(x); } }; } /** * Returns a predicate evaluating to the disjuntion of its contained predicates */ public static DoublePredicate orPredicate (final DoublePredicate first, final DoublePredicate second) { return new DoublePredicate() { public final boolean evaluate(double x) { return first.evaluate(x) || second.evaluate(x); } }; } /** * Returns a predicate evaluating to the conjunction of its contained predicates */ public static LongPredicate andPredicate (final LongPredicate first, final LongPredicate second) { return new LongPredicate() { public final boolean evaluate(long x) { return first.evaluate(x) && second.evaluate(x); } }; } /** * Returns a predicate evaluating to the disjuntion of its contained predicates */ public static LongPredicate orPredicate (final LongPredicate first, final LongPredicate second) { return new LongPredicate() { public final boolean evaluate(long x) { return first.evaluate(x) || second.evaluate(x); } }; } /** * Returns a predicate evaluating to true if its argument is non-null */ public static Predicate isNonNullPredicate() { return IsNonNullPredicate.predicate; } static final class IsNonNullPredicate implements Predicate { static final IsNonNullPredicate predicate = new IsNonNullPredicate(); public final boolean evaluate(Object x) { return x != null; } } /** * Returns a predicate evaluating to true if its argument is null */ public static Predicate isNullPredicate() { return IsNullPredicate.predicate; } static final class IsNullPredicate implements Predicate { static final IsNullPredicate predicate = new IsNullPredicate(); public final boolean evaluate(Object x) { return x != null; } } /** * Returns a predicate evaluating to true if its argument is an instance * of (see {@link Class#isInstance} the given type (class). */ public static Predicate instanceofPredicate(final Class type) { return new Predicate() { public final boolean evaluate(Object x) { return type.isInstance(x); } }; } /** * Returns a predicate evaluating to true if its argument is assignable * from (see {@link Class#isAssignableFrom} the given type (class). */ public static Predicate isAssignablePredicate(final Class type) { return new Predicate() { public final boolean evaluate(Object x) { return type.isAssignableFrom(x.getClass()); } }; } /** * Returns a reducer that adds two double elements */ public static DoubleReducer doubleAdder() { return DoubleAdder.adder; } static final class DoubleAdder implements DoubleReducer { static final DoubleAdder adder = new DoubleAdder(); public double combine(double a, double b) { return a + b; } } /** * Returns a reducer that adds two long elements */ public static LongReducer longAdder() { return LongAdder.adder; } static final class LongAdder implements LongReducer { static final LongAdder adder = new LongAdder(); public long combine(long a, long b) { return a + b; } } /** * Returns a reducer that adds two int elements */ public static IntReducer intAdder() { return IntAdder.adder; } static final class IntAdder implements IntReducer { static final IntAdder adder = new IntAdder(); public int combine(int a, int b) { return a + b; } } /** * Returns a generator producing uniform random values between * zero and one, with the same properties as {@link * java.util.Random#nextDouble} but operating independently across * ForkJoinWorkerThreads and usable only within forkjoin * computations. */ public static DoubleGenerator doubleRandom() { return DoubleRandomGenerator.generator; } static final class DoubleRandomGenerator implements DoubleGenerator { static final DoubleRandomGenerator generator = new DoubleRandomGenerator(); public double generate() { return ForkJoinWorkerThread.nextRandomDouble(); } } /** * Returns a generator producing uniform random values between * zero and the given bound, with the same properties as {@link * java.util.Random#nextDouble} but operating independently across * ForkJoinWorkerThreads and usable only within forkjoin * computations. * @param bound the upper bound (exclusive) of generated values */ public static DoubleGenerator doubleRandom(double bound) { return new DoubleBoundedRandomGenerator(bound); } static final class DoubleBoundedRandomGenerator implements DoubleGenerator { final double bound; DoubleBoundedRandomGenerator(double bound) { this.bound = bound; } public double generate() { return ForkJoinWorkerThread.nextRandomDouble() * bound; } } /** * Returns a generator producing uniform random values between the * given least value (inclusive) and bound (exclusive), operating * independently across ForkJoinWorkerThreads and usable only * within forkjoin computations. * @param least the least value returned * @param bound the upper bound (exclusive) of generated values */ public static DoubleGenerator doubleRandom(double least, double bound) { return new DoubleIntervalRandomGenerator(least, bound); } static final class DoubleIntervalRandomGenerator implements DoubleGenerator { final double least; final double range; DoubleIntervalRandomGenerator(double least, double bound) { this.least = least; this.range = bound - least; } public double generate() { return ForkJoinWorkerThread.nextRandomDouble() * range + least; } } /** * Returns a generator producing uniform random values with the * same properties as {@link java.util.Random#nextLong} but * operating independently across ForkJoinWorkerThreads and usable * only within forkjoin computations. */ public static LongGenerator longRandom() { return LongRandomGenerator.generator; } static final class LongRandomGenerator implements LongGenerator { static final LongRandomGenerator generator = new LongRandomGenerator(); public long generate() { return ForkJoinWorkerThread.nextRandomLong(); } } /** * Returns a generator producing uniform random values with the * same properties as {@link java.util.Random#nextInt(int)} but * operating independently across ForkJoinWorkerThreads and usable * only within forkjoin computations. * @param bound the upper bound (exclusive) of generated values */ public static LongGenerator longRandom(long bound) { if (bound <= 0) throw new IllegalArgumentException(); return new LongBoundedRandomGenerator(bound); } static final class LongBoundedRandomGenerator implements LongGenerator { final long bound; LongBoundedRandomGenerator(long bound) { this.bound = bound; } public long generate() { return ForkJoinWorkerThread.nextRandomLong(bound); } } /** * Returns a generator producing uniform random values between the * given least value (inclusive) and bound (exclusive), operating * independently across ForkJoinWorkerThreads and usable only * within forkjoin computations. * @param least the least value returned * @param bound the upper bound (exclusive) of generated values */ public static LongGenerator longRandom(long least, long bound) { if (least >= bound) throw new IllegalArgumentException(); return new LongIntervalRandomGenerator(least, bound); } static final class LongIntervalRandomGenerator implements LongGenerator { final long least; final long range; LongIntervalRandomGenerator(long least, long bound) { this.least = least; this.range = bound - least; } public long generate() { return ForkJoinWorkerThread.nextRandomLong(range) + least; } } /** * Returns a generator producing uniform random values with the * same properties as {@link java.util.Random#nextInt} but * operating independently across ForkJoinWorkerThreads and usable * only within forkjoin computations. */ public static IntGenerator intRandom() { return IntRandomGenerator.generator; } static final class IntRandomGenerator implements IntGenerator { static final IntRandomGenerator generator = new IntRandomGenerator(); public int generate() { return ForkJoinWorkerThread.nextRandomInt(); } } /** * Returns a generator producing uniform random values with the * same properties as {@link java.util.Random#nextInt(int)} but * operating independently across ForkJoinWorkerThreads and usable * only within forkjoin computations. * @param bound the upper bound (exclusive) of generated values */ public static IntGenerator intRandom(int bound) { if (bound <= 0) throw new IllegalArgumentException(); return new IntBoundedRandomGenerator(bound); } static final class IntBoundedRandomGenerator implements IntGenerator { final int bound; IntBoundedRandomGenerator(int bound) { this.bound = bound; } public int generate() { return ForkJoinWorkerThread.nextRandomInt(bound); } } /** * Returns a generator producing uniform random values between the * given least value (inclusive) and bound (exclusive), operating * independently across ForkJoinWorkerThreads and usable only * within forkjoin computations. * @param least the least value returned * @param bound the upper bound (exclusive) of generated values */ public static IntGenerator intRandom(int least, int bound) { if (least >= bound) throw new IllegalArgumentException(); return new IntIntervalRandomGenerator(least, bound); } static final class IntIntervalRandomGenerator implements IntGenerator { final int least; final int range; IntIntervalRandomGenerator(int least, int bound) { this.least = least; this.range = bound - least; } public int generate() { return ForkJoinWorkerThread.nextRandomInt(range) + least; } } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/RecursiveTask.java0000644000000000000000000000557410735315511024103 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; /** * Recursive result-bearing ForkJoinTasks. *

For a classic example, here is a task computing Fibonacci numbers: * *

 * class Fibonacci extends RecursiveTask<Integer> {
 *   final int n;
 *   Fibonnaci(int n) { this.n = n; }
 *   Integer compute() {
 *     if (n <= 1)
 *        return n;
 *     Fibonacci f1 = new Fibonacci(n - 1);
 *     f1.fork();
 *     Fibonacci f2 = new Fibonacci(n - 2);
 *     return f2.forkJoin() + f1.join();
 *   }
 * }
 * 
* * However, besides being a dumb way to compute Fibonacci functions * (there is a simple fast linear algorithm that you'd use in * practice), this is likely to perform poorly because the smallest * subtasks are too small to be worthwhile splitting up. Instead, as * is the case for nearly all fork/join applications, you'd pick some * minimum granularity size (for example 10 here) for which you always * sequentially solve rather than subdividing. Note also the use of * f2.forkJoin() instead of f2.fork(); f2.join(), * which is both more convenient and more efficient. * */ public abstract class RecursiveTask extends ForkJoinTask { /** * The result returned by compute method. */ V result; /** * The main computation performed by this task. While you must * define this method, you should not in general call it directly. * To immediately perform the computation, use forkJoin. * @return result of the computation */ protected abstract V compute(); public final V rawResult() { return result; } public final V forkJoin() { V v = null; if (exception == null) { try { result = v = compute(); } catch(Throwable rex) { setDoneExceptionally(rex); } } Throwable ex = setDone(); if (ex != null) rethrowException(ex); return v; } public final Throwable exec() { if (exception == null) { try { result = compute(); } catch(Throwable rex) { return setDoneExceptionally(rex); } } return setDone(); } public final void finish(V result) { this.result = result; setDone(); } public final void finishExceptionally(Throwable ex) { setDoneExceptionally(ex); } public final void reinitialize() { result = null; super.reinitialize(); } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/ForkJoinPool.java0000644000000000000000000011101110735315511023644 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.*; import java.util.concurrent.atomic.*; /** * Host for a group of ForkJoinWorkerThreads that perform * ForkJoinTasks. A ForkJoinPool also provides the entry point for * tasks submitted from non-ForkJoinTasks, as well as management and * monitoring operations. Normally a single ForkJoinPool is used for * a large number of submitted tasks. Otherwise, use would not always * outweigh the construction overhead of creating a large set of * threads and the associated startup bookkeeping. * *

Class ForkJoinPool does not implement the ExecutorService * interface because it only executes ForkJoinTasks, not arbitrary * Runnables. However, for the sake of uniformity, it supports * analogous lifecycle control methods such as shutdown. * *

A ForkJoinPool may be constructed with any number of worker * threads, and worker threads may be added and removed dynamically. * However, as a general rule, using a pool size of the number of * processors on a given system (as arranged by the default * constructor) will result in the best performance. Resizing may be * expensive and may cause transient imbalances and slowdowns. * *

In addition to execution and lifecycle control methods, this * class provides status check methods (for example * getStealCount) that are intended to aid in developing, * tuning, and monitoring fork/join applications. */ public class ForkJoinPool implements ForkJoinExecutor { /* * This is an overhauled version of the framework described in "A * Java Fork/Join Framework" by Doug Lea, in, Proceedings, ACM * JavaGrande Conference, June 2000 * (http://gee.cs.oswego.edu/dl/papers/fj.pdf). It retains most of * the basic structure, but includes a number of algorithmic * improvements, along with integration with other * java.util.concurrent components. */ /** * Factory for creating new ForkJoinWorkerThreads. A * ForkJoinWorkerThreadFactory must be defined and used for * ForkJoinWorkerThread subclasses that extend base functionality * or initialize threads with different contexts. */ public static interface ForkJoinWorkerThreadFactory { /** * Returns a new worker thread operating in the given pool. * * @param pool the pool this thread works in * @throws NullPointerException if pool is null; */ public ForkJoinWorkerThread newThread(ForkJoinPool pool); } /** * The default ForkJoinWorkerThreadFactory, used unless overridden * in ForkJoinPool constructors. */ public static class DefaultForkJoinWorkerThreadFactory implements ForkJoinWorkerThreadFactory { public ForkJoinWorkerThread newThread(ForkJoinPool pool) { return new ForkJoinWorkerThread(pool); } } private static final DefaultForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory = new DefaultForkJoinWorkerThreadFactory(); /** * Permission required for callers of methods that may start or * kill threads. */ private static final RuntimePermission modifyThreadPermission = new RuntimePermission("modifyThread"); /** * If there is a security manager, makes sure caller has * permission to modify threads. */ private static void checkPermission() { SecurityManager security = System.getSecurityManager(); if (security != null) security.checkPermission(modifyThreadPermission); } /** * Generator for assigning sequence numbers as thread names. */ private static final AtomicInteger poolNumberGenerator = new AtomicInteger(); /** * Creation factory for worker threads. */ private final ForkJoinWorkerThreadFactory factory; /** * Array holding all worker threads in the pool. Acts similarly to * a CopyOnWriteArrayList -- updates are protected by workerLock. * But it additionally allows in-place nulling out or replacements * of slots upon termination. All uses of this array should first * assign as local, and must screen out nulls. */ private volatile ForkJoinWorkerThread[] workers; /** * Lock protecting access to workers. */ private final ReentrantLock workerLock; /** * Condition for awaitTermination. */ private final Condition termination; /** * The current targetted pool size. Updated only under worker lock * but volatile to allow concurrent reads. */ volatile int poolSize; /** * The number of workers that have started but not yet terminated * Accessed only under workerLock. */ private int runningWorkers; /** * Queue of external submissions. */ private final SubmissionQueue submissionQueue; /** * Lifecycle control. */ private final RunState runState; /** * Pool wide synchronization control. Workers are enabled to look * for work when the barrier's count is incremented. If they fail * to find some, they may wait for next count. Synchronization * events occur only in enough contexts to maintain overall * liveness: * * - Submission of a new task * - Termination of pool or worker * - A worker pushing a task on an empty per-worker queue * - A worker completing a stolen or cancelled task * * So, signals and waits occur relatively rarely during normal * processing, which minimizes contention on this global * synchronizer. Even so, the PoolBarrier is designed to minimize * blockages by threads that have better things to do. */ private final PoolBarrier poolBarrier; /** * The number of submissions that are running in pool. */ private final AtomicInteger runningSubmissions; /** * Number of workers that are (probably) executing tasks. * Atomically incremented when a worker gets a task to run, and * decremented when worker has no tasks and cannot find any. */ private final AtomicInteger activeWorkerCounter; /** * The uncaught exception handler used when any worker * abrupty terminates */ private Thread.UncaughtExceptionHandler ueh; /** * Pool number, just for assigning useful names to worker threads */ private final int poolNumber; /** * Create new worker using factory. * @param index the index to assign worker */ private ForkJoinWorkerThread createWorker(int index) { ForkJoinWorkerThread w = factory.newThread(this); w.setDaemon(true); w.setWorkerPoolIndex(index); w.setName("ForkJoinPool-" + poolNumber + "-worker-" + index); Thread.UncaughtExceptionHandler h = ueh; if (h != null) w.setUncaughtExceptionHandler(h); activeWorkerCounter.incrementAndGet(); // initially active state return w; } /** * Creates a ForkJoinPool with a pool size equal to the number of * processors available on the system and using the default * ForkJoinWorkerThreadFactory, * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link * java.lang.RuntimePermission}("modifyThread"), */ public ForkJoinPool() { this(Runtime.getRuntime().availableProcessors(), defaultForkJoinWorkerThreadFactory); } /** * Creates a ForkJoinPool with the indicated number of Worker * threads, and using the default ForkJoinWorkerThreadFactory, * @param poolSize the number of worker threads * @throws IllegalArgumentException if poolSize less than or * equal to zero * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link * java.lang.RuntimePermission}("modifyThread"), */ public ForkJoinPool(int poolSize) { this(poolSize, defaultForkJoinWorkerThreadFactory); } /** * Creates a ForkJoinPool with a pool size equal to the number of * processors available on the system and using the given * ForkJoinWorkerThreadFactory, * @param factory the factory for creating new threads * @throws NullPointerException if factory is null * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link * java.lang.RuntimePermission}("modifyThread"), */ public ForkJoinPool(ForkJoinWorkerThreadFactory factory) { this(Runtime.getRuntime().availableProcessors(), factory); } /** * Creates a ForkJoinPool with the indicated number of worker * threads and the given factory. * *

You can also add and remove threads while the pool is * running. But it is generally more efficient and leads to more * predictable performance to initialize the pool with a * sufficient number of threads to support the desired concurrency * level and leave this value fixed. * * @param poolSize the number of worker threads * @param factory the factory for creating new threads * @throws IllegalArgumentException if poolSize less than or * equal to zero * @throws NullPointerException if factory is null * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link * java.lang.RuntimePermission}("modifyThread"), */ public ForkJoinPool(int poolSize, ForkJoinWorkerThreadFactory factory) { checkPermission(); if (poolSize <= 0) throw new IllegalArgumentException(); if (factory == null) throw new NullPointerException(); this.poolSize = poolSize; this.factory = factory; this.poolNumber = poolNumberGenerator.incrementAndGet(); this.workers = new ForkJoinWorkerThread[poolSize]; this.poolBarrier = new PoolBarrier(); this.activeWorkerCounter = new AtomicInteger(); this.runningSubmissions = new AtomicInteger(); this.submissionQueue = new SubmissionQueue(); this.runState = new RunState(); this.workerLock = new ReentrantLock(); this.termination = workerLock.newCondition(); createAndStartWorkers(); } /** * Initial worker startup */ private void createAndStartWorkers() { final ReentrantLock lock = this.workerLock; lock.lock(); try { ForkJoinWorkerThread[] ws = workers; for (int i = 0; i < ws.length; ++i) ws[i] = createWorker(i); for (int i = 0; i < ws.length; ++i) { ws[i].start(); ++runningWorkers; } } finally { lock.unlock(); } } /** * Performs the given task; returning its result upon completion * @param task the task * @return the task's result * @throws NullPointerException if task is null * @throws RejectedExecutionException if pool is shut down */ public T invoke(ForkJoinTask task) { return doSubmit(task).awaitInvoke(); } /** * Arranges for (asynchronous) execution of the given task, * returning a Future that may be used to obtain results * upon completion. * @param task the task * @return a Future that can be used to get the task's results. * @throws NullPointerException if task is null * @throws RejectedExecutionException if pool is shut down */ public Future submit(ForkJoinTask task) { return doSubmit(task); } /** * Arranges for (asynchronous) execution of the given task. * @param task the task * @throws NullPointerException if task is null * @throws RejectedExecutionException if pool is shut down */ public void execute(ForkJoinTask task) { doSubmit(task); } /** * Common code for invoke and submit */ private Submission doSubmit(ForkJoinTask task) { if (task == null) throw new NullPointerException(); if (runState.isAtLeastShutdown()) throw new RejectedExecutionException(); Submission job = new Submission(task, this); submissionQueue.add(job); poolBarrier.poolSignal(); return job; } /** * Returns the targetted number of worker threads in this pool. * This value does not necessarily reflect transient changes as * threads are added, removed, or abruptly terminate. * * @return the number of worker threads in this pool */ public int getPoolSize() { return poolSize; } /** * Equivalent to {@link #getPoolSize}. * * @return the number of worker threads in this pool */ public int getParallelismLevel() { return poolSize; } /** * Returns the number of worker threads that have started but not * yet terminated. This result returned by this method may differ * from getPoolSize when threads are added, removed, or * abruptly terminate. * * @return the number of worker threads */ public int getRunningWorkerCount() { int r; final ReentrantLock lock = this.workerLock; lock.lock(); try { r = runningWorkers; } finally { lock.unlock(); } return r; } /** * Sets the handler for internal worker threads that terminate due * to unrecoverable errors encountered while executing tasks. * Unless set, the current default or ThreadGroup handler is used * as handler. * * @param h the new handler * @return the old handler, or null if none * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link * java.lang.RuntimePermission}("modifyThread"), */ public Thread.UncaughtExceptionHandler setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler h) { checkPermission(); Thread.UncaughtExceptionHandler old = null; final ReentrantLock lock = this.workerLock; lock.lock(); try { old = ueh; ueh = h; ForkJoinWorkerThread[] ws = workers; for (int i = 0; i < ws.length; ++i) { ForkJoinWorkerThread w = ws[i]; if (w != null) w.setUncaughtExceptionHandler(h); } } finally { lock.unlock(); } return old; } /** * Returns the handler for internal worker threads that terminate * due to unrecoverable errors encountered while executing tasks. * @return the handler, or null if none */ public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { Thread.UncaughtExceptionHandler h; final ReentrantLock lock = this.workerLock; lock.lock(); try { h = ueh; } finally { lock.unlock(); } return h; } /** * Update cached poolSize to all workers */ private void broadcastPoolSize() { int ps = poolSize; ForkJoinWorkerThread[] ws = workers; for (int i = 0; i < ws.length; ++i) { ForkJoinWorkerThread w = ws[i]; if (w != null) w.setPoolSize(ps); } } /** * Tries to adds the indicated number of new worker threads to the * pool. This method may be used to increase the amount of * parallelism available to tasks. The actual number of * threads added may be less than requested if the pool * is terminating or terminated * @return the number of threads added * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link * java.lang.RuntimePermission}("modifyThread"), */ public int addWorkers(int numberToAdd) { int nadded = 0; checkPermission(); final ReentrantLock lock = this.workerLock; lock.lock(); try { if (!runState.isAtLeastStopping()) { ForkJoinWorkerThread[] ws = workers; int len = ws.length; int newLen = len + numberToAdd; ForkJoinWorkerThread[] nws = new ForkJoinWorkerThread[newLen]; System.arraycopy(ws, 0, nws, 0, len); for (int i = len; i < newLen; ++i) nws[i] = createWorker(i); workers = nws; for (int i = len; i < newLen; ++i) { nws[i].start(); ++runningWorkers; } poolSize += numberToAdd; nadded = numberToAdd; } } finally { lock.unlock(); } broadcastPoolSize(); return nadded; } /** * Tries to remove the indicated number of worker threads from the * pool. The workers will exit the next time they are idle. This * method may be used to decrease the amount of parallelism * available to tasks. The actual number of workers removed * may be less than requested if the pool size would become * zero or the pool is terminating or terminated. * @return the number removed. * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link * java.lang.RuntimePermission}("modifyThread"), */ public int removeWorkers(int numberToRemove) { int nremoved = 0; checkPermission(); final ReentrantLock lock = this.workerLock; lock.lock(); try { // shutdown in rightmost order to enable shrinkage in // workerTerminated ForkJoinWorkerThread[] ws = workers; int k = ws.length; while (!runState.isAtLeastStopping() && --k > 0 && // don't kill ws[0] nremoved < numberToRemove) { ForkJoinWorkerThread w = ws[k]; if (w != null) { RunState rs = w.getRunState(); if (rs.transitionToShutdown()) { --poolSize; ++nremoved; } } } } finally { lock.unlock(); } broadcastPoolSize(); return nremoved; } /** * Tries to add or remove workers to attain the given pool size. * This may fail to attain the given target if the pool is * terminating or terminated. * @param newSize the target poolSize * @return the pool size upon exit of this method * @throws IllegalArgumentException if newSize less than or * equal to zero * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link * java.lang.RuntimePermission}("modifyThread"), */ public int setPoolSize(int newSize) { checkPermission(); if (newSize <= 0) throw new IllegalArgumentException(); final ReentrantLock lock = this.workerLock; lock.lock(); try { int ps = poolSize; if (newSize > ps) addWorkers(newSize - ps); else if (newSize < ps) removeWorkers(ps - newSize); } finally { lock.unlock(); } return poolSize; } /** * Callback from terminating worker. * @param w the worker * @param ex the exception causing abrupt termination, or null if * completed normally */ final void workerTerminated(ForkJoinWorkerThread w, Throwable ex) { try { final ReentrantLock lock = this.workerLock; lock.lock(); try { // Unless stopping, null slot, and if rightmost slots // now null, shrink if (!runState.isAtLeastStopping()) { int idx = w.getWorkerPoolIndex(); ForkJoinWorkerThread[] ws = workers; int len = ws.length; if (idx >= 0 && idx < len && ws[idx] == w) { ws[idx] = null; int newlen = len; while (newlen > 0 && ws[newlen-1] == null) --newlen; if (newlen < len) { ForkJoinWorkerThread[] nws = new ForkJoinWorkerThread[newlen]; System.arraycopy(ws, 0, nws, 0, newlen); workers = nws; poolBarrier.signal(); } } } if (--runningWorkers == 0) { terminate(); // no-op if already stopping runState.transitionToTerminated(); termination.signalAll(); } } finally { lock.unlock(); } } finally { if (ex != null) ForkJoinTask.rethrowException(ex); } } // lifecycle control /** * Initiates an orderly shutdown in which previously submitted * tasks are executed, but no new tasks will be accepted. * Invocation has no additional effect if already shut down. * Tasks that are in the process of being submitted concurrently * during the course of this method may or may not be rejected. * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link * java.lang.RuntimePermission}("modifyThread"), */ public void shutdown() { checkPermission(); runState.transitionToShutdown(); tryTerminateOnShutdown(); } /** * Attempts to stop all actively executing tasks, and cancels all * waiting tasks. Tasks that are in the process of being * submitted or executed concurrently during the course of this * method may or may not be rejected. * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link * java.lang.RuntimePermission}("modifyThread"), */ public void shutdownNow() { checkPermission(); terminate(); } /** * Returns true if this pool has been shut down. * * @return true if this pool has been shut down */ public boolean isShutdown() { return runState.isAtLeastShutdown(); } /** * Returns true if all tasks have completed following shut down. * * @return true if all tasks have completed following shut down */ public boolean isTerminated() { return runState.isTerminated(); } /** * Returns true if termination has commenced but has * not yet completed. * * @return true if in the process of terminating */ public boolean isTerminating() { return runState.isStopping(); } /** * Blocks until all tasks have completed execution after a shutdown * request, or the timeout occurs, or the current thread is * interrupted, whichever happens first. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument * @return true if this executor terminated and * false if the timeout elapsed before termination * @throws InterruptedException if interrupted while waiting */ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.workerLock; lock.lock(); try { for (;;) { if (runState.isTerminated()) return true; if (nanos <= 0) return false; nanos = termination.awaitNanos(nanos); } } finally { lock.unlock(); } } /** * Initiate termination. */ private void terminate() { if (runState.transitionToStopping()) { stopAllWorkers(); cancelQueuedSubmissions(); cancelQueuedWorkerTasks(); interruptUnterminatedWorkers(); } } /** * Check for termination in shutdown state */ private void tryTerminateOnShutdown() { if (runState.isAtLeastShutdown() && runningSubmissions.get() == 0 && submissionQueue.isEmpty() && runningSubmissions.get() == 0) // recheck terminate(); } /** * Clear out and cancel submissions */ private void cancelQueuedSubmissions() { Submission task; while (!submissionQueue.isEmpty() && (task = submissionQueue.poll()) != null) task.cancel(false); } /** * Clean out worker queues. */ private void cancelQueuedWorkerTasks() { final ReentrantLock lock = this.workerLock; lock.lock(); try { ForkJoinWorkerThread[] ws = workers; for (int i = 0; i < ws.length; ++i) { ForkJoinWorkerThread t = ws[i]; if (t != null) t.cancelTasks(); } } finally { lock.unlock(); } } /** * Set each worker's status to stopping. Requires lock to avoid * conflicts with add/remove */ private void stopAllWorkers() { final ReentrantLock lock = this.workerLock; lock.lock(); try { ForkJoinWorkerThread[] ws = workers; for (int i = 0; i < ws.length; ++i) { ForkJoinWorkerThread t = ws[i]; if (t != null) { RunState rs = t.getRunState(); rs.transitionToStopping(); } } } finally { lock.unlock(); } poolBarrier.poolSignal(); } /** * Interrupt all unterminated workers. This is not required for * sake of internal control, but may help unstick user code during * shutdown. */ private void interruptUnterminatedWorkers() { final ReentrantLock lock = this.workerLock; lock.lock(); try { ForkJoinWorkerThread[] ws = workers; for (int i = 0; i < ws.length; ++i) { ForkJoinWorkerThread t = ws[i]; if (t != null) { RunState rs = t.getRunState(); if (!rs.isTerminated()) { try { t.interrupt(); } catch (SecurityException ignore) { } } } } } finally { lock.unlock(); } } // Status queries /** * Returns true if all worker threads are currently idle. An idle * worker is one that cannot obtain a task to execute because none * are available to steal from other threads, and there are no * pending submissions to the pool. This method is conservative: * It might not return true immediately upon idleness of all * threads, but will eventually become true if threads remain * inactive. * @return true if all threads are currently idle */ public final boolean isQuiescent() { return activeWorkerCounter.get() == 0; } /** * Returns the approximate number of threads that are * currently executing tasks. This method may overestimate * the number of active threads. * @return the number of active threads. */ public int getActiveThreadCount() { return activeWorkerCounter.get(); } /** * Returns the approximate number of threads that are currently * idle waiting for tasks. This method may underestimate the * number of idel threads. * @return the number of idle threads. */ public int getIdleThreadCount() { return poolSize - activeWorkerCounter.get(); } /** * Returns the total number of tasks stolen from one thread's work * queue by another. This value is only an approximation, obtained * by iterating across all threads in the pool, and may lag the * actual total number of steals when the pool is not * quiescent. But the value is still useful for monitoring and * tuning fork/join programs: In general, steal counts should be * high enough to keep threads busy, but low enough to avoid * overhead and contention across threads. * @return the number of steals. */ public long getStealCount() { long sum = 0; ForkJoinWorkerThread[] ws = workers; for (int i = 0; i < ws.length; ++i) { ForkJoinWorkerThread t = ws[i]; if (t != null) sum += t.getWorkerStealCount(); } return sum; } /** * Returns the total number of tasks currently held in queues by * worker threads (but not including tasks submitted to the pool * that have not begun executing). This value is only an * approximation, obtained by iterating across all threads in the * pool. This method may be useful for tuning task granularities. * @return the number of tasks. */ public long getTotalPerThreadQueueSize() { long count = 0; ForkJoinWorkerThread[] ws = workers; for (int i = 0; i < ws.length; ++i) { ForkJoinWorkerThread t = ws[i]; if (t != null) count += t.getQueueSize(); } return count; } /** * Returns true if there are any tasks submitted to this pool * that have not yet begun executing. * @return true if there are any queued submissions. */ public boolean hasQueuedSubmissions() { return !submissionQueue.isEmpty(); } /** * Returns the number of tasks that have been submitted (via * submit or invoke) and are currently executing * in the pool. * @return the number of tasks. */ public int getActiveSubmissionCount() { return runningSubmissions.get(); } /** * Returns the factory used for constructing new workers * * @return the factory used for constructing new workers */ public ForkJoinWorkerThreadFactory getFactory() { return factory; } // Methods callable from workers. /** * Return current workers array (not cached by workers) */ final ForkJoinWorkerThread[] getWorkers() { return workers; } /** * Return submission queue (not cached by workers) */ final SubmissionQueue getSubmissionQueue() { return submissionQueue; } /** * Return counter (cached by workers) */ final AtomicInteger getActiveWorkerCounter() { return activeWorkerCounter; } /** * Return counter (cached by workers) */ final PoolBarrier getPoolBarrier() { return poolBarrier; } // Callbacks from submissions /** * Callback on starting execution of externally submitted job. */ final void submissionStarting() { runningSubmissions.incrementAndGet(); } /** * Completion callback from externally submitted job. */ final void submissionCompleted() { if (runningSubmissions.decrementAndGet() == 0 && runState.isAtLeastShutdown()) tryTerminateOnShutdown(); } /** * SubmissionQueues hold submissions not yet started by * workers. This is a variant of an M&S queue supporting * a fast check for apparent emptiness. */ static final class SubmissionQueue { /** Opportunistically subclasses AtromicReference for next-field */ static final class SQNode extends AtomicReference { Submission submission; SQNode(Submission s) { submission = s; } } private volatile SQNode head; private volatile SQNode tail; SubmissionQueue() { SQNode dummy = new SQNode(null); head = dummy; tail = dummy; } private static final AtomicReferenceFieldUpdater tailUpdater = AtomicReferenceFieldUpdater.newUpdater (SubmissionQueue.class, SQNode.class, "tail"); private static final AtomicReferenceFieldUpdater headUpdater = AtomicReferenceFieldUpdater.newUpdater (SubmissionQueue.class, SQNode.class, "head"); private boolean casTail(SQNode cmp, SQNode val) { return tailUpdater.compareAndSet(this, cmp, val); } private boolean casHead(SQNode cmp, SQNode val) { return headUpdater.compareAndSet(this, cmp, val); } /** * Quick check for likely non-emptiness. Returns true if an * add fully completed but not yet fully taken. */ boolean isApparentlyNonEmpty() { SQNode h = head; SQNode t = tail; return h != t; } boolean isEmpty() { for (;;) { SQNode h = head; SQNode t = tail; SQNode f = h.get(); if (h == head) { if (f == null) return true; else if (h != t) return false; else casTail(t, f); } } } void add(Submission x) { SQNode n = new SQNode(x); for (;;) { SQNode t = tail; SQNode s = t.get(); if (t == tail) { if (s != null) casTail(t, s); else if (t.compareAndSet(s, n)) { casTail(t, n); return; } } } } Submission poll() { for (;;) { SQNode h = head; SQNode t = tail; SQNode f = h.get(); if (h == head) { if (f == null) return null; else if (h == t) casTail(t, f); else if (casHead(h, f)) { Submission x = f.submission; f.submission = null; x.setStolen(); return x; } } } } } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/ParallelArray.java0000644000000000000000000036002710740452246024044 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import static jsr166y.forkjoin.Ops.*; import java.util.*; import java.util.concurrent.atomic.*; import java.lang.reflect.Array; /** * An array supporting parallel operations. * *

A ParallelArray maintains a {@link ForkJoinExecutor} and an * array in order to provide parallel aggregate operations. The main * operations are to apply some procedure to each element, to * map each element to a new element, to replace * each element, to select a subset of elements based on * matching a predicate or ranges of indices, and to reduce * all elements into a single value such as a sum. * *

A ParallelArray is constructed by allocating, using, or copying * an array, using one of the static factory methods {@link #create}, * {@link #createEmpty}, {@link #createUsingHandoff} and {@link * #createFromCopy}. Upon construction, the encapsulated array managed * by the ParallelArray must not be shared between threads without * external synchronization. In particular, as is the case with any * array, access by another thread of an element of a ParallelArray * while another operation is in progress has undefined effects. * *

The ForkJoinExecutor used to construct a ParallelArray can be * shared safely by other threads (and used in other * ParallelArrays). To avoid the overhead associated with creating * multiple executors, it is often a good idea to use the {@link * #defaultExecutor()} across all ParallelArrays. However, you might * choose to use different ones for the sake of controlling processor * usage, isolating faults, and/or ensuring progress. * *

A ParallelArray is not a List. It relies on random access across * array elements to support efficient parallel operations. However, * a ParallelArray can be viewed and manipulated as a List, via method * {@link ParallelArray#asList}. The asList view allows * incremental insertion and modification of elements while setting up * a ParallelArray, generally before using it for parallel * operations. Similarly, the list view may be useful when accessing * the results of computations in sequential contexts. A * ParallelArray may also be created using the elements of any other * Collection, by constructing from the array returned by the * Collection's toArray method. The effects of mutative * asList operations may also be achieved directly using * method {@link #setLimit} along with element-by-element access * methods {@link #get} and {@link #set}. * *

Most operations can be prefixed with range bounds, filters, and * mappings using withBounds, withFilter, and * withMapping, respectively. For example, * aParallelArray.withFilter(aPredicate).all() creates a new * ParallelArray containing only those elements matching the * predicate. As illustrated below, a mapping often * represents accessing some field or invoking some method of an * element. These versions are typically more efficient than * performing selections, then mappings, then other operations in * multiple (parallel) steps. The basic ideas and usages of filtering * and mapping are similar to those in database query systems such as * SQL, but take a more restrictive form. Series of filter and * mapping prefixes may each be cascaded, but all filter prefixes * must precede all mapping prefixes, to ensure efficient execution in * s single parallel step. Instances of WithFilter etc are * useful only as operation prefixes, and should not normally be * stored in variables for future use. * *

This class includes some reductions, such as min, that * are commonly useful for most element types, as well as a combined * version, summary, that computes all of them in a single * parallel step, which is normally more efficient that computing each * in turn. * *

While ParallelArrays can be based on any kind of an object * array, including "boxed" types such as Long, parallel operations on * scalar "unboxed" type are likely to be substantially more * efficient. For this reason, classes {@link ParallelLongArray}, and * {@link ParallelDoubleArray} are also supplied, and designed to * smoothly interoperate with ParallelArrays. You should also use a * ParallelLongArray for processing other integral scalar data * (int, short, etc). And similarly use a * ParallelDoubleArray for float data. (Further * specializations for these other types would add clutter without * significantly improving performance beyond that of the Long and * Double versions.) * *

The methods in this class are designed to perform efficiently * with both large and small pools, even with single-thread pools on * uniprocessors. However, there is some overhead in parallelizing * operations, so short computations on small arrays might not execute * faster than sequential versions, and might even be slower. * *

Sample usages. * * The main difference between programming with plain arrays and * programming with aggregates is that you must separately define each * of the component functions on elements. For example, the following * returns the maximum Grade Point Average across all senior students, * given a (fictional) Student class: * *

 * import static Ops.*;
 * class StudentStatistics {
 *   ParallelArray<Student> students = ...
 *   // ...
 *   public double getMaxSeniorGpa() {
 *     return students.withFilter(isSenior).withMapping(gpaField).max();
 *   }
 *
 *   // helpers:
 *   static final class IsSenior implements Predicate<Student> {
 *     public boolean evaluate(Student s) { return s.credits > 90; }
 *   }
 *   static final IsSenior isSenior = new IsSenior();
 *   static final class GpaField implements MapperToDouble<Student> {
 *     public double map(Student s) { return s.gpa; }
 *   }
 *   static final GpaField gpaField = new GpaField();
 * }
 * 
* */ public class ParallelArray implements Iterable { /* * See class PAS for most of the underlying parallel execution * code and explanation. */ /** * Returns a common default executor for use in ParallelArrays. * This executor arranges enough parallelism to use most, but not * necessarily all, of the avaliable processors on this system. * @return the executor */ public static ForkJoinExecutor defaultExecutor() { return PAS.defaultExecutor(); } /** The executor */ final ForkJoinExecutor ex; /** The array -- can be replaced within AsList operations */ T[] array; /** upper bound of effective region usef dor parallel operations */ int limit; /** Lazily constructed list view */ AsList listView; /** * Constructor for use by subclasses to create a new ParallelArray * using the given executor, and initially using the supplied * array, with effective size bound by the given limit. This * constructor is designed to enable extensions via * subclassing. To create a ParallelArray, use {@link #create}, * {@link #createEmpty}, {@link #createUsingHandoff} or {@link * #createFromCopy}. * @param executor the executor * @param array the array * @param limit the upper bound limit */ protected ParallelArray(ForkJoinExecutor executor, T[] array, int limit) { if (executor == null || array == null) throw new NullPointerException(); if (limit < 0 || limit > array.length) throw new IllegalArgumentException(); this.ex = executor; this.array = array; this.limit = limit; } /** * Trusted internal version of protected constructor. */ ParallelArray(ForkJoinExecutor executor, T[] array) { this.ex = executor; this.array = array; this.limit = array.length; } /** * Creates a new ParallelArray using the given executor and * an array of the given size constructed using the * indicated base element type. * @param size the array size * @param elementType the type of the elements * @param executor the executor */ public static ParallelArray create (int size, Class elementType, ForkJoinExecutor executor) { T[] array = (T[])Array.newInstance(elementType, size); return new ParallelArray(executor, array, size); } /** * Creates a new ParallelArray initially using the given array and * executor. In general, the handed off array should not be used * for other purposes once constructing this ParallelArray. The * given array may be internally replaced by another array in the * course of methods that add or remove elements. * @param handoff the array * @param executor the executor */ public static ParallelArray createUsingHandoff (T[] handoff, ForkJoinExecutor executor) { return new ParallelArray(executor, handoff, handoff.length); } /** * Creates a new ParallelArray using the given executor and * initially holding copies of the given * source elements. * @param source the source of initial elements * @param executor the executor */ public static ParallelArray createFromCopy (T[] source, ForkJoinExecutor executor) { // For now, avoid copyOf so people can compile with Java5 int size = source.length; T[] array = (T[])Array.newInstance (source.getClass().getComponentType(), size); System.arraycopy(source, 0, array, 0, size); return new ParallelArray(executor, array, size); } /** * Creates a new ParallelArray using an array of the given size, * initially holding copies of the given source truncated or * padded with nulls to obtain the specified length. * @param source the source of initial elements * @param size the array size * @param executor the executor */ public static ParallelArray createFromCopy (int size, T[] source, ForkJoinExecutor executor) { // For now, avoid copyOf so people can compile with Java5 T[] array = (T[])Array.newInstance (source.getClass().getComponentType(), size); System.arraycopy(source, 0, array, 0, Math.min(source.length, size)); return new ParallelArray(executor, array, size); } /** * Creates a new ParallelArray using the given executor and an * array of the given size constructed using the indicated base * element type, but with an initial effective size of zero, * enabling incremental insertion via {@link ParallelArray#asList} * operations. * @param size the array size * @param elementType the type of the elements * @param executor the executor */ public static ParallelArray createEmpty (int size, Class elementType, ForkJoinExecutor executor) { T[] array = (T[])Array.newInstance(elementType, size); return new ParallelArray(executor, array, 0); } /** * Summary statistics for a possibly bounded, filtered, and/or * mapped ParallelArray. */ public static interface SummaryStatistics { /** Return the number of elements */ public int size(); /** Return the minimum element, or null if empty */ public T min(); /** Return the maximum element, or null if empty */ public T max(); /** Return the index of the minimum element, or -1 if empty */ public int indexOfMin(); /** Return the index of the maximum element, or -1 if empty */ public int indexOfMax(); } /** * Returns the executor used for computations * @return the executor */ public ForkJoinExecutor getExecutor() { return ex; } /** * Applies the given procedure to elements * @param procedure the procedure */ public void apply(Procedure procedure) { new WithBounds(this).apply(procedure); } /** * Returns reduction of elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public T reduce(Reducer reducer, T base) { return new WithBounds(this).reduce(reducer, base); } /** * Returns a new ParallelArray holding all elements * @return a new ParallelArray holding all elements */ public ParallelArray all() { return new WithBounds(this).all(); } /** * Returns a new ParallelArray with the given element type holding * all elements * @param elementType the type of the elements * @return a new ParallelArray holding all elements */ public ParallelArray all(Class elementType) { return new WithBounds(this).all(elementType); } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelArray combine (U[] other, Combiner combiner) { return new WithBounds(this).combine(other, combiner); } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is not * the same length as this array. */ public ParallelArray combine (ParallelArray other, Combiner combiner) { return new WithBounds(this).combine(other, combiner); } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @param elementType the type of elements of returned array * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelArray combine (U[] other, Combiner combiner, Class elementType) { return new WithBounds(this).combine(other, combiner, elementType); } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array segment * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other segment is * shorter than this array. */ public ParallelArray combine (ParallelArray.WithBounds other, Combiner combiner) { return new WithBounds(this).combine(other, combiner); } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array segment * @param combiner the combiner * @param elementType the type of elements of returned array * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelArray combine (ParallelArray.WithBounds other, Combiner combiner, Class elementType) { return new WithBounds(this).combine(other, combiner, elementType); } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @param elementType the type of elements of returned array * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is not * the same length as this array. */ public ParallelArray combine (ParallelArray other, Combiner combiner, Class elementType) { return new WithBounds(this).combine(other.array, combiner, elementType); } /** * Replaces elements with the results of applying the given mapper * to their current values. * @param mapper the mapper */ public void replaceWithTransform(Mapper mapper) { new WithBounds(this).replaceWithTransform(mapper); } /** * Replaces elements with the results of applying the given * mapper to their indices. * @param mapper the mapper */ public void replaceWithMappedIndex(MapperFromInt mapper) { new WithBounds(this).replaceWithMappedIndex(mapper); } /** * Replaces elements with the results of applying the given * generator. * @param generator the generator */ public void replaceWithGeneratedValue(Generator generator) { new WithBounds(this).replaceWithGeneratedValue(generator); } /** * Replaces elements with the given value. * @param value the value */ public void replaceWithValue(T value) { new WithBounds(this).replaceWithValue(value); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer elements than this array. */ public void replaceWithCombination (ParallelArray other, Reducer combiner) { new WithBounds(this).replaceWithCombination(other.array, combiner); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer elements than this array. */ public void replaceWithCombination(T[] other, Reducer combiner) { new WithBounds(this).replaceWithCombination(other, combiner); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array segment * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other segment has * fewer elements.than this array, */ public void replaceWithCombination (ParallelArray.WithBounds other, Reducer combiner) { new WithBounds(this).replaceWithCombination(other, combiner); } /** * Returns the index of some element equal to given target, * or -1 if not present * @param target the element to search for * @return the index or -1 if not present */ public int indexOf(T target) { return new WithBounds(this).indexOf(target); } /** * Assuming this array is sorted, returns the index of an element * equal to given target, or -1 if not present. If the array * is not sorted, the results are undefined. * @param target the element to search for * @return the index or -1 if not present */ public int binarySearch(T target) { int lo = 0; int hi = limit - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; int c = ((Comparable)target).compareTo((Comparable)(array[mid])); if (c == 0) return mid; else if (c < 0) hi = mid - 1; else lo = mid + 1; } return -1; } /** * Assuming this array is sorted with respect to the given * comparator, returns the index of an element equal to given * target, or -1 if not present. If the array is not sorted, the * results are undefined. * @param target the element to search for * @param comparator the comparator * @return the index or -1 if not present */ public int binarySearch(T target, Comparator comparator) { int lo = 0; int hi = limit - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; int c = comparator.compare(target, array[mid]); if (c == 0) return mid; else if (c < 0) hi = mid - 1; else lo = mid + 1; } return -1; } /** * Returns summary statistics, using the given comparator * to locate minimum and maximum elements. * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelArray.SummaryStatistics summary (Comparator comparator) { return new WithBounds(this).summary(comparator); } /** * Returns summary statistics, assuming that all elements are * Comparables * @return the summary. */ public ParallelArray.SummaryStatistics summary() { return new WithBounds(this).summary(); } /** * Returns the minimum element, or null if empty * @param comparator the comparator * @return minimum element, or null if empty */ public T min(Comparator comparator) { return new WithBounds(this).min(comparator); } /** * Returns the minimum element, or null if empty, * assuming that all elements are Comparables * @return minimum element, or null if empty * @throws ClassCastException if any element is not Comparable. */ public T min() { return new WithBounds(this).min(); } /** * Returns the maximum element, or null if empty * @param comparator the comparator * @return maximum element, or null if empty */ public T max(Comparator comparator) { return new WithBounds(this).max(comparator); } /** * Returns the maximum element, or null if empty * assuming that all elements are Comparables * @return maximum element, or null if empty * @throws ClassCastException if any element is not Comparable. */ public T max() { return new WithBounds(this).max(); } /** * Replaces each element with the running cumulation of applying * the given reducer. For example, if the contents are the numbers * 1, 2, 3, and the reducer operation adds numbers, then * after invocation of this method, the contents would be 1, * 3, 6 (that is, 1, 1+2, 1+2+3); * @param reducer the reducer * @param base the result for an empty array */ public void cumulate(Reducer reducer, T base) { new WithBounds(this).cumulate(reducer, base); } /** * Replaces each element with the cumulation of applying the given * reducer to all previous values, and returns the total * reduction. For example, if the contents are the numbers 1, * 2, 3, and the reducer operation adds numbers, then after * invocation of this method, the contents would be 0, 1, * 3 (that is, 0, 0+1, 0+1+2, and the return value * would be 6 (that is, 1+2+3); * @param reducer the reducer * @param base the result for an empty array * @return the total reduction */ public T precumulate(Reducer reducer, T base) { return (T)(new WithBounds(this).precumulate(reducer, base)); } /** * Sorts the array. Unlike Arrays.sort, this sort does * not guarantee that elements with equal keys maintain their * relative position in the array. * @param comparator the comparator to use */ public void sort(Comparator comparator) { new WithBounds(this).sort(comparator); } /** * Sorts the array, assuming all elements are Comparable. Unlike * Arrays.sort, this sort does not guarantee that elements * with equal keys maintain their relative position in the array. * @throws ClassCastException if any element is not Comparable. */ public void sort() { new WithBounds(this).sort(); } /** * Removes consecutive elements that are equal (or null), shifting * others leftward, and possibly decreasing size. This method * uses each non-null element's equals method to test for * duplication. This method may be used after sorting to ensure * that this ParallelArray contains a set of unique elements. */ public void removeConsecutiveDuplicates() { new WithBounds(this).removeConsecutiveDuplicates(); } /** * Removes null elements, shifting others leftward, and possibly * decreasing size. */ public void removeNulls() { new WithBounds(this).removeNulls(); } /** * Returns a new ParallelArray containing only the non-null unique * elements of this array (that is, without any duplicates). This * method uses each element's equals method to test for * duplication. * @return the new ParallelArray */ public ParallelArray allUniqueElements() { return new WithBounds(this).allUniqueElements(); } /** * Returns a new ParallelArray containing only the non-null unique * elements of this array (that is, without any duplicates). This * method uses reference identity to test for duplication. * @return the new ParallelArray */ public ParallelArray allNonidenticalElements() { return new WithBounds(this).allNonidenticalElements(); } /** * Returns an operation prefix that causes a method to * operate only on the elements of the array between * firstIndex (inclusive) and upperBound (exclusive). * @param firstIndex the lower bound (inclusive) * @param upperBound the upper bound (exclusive) * @return operation prefix */ public WithBounds withBounds(int firstIndex, int upperBound) { if (firstIndex > upperBound) throw new IllegalArgumentException ("firstIndex(" + firstIndex + ") > upperBound(" + upperBound+")"); if (firstIndex < 0) throw new ArrayIndexOutOfBoundsException(firstIndex); if (upperBound > this.limit) throw new ArrayIndexOutOfBoundsException(upperBound); return new WithBounds(this, firstIndex, upperBound); } /** * Returns an operation prefix that causes a method to operate * only on the elements of the array for which the given selector * returns true * @param selector the selector * @return operation prefix */ public WithFilter withFilter(Predicate selector) { return new WithBoundedFilter(this, 0, limit, selector); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithMapping withMapping (Mapper mapper) { return new WithBoundedMapping(this, 0, limit, mapper); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithDoubleMapping withMapping (MapperToDouble mapper) { return new WithBoundedDoubleMapping(this, 0, limit, mapper); } /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public WithLongMapping withMapping (MapperToLong mapper) { return new WithBoundedLongMapping(this, 0, limit, mapper); } /** * A modifier for parallel array operations to apply to mappings * of elements, not to the elements themselves */ public static abstract class WithMapping extends PAS.RPrefix { WithMapping(ParallelArray pa, int firstIndex, int upperBound) { super(pa, firstIndex, upperBound); } /** * Applies the given procedure to elements * @param procedure the procedure */ public void apply(Procedure procedure) { ex.invoke(new PAS.FJRApply(this, firstIndex, upperBound, null, procedure)); } /** * Returns reduction of elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public U reduce(Reducer reducer, U base) { PAS.FJRReduce f = new PAS.FJRReduce (this, firstIndex, upperBound, null, reducer, base); ex.invoke(f); return (U)(f.result); } /** * Returns the index of some element matching bound and filter * constraints, or -1 if none. * @return index of matching element, or -1 if none. */ public abstract int anyIndex(); /** * Returns some element matching bound and filter * constraints, or null if none. * @return an element, or null if none. */ public abstract U any(); /** * Returns the minimum element, or null if empty * @param comparator the comparator * @return minimum element, or null if empty */ public U min(Comparator comparator) { return reduce(Ops.minReducer(comparator), null); } /** * Returns the minimum element, or null if empty, * assuming that all elements are Comparables * @return minimum element, or null if empty * @throws ClassCastException if any element is not Comparable. */ public U min() { return reduce((Reducer)(Ops.castedMinReducer()), null); } /** * Returns the maximum element, or null if empty * @param comparator the comparator * @return maximum element, or null if empty */ public U max(Comparator comparator) { return reduce(Ops.maxReducer(comparator), null); } /** * Returns the maximum element, or null if empty * assuming that all elements are Comparables * @return maximum element, or null if empty * @throws ClassCastException if any element is not Comparable. */ public U max() { return reduce((Reducer)(Ops.castedMaxReducer()), null); } /** * Returns summary statistics, using the given comparator * to locate minimum and maximum elements. * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelArray.SummaryStatistics summary (Comparator comparator) { PAS.FJRStats f = new PAS.FJRStats (this, firstIndex, upperBound, null, comparator); ex.invoke(f); return (ParallelArray.SummaryStatistics)f; } /** * Returns summary statistics, assuming that all elements are * Comparables * @return the summary. */ public ParallelArray.SummaryStatistics summary() { PAS.FJRStats f = new PAS.FJRStats (this, firstIndex, upperBound, null, (Comparator)(Ops.castedComparator())); ex.invoke(f); return (ParallelArray.SummaryStatistics)f; } /** * Returns a new ParallelArray holding elements * @return a new ParallelArray holding elements */ public abstract ParallelArray all(); /** * Returns a new ParallelArray with the given element type * holding elements * @param elementType the type of the elements * @return a new ParallelArray holding elements */ public abstract ParallelArray all(Class elementType); /** * Return the number of elements selected using bound or * filter restrictions. Note that this method must evaluate * all selectors to return its result. * @return the number of elements */ public abstract int size(); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper * applied to current mapper's results * @param mapper the mapper * @return operation prefix */ public abstract WithMapping withMapping (Mapper mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper * applied to current mapper's results * @param mapper the mapper * @return operation prefix */ public abstract WithDoubleMapping withMapping (MapperToDouble mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper * applied to current mapper's results * @param mapper the mapper * @return operation prefix */ public abstract WithLongMapping withMapping (MapperToLong mapper); } /** * A restriction of parallel array operations to apply only to * elements for which a selector returns true */ public static abstract class WithFilter extends WithMapping{ WithFilter(ParallelArray pa, int firstIndex, int upperBound) { super(pa, firstIndex, upperBound); } public void apply(Procedure procedure) { ex.invoke(new PAS.FJRApply (this, firstIndex, upperBound, null, procedure)); } public T reduce(Reducer reducer, T base) { PAS.FJRReduce f = new PAS.FJRReduce (this, firstIndex, upperBound, null, reducer, base); ex.invoke(f); return (T)(f.result); } public T min(Comparator comparator) { return reduce(Ops.minReducer(comparator), null); } public T min() { return reduce((Reducer)(Ops.castedMinReducer()), null); } public T max(Comparator comparator) { return reduce(Ops.maxReducer(comparator), null); } public T max() { return reduce((Reducer)(Ops.castedMaxReducer()), null); } public ParallelArray.SummaryStatistics summary (Comparator comparator) { PAS.FJRStats f = new PAS.FJRStats (this, firstIndex, upperBound, null, comparator); ex.invoke(f); return (ParallelArray.SummaryStatistics)f; } public ParallelArray.SummaryStatistics summary() { PAS.FJRStats f = new PAS.FJRStats (this, firstIndex, upperBound, null, (Comparator)(Ops.castedComparator())); ex.invoke(f); return (ParallelArray.SummaryStatistics)f; } /** * Replaces elements with the results of applying the given * mapper to their current values. * @param mapper the mapper */ public void replaceWithTransform (Mapper mapper) { ex.invoke(new PAS.FJRTransform(this, firstIndex, upperBound, null, mapper)); } /** * Replaces elements with the results of applying the given * mapper to their indices * @param mapper the mapper */ public void replaceWithMappedIndex (MapperFromInt mapper) { ex.invoke(new PAS.FJRIndexMap(this, firstIndex, upperBound, null, mapper)); } /** * Replaces elements with results of applying the given * generator. * @param generator the generator */ public void replaceWithGeneratedValue (Generator generator) { ex.invoke(new PAS.FJRGenerate (this, firstIndex, upperBound, null, generator)); } /** * Replaces elements with the given value. * @param value the value */ public void replaceWithValue(T value) { ex.invoke(new PAS.FJRFill(this, firstIndex, upperBound, null, value)); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer than upperBound elements. */ public void replaceWithCombination (ParallelArray other, Reducer combiner) { if (other.size() < size()) throw new ArrayIndexOutOfBoundsException(); ex.invoke(new PAS.FJRCombineInPlace (this, firstIndex, upperBound, null, other.array, 0, combiner)); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array segment * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer than upperBound elements. */ public void replaceWithCombination (ParallelArray.WithBounds other, Reducer combiner) { if (other.size() < size()) throw new ArrayIndexOutOfBoundsException(); ex.invoke(new PAS.FJRCombineInPlace (this, firstIndex, upperBound, null, other.pa.array, other.firstIndex-firstIndex, combiner)); } /** * Replaces elements with results of applying * combine(thisElement, otherElement) * @param other the other array * @param combiner the combiner * @throws ArrayIndexOutOfBoundsException if other array has * fewer than upperBound elements. */ public void replaceWithCombination (T[] other, Reducer combiner) { if (other.length < size()) throw new ArrayIndexOutOfBoundsException(); ex.invoke(new PAS.FJRCombineInPlace (this, firstIndex, upperBound, null, other, -firstIndex, combiner)); } /** * Removes from the array all elements matching bound and/or * filter constraints. */ public abstract void removeAll(); /** * Returns a new ParallelArray containing only non-null unique * elements (that is, without any duplicates). This method * uses each element's equals method to test for * duplication. * @return the new ParallelArray */ public abstract ParallelArray allUniqueElements(); /** * Returns a new ParallelArray containing only non-null unique * elements (that is, without any duplicates). This method * uses reference identity to test for duplication. * @return the new ParallelArray */ public abstract ParallelArray allNonidenticalElements(); /** * Returns an operation prefix that causes a method to operate * only on elements for which the current selector (if * present) and the given selector returns true * @param selector the selector * @return operation prefix */ public abstract WithFilter withFilter (Predicate selector); /** * Returns an operation prefix that causes a method to operate * only on elements for which the current selector (if * present) or the given selector returns true * @param selector the selector * @return operation prefix */ public abstract WithFilter orFilter (Predicate selector); final void leafTransfer(int lo, int hi, Object[] dest, int offset) { final Object[] array = pa.array; for (int i = lo; i < hi; ++i) dest[offset++] = (array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, Object[] dest, int offset) { final Object[] array = pa.array; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = (array[indices[i]]); } } /** * A restriction of parallel array operations to apply only within * a given range of indices. */ public static final class WithBounds extends WithFilter { WithBounds(ParallelArray pa, int firstIndex, int upperBound) { super(pa, firstIndex, upperBound); } /** Version for implementing main ParallelArray methods */ WithBounds(ParallelArray pa) { super(pa, 0, pa.limit); } /** * Returns an operation prefix that causes a method to operate * only on the elements of the array between firstIndex * (inclusive) and upperBound (exclusive). The bound * arguments are relative to the current bounds. For example * pa.withBounds(2, 8).withBounds(3, 5) indexes the * 5th (= 2+3) and 6th elements of pa. However, indices * returned by methods such as indexOf are * with respect to the underlying ParallelArray. * @param firstIndex the lower bound (inclusive) * @param upperBound the upper bound (exclusive) * @return operation prefix */ public WithBounds withBounds(int firstIndex, int upperBound) { if (firstIndex > upperBound) throw new IllegalArgumentException ("firstIndex(" + firstIndex + ") > upperBound(" + upperBound+")"); if (firstIndex < 0) throw new ArrayIndexOutOfBoundsException(firstIndex); if (upperBound - firstIndex > this.upperBound - this.firstIndex) throw new ArrayIndexOutOfBoundsException(upperBound); return new WithBounds(pa, this.firstIndex + firstIndex, this.firstIndex + upperBound); } public WithFilter withFilter(Predicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, selector); } public WithMapping withMapping (Mapper mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, mapper); } public WithDoubleMapping withMapping (MapperToDouble mapper) { return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, mapper); } public WithLongMapping withMapping (MapperToLong mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, mapper); } public WithFilter orFilter(Predicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, selector); } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } public T any() { return (firstIndex < upperBound)? (T)(pa.array[firstIndex]) : null; } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelArray combine (U[] other, Combiner combiner) { int size = upperBound - firstIndex; if (other.length < size) throw new ArrayIndexOutOfBoundsException(); V[] dest = (V[])new Object[size]; ex.invoke(new PAS.FJRCombine (this, firstIndex, upperBound, null, other, -firstIndex, dest, combiner)); return new ParallelArray(ex, dest); } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @param elementType the type of elements of returned array * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelArray combine (U[] other, Combiner combiner, Class elementType) { int size = upperBound - firstIndex; if (other.length < size) throw new ArrayIndexOutOfBoundsException(); V[] dest = (V[])Array.newInstance(elementType, size); ex.invoke(new PAS.FJRCombine (this, firstIndex, upperBound, null, other, -firstIndex, dest, combiner)); return new ParallelArray(ex, dest); } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelArray combine (ParallelArray other, Combiner combiner) { int size = upperBound - firstIndex; if (other.size() < size) throw new ArrayIndexOutOfBoundsException(); V[] dest = (V[])new Object[size]; ex.invoke(new PAS.FJRCombine (this, firstIndex, upperBound, null, other.array, -firstIndex, dest, combiner)); return new ParallelArray(ex, dest); } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array * @param combiner the combiner * @param elementType the type of elements of returned array * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelArray combine (ParallelArray other, Combiner combiner, Class elementType) { int size = upperBound - firstIndex; if (other.size() < size) throw new ArrayIndexOutOfBoundsException(); V[] dest = (V[])Array.newInstance(elementType, size); ex.invoke(new PAS.FJRCombine(this, firstIndex, upperBound, null, other.array, -firstIndex, dest, combiner)); return new ParallelArray(ex, dest); } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array segment * @param combiner the combiner * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other segment is * shorter than this array. */ public ParallelArray combine (ParallelArray.WithBounds other, Combiner combiner) { int size = upperBound - firstIndex; if (other.size() < size) throw new ArrayIndexOutOfBoundsException(); V[] dest = (V[])new Object[size]; ex.invoke(new PAS.FJRCombine(this, firstIndex, upperBound, null, other.pa.array, other.firstIndex - firstIndex, dest, combiner)); return new ParallelArray(ex, dest); } /** * Returns a ParallelArray containing results of * applying combine(thisElement, otherElement) * for each element. * @param other the other array segment * @param combiner the combiner * @param elementType the type of elements of returned array * @return the array of mappings * @throws ArrayIndexOutOfBoundsException if other array is * shorter than this array. */ public ParallelArray combine (ParallelArray.WithBounds other, Combiner combiner, Class elementType) { int size = upperBound - firstIndex; if (other.size() < size) throw new ArrayIndexOutOfBoundsException(); V[] dest = (V[])Array.newInstance(elementType, size); ex.invoke(new PAS.FJRCombine(this, firstIndex, upperBound, null, other.pa.array, other.firstIndex - firstIndex, dest, combiner)); return new ParallelArray(ex, dest); } public ParallelArray all() { final Object[] array = pa.array; // For now, avoid copyOf so people can compile with Java5 int size = upperBound - firstIndex; T[] dest = (T[])Array.newInstance (array.getClass().getComponentType(), size); System.arraycopy(array, firstIndex, dest, 0, size); return new ParallelArray(ex, dest); } public ParallelArray all(Class elementType) { final Object[] array = pa.array; int size = upperBound - firstIndex; T[] dest = (T[])Array.newInstance(elementType, size); System.arraycopy(array, firstIndex, dest, 0, size); return new ParallelArray(ex, dest); } public ParallelArray allUniqueElements() { PAS.RUniquifierTable tab = new PAS.RUniquifierTable (upperBound - firstIndex, pa.array, null, false); PAS.FJUniquifier f = new PAS.FJUniquifier (this, firstIndex, upperBound, null, tab); ex.invoke(f); T[] res = (T[])(tab.uniqueElements(f.count)); return new ParallelArray(ex, res); } public ParallelArray allNonidenticalElements() { PAS.RUniquifierTable tab = new PAS.RUniquifierTable (upperBound - firstIndex, pa.array, null, true); PAS.FJUniquifier f = new PAS.FJUniquifier (this, firstIndex, upperBound, null, tab); ex.invoke(f); T[] res = (T[])(tab.uniqueElements(f.count)); return new ParallelArray(ex, res); } /** * Returns the index of some element equal to given target, or * -1 if not present * @param target the element to search for * @return the index or -1 if not present */ public int indexOf(T target) { AtomicInteger result = new AtomicInteger(-1); PAS.FJRIndexOf f = new PAS.FJRIndexOf (this, firstIndex, upperBound, null, result, target); ex.invoke(f); return result.get(); } /** * Assuming this array is sorted, returns the index of an * element equal to given target, or -1 if not present. If the * array is not sorted, the results are undefined. * @param target the element to search for * @return the index or -1 if not present */ public int binarySearch(T target) { final Object[] array = pa.array; int lo = firstIndex; int hi = upperBound - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; int c = ((Comparable)target).compareTo((Comparable)array[mid]); if (c == 0) return mid; else if (c < 0) hi = mid - 1; else lo = mid + 1; } return -1; } /** * Assuming this array is sorted with respect to the given * comparator, returns the index of an element equal to given * target, or -1 if not present. If the array is not sorted, * the results are undefined. * @param target the element to search for * @param comparator the comparator * @return the index or -1 if not present */ public int binarySearch(T target, Comparator comparator) { Comparator cmp = comparator; final Object[] array = pa.array; int lo = firstIndex; int hi = upperBound - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; int c = cmp.compare(target, array[mid]); if (c == 0) return mid; else if (c < 0) hi = mid - 1; else lo = mid + 1; } return -1; } public int size() { return upperBound - firstIndex; } /** * Replaces each element with the running cumulation of applying * the given reducer. * @param reducer the reducer * @param base the result for an empty array */ public void cumulate(Reducer reducer, T base) { PAS.FJRCumulateOp op = new PAS.FJRCumulateOp(this, reducer, base); PAS.FJRScan r = new PAS.FJRScan(null, op, firstIndex, upperBound); ex.invoke(r); } /** * Replaces each element with the cumulation of applying the given * reducer to all previous values, and returns the total * reduction. * @param reducer the reducer * @param base the result for an empty array * @return the total reduction */ public T precumulate(Reducer reducer, T base) { PAS.FJRPrecumulateOp op = new PAS.FJRPrecumulateOp (this, reducer, base); PAS.FJRScan r = new PAS.FJRScan(null, op, firstIndex, upperBound); ex.invoke(r); return (T)(r.out); } /** * Sorts the elements. * Unlike Arrays.sort, this sort does * not guarantee that elements with equal keys maintain their * relative position in the array. * @param cmp the comparator to use */ public void sort(Comparator cmp) { final Object[] array = pa.array; Class tc = array.getClass().getComponentType(); T[] ws = (T[])Array.newInstance(tc, upperBound); ex.invoke(new PAS.FJRSorter (cmp, array, ws, firstIndex, upperBound - firstIndex, threshold)); } /** * Sorts the elements, assuming all elements are * Comparable. Unlike Arrays.sort, this sort does not * guarantee that elements with equal keys maintain their relative * position in the array. * @throws ClassCastException if any element is not Comparable. */ public void sort() { final Object[] array = pa.array; Class tc = array.getClass().getComponentType(); if (!Comparable.class.isAssignableFrom(tc)) { sort(Ops.castedComparator()); return; } Comparable[] ca = (Comparable[])array; Comparable[] ws = (Comparable[])Array.newInstance(tc, upperBound); pa.ex.invoke(new PAS.FJRCSorter (ca, ws, firstIndex, upperBound - firstIndex, threshold)); } public void removeAll() { pa.removeSlotsAt(firstIndex, upperBound); } /** * Removes consecutive elements that are equal (or null), * shifting others leftward, and possibly decreasing size. This * method may be used after sorting to ensure that this * ParallelArray contains a set of unique elements. */ public void removeConsecutiveDuplicates() { // Sequential implementation for now int k = firstIndex; int n = upperBound; Object[] arr = pa.array; Object last = null; for (int i = k; i < n; ++i) { Object x = arr[i]; if (x != null && (last == null || !last.equals(x))) arr[k++] = last = x; } pa.removeSlotsAt(k, n); } /** * Removes null elements, shifting others leftward, and possibly * decreasing size. */ public void removeNulls() { // Sequential implementation for now int k = firstIndex; int n = upperBound; Object[] arr = pa.array; for (int i = k; i < n; ++i) { Object x = arr[i]; if (x != null) arr[k++] = x; } pa.removeSlotsAt(k, n); } void leafApply(int lo, int hi, Procedure procedure) { final Object[] array = pa.array; for (int i = lo; i < hi; ++i) procedure.apply(array[i]); } void leafTransform(int lo, int hi, Mapper mapper) { final Object[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = mapper.map(array[i]); } void leafIndexMap(int lo, int hi, MapperFromInt mapper) { final Object[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = mapper.map(i); } void leafGenerate(int lo, int hi, Generator generator) { final Object[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = generator.generate(); } void leafFillValue(int lo, int hi, Object value) { final Object[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = value; } void leafCombineInPlace(int lo, int hi, Object[] other, int otherOffset, Reducer combiner) { final Object[] array = pa.array; for (int i = lo; i < hi; ++i) array[i] = combiner.combine(array[i], other[i+otherOffset]); } void leafCombine(int lo, int hi, Object[] other, int otherOffset, Object[] dest, Combiner combiner) { final Object[] array = pa.array; int k = lo - firstIndex; for (int i = lo; i < hi; ++i) { dest[k] = combiner.combine(array[i], other[i + otherOffset]); ++k; } } Object leafReduce(int lo, int hi, Reducer reducer, Object base) { if (lo >= hi) return base; final Object[] array = pa.array; Object r = array[lo]; for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, array[i]); return r; } void leafStats(int lo, int hi, PAS.FJRStats task) { final Object[] array = pa.array; task.size = hi - lo; for (int i = lo; i < hi; ++i) { Object x = array[i]; task.updateMin(i, x); task.updateMax(i, x); } } } static final class WithBoundedFilter extends WithFilter { final Predicate selector; WithBoundedFilter(ParallelArray pa, int firstIndex, int upperBound, Predicate selector) { super(pa, firstIndex, upperBound); this.selector = selector; } public WithFilter withFilter(Predicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, Ops.andPredicate(this.selector, selector)); } public WithFilter orFilter(Predicate selector) { return new WithBoundedFilter (pa, firstIndex, upperBound, Ops.orPredicate(this.selector, selector)); } public WithMapping withMapping (Mapper mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, mapper); } public WithDoubleMapping withMapping (MapperToDouble mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, mapper); } public WithLongMapping withMapping (MapperToLong mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, mapper); } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJRSelectAny f = new PAS.FJRSelectAny (this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public T any() { int idx = anyIndex(); final Object[] array = pa.array; return (idx < 0)? null : (T)(array[idx]); } public ParallelArray all() { final Object[] array = pa.array; Class elementType = (Class)array.getClass().getComponentType(); PAS.FJRSelectAllDriver r = new PAS.FJRSelectAllDriver (this, elementType); ex.invoke(r); return new ParallelArray(ex, (T[])(r.results)); } public ParallelArray all(Class elementType) { PAS.FJRSelectAllDriver r = new PAS.FJRSelectAllDriver (this, elementType); ex.invoke(r); return new ParallelArray(ex, (T[])(r.results)); } public int size() { PAS.FJRCountSelected f = new PAS.FJRCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public ParallelArray allUniqueElements() { PAS.RUniquifierTable tab = new PAS.RUniquifierTable (upperBound - firstIndex, pa.array, selector, false); PAS.FJUniquifier f = new PAS.FJUniquifier (this, firstIndex, upperBound, null, tab); ex.invoke(f); T[] res = (T[])(tab.uniqueElements(f.count)); return new ParallelArray(ex, res); } public ParallelArray allNonidenticalElements() { PAS.RUniquifierTable tab = new PAS.RUniquifierTable (upperBound - firstIndex, pa.array, selector, true); PAS.FJUniquifier f = new PAS.FJUniquifier (this, firstIndex, upperBound, null, tab); ex.invoke(f); T[] res = (T[])(tab.uniqueElements(f.count)); return new ParallelArray(ex, res); } public void removeAll() { PAS.FJRemoveAllDriver f = new PAS.FJRemoveAllDriver (this, firstIndex, upperBound); ex.invoke(f); pa.removeSlotsAt(f.offset, upperBound); } void leafApply(int lo, int hi, Procedure procedure) { final Predicate sel = selector; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) procedure.apply(x); } } void leafTransform(int lo, int hi, Mapper mapper) { final Predicate sel = selector; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) array[i] = mapper.map(x); } } void leafIndexMap(int lo, int hi, MapperFromInt mapper) { final Predicate sel = selector; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) array[i] = mapper.map(i); } } void leafGenerate(int lo, int hi, Generator generator) { final Predicate sel = selector; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) array[i] = generator.generate(); } } void leafFillValue(int lo, int hi, Object value) { final Predicate sel = selector; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) array[i] = value; } } void leafCombineInPlace(int lo, int hi, Object[] other, int otherOffset, Reducer combiner) { final Predicate sel = selector; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) array[i] = combiner.combine(x, other[i+otherOffset]); } } Object leafReduce(int lo, int hi, Reducer reducer, Object base) { final Predicate sel = selector; boolean gotFirst = false; Object r = base; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) { if (!gotFirst) { gotFirst = true; r = x; } else r = reducer.combine(r, x); } } return r; } void leafStats(int lo, int hi, PAS.FJRStats task) { final Predicate sel = selector; final Object[] array = pa.array; int count = 0; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) { ++count; task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final Predicate sel = selector; final Object[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final Predicate sel = selector; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } static final class WithBoundedMapping extends WithMapping { final Mapper mapper; WithBoundedMapping(ParallelArray pa, int firstIndex, int upperBound, Mapper mapper) { super(pa, firstIndex, upperBound); this.mapper = mapper; } public ParallelArray all() { int n = upperBound - firstIndex; U[] dest = (U[])new Object[n]; PAS.FJRMap f = new PAS.FJRMap (this, firstIndex, upperBound, null, dest, firstIndex); ex.invoke(f); return new ParallelArray(ex, dest); } public ParallelArray all(Class elementType) { int n = upperBound - firstIndex; U[] dest = (U[])Array.newInstance(elementType, n); PAS.FJRMap f = new PAS.FJRMap (this, firstIndex, upperBound, null, dest, 0); ex.invoke(f); return new ParallelArray(ex, dest); } public int size() { return upperBound - firstIndex; } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } public U any() { final Mapper mpr = mapper; final Object[] array = pa.array; return (firstIndex < upperBound)? (U)(mpr.map(array[firstIndex])) : null; } public WithMapping withMapping (Mapper mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithDoubleMapping withMapping (MapperToDouble mapper) { return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping (MapperToLong mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, Procedure procedure) { final Mapper mpr = mapper; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) procedure.apply(mpr.map(array[i])); } Object leafReduce(int lo, int hi, Reducer reducer, Object base) { if (lo >= hi) return base; final Object[] array = pa.array; final Mapper mpr = mapper; Object r = mpr.map(array[lo]); for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, mpr.map(array[i])); return r; } void leafStats(int lo, int hi, PAS.FJRStats task) { final Object[] array = pa.array; final Mapper mpr = mapper; task.size = hi - lo; for (int i = lo; i < hi; ++i) { Object x = mpr.map(array[i]); task.updateMin(i, x); task.updateMax(i, x); } } void leafTransfer(int lo, int hi, Object[] dest, int offset) { final Mapper mpr = mapper; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, Object[] dest, int offset) { final Object[] array = pa.array; final Mapper mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = mpr.map(array[indices[i]]); } } static final class WithBoundedFilteredMapping extends WithMapping { final Predicate selector; final Mapper mapper; WithBoundedFilteredMapping(ParallelArray pa, int firstIndex, int upperBound, Predicate selector, Mapper mapper) { super(pa, firstIndex, upperBound); this.selector = selector; this.mapper = mapper; } public ParallelArray all() { PAS.FJRSelectAllDriver r = new PAS.FJRSelectAllDriver (this, Object.class); ex.invoke(r); return new ParallelArray(ex, (U[])(r.results)); } public ParallelArray all(Class elementType) { PAS.FJRSelectAllDriver r = new PAS.FJRSelectAllDriver (this, elementType); ex.invoke(r); return new ParallelArray(ex, (U[])(r.results)); } public int size() { PAS.FJRCountSelected f = new PAS.FJRCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJRSelectAny f = new PAS.FJRSelectAny (this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public U any() { int idx = anyIndex(); final Object[] array = pa.array; final Mapper mpr = mapper; return (idx < 0)? null : (U)(mpr.map(array[idx])); } public WithMapping withMapping (Mapper mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithDoubleMapping withMapping (MapperToDouble mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping (MapperToLong mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, Procedure procedure) { final Predicate sel = selector; final Object[] array = pa.array; final Mapper mpr = mapper; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) procedure.apply(mpr.map(x)); } } Object leafReduce(int lo, int hi, Reducer reducer, Object base) { final Predicate sel = selector; final Object[] array = pa.array; final Mapper mpr = mapper; boolean gotFirst = false; Object r = base; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) { Object y = mpr.map(x); if (!gotFirst) { gotFirst = true; r = y; } else r = reducer.combine(r, y); } } return r; } void leafStats(int lo, int hi, PAS.FJRStats task) { final Predicate sel = selector; final Object[] array = pa.array; final Mapper mpr = mapper; int count = 0; for (int i = lo; i < hi; ++i) { Object t = array[i]; if (sel.evaluate(t)) { ++count; Object x = mpr.map(t); task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } void leafTransfer(int lo, int hi, Object[] dest, int offset) { final Object[] array = pa.array; final Mapper mpr = mapper; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, Object[] dest, int offset) { final Object[] array = pa.array; final Mapper mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = mpr.map(array[indices[i]]); } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final Predicate sel = selector; final Object[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final Predicate sel = selector; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } /** * A modifier for parallel array operations to apply to mappings * of elements to doubles, not to the elements themselves */ public static abstract class WithDoubleMapping extends PAS.RPrefix { final MapperToDouble mapper; WithDoubleMapping(ParallelArray pa, int firstIndex, int upperBound, MapperToDouble mapper) { super(pa, firstIndex, upperBound); this.mapper = mapper; } /** * Applies the given procedure * @param procedure the procedure */ public void apply(DoubleProcedure procedure) { ex.invoke(new PAS.FJDApply (this, firstIndex, upperBound, null, procedure)); } /** * Returns reduction of mapped elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public double reduce(DoubleReducer reducer, double base) { PAS.FJDReduce f = new PAS.FJDReduce (this, firstIndex, upperBound, null, reducer, base); ex.invoke(f); return f.result; } /** * Returns the minimum element, or Double.MAX_VALUE if empty * @return minimum element, or Double.MAX_VALUE if empty */ public double min() { return reduce(naturalDoubleMinReducer(), Double.MAX_VALUE); } /** * Returns the minimum element, or Double.MAX_VALUE if empty * @param comparator the comparator * @return minimum element, or Double.MAX_VALUE if empty */ public double min(DoubleComparator comparator) { return reduce(doubleMinReducer(comparator), Double.MAX_VALUE); } /** * Returns the maximum element, or -Double.MAX_VALUE if empty * @return maximum element, or -Double.MAX_VALUE if empty */ public double max() { return reduce(naturalDoubleMaxReducer(), -Double.MAX_VALUE); } /** * Returns the maximum element, or -Double.MAX_VALUE if empty * @param comparator the comparator * @return maximum element, or -Double.MAX_VALUE if empty */ public double max(DoubleComparator comparator) { return reduce(doubleMaxReducer(comparator), -Double.MAX_VALUE); } /** * Returns the sum of elements * @return the sum of elements */ public double sum() { return reduce(Ops.doubleAdder(), 0.0); } /** * Returns summary statistics * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelDoubleArray.SummaryStatistics summary (DoubleComparator comparator) { PAS.FJDStats f = new PAS.FJDStats (this, firstIndex, upperBound, null, comparator); ex.invoke(f); return f; } /** * Returns summary statistics, using natural comparator * @return the summary. */ public ParallelDoubleArray.SummaryStatistics summary() { PAS.FJDStats f = new PAS.FJDStats (this, firstIndex, upperBound, null, naturalDoubleComparator()); ex.invoke(f); return f; } /** * Returns a new ParallelDoubleArray holding mappings * @return a new ParallelDoubleArray holding mappings */ public abstract ParallelDoubleArray all(); /** * Return the number of elements selected using bound or * filter restrictions. Note that this method must evaluate * all selectors to return its result. * @return the number of elements */ public abstract int size(); /** * Returns the index of some element matching bound and filter * constraints, or -1 if none. * @return index of matching element, or -1 if none. */ public abstract int anyIndex(); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithDoubleMapping withMapping (DoubleMapper mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithLongMapping withMapping (MapperFromDoubleToLong mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithMapping withMapping (MapperFromDouble mapper); final void leafTransfer(int lo, int hi, double[] dest, int offset) { final MapperToDouble mpr = mapper; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, double[] dest, int offset) { final Object[] array = pa.array; final MapperToDouble mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = mpr.map(array[indices[i]]); } } static final class WithBoundedDoubleMapping extends WithDoubleMapping { WithBoundedDoubleMapping(ParallelArray pa, int firstIndex, int upperBound, MapperToDouble mapper) { super(pa, firstIndex, upperBound, mapper); } public ParallelDoubleArray all() { double[] dest = new double[upperBound - firstIndex]; PAS.FJDMap f = new PAS.FJDMap (this, firstIndex, upperBound, null, dest, firstIndex); ex.invoke(f); return new ParallelDoubleArray(ex, dest); } public int size() { return upperBound - firstIndex; } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } public WithDoubleMapping withMapping (DoubleMapper mapper) { return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping (MapperFromDoubleToLong mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromDouble mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, DoubleProcedure procedure) { final MapperToDouble mpr = mapper; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) procedure.apply(mpr.map(array[i])); } double leafReduce(int lo, int hi, DoubleReducer reducer, double base) { if (lo >= hi) return base; final Object[] array = pa.array; final MapperToDouble mpr = mapper; double r = mpr.map(array[lo]); for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, mpr.map(array[i])); return r; } void leafStats(int lo, int hi, PAS.FJDStats task) { final Object[] array = pa.array; final MapperToDouble mpr = mapper; task.size = hi - lo; for (int i = lo; i < hi; ++i) { double x = mpr.map(array[i]); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } } static final class WithBoundedFilteredDoubleMapping extends WithDoubleMapping { final Predicate selector; WithBoundedFilteredDoubleMapping (ParallelArray pa, int firstIndex, int upperBound, Predicate selector, MapperToDouble mapper) { super(pa, firstIndex, upperBound, mapper); this.selector = selector; } public ParallelDoubleArray all() { PAS.FJDSelectAllDriver r = new PAS.FJDSelectAllDriver(this); ex.invoke(r); return new ParallelDoubleArray(ex, r.results); } public int size() { PAS.FJRCountSelected f = new PAS.FJRCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJRSelectAny f = new PAS.FJRSelectAny (this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public WithDoubleMapping withMapping (DoubleMapper mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping (MapperFromDoubleToLong mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromDouble mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, DoubleProcedure procedure) { final Predicate sel = selector; final Object[] array = pa.array; final MapperToDouble mpr = mapper; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) procedure.apply(mpr.map(x)); } } double leafReduce(int lo, int hi, DoubleReducer reducer, double base) { final Predicate sel = selector; final MapperToDouble mpr = mapper; boolean gotFirst = false; double r = base; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object t = array[i]; if (sel.evaluate(t)) { double y = mpr.map(t); if (!gotFirst) { gotFirst = true; r = y; } else r = reducer.combine(r, y); } } return r; } void leafStats(int lo, int hi, PAS.FJDStats task) { final Predicate sel = selector; final Object[] array = pa.array; final MapperToDouble mpr = mapper; int count = 0; for (int i = lo; i < hi; ++i) { Object t = array[i]; if (sel.evaluate(t)) { ++count; double x = mpr.map(t); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final Predicate sel = selector; final Object[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final Predicate sel = selector; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } /** * A modifier for parallel array operations to apply to mappings * of elements to longs, not to the elements themselves */ public static abstract class WithLongMapping extends PAS.RPrefix { final MapperToLong mapper; WithLongMapping(ParallelArray pa, int firstIndex, int upperBound, final MapperToLong mapper) { super(pa, firstIndex, upperBound); this.mapper = mapper; } /** * Applies the given procedure * @param procedure the procedure */ public void apply(LongProcedure procedure) { ex.invoke(new PAS.FJLApply (this, firstIndex, upperBound, null, procedure)); } /** * Returns reduction of mapped elements * @param reducer the reducer * @param base the result for an empty array * @return reduction */ public long reduce(LongReducer reducer, long base) { PAS.FJLReduce f = new PAS.FJLReduce (this, firstIndex, upperBound, null, reducer, base); ex.invoke(f); return f.result; } /** * Returns the minimum element, or Long.MAX_VALUE if empty * @return minimum element, or Long.MAX_VALUE if empty */ public long min() { return reduce(naturalLongMinReducer(), Long.MAX_VALUE); } /** * Returns the minimum element, or Long.MAX_VALUE if empty * @param comparator the comparator * @return minimum element, or Long.MAX_VALUE if empty */ public long min(LongComparator comparator) { return reduce(longMinReducer(comparator), Long.MAX_VALUE); } /** * Returns the maximum element, or Long.MIN_VALUE if empty * @return maximum element, or Long.MIN_VALUE if empty */ public long max() { return reduce(naturalLongMaxReducer(), Long.MIN_VALUE); } /** * Returns the maximum element, or Long.MIN_VALUE if empty * @param comparator the comparator * @return maximum element, or Long.MIN_VALUE if empty */ public long max(LongComparator comparator) { return reduce(longMaxReducer(comparator), Long.MIN_VALUE); } /** * Returns the sum of elements * @return the sum of elements */ public long sum() { return reduce(Ops.longAdder(), 0L); } /** * Returns summary statistics * @param comparator the comparator to use for * locating minimum and maximum elements * @return the summary. */ public ParallelLongArray.SummaryStatistics summary (LongComparator comparator) { PAS.FJLStats f = new PAS.FJLStats (this, firstIndex, upperBound, null, comparator); ex.invoke(f); return f; } /** * Returns summary statistics, using natural comparator * @return the summary. */ public ParallelLongArray.SummaryStatistics summary() { PAS.FJLStats f = new PAS.FJLStats (this, firstIndex, upperBound, null, naturalLongComparator()); ex.invoke(f); return f; } /** * Returns a new ParallelLongArray holding mappings * @return a new ParallelLongArray holding mappings */ public abstract ParallelLongArray all(); /** * Return the number of elements selected using bound or * filter restrictions. Note that this method must evaluate * all selectors to return its result. * @return the number of elements */ public abstract int size(); /** * Returns the index of some element matching bound and filter * constraints, or -1 if none. * @return index of matching element, or -1 if none. */ public abstract int anyIndex(); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithDoubleMapping withMapping (MapperFromLongToDouble mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithLongMapping withMapping (LongMapper mapper); /** * Returns an operation prefix that causes a method to operate * on mapped elements of the array using the given mapper. * @param mapper the mapper * @return operation prefix */ public abstract WithMapping withMapping (MapperFromLong mapper); final void leafTransfer(int lo, int hi, long[] dest, int offset) { final MapperToLong mpr = mapper; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) dest[offset++] = mpr.map(array[i]); } final void leafTransferByIndex(int[] indices, int loIdx, int hiIdx, long[] dest, int offset) { final Object[] array = pa.array; final MapperToLong mpr = mapper; for (int i = loIdx; i < hiIdx; ++i) dest[offset++] = mpr.map(array[indices[i]]); } } static final class WithBoundedLongMapping extends WithLongMapping { WithBoundedLongMapping(ParallelArray pa, int firstIndex, int upperBound, MapperToLong mapper) { super(pa, firstIndex, upperBound, mapper); } public ParallelLongArray all() { long[] dest = new long[upperBound - firstIndex]; PAS.FJLMap f = new PAS.FJLMap (this, firstIndex, upperBound, null, dest, firstIndex); ex.invoke(f); return new ParallelLongArray(ex, dest); } public int size() { return upperBound - firstIndex; } public int anyIndex() { return (firstIndex < upperBound)? firstIndex : -1; } public WithDoubleMapping withMapping (MapperFromLongToDouble mapper) { return new WithBoundedDoubleMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping (LongMapper mapper) { return new WithBoundedLongMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromLong mapper) { return new WithBoundedMapping (pa, firstIndex, upperBound, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, LongProcedure procedure) { final Object[] array = pa.array; final MapperToLong mpr = mapper; for (int i = lo; i < hi; ++i) procedure.apply(mpr.map(array[i])); } long leafReduce(int lo, int hi, LongReducer reducer, long base) { if (lo >= hi) return base; final Object[] array = pa.array; final MapperToLong mpr = mapper; long r = mpr.map(array[lo]); for (int i = lo+1; i < hi; ++i) r = reducer.combine(r, mpr.map(array[i])); return r; } void leafStats(int lo, int hi, PAS.FJLStats task) { final Object[] array = pa.array; final MapperToLong mpr = mapper; task.size = hi - lo; for (int i = lo; i < hi; ++i) { long x = mpr.map(array[i]); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } } static final class WithBoundedFilteredLongMapping extends WithLongMapping { final Predicate selector; WithBoundedFilteredLongMapping (ParallelArray pa, int firstIndex, int upperBound, Predicate selector, MapperToLong mapper) { super(pa, firstIndex, upperBound, mapper); this.selector = selector; } public ParallelLongArray all() { PAS.FJLSelectAllDriver r = new PAS.FJLSelectAllDriver(this); ex.invoke(r); return new ParallelLongArray(ex, r.results); } public int size() { PAS.FJRCountSelected f = new PAS.FJRCountSelected (this, firstIndex, upperBound, null, selector); ex.invoke(f); return f.count; } public int anyIndex() { AtomicInteger result = new AtomicInteger(-1); PAS.FJRSelectAny f = new PAS.FJRSelectAny (this, firstIndex, upperBound, null, result, selector); ex.invoke(f); return result.get(); } public WithDoubleMapping withMapping (MapperFromLongToDouble mapper) { return new WithBoundedFilteredDoubleMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithLongMapping withMapping (LongMapper mapper) { return new WithBoundedFilteredLongMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } public WithMapping withMapping (MapperFromLong mapper) { return new WithBoundedFilteredMapping (pa, firstIndex, upperBound, selector, Ops.compoundMapper(this.mapper, mapper)); } void leafApply(int lo, int hi, LongProcedure procedure) { final Predicate sel = selector; final Object[] array = pa.array; final MapperToLong mpr = mapper; for (int i = lo; i < hi; ++i) { Object x = array[i]; if (sel.evaluate(x)) procedure.apply(mpr.map(x)); } } long leafReduce(int lo, int hi, LongReducer reducer, long base) { final Predicate sel = selector; final MapperToLong mpr = mapper; boolean gotFirst = false; long r = base; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object t = array[i]; if (sel.evaluate(t)) { long y = mpr.map(t); if (!gotFirst) { gotFirst = true; r = y; } else r = reducer.combine(r, y); } } return r; } void leafStats(int lo, int hi, PAS.FJLStats task) { final Predicate sel = selector; final Object[] array = pa.array; final MapperToLong mpr = mapper; int count = 0; for (int i = lo; i < hi; ++i) { Object t = array[i]; if (sel.evaluate(t)) { ++count; long x = mpr.map(t); task.sum += x; task.updateMin(i, x); task.updateMax(i, x); } } task.size = count; } int leafIndexSelected(int lo, int hi, boolean positive, int[] indices){ final Predicate sel = selector; final Object[] array = pa.array; int k = 0; for (int i = lo; i < hi; ++i) { if (sel.evaluate(array[i]) == positive) indices[lo + k++] = i; } return k; } int leafMoveSelected(int lo, int hi, int offset, boolean positive) { final Predicate sel = selector; final Object[] array = pa.array; for (int i = lo; i < hi; ++i) { Object t = array[i]; if (sel.evaluate(t) == positive) array[offset++] = t; } return offset; } } /** * Returns an iterator stepping through each element of the array * up to the current limit. This iterator does not * support the remove operation. However, a full * ListIterator supporting add, remove, and set * operations is available via {@link #asList}. * @return an iterator stepping through each element. */ public Iterator iterator() { return new ParallelArrayIterator(array, limit); } static final class ParallelArrayIterator implements Iterator { int cursor; final T[] arr; final int hi; ParallelArrayIterator(T[] a, int limit) { arr = a; hi = limit; } public boolean hasNext() { return cursor < hi; } public T next() { if (cursor >= hi) throw new NoSuchElementException(); return arr[cursor++]; } public void remove() { throw new UnsupportedOperationException(); } } // List support /** * Returns a view of this ParallelArray as a List. This List has * the same structural and performance characteristics as {@link * ArrayList}, and may be used to modify, replace or extend the * bounds of the array underlying this ParallelArray. The methods * supported by this list view are not in general * implemented as parallel operations. This list is also not * itself thread-safe. In particular, performing list updates * while other parallel operations are in progress has undefined * (and surely undesired) effects. * @return a list view */ public List asList() { AsList lv = listView; if (lv == null) listView = lv = new AsList(); return lv; } /** * Returns the effective size of the underlying array. The * effective size is the current limit, if used (see {@link * #setLimit}), or the length of the array otherwise. * @return the effective size of array */ public int size() { return limit; } /** * Returns the element of the array at the given index * @param i the index * @return the element of the array at the given index */ public T get(int i) { return array[i]; } /** * Sets the element of the array at the given index to the given value * @param i the index * @param x the value */ public void set(int i, T x) { array[i] = x; } /** * Returns the underlying array used for computations * @return the array */ public T[] getArray() { return array; } /** * Equivalent to asList().toString() * @return a string representation */ public String toString() { return asList().toString(); } /** * Equivalent to AsList.addAll but specialized for array * arguments and likely to be more efficient. * @param other the elements to add */ public void addAll(T[] other) { int csize = other.length; int end = limit; insertSlotsAt(end, csize); System.arraycopy(other, 0, array, end, csize); } /** * Equivalent to AsList.addAll but specialized for * ParallelArray arguments and likely to be more efficient. * @param other the elements to add */ public void addAll(ParallelArray other) { int csize = other.size(); int end = limit; insertSlotsAt(end, csize); System.arraycopy(other.array, 0, array, end, csize); } /** * Equivalent to AsList.addAll but specialized for * ParallelArray arguments and likely to be more efficient. * @param other the elements to add */ public void addAll(ParallelArray.WithBounds other) { int csize = other.size(); int end = limit; insertSlotsAt(end, csize); System.arraycopy(other.pa.array, other.firstIndex, array, end, csize); } /** * Ensures that the underlying array can be accessed up to the * given upper bound, reallocating and copying the underlying * array to expand if necessary. Or, if the given limit is less * than the length of the underlying array, causes computations to * ignore elements past the given limit. * @param newLimit the new upper bound * @throws IllegalArgumentException if newLimit less than zero. */ public final void setLimit(int newLimit) { if (newLimit < 0) throw new IllegalArgumentException(); int cap = array.length; if (newLimit > cap) resizeArray(newLimit); limit = newLimit; } final void replaceElementsWith(T[] a) { System.arraycopy(a, 0, array, 0, a.length); limit = a.length; } final void resizeArray(int newCap) { int cap = array.length; if (newCap > cap) { Class elementType = array.getClass().getComponentType(); T[] a =(T[])Array.newInstance(elementType, newCap); System.arraycopy(array, 0, a, 0, cap); array = a; } } final void insertElementAt(int index, T e) { int hi = limit++; if (hi >= array.length) resizeArray((hi * 3)/2 + 1); if (hi > index) System.arraycopy(array, index, array, index+1, hi - index); array[index] = e; } final void appendElement(T e) { int hi = limit++; if (hi >= array.length) resizeArray((hi * 3)/2 + 1); array[hi] = e; } /** * Make len slots available at index */ final void insertSlotsAt(int index, int len) { if (len <= 0) return; int cap = array.length; int newSize = limit + len; if (cap < newSize) { cap = (cap * 3)/2 + 1; if (cap < newSize) cap = newSize; resizeArray(cap); } if (index < limit) System.arraycopy(array, index, array, index + len, limit - index); limit = newSize; } final void removeSlotAt(int index) { System.arraycopy(array, index + 1, array, index, limit - index - 1); array[--limit] = null; } final void removeSlotsAt(int fromIndex, int toIndex) { if (fromIndex < toIndex) { int size = limit; System.arraycopy(array, toIndex, array, fromIndex, size - toIndex); int newSize = size - (toIndex - fromIndex); limit = newSize; while (size > newSize) array[--size] = null; } } final int seqIndexOf(Object target) { T[] arr = array; int fence = limit; if (target == null) { for (int i = 0; i < fence; i++) if (arr[i] == null) return i; } else { for (int i = 0; i < fence; i++) if (target.equals(arr[i])) return i; } return -1; } final int seqLastIndexOf(Object target) { T[] arr = array; int last = limit - 1; if (target == null) { for (int i = last; i >= 0; i--) if (arr[i] == null) return i; } else { for (int i = last; i >= 0; i--) if (target.equals(arr[i])) return i; } return -1; } final class ListIter implements ListIterator { int cursor; int lastRet; T[] arr; // cache array and bound int hi; ListIter(int lo) { this.cursor = lo; this.lastRet = -1; this.arr = ParallelArray.this.array; this.hi = ParallelArray.this.limit; } public boolean hasNext() { return cursor < hi; } public T next() { int i = cursor; if (i < 0 || i >= hi) throw new NoSuchElementException(); T next = arr[i]; lastRet = i; cursor = i + 1; return next; } public void remove() { int k = lastRet; if (k < 0) throw new IllegalStateException(); ParallelArray.this.removeSlotAt(k); hi = ParallelArray.this.limit; if (lastRet < cursor) cursor--; lastRet = -1; } public boolean hasPrevious() { return cursor > 0; } public T previous() { int i = cursor - 1; if (i < 0 || i >= hi) throw new NoSuchElementException(); T previous = arr[i]; lastRet = cursor = i; return previous; } public int nextIndex() { return cursor; } public int previousIndex() { return cursor - 1; } public void set(T e) { int i = lastRet; if (i < 0 || i >= hi) throw new NoSuchElementException(); arr[i] = e; } public void add(T e) { int i = cursor; ParallelArray.this.insertElementAt(i, e); arr = ParallelArray.this.array; hi = ParallelArray.this.limit; lastRet = -1; cursor = i + 1; } } final class AsList extends AbstractList implements RandomAccess { public T get(int i) { if (i >= limit) throw new IndexOutOfBoundsException(); return array[i]; } public T set(int i, T x) { if (i >= limit) throw new IndexOutOfBoundsException(); T[] arr = array; T t = arr[i]; arr[i] = x; return t; } public boolean isEmpty() { return limit == 0; } public int size() { return limit; } public Iterator iterator() { return new ListIter(0); } public ListIterator listIterator() { return new ListIter(0); } public ListIterator listIterator(int index) { if (index < 0 || index > limit) throw new IndexOutOfBoundsException(); return new ListIter(index); } public boolean add(T e) { appendElement(e); return true; } public void add(int index, T e) { if (index < 0 || index > limit) throw new IndexOutOfBoundsException(); insertElementAt(index, e); } public boolean addAll(Collection c) { int csize = c.size(); if (csize == 0) return false; int hi = limit; setLimit(hi + csize); T[] arr = array; for (T e : c) arr[hi++] = e; return true; } public boolean addAll(int index, Collection c) { if (index < 0 || index > limit) throw new IndexOutOfBoundsException(); int csize = c.size(); if (csize == 0) return false; insertSlotsAt(index, csize); T[] arr = array; for (T e : c) arr[index++] = e; return true; } public void clear() { T[] arr = array; for (int i = 0; i < limit; ++i) arr[i] = null; limit = 0; } public boolean remove(Object o) { int idx = seqIndexOf(o); if (idx < 0) return false; removeSlotAt(idx); return true; } public T remove(int index) { T oldValue = get(index); removeSlotAt(index); return oldValue; } protected void removeRange(int fromIndex, int toIndex) { removeSlotsAt(fromIndex, toIndex); } public boolean contains(Object o) { return seqIndexOf(o) >= 0; } public int indexOf(Object o) { return seqIndexOf(o); } public int lastIndexOf(Object o) { return seqLastIndexOf(o); } public Object[] toArray() { int len = limit; Object[] a = new Object[len]; System.arraycopy(array, 0, a, 0, len); return a; } public V[] toArray(V a[]) { int len = limit; if (a.length < len) { Class elementType = a.getClass().getComponentType(); a =(V[])Array.newInstance(elementType, len); } System.arraycopy(array, 0, a, 0, len); if (a.length > len) a[len] = null; return a; } } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/CyclicAction.java0000644000000000000000000000716210735315511023650 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; /** * A computation that is broken into a series of task executions, each * separated by a TaskBarrier arrival. Concrete subclasses must * define method compute, that performs the action occurring * at each step of the barrier. Upon invocation of this task, the * compute method is repeatedly invoked until the barrier * isTerminated or until its execution throws an exception. * *

Sample Usage. Here is a sketch of a set of CyclicActions * that each perform 500 iterations of an imagined image smoothing * operation. Note that the aggregate ImageSmoother task itself is not * a CyclicTask. * *

 * class ImageSmoother extends RecursiveAction {
 *   protected void compute() {
 *     TaskBarrier b = new TaskBarrier() {
 *       protected boolean terminate(int cycle, int registeredParties) {
 *          return registeredParties <= 0 || cycle >= 500;
 *       }
 *     }
 *     int n = pool.getPoolSize();
 *     CyclicAction[] actions = new CyclicAction[n];
 *     for (int i = 0; i < n; ++i) {
 *       action[i] = new CyclicAction(b) {
 *         protected void compute() {
 *           smoothImagePart(i);
 *         }
 *       }
 *     }
 *     for (int i = 0; i < n; ++i) 
 *       actions[i].fork();
 *     for (int i = 0; i < n; ++i) 
 *       actions[i].join();
 *   }
 * }
 * 
*/ public abstract class CyclicAction extends ForkJoinTask { final TaskBarrier barrier; int phase = -1; /** * Constructs a new CyclicAction using the supplied barrier, * registering for this barrier upon construction. * @param barrier the barrier */ public CyclicAction(TaskBarrier barrier) { this.barrier = barrier; barrier.register(); } /** * The computation performed by this task on each cycle of the * barrier. While you must define this method, you should not in * general call it directly. */ protected abstract void compute(); /** * Returns the barrier */ public final TaskBarrier getBarrier() { return barrier; } /** * Returns the current cycle of the barrier */ public final int getCycle() { return barrier.getCycle(); } /** * Always returns null. * @return null */ public final Void rawResult() { return null; } public final Throwable exec() { TaskBarrier b = barrier; if (isDone()) { b.arriveAndDeregister(); return getException(); } if (phase < 0) phase = b.getCycle(); else phase = b.awaitCycleAdvance(phase); if (phase < 0) return setDone(); try { compute(); } catch (Throwable rex) { b.arriveAndDeregister(); return setDoneExceptionally(rex); } b.arrive(); this.fork(); return null; } public final Void forkJoin() { exec(); return join(); } /** * Equivalent to finish(null). */ public final void finish() { setDone(); } public final void finish(Void result) { setDone(); } public final void finishExceptionally(Throwable ex) { setDoneExceptionally(ex); } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/ForkJoinWorkerThread.java0000644000000000000000000010565510735315511025355 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import sun.misc.Unsafe; import java.lang.reflect.*; /** * A thread that is internally managed by a ForkJoinPool to execute * ForkJoinTasks. This class additionally provides public * static methods accessing some basic scheduling and * execution mechanics for the current * ForkJoinWorkerThread. These methods may be invoked only from within * other ForkJoinTask computations. Attempts to invoke in other * contexts result in exceptions or errors including * ClassCastException. These methods enable construction of * special-purpose task classes, as well as specialized idioms * occasionally useful in ForkJoinTask processing. * *

The form of supported static methods reflects the fact that * worker threads may access and process tasks obtained in any of * three ways. In preference order: Local tasks are processed * in LIFO (newest first) order. Stolen tasks are obtained * from other threads in FIFO (oldest first) order, only if there are * no local tasks to run. Submissions form a FIFO queue * common to the entire pool, and are started only if no other * work is available. * *

This class is subclassable solely for the sake of adding * functionality -- there are no overridable methods dealing with * scheduling or execution. However, you can override initialization * and termination cleanup methods surrounding the main task * processing loop. If you do create such a subclass, you will also * need to supply a custom ForkJoinWorkerThreadFactory to use it in a * ForkJoinPool. * */ public class ForkJoinWorkerThread extends Thread { /** * The pool this thread works in. */ final ForkJoinPool pool; /** * Pool-wide sync barrier, cached from pool upon construction */ private final PoolBarrier poolBarrier; /** * Pool-wide count of active workers, cached from pool upon * construction */ private final AtomicInteger activeWorkerCounter; /** * Run state of this worker, set only by pool (except for termination) */ private final RunState runState; /** * Each thread's work-stealing queue is represented via the * resizable "queue" array plus base and sp indices. * Work-stealing queues are special forms of Deques that support * only three of the four possible end-operations -- push, pop, * and steal (aka dequeue), and only do so under the constraints * that push and pop are called only from the owning thread, while * steal may be called from other threads. The work-stealing * queue here uses a variant of the algorithm described in * "Dynamic Circular Work-Stealing Deque" by David Chase and Yossi * Lev, SPAA 2005. For an explanation, read the paper. * (http://research.sun.com/scalable/pubs/index.html). The main * differences here stem from ensuring that queue slots * referencing popped and stolen tasks are cleared, as well as * spin/wait control. (Also. method and variable names differ.) * * The length of the queue array must always be a power of * two. Even though these queues don't usually become all that * big, the initial size must be large enough to counteract cache * contention effects across multiple queues. Currently, they are * initialized upon construction. However, all queue-related * methods except pushTask are written in a way that allows them * to instead be lazily allocated and/or disposed of when empty. */ private ForkJoinTask[] queue; private static final int INITIAL_CAPACITY = 1 << 13; private static final int MAXIMUM_CAPACITY = 1 << 30; /** * Index (mod queue.length) of least valid queue slot, which is * always the next position to steal from if nonempty. Updated * only via casBase(). */ private volatile long base; /** * Index (mod queue.length-1) of next queue slot to push to * or pop from */ private volatile long sp; /** * Number of steals, just for monitoring purposes, */ private volatile long fullStealCount; /** * The last event count waited for */ private long eventCount; /** * Number of steals, transferred to fullStealCount at syncs */ private int stealCount; /** * Cached from pool */ private int poolSize; /** * Index of this worker in pool array. Set once by pool before running. */ private int poolIndex; /** * Seed for random number generator for choosing steal victims */ private int randomVictimSeed; /** * Number of scans (calls to getTask() or variants) since last * successfully getting a task. Always zero (== "active" status) * when busy executing tasks. Incremented after a failed scan to * help control spins and maintain active worker count. On * transition from or to sero, the pool's activeWorkerCounter must * be adjusted. Must be zero when executing tasks, and BEFORE * stealing a submission. To avoid continual flickering and * contention, this is done only if worker queues appear to be * non-empty. */ private int scans; /** * Seed for juRandom. Kept with worker fields to minimize * cacheline sharing */ long juRandomSeed; /** * Exported random numbers */ final JURandom juRandom; // Transient state indicators, used as argument, not field values. /** * Signifies that the current thread is not currently executing * any task. Used only from mainLoop. */ private static final int IDLING = 0; /** * Signifies that the current thread is helping while waiting for * another task to be joined. */ private static final int JOINING = 1; /** * Signifies that the current thread is willing to run a task, but * cannot block if none are available. */ private static final int POLLING = 2; /** * Threshold for checking with PoolBarrier and possibly blocking * when idling threads cannot find work. This value must be at * least 3 for scan control logic to work. * * Scans for work (see getTask()) are nearly read-only, and likely * to be much faster than context switches that may occur within * syncs. So there's no reason to make this value especially * small. On the other hand, useless scans waste CPU time, and * syncs may help wake up other threads that may allow further * progress. So the value should not be especially large either. */ private static final int IDLING_SCANS_PER_SYNC = 32; /** * Threshold for checking with PoolBarrier and possibly blocking * when joining threads cannot find work. This value must be at * least IDLING_SCANS_PER_SYNC. * * Unlike idling threads, joining threads "know" that they will be * able to continue at some point. However, we still force them to * sometimes sync to reduce wasted CPU time in the face of * programmer errors as well as to cope better when some worker * threads are making very slow progress. */ private static final int JOINING_SCANS_PER_SYNC = 1024; /** * Generator for per-thread randomVictimSeeds */ private static final Random randomSeedGenerator = new Random(); // Methods called only by pool final void setWorkerPoolIndex(int i) { poolIndex = i; } final int getWorkerPoolIndex() { return poolIndex; } final void setPoolSize(int ps) { poolSize = ps; } final long getWorkerStealCount() { return fullStealCount; } final RunState getRunState() { return runState; } final int getQueueSize() { long n = sp - base; return n < 0? 0 : (int)n; // suppress momentarily negative values } /** * Reports true if this thread has no tasks and has unsuccessfully * tried to obtain a task to run. */ final boolean workerIsIdle() { return base >= sp && scans != 0; // ensure volatile read first } // Construction and lifecycle methods /** * Creates a ForkJoinWorkerThread operating in the given pool. * @param pool the pool this thread works in * @throws NullPointerException if pool is null; */ protected ForkJoinWorkerThread(ForkJoinPool pool) { if (pool == null) throw new NullPointerException(); this.pool = pool; this.activeWorkerCounter = pool.getActiveWorkerCounter(); this.poolBarrier = pool.getPoolBarrier(); this.poolSize = pool.getPoolSize(); this.juRandomSeed = randomSeedGenerator.nextLong(); int rseed = randomSeedGenerator.nextInt(); this.randomVictimSeed = (rseed == 0)? 1 : rseed; // must be nonzero this.juRandom = new JURandom(); this.runState = new RunState(); this.queue = new ForkJoinTask[INITIAL_CAPACITY]; } /** * This method is required to be public, but should never be * called explicitly. It executes the main run loop to execute * ForkJoinTasks. */ public void run() { Throwable exception = null; try { onStart(); while (runState.isRunning()) { ForkJoinTask t = getTask(); if (t == null) onEmptyScan(IDLING); else t.exec(); } clearLocalTasks(); } catch (Throwable ex) { exception = ex; } finally { onTermination(exception); } } /** * Initializes internal state after construction but before * processing any tasks. If you override this method, you must * invoke super.onStart() at the beginning of the method. * Initialization requires care: Most fields must have legal * default values, to ensure that attempted accesses from other * threads work correctly even before this thread starts * processing tasks. */ protected void onStart() { } /** * Perform cleanup associated with termination of this worker * thread. If you override this method, you must invoke * super.onTermination at the end of the overridden method. * * @param exception the exception causing this thread to abort due * to an unrecoverable error, or null if completed normally. */ protected void onTermination(Throwable exception) { try { if (scans == 0) { scans = 1; activeWorkerCounter.decrementAndGet(); } cancelTasks(); runState.transitionToTerminated(); } finally { pool.workerTerminated(this, exception); } } /** * Primary method for getting a task to run. Tries local, then * stolen, then submitted tasks. * @return a task or null if none */ private ForkJoinTask getTask() { ForkJoinTask popped, stolen; if ((popped = popTask()) != null) return popped; else if ((stolen = getStolenTask()) != null) return stolen; else return getSubmission(); } /** * Actions to take on failed getTask, depending on calling * context. * @param context: IDLING, JOINING, or POLLING */ private void onEmptyScan(int context) { int s = scans; if (s == 0) { // inactivate scans = 1; activeWorkerCounter.decrementAndGet(); } else if (s <= IDLING_SCANS_PER_SYNC || (s <= JOINING_SCANS_PER_SYNC && context == JOINING)) scans = s + 1; else { scans = 1; // reset scans to 1 (not 0) on resumption // transfer steal counts so pool can read int sc = stealCount; if (sc != 0) { stealCount = 0; if (sc < 0) sc = Integer.MAX_VALUE; // wraparound fullStealCount += sc; } if (runState.isAtLeastStopping()) { // abort if joining; else return so caller can check state if (context == JOINING) throw new CancellationException(); } else if (context == POLLING) Thread.yield(); else eventCount = poolBarrier.sync(this, eventCount); } } // Main work-stealing queue methods /* * Resizes queue */ private void growQueue() { ForkJoinTask[] oldQ = queue; int oldSize = oldQ.length; int newSize = oldSize << 1; if (newSize > MAXIMUM_CAPACITY) throw new RejectedExecutionException("Queue capacity exceeded"); ForkJoinTask[] newQ = new ForkJoinTask[newSize]; int oldMask = oldSize - 1; int newMask = newSize - 1; long s = sp; for (long i = base; i < s; ++i) newQ[((int)i) & newMask] = oldQ[((int)i) & oldMask]; sp = s; // need volatile write here just to force ordering queue = newQ; } /** * Pushes a task. Also wakes up other workers if queue was * previously empty. Called only by current thread. * @param x the task */ final void pushTask(ForkJoinTask x) { long s = sp; ForkJoinTask[] q = queue; int mask = q.length - 1; q[((int)s) & mask] = x; sp = s + 1; if ((s -= base) >= mask - 1) growQueue(); else if (s <= 0) poolBarrier.signal(); } /** * Returns a popped task, or null if empty. Called only by * current thread. */ private ForkJoinTask popTask() { ForkJoinTask x = null; long s = sp - 1; ForkJoinTask[] q = queue; if (q != null) { int idx = ((int)s) & (q.length-1); x = q[idx]; sp = s; q[idx] = null; long b = base; if (s <= b) { if (s < b || !casBase(b, ++b)) // note ++b side effect x = null; // lost race vs steal sp = b; } } return x; } /** * Specialized version of popTask to pop only if * topmost element is the given task. * @param task the task to match, null OK (but never matched) */ private boolean popIfNext(ForkJoinTask task) { if (task != null) { long s = sp - 1; ForkJoinTask[] q = queue; if (q != null) { int idx = ((int)s) & (q.length-1); if (q[idx] == task) { sp = s; q[idx] = null; long b = base; if (s > b) return true; if (s == b && casBase(b, ++b)) { sp = b; return true; } sp = b; } } } return false; } /** * Tries to take a task from the base of the queue. Returns null * upon contention. * @return a task, or null if none */ private ForkJoinTask tryStealTask() { ForkJoinTask[] q; long b = base; if (b < sp && (q = queue) != null) { int k = ((int)b) & (q.length-1); ForkJoinTask t = q[k]; if (t != null && casBase(b, b+1)) { clearSlot(q, k, t); t.setStolen(); return t; } } return null; } /** * Tries to find a worker with a non-empty queue. Starts at a * random index of workers array, and probes workers until finding * one with non-empty queue or finding that all are empty. This * doesn't require a very high quality generator, but also not a * crummy one. It uses Marsaglia xorshift to generate first n * probes. If these are empty, it resorts to full incremental * circular traversal. * @return a worker with (currently) non-empty queue, or null if none */ private ForkJoinWorkerThread randomVictim() { int r = randomVictimSeed; ForkJoinWorkerThread victim = null; ForkJoinWorkerThread[] ws = pool.getWorkers(); if (ws != null) { int n = ws.length; int remaining = n << 1; int idx = 0; do { if (remaining-- >= n) { // avoid % for power of 2 idx = (n & (n-1)) == 0? (r & (n-1)) : ((r >>> 1) % n); r ^= r << 1; r ^= r >>> 3; r ^= r << 10; } else if (++idx >= n) idx = 0; ForkJoinWorkerThread v = ws[idx]; if (v != null && v.base < v.sp) { victim = v; break; } } while (remaining >= 0); } randomVictimSeed = r; return victim; } /** * Tries to steal a task from a random worker. * @return a task, or null if none */ private ForkJoinTask getStolenTask() { ForkJoinWorkerThread v; while ((v = randomVictim()) != null) { if (scans != 0) { // Rescan if taken while trying to activate. AtomicInteger awc = activeWorkerCounter; do { int c = awc.get(); if (awc.compareAndSet(c, c+1)) { scans = 0; break; } } while (v.base < v.sp); } if (scans == 0) { ForkJoinTask t = v.tryStealTask(); if (t != null) { ++stealCount; return t; } } } return null; } // misc utilities /** * Tries to get a submission. Same basic logic as getStolenTask * @return a task, or null if none */ private ForkJoinTask getSubmission() { ForkJoinPool.SubmissionQueue sq = pool.getSubmissionQueue(); while (sq.isApparentlyNonEmpty()) { if (scans != 0) { AtomicInteger awc = activeWorkerCounter; int c = awc.get(); if (awc.compareAndSet(c, c+1)) scans = 0; } if (scans == 0) { ForkJoinTask t = sq.poll(); if (t != null) return t; } } return null; } /** * Returns next task to pop. Called only by current thread. */ private ForkJoinTask peekTask() { ForkJoinTask[] q = queue; long s = sp - 1; if (q == null || s <= base) return null; else return q[((int)s) & (q.length-1)]; } /** * Run or cancel all local tasks on exit from main. Exceptions * will cause aborts that will eventually trigger cancelTasks. */ private void clearLocalTasks() { for (;;) { ForkJoinTask t = popTask(); if (t == null) break; if (runState.isAtLeastStopping()) t.cancel(); else t.exec(); } } /* * Remove (via steal) and cancel all tasks in queue. Can be * called from any thread. */ final void cancelTasks() { while (base < sp) { ForkJoinTask t = tryStealTask(); if (t != null) // avoid exceptions due to cancel() t.setDoneExceptionally(new CancellationException()); } } // Public methods on current thread /** * Returns the pool hosting the current task execution. * @return the pool */ public static ForkJoinPool getPool() { return ((ForkJoinWorkerThread)(Thread.currentThread())).pool; } /** * Returns the index number of the current worker thread in its * pool. The return value is in the range * 0...getPool().getPoolSize()-1. This method may be * useful for applications that track status or collect results * per-worker rather than per-task. * @return the index number. */ public static int getPoolIndex() { return ((ForkJoinWorkerThread)(Thread.currentThread())).poolIndex; } /** * Returns the number of tasks waiting to be run by the current * worker thread. This value may be useful for heuristic decisions * about whether to fork other tasks. * @return the number of tasks */ public static int getLocalQueueSize() { ForkJoinWorkerThread w = (ForkJoinWorkerThread)(Thread.currentThread()); long n = w.sp - w.base; return n < 0? 0 : (int)n; } /** * Returns an estimate of how many more locally queued tasks there * are than idle worker threads that might steal them. This value * may be useful for heuristic decisions about whether to fork * other tasks. * @return the number of tasks, which is negative if there are * fewer tasks than idle workers */ public static int getEstimatedSurplusTaskCount() { ForkJoinWorkerThread w = (ForkJoinWorkerThread)(Thread.currentThread()); return (int)(w.sp - w.base) - (w.poolSize - w.activeWorkerCounter.get()); } /** * Returns, but does not remove or execute, the next task locally * queued for execution by the current worker thread. There is no * guarantee that this task will be the next one actually returned * or executed from other polling or execution methods. * @return the next task or null if none */ public static ForkJoinTask peekLocalTask() { return ((ForkJoinWorkerThread)(Thread.currentThread())).peekTask(); } /** * Removes and returns, without executing, the next task queued * for execution in the current worker thread's local queue. * @return the next task to execute, or null if none */ public static ForkJoinTask pollLocalTask() { return ((ForkJoinWorkerThread)(Thread.currentThread())).popTask(); } /** * Removes and returns, without executing, the given task from the * queue hosting current execution only if it would be the next * task executed by the current worker. Among other usages, this * method may be used to bypass task execution during * cancellation. * @param task the task * @return true if removed */ public static boolean removeIfNextLocalTask(ForkJoinTask task) { return ((ForkJoinWorkerThread)(Thread.currentThread())).popIfNext(task); } /** * Execute the next task locally queued by the current worker, if * one is available. * @return true if a task was run; a false return indicates * that no task was available. */ public static boolean executeLocalTask() { ForkJoinTask t = ((ForkJoinWorkerThread)(Thread.currentThread())).popTask(); if (t == null) return false; t.exec(); return true; } /** * Removes and returns, without executing, the next task available * for execution by the current worker thread, which may be a * locally queued task, one stolen from another worker, or a pool * submission. * @return the next task to execute, or null if none */ public static ForkJoinTask pollTask() { ForkJoinWorkerThread w = (ForkJoinWorkerThread)(Thread.currentThread()); ForkJoinTask t = w.getTask(); if (t == null) w.onEmptyScan(POLLING); return t; } /** * Helps this program complete by processing a local, stolen or * submitted task, if one is available. This method may be useful * when several tasks are forked, and only one of them must be * joined, as in: *

     *   while (!t1.isDone() && !t2.isDone()) 
     *     ForkJoinWorkerThread.executeTask();
     * 
* Similarly, you can help process tasks until all computations * complete via *
     *   while(ForkJoinWorkerThread.executeTask() || 
     *         !ForkJoinWorkerThread.getPool().isQuiescent()) 
     *      ;
     * 
* * @return true if a task was run; a false return indicates * that no task was available. */ public static boolean executeTask() { ForkJoinWorkerThread w = (ForkJoinWorkerThread)(Thread.currentThread()); ForkJoinTask t = w.getTask(); if (t == null) { w.onEmptyScan(POLLING); return false; } t.exec(); return true; } // per-worker exported random numbers /** * A workalike for java.util.Random, but specialized * for exporting to users of worker threads. */ final class JURandom { // non-static, use worker seed // Guarantee same constants as java.util.Random final static long Multiplier = 0x5DEECE66DL; final static long Addend = 0xBL; final static long Mask = (1L << 48) - 1; int next(int bits) { long next = (juRandomSeed * Multiplier + Addend) & Mask; juRandomSeed = next; return (int)(next >>> (48 - bits)); } int nextInt() { return next(32); } int nextInt(int n) { if (n <= 0) throw new IllegalArgumentException("n must be positive"); int bits = next(31); if ((n & -n) == n) return (int)((n * (long)bits) >> 31); for (;;) { int val = bits % n; if (bits - val + (n-1) >= 0) return val; bits = next(31); } } long nextLong() { return ((long)(next(32)) << 32) + next(32); } long nextLong(long n) { if (n <= 0) throw new IllegalArgumentException("n must be positive"); long offset = 0; while (n >= Integer.MAX_VALUE) { // randomly pick half range int bits = next(2); // 2nd bit for odd vs even split long half = n >>> 1; long nextn = ((bits & 2) == 0)? half : n - half; if ((bits & 1) == 0) offset += n - nextn; n = nextn; } return offset + nextInt((int)n); } double nextDouble() { return (((long)(next(26)) << 27) + next(27)) / (double)(1L << 53); } } /** * Returns a random integer using a per-worker random * number generator with the same properties as * {@link java.util.Random#nextInt} * @return the next pseudorandom, uniformly distributed {@code int} * value from this worker's random number generator's sequence */ public static int nextRandomInt() { ForkJoinWorkerThread w = (ForkJoinWorkerThread)(Thread.currentThread()); return w.juRandom.nextInt(); } /** * Returns a random integer using a per-worker random * number generator with the same properties as * {@link java.util.Random#nextInt(int)} * @param n the bound on the random number to be returned. Must be * positive. * @return the next pseudorandom, uniformly distributed {@code int} * value between {@code 0} (inclusive) and {@code n} (exclusive) * from this worker's random number generator's sequence * @throws IllegalArgumentException if n is not positive */ public static int nextRandomInt(int n) { ForkJoinWorkerThread w = (ForkJoinWorkerThread)(Thread.currentThread()); return w.juRandom.nextInt(n); } /** * Returns a random long using a per-worker random * number generator with the same properties as * {@link java.util.Random#nextLong} * @return the next pseudorandom, uniformly distributed {@code long} * value from this worker's random number generator's sequence */ public static long nextRandomLong() { ForkJoinWorkerThread w = (ForkJoinWorkerThread)(Thread.currentThread()); return w.juRandom.nextLong(); } /** * Returns a random integer using a per-worker random * number generator with the same properties as * {@link java.util.Random#nextInt(int)} * @param n the bound on the random number to be returned. Must be * positive. * @return the next pseudorandom, uniformly distributed {@code int} * value between {@code 0} (inclusive) and {@code n} (exclusive) * from this worker's random number generator's sequence * @throws IllegalArgumentException if n is not positive */ public static long nextRandomLong(long n) { ForkJoinWorkerThread w = (ForkJoinWorkerThread)(Thread.currentThread()); return w.juRandom.nextLong(n); } /** * Returns a random double using a per-worker random * number generator with the same properties as * {@link java.util.Random#nextDouble} * @return the next pseudorandom, uniformly distributed {@code double} * value between {@code 0.0} and {@code 1.0} from this * worker's random number generator's sequence */ public static double nextRandomDouble() { ForkJoinWorkerThread w = (ForkJoinWorkerThread)(Thread.currentThread()); return w.juRandom.nextDouble(); } // Package-local support for core ForkJoinTask methods /** * Called only from ForkJoinTask, upon completion * of stolen or cancelled task. */ static void signalTaskCompletion() { Thread t = Thread.currentThread(); if (t instanceof ForkJoinWorkerThread) ((ForkJoinWorkerThread)t).poolBarrier.signal(); // else external cancel -- OK not to signal } /** * Implements ForkJoinTask.join */ final T doJoinTask(ForkJoinTask joinMe) { for (;;) { Throwable ex = joinMe.exception; if (ex != null) ForkJoinTask.rethrowException(ex); if (joinMe.status < 0) return joinMe.rawResult(); ForkJoinTask t; if ((t = getTask()) == null) onEmptyScan(JOINING); else t.exec(); } } /** * Implements ForkJoinTask.quietlyJoin */ final Throwable doQuietlyJoinTask(ForkJoinTask joinMe) { for (;;) { Throwable ex = joinMe.exception; if (ex != null) return ex; if (joinMe.status < 0) return null; ForkJoinTask t; if ((t = getTask()) == null) onEmptyScan(JOINING); else t.exec(); } } /** * Timeout version of join for Submissions. * Returns false if timed out before complated */ final boolean doTimedJoinTask(ForkJoinTask joinMe, long nanos) { long startTime = System.nanoTime(); for (;;) { if (joinMe.exception != null || joinMe.status < 0) return true; if (nanos - (System.nanoTime() - startTime) <= 0) return false; ForkJoinTask t; if ((t = getTask()) == null) onEmptyScan(JOINING); else t.exec(); } } final void doForkJoin(RecursiveAction t1, RecursiveAction t2) { int touch = t1.status + t2.status; // force null pointer check pushTask(t2); Throwable ex1 = t1.exec(); Throwable ex2 = popIfNext(t2)? t2.exec() : doQuietlyJoinTask(t2); if (ex2 != null) ForkJoinTask.rethrowException(ex2); else if (ex1 != null) ForkJoinTask.rethrowException(ex1); } // Temporary Unsafe mechanics for preliminary release private static Unsafe getUnsafe() { try { if (ForkJoinWorkerThread.class.getClassLoader() != null) { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); return (Unsafe)f.get(null); } else return Unsafe.getUnsafe(); } catch (Exception e) { throw new RuntimeException("Could not initialize intrinsics", e); } } private static final Unsafe _unsafe = getUnsafe(); private static final long baseOffset; private static final long arrayBase; private static final int arrayShift; private static int computeArrayShift() { int s = _unsafe.arrayIndexScale(ForkJoinTask[].class); if ((s & (s-1)) != 0) throw new Error("data type scale not a power of two"); return 31 - Integer.numberOfLeadingZeros(s); } static { try { baseOffset = _unsafe.objectFieldOffset (ForkJoinWorkerThread.class.getDeclaredField("base")); arrayBase = _unsafe.arrayBaseOffset(ForkJoinTask[].class); arrayShift = computeArrayShift(); } catch (Exception ex) { throw new Error(ex); } } private final boolean casBase(long cmp, long val) { return _unsafe.compareAndSwapLong(this, baseOffset, cmp, val); } private static final void clearSlot(ForkJoinTask[] array, int i, ForkJoinTask expect) { _unsafe.compareAndSwapObject(array, arrayBase + ((long)i << arrayShift), expect, null); } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/RunState.java0000644000000000000000000000321310735315511023042 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import java.util.concurrent.atomic.*; /** * Maintains lifecycle control for pool and workers. * Opportunistically subclasses AtomicInteger. Don't directly use the * AtomicInteger methods though. */ final class RunState extends AtomicInteger { // Order among values matters static final int RUNNING = 0; static final int SHUTDOWN = 1; static final int STOPPING = 2; static final int TERMINATED = 4; boolean isRunning() { return get() == RUNNING; } boolean isShutdown() { return get() == SHUTDOWN; } boolean isStopping() { return get() == STOPPING; } boolean isTerminated() { return get() == TERMINATED; } boolean isAtLeastShutdown() { return get() >= SHUTDOWN; } boolean isAtLeastStopping() { return get() >= STOPPING; } boolean transitionToShutdown() { return transitionTo(SHUTDOWN); } boolean transitionToStopping() { return transitionTo(STOPPING); } boolean transitionToTerminated() { return transitionTo(TERMINATED); } /** * Transition to at least the given state. Return true if not * already at least given state. */ boolean transitionTo(int state) { for (;;) { int s = get(); if (s >= state) return false; if (compareAndSet(s, state)) return true; } } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/ForkJoinExecutor.java0000644000000000000000000000403710735315511024542 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import java.util.concurrent.*; /** * An object that executes {@link ForkJoinTask} computations. This * interface does not expose lifecycle, status, or management methods * corresponding to implementations, so may be useful as a basis * for classes that must restrict access to such methods. * */ public interface ForkJoinExecutor { /** * Arranges for (asynchronous) execution of the given task. * @param task the task * @throws NullPointerException if task is null * @throws RejectedExecutionException if the executor is * not in a state that allows execution. */ public void execute(ForkJoinTask task); /** * Performs the given task; returning its result upon completion * @param task the task * @return the task's result * @throws NullPointerException if task is null * @throws RejectedExecutionException if the executor is * not in a state that allows execution. */ public T invoke(ForkJoinTask task); /** * Arranges for (asynchronous) execution of the given task, * returning a Future that may be used to obtain results * upon completion. * @param task the task * @return a Future that can be used to get the task's results. * @throws NullPointerException if task is null * @throws RejectedExecutionException if the executor is * not in a state that allows execution. */ public Future submit(ForkJoinTask task); /** * Returns an estimate of how many tasks (including subtasks) * may execute at once. This value normally corresponds to the * number of threads available for executing tasks by this * executor. * @return the parallelism level */ public int getParallelismLevel(); } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/AsyncAction.java0000644000000000000000000000370610735315511023517 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * */ package jsr166y.forkjoin; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; /** * Resultless ForkJoinTasks with explicit completions. Unlike some * other kinds of tasks, AsyncActions do not intrinisically complete * upon exit from their compute methods, but instead require * explicit invocation of their finish methods. * *

Unlike LinkedAsyncActions, AsyncActions do not establish links * to parent tasks or count child tasks. This class can thus form a * more flexible basis for classes creating custom linkages. * */ public abstract class AsyncAction extends ForkJoinTask { /** * The asynchronous part of the computation performed by this * task. While you must define this method, you should not in * general call it directly (although you can invoke immediately * via exec.) If this method throws an excaption, * finishExceptionally is immediately invoked. */ protected abstract void compute(); /** * Equivalent to finish(null). */ public final void finish() { setDone(); } public final void finish(Void result) { setDone(); } public final void finishExceptionally(Throwable ex) { setDoneExceptionally(ex); } /** * Always returns null. * @return null */ public final Void rawResult() { return null; } public final Void forkJoin() { exec(); return join(); } public final Throwable exec() { try { if (exception == null) compute(); } catch(Throwable rex) { return setDoneExceptionally(rex); } return exception; } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/Submission.java0000644000000000000000000001532710735315511023441 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y.forkjoin; import java.util.concurrent.*; import java.util.concurrent.locks.*; /** * Adapter class to allow tasks submitted to a pool to act as Futures. * Methods are implemented in the same way as in the RecursiveTask * class, but with extra bookkeeping and signalling to cover three * kinds of adaptation: * * (1) Unlike internal fork/join processing, get() must block if the * caller is a normal thread (not FJ worker thread). We use a simpler * variant of the mechanics used in FutureTask, but bypass them and * use helping joins if the caller is itself a ForkJoinWorkerThread. * * (2) Regular Futures encase RuntimeExceptions within * ExecutionExeptions, while internal tasks just throw them directly, * so these must be trapped and wrapped. * * (3) External submissions are tracked for the sake of managing * worker threads. The pool submissionStarting and submissionCompleted * methods perform the associated bookkeeping. This requires some care * with cancellation and early termination -- the completion signal * can be issued only if a start signal ever was. * */ final class Submission extends ForkJoinTask implements Future { // Status values for sync. We need to keep track of RUNNING status // just to make sure callbacks to pool are balanced. static final int INITIAL = 0; static final int RUNNING = 1; static final int DONE = 2; /** * Stripped-down variant of FutureTask.sync */ static final class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 4982264981922014374L; public int tryAcquireShared(int acquires) { return getState() == DONE? 1 : -1; } public boolean tryReleaseShared(int releases) { return true; } public void reset() { setState(INITIAL); } public boolean isDone() { return getState() == DONE; } public boolean transitionToRunning() { return compareAndSetState(INITIAL, RUNNING); } /** Set status to DONE, release waiters, and return old state */ public int transitionToDone() { for (;;) { int c = getState(); if (c == DONE || compareAndSetState(c, DONE)) { releaseShared(0); return c; } } } } private final ForkJoinTask task; private final ForkJoinPool pool; private final Sync sync; private volatile V result; Submission(ForkJoinTask t, ForkJoinPool p) { t.setStolen(); // All submitted tasks treated as stolen task = t; pool = p; sync = new Sync(); } /** * Transition sync and notify pool.that task finished, only if it * was initially notified that task started. */ private void complete() { if (sync.transitionToDone() == RUNNING) pool.submissionCompleted(); } protected V compute() { try { V ret = null; if (sync.transitionToRunning()) { pool.submissionStarting(); ret = task.forkJoin(); } // else was cancelled, so result doesn't matter return ret; } finally { complete(); } } /** * ForkJoinTask version of cancel */ public void cancel() { try { // Don't bother trying to cancel if already done if (getException() == null && !sync.isDone()) { // avoid recursive call to cancel setDoneExceptionally(new CancellationException()); task.cancel(); } } finally { complete(); } } /** * Future version of cancel */ public boolean cancel(boolean ignore) { this.cancel(); return isCancelled(); } public V get() throws InterruptedException, ExecutionException { // If caller is FJ worker, help instead of block, but fall // through.to acquire, to preserve Submission sync guarantees Thread t = Thread.currentThread(); if (t instanceof ForkJoinWorkerThread) quietlyJoin(); sync.acquireSharedInterruptibly(1); return task.reportAsFutureResult(); } public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { long nanos = unit.toNanos(timeout); Thread t = Thread.currentThread(); if (t instanceof ForkJoinWorkerThread) { if(!((ForkJoinWorkerThread)t).doTimedJoinTask(this, nanos)) throw new TimeoutException(); // Preserve Submission sync guarantees sync.acquireSharedInterruptibly(1); } else if (!sync.tryAcquireSharedNanos(1, nanos)) throw new TimeoutException(); return task.reportAsFutureResult(); } /** * Interrupt-less get for ForkJoinPool.invoke */ public V awaitInvoke() { Thread t = Thread.currentThread(); if (t instanceof ForkJoinWorkerThread) quietlyJoin(); sync.acquireShared(1); return task.reportAsForkJoinResult(); } public void finish(V result) { try { this.result = result; setDone(); } finally { complete(); } } public void finishExceptionally(Throwable ex) { try { setDoneExceptionally(ex); task.setDoneExceptionally(ex); } finally { complete(); } } public V forkJoin() { V v = null; if (exception == null) { try { result = v = compute(); } catch(Throwable rex) { finishExceptionally(rex); } } Throwable ex = setDone(); if (ex != null) rethrowException(ex); return v; } public Throwable exec() { if (exception == null) { try { result = compute(); } catch(Throwable rex) { return setDoneExceptionally(rex); } } return setDone(); } public V rawResult() { return result; } public void reinitialize() { // Of dubious value. result = null; sync.reset(); super.reinitialize(); } } libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/LinkedTransferQueue.java0000644000000000000000000005615610735315511023412 0ustar /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package jsr166y; import java.util.concurrent.*; import java.util.concurrent.locks.*; import java.util.concurrent.atomic.*; import java.util.*; import java.io.*; /** * An unbounded {@linkplain TransferQueue} based on linked nodes. * This queue orders elements FIFO (first-in-first-out) with respect * to any given producer. The head of the queue is that * element that has been on the queue the longest time for some * producer. The tail of the queue is that element that has * been on the queue the shortest time for some producer. * *

Beware that, unlike in most collections, the size * method is NOT a constant-time operation. Because of the * asynchronous nature of these queues, determining the current number * of elements requires a traversal of the elements. * *

This class and its iterator implement all of the * optional methods of the {@link Collection} and {@link * Iterator} interfaces. * *

Memory consistency effects: As with other concurrent * collections, actions in a thread prior to placing an object into a * {@code LinkedTransferQueue} * happen-before * actions subsequent to the access or removal of that element from * the {@code LinkedTransferQueue} in another thread. * *

This class is a member of the * * Java Collections Framework. * * @since 1.7 * @author Doug Lea * @param the type of elements held in this collection * */ public class LinkedTransferQueue extends AbstractQueue implements TransferQueue, java.io.Serializable { private static final long serialVersionUID = -3223113410248163686L; /* * This is still a work in prgress... * * This class extends the approach used in FIFO-mode * SynchronousQueues. See the internal documentation, as well as * the PPoPP 2006 paper "Scalable Synchronous Queues" by Scherer, * Lea & Scott * (http://www.cs.rice.edu/~wns1/papers/2006-PPoPP-SQ.pdf) * * The main extension is to provide different Wait modes * for the main "xfer" method that puts or takes items. * These don't impact the basic dual-queue logic, but instead * control whether or how threads block upon insertion * of request or data nodes into the dual queue. */ // Wait modes for xfer method static final int NOWAIT = 0; static final int TIMEOUT = 1; static final int WAIT = 2; /** The number of CPUs, for spin control */ static final int NCPUS = Runtime.getRuntime().availableProcessors(); /** * The number of times to spin before blocking in timed waits. * The value is empirically derived -- it works well across a * variety of processors and OSes. Empirically, the best value * seems not to vary with number of CPUs (beyond 2) so is just * a constant. */ static final int maxTimedSpins = (NCPUS < 2)? 0 : 32; /** * The number of times to spin before blocking in untimed waits. * This is greater than timed value because untimed waits spin * faster since they don't need to check times on each spin. */ static final int maxUntimedSpins = maxTimedSpins * 16; /** * The number of nanoseconds for which it is faster to spin * rather than to use timed park. A rough estimate suffices. */ static final long spinForTimeoutThreshold = 1000L; /** * Node class for LinkedTransferQueue. Opportunistically subclasses from * AtomicReference to represent item. Uses Object, not E, to allow * setting item to "this" after use, to avoid garbage * retention. Similarly, setting the next field to this is used as * sentinel that node is off list. */ static final class QNode extends AtomicReference { volatile QNode next; volatile Thread waiter; // to control park/unpark final boolean isData; QNode(Object item, boolean isData) { super(item); this.isData = isData; } static final AtomicReferenceFieldUpdater nextUpdater = AtomicReferenceFieldUpdater.newUpdater (QNode.class, QNode.class, "next"); boolean casNext(QNode cmp, QNode val) { return nextUpdater.compareAndSet(this, cmp, val); } } /** * Padded version of AtomicReference used for head, tail and * cleanMe, to alleviate contention across threads CASing one vs * the other. */ static final class PaddedAtomicReference extends AtomicReference { // enough padding for 64bytes with 4byte refs Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe; PaddedAtomicReference(T r) { super(r); } } private final QNode dummy = new QNode(null, false); private final PaddedAtomicReference head = new PaddedAtomicReference(dummy); private final PaddedAtomicReference tail = new PaddedAtomicReference(dummy); /** * Reference to a cancelled node that might not yet have been * unlinked from queue because it was the last inserted node * when it cancelled. */ private final PaddedAtomicReference cleanMe = new PaddedAtomicReference(null); /** * Tries to cas nh as new head; if successful, unlink * old head's next node to avoid garbage retention. */ private boolean advanceHead(QNode h, QNode nh) { if (h == head.get() && head.compareAndSet(h, nh)) { h.next = h; // forget old next return true; } return false; } /** * Puts or takes an item. Used for most queue operations (except * poll() and tryTransfer()) * @param e the item or if null, signfies that this is a take * @param mode the wait mode: NOWAIT, TIMEOUT, WAIT * @param nanos timeout in nanosecs, used only if mode is TIMEOUT * @return an item, or null on failure */ private Object xfer(Object e, int mode, long nanos) { boolean isData = (e != null); QNode s = null; final PaddedAtomicReference head = this.head; final PaddedAtomicReference tail = this.tail; for (;;) { QNode t = tail.get(); QNode h = head.get(); if (t != null && (t == h || t.isData == isData)) { if (s == null) s = new QNode(e, isData); QNode last = t.next; if (last != null) { if (t == tail.get()) tail.compareAndSet(t, last); } else if (t.casNext(null, s)) { tail.compareAndSet(t, s); return awaitFulfill(t, s, e, mode, nanos); } } else if (h != null) { QNode first = h.next; if (t == tail.get() && first != null && advanceHead(h, first)) { Object x = first.get(); if (x != first && first.compareAndSet(x, e)) { LockSupport.unpark(first.waiter); return isData? e : x; } } } } } /** * Version of xfer for poll() and tryTransfer, which * simpifies control paths both here and in xfer */ private Object fulfill(Object e) { boolean isData = (e != null); final PaddedAtomicReference head = this.head; final PaddedAtomicReference tail = this.tail; for (;;) { QNode t = tail.get(); QNode h = head.get(); if (t != null && (t == h || t.isData == isData)) { QNode last = t.next; if (t == tail.get()) { if (last != null) tail.compareAndSet(t, last); else return null; } } else if (h != null) { QNode first = h.next; if (t == tail.get() && first != null && advanceHead(h, first)) { Object x = first.get(); if (x != first && first.compareAndSet(x, e)) { LockSupport.unpark(first.waiter); return isData? e : x; } } } } } /** * Spins/blocks until node s is fulfilled or caller gives up, * depending on wait mode. * * @param pred the predecessor of waiting node * @param s the waiting node * @param e the comparison value for checking match * @param mode mode * @param nanos timeout value * @return matched item, or s if cancelled */ private Object awaitFulfill(QNode pred, QNode s, Object e, int mode, long nanos) { if (mode == NOWAIT) return null; long lastTime = (mode == TIMEOUT)? System.nanoTime() : 0; Thread w = Thread.currentThread(); int spins = -1; // set to desired spin count below for (;;) { if (w.isInterrupted()) s.compareAndSet(e, s); Object x = s.get(); if (x != e) { // Node was matched or cancelled advanceHead(pred, s); // unlink if head if (x == s) // was cancelled return clean(pred, s); else if (x != null) { s.set(s); // avoid garbage retention return x; } else return e; } if (mode == TIMEOUT) { long now = System.nanoTime(); nanos -= now - lastTime; lastTime = now; if (nanos <= 0) { s.compareAndSet(e, s); // try to cancel continue; } } if (spins < 0) { QNode h = head.get(); // only spin if at head spins = ((h != null && h.next == s) ? (mode == TIMEOUT? maxTimedSpins : maxUntimedSpins) : 0); } if (spins > 0) --spins; else if (s.waiter == null) s.waiter = w; else if (mode != TIMEOUT) { // LockSupport.park(this); LockSupport.park(); // allows run on java5 s.waiter = null; spins = -1; } else if (nanos > spinForTimeoutThreshold) { // LockSupport.parkNanos(this, nanos); LockSupport.parkNanos(nanos); s.waiter = null; spins = -1; } } } /** * Gets rid of cancelled node s with original predecessor pred. * @return null (to simplify use by callers) */ private Object clean(QNode pred, QNode s) { Thread w = s.waiter; if (w != null) { // Wake up thread s.waiter = null; if (w != Thread.currentThread()) LockSupport.unpark(w); } for (;;) { if (pred.next != s) // already cleaned return null; QNode h = head.get(); QNode hn = h.next; // Absorb cancelled first node as head if (hn != null && hn.next == hn) { advanceHead(h, hn); continue; } QNode t = tail.get(); // Ensure consistent read for tail if (t == h) return null; QNode tn = t.next; if (t != tail.get()) continue; if (tn != null) { // Help advance tail tail.compareAndSet(t, tn); continue; } if (s != t) { // If not tail, try to unsplice QNode sn = s.next; if (sn == s || pred.casNext(s, sn)) return null; } QNode dp = cleanMe.get(); if (dp != null) { // Try unlinking previous cancelled node QNode d = dp.next; QNode dn; if (d == null || // d is gone or d == dp || // d is off list or d.get() != d || // d not cancelled or (d != t && // d not tail and (dn = d.next) != null && // has successor dn != d && // that is on list dp.casNext(d, dn))) // d unspliced cleanMe.compareAndSet(dp, null); if (dp == pred) return null; // s is already saved node } else if (cleanMe.compareAndSet(null, pred)) return null; // Postpone cleaning s } } /** * Creates an initially empty LinkedTransferQueue. */ public LinkedTransferQueue() { } /** * Creates a LinkedTransferQueue * initially containing the elements of the given collection, * added in traversal order of the collection's iterator. * @param c the collection of elements to initially contain * @throws NullPointerException if the specified collection or any * of its elements are null */ public LinkedTransferQueue(Collection c) { addAll(c); } public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); if (Thread.interrupted()) throw new InterruptedException(); xfer(e, NOWAIT, 0); } public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException { if (e == null) throw new NullPointerException(); if (Thread.interrupted()) throw new InterruptedException(); xfer(e, NOWAIT, 0); return true; } public boolean offer(E e) { if (e == null) throw new NullPointerException(); xfer(e, NOWAIT, 0); return true; } public void transfer(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); if (xfer(e, WAIT, 0) == null) { Thread.interrupted(); throw new InterruptedException(); } } public boolean tryTransfer(E e, long timeout, TimeUnit unit) throws InterruptedException { if (e == null) throw new NullPointerException(); if (xfer(e, TIMEOUT, unit.toNanos(timeout)) != null) return true; if (!Thread.interrupted()) return false; throw new InterruptedException(); } public boolean tryTransfer(E e) { if (e == null) throw new NullPointerException(); return fulfill(e) != null; } public E take() throws InterruptedException { Object e = xfer(null, WAIT, 0); if (e != null) return (E)e; Thread.interrupted(); throw new InterruptedException(); } public E poll(long timeout, TimeUnit unit) throws InterruptedException { Object e = xfer(null, TIMEOUT, unit.toNanos(timeout)); if (e != null || !Thread.interrupted()) return (E)e; throw new InterruptedException(); } public E poll() { return (E)fulfill(null); } public int drainTo(Collection c) { if (c == null) throw new NullPointerException(); if (c == this) throw new IllegalArgumentException(); int n = 0; E e; while ( (e = poll()) != null) { c.add(e); ++n; } return n; } public int drainTo(Collection c, int maxElements) { if (c == null) throw new NullPointerException(); if (c == this) throw new IllegalArgumentException(); int n = 0; E e; while (n < maxElements && (e = poll()) != null) { c.add(e); ++n; } return n; } // Traversal-based methods /** * Return head after performing any outstanding helping steps */ private QNode traversalHead() { for (;;) { QNode t = tail.get(); QNode h = head.get(); if (h != null && t != null) { QNode last = t.next; QNode first = h.next; if (t == tail.get()) { if (last != null) tail.compareAndSet(t, last); else if (first != null) { Object x = first.get(); if (x == first) advanceHead(h, first); else return h; } else return h; } } } } public Iterator iterator() { return new Itr(); } /** * Iterators. Basic strategy os to travers list, treating * non-data (i.e., request) nodes as terminating list. * Once a valid data node is found, the item is cached * so that the next call to next() will return it even * if subsequently removed. */ class Itr implements Iterator { QNode nextNode; // Next node to return next QNode currentNode; // last returned node, for remove() QNode prevNode; // predecessor of last returned node E nextItem; // Cache of next item, once commited to in next Itr() { nextNode = traversalHead(); advance(); } E advance() { prevNode = currentNode; currentNode = nextNode; E x = nextItem; QNode p = nextNode.next; for (;;) { if (p == null || !p.isData) { nextNode = null; nextItem = null; return x; } Object item = p.get(); if (item != p && item != null) { nextNode = p; nextItem = (E)item; return x; } prevNode = p; p = p.next; } } public boolean hasNext() { return nextNode != null; } public E next() { if (nextNode == null) throw new NoSuchElementException(); return advance(); } public void remove() { QNode p = currentNode; QNode prev = prevNode; if (prev == null || p == null) throw new IllegalStateException(); Object x = p.get(); if (x != null && x != p && p.compareAndSet(x, p)) clean(prev, p); } } public E peek() { for (;;) { QNode h = traversalHead(); QNode p = h.next; if (p == null) return null; Object x = p.get(); if (p != x) { if (!p.isData) return null; if (x != null) return (E)x; } } } public boolean isEmpty() { for (;;) { QNode h = traversalHead(); QNode p = h.next; if (p == null) return true; Object x = p.get(); if (p != x) { if (!p.isData) return true; if (x != null) return false; } } } public boolean hasWaitingConsumer() { for (;;) { QNode h = traversalHead(); QNode p = h.next; if (p == null) return false; Object x = p.get(); if (p != x) return !p.isData; } } /** * Returns the number of elements in this queue. If this queue * contains more than Integer.MAX_VALUE elements, returns * Integer.MAX_VALUE. * *

Beware that, unlike in most collections, this method is * NOT a constant-time operation. Because of the * asynchronous nature of these queues, determining the current * number of elements requires an O(n) traversal. * * @return the number of elements in this queue */ public int size() { int count = 0; QNode h = traversalHead(); for (QNode p = h.next; p != null && p.isData; p = p.next) { Object x = p.get(); if (x != null && x != p) { if (++count == Integer.MAX_VALUE) // saturated break; } } return count; } public int getWaitingConsumerCount() { int count = 0; QNode h = traversalHead(); for (QNode p = h.next; p != null && !p.isData; p = p.next) { if (p.get() == null) { if (++count == Integer.MAX_VALUE) break; } } return count; } public int remainingCapacity() { return Integer.MAX_VALUE; } /** * Save the state to a stream (that is, serialize it). * * @serialData All of the elements (each an E) in * the proper order, followed by a null * @param s the stream */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject(); for (Iterator it = iterator(); it.hasNext(); ) s.writeObject(it.next()); // Use trailing null as sentinel s.writeObject(null); } /** * Reconstitute the Queue instance from a stream (that is, * deserialize it). * @param s the stream */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); for (;;) { E item = (E)s.readObject(); if (item == null) break; else offer(item); } } } libjsr166y-java-0.1.20080107.orig/pom.xml0000644000000000000000000000063210740452246014253 0ustar 4.0.0 org.coconut.forkjoin coconut-forkjoin-parent 0.1 ../pom.xml jsr166y Coconut Jsr166y 070108 jar