libjsr166y-java-0.1.20080107.orig/ 0000755 0000000 0000000 00000000000 11412734661 012736 5 ustar libjsr166y-java-0.1.20080107.orig/src/ 0000755 0000000 0000000 00000000000 11412734657 013532 5 ustar libjsr166y-java-0.1.20080107.orig/src/main/ 0000755 0000000 0000000 00000000000 11412734657 014456 5 ustar libjsr166y-java-0.1.20080107.orig/src/main/java/ 0000755 0000000 0000000 00000000000 11412734657 015377 5 ustar libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/ 0000755 0000000 0000000 00000000000 11412734661 016616 5 ustar libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/package-info.java 0000644 0000000 0000000 00000000434 10735315511 022002 0 ustar /*
* 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.java 0000644 0000000 0000000 00000012531 10735315511 022250 0 ustar /*
* 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/ 0000755 0000000 0000000 00000000000 11412734661 020437 5 ustar libjsr166y-java-0.1.20080107.orig/src/main/java/jsr166y/forkjoin/RecursiveAction.java 0000644 0000000 0000000 00000021756 10735315511 024416 0 ustar /*
* 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 extends RecursiveAction> 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.java 0000644 0000000 0000000 00000355060 10740452246 021735 0 ustar /*
* 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.java 0000644 0000000 0000000 00000317447 10740452246 025207 0 ustar /*
* 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 extends U> 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 extends U> mapper;
WithMapping(ParallelDoubleArray pa,
int firstIndex, int upperBound,
MapperFromDouble extends U> mapper) {
super(pa, firstIndex, upperBound);
this.mapper = mapper;
}
/**
* Applies the given procedure to mapped elements
* @param procedure the procedure
*/
public void apply(Procedure super U> 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 super U> 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 super U> 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 super U> 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 super U>)(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 super U> 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 super U, ? extends V> 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 super U> 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 super U> 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 extends U> 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 super U> 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 super U, ? extends V> mapper) {
return new WithBoundedMapping
(pa, firstIndex, upperBound,
Ops.compoundMapper(this.mapper, mapper));
}
public WithDoubleMapping withMapping(MapperToDouble super U> mapper){
return new WithBoundedDoubleMapping
(pa, firstIndex, upperBound,
Ops.compoundMapper(this.mapper, mapper));
}
public WithLongMapping withMapping(MapperToLong super U> 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 extends U> 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 super U> 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 super U, ? extends V> mapper) {
return new WithBoundedFilteredMapping
(pa, firstIndex, upperBound, selector,
Ops.compoundMapper(this.mapper, mapper));
}
public WithDoubleMapping withMapping
(MapperToDouble super U> mapper) {
return new WithBoundedFilteredDoubleMapping
(pa, firstIndex, upperBound, selector,
Ops.compoundMapper(this.mapper, mapper));
}
public WithLongMapping withMapping
(MapperToLong super U> 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 extends U> 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 extends U> 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 extends U> 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 extends U> 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 extends U> 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 extends U> 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 extends U> 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 extends U> 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 extends Double> 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 extends Double> 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.java 0000644 0000000 0000000 00000031343 10735315511 023513 0 ustar /*
* 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.
*
*
*
*
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.
*
*
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.)
*
*
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.
*
*
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.java 0000644 0000000 0000000 00000027465 10735315511 024656 0 ustar /*
* 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.java 0000644 0000000 0000000 00000036346 10735315511 023656 0 ustar /*
* 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.java 0000644 0000000 0000000 00000003611 10735315511 023623 0 ustar /*
* 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.java 0000644 0000000 0000000 00000313100 10740452246 024652 0 ustar /*
* 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 extends U> 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 extends U> mapper;
WithMapping(ParallelLongArray pa, int firstIndex, int upperBound,
MapperFromLong extends U> mapper) {
super(pa, firstIndex, upperBound);
this.mapper = mapper;
}
/**
* Applies the given procedure to mapped elements
* @param procedure the procedure
*/
public void apply(Procedure super U> 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 super U> 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 super U> 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 super U> 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 super U>)(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 super U> 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 super U, ? extends V> 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 super U> 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 super U> 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 extends U> 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 super U> 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 super U, ? extends V> mapper) {
return new WithBoundedMapping
(pa, firstIndex, upperBound,
Ops.compoundMapper(this.mapper, mapper));
}
public WithLongMapping withMapping
(MapperToLong super U> mapper) {
return new WithBoundedLongMapping
(pa, firstIndex, upperBound,
Ops.compoundMapper(this.mapper, mapper));
}
public WithDoubleMapping withMapping
(MapperToDouble super U> 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 extends U> 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 super U> 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 super U, ? extends V> mapper) {
return new WithBoundedFilteredMapping
(pa, firstIndex, upperBound, selector,
Ops.compoundMapper(this.mapper, mapper));
}
public WithLongMapping withMapping
(MapperToLong super U> mapper) {
return new WithBoundedFilteredLongMapping
(pa, firstIndex, upperBound, selector,
Ops.compoundMapper(this.mapper, mapper));
}
public WithDoubleMapping withMapping
(MapperToDouble super U> 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 extends U> 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 extends U> 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 extends U> 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 extends U> 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 extends U> 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 extends U> 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 extends U> 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 extends U> 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 extends Long> 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 extends Long> 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.java 0000644 0000000 0000000 00000011760 10735315511 023523 0 ustar /*
* 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.java 0000644 0000000 0000000 00000122240 10740452246 022043 0 ustar /*
* 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 super T> 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 super T> 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