public override void onCompletion <T1>(CountedCompleter <T1> caller) { if (Node != null) { // Dump buffered elements from this leaf into the sink Node.ForEach(Action); Node = null; } else if (Spliterator != null) { // Dump elements output from this leaf's pipeline into the sink Helper.WrapAndCopyInto(Action, Spliterator); Spliterator = null; } // The completion of this task *and* the dumping of elements // "happens-before" completion of the associated left-most leaf task // of right subtree (if any, which can be this task's right sibling) // ForEachOrderedTask <S, T> leftDescendant = CompletionMap.Remove(this); if (leftDescendant != null) { leftDescendant.TryComplete(); } }
internal static void doCompute <S, T>(ForEachOrderedTask <S, T> task) { Spliterator <S> rightSplit = task.Spliterator, leftSplit; long sizeThreshold = task.TargetSize; bool forkRight = false; while (rightSplit.EstimateSize() > sizeThreshold && (leftSplit = rightSplit.TrySplit()) != null) { ForEachOrderedTask <S, T> leftChild = new ForEachOrderedTask <S, T>(task, leftSplit, task.LeftPredecessor); ForEachOrderedTask <S, T> rightChild = new ForEachOrderedTask <S, T>(task, rightSplit, leftChild); // Fork the parent task // Completion of the left and right children "happens-before" // completion of the parent task.AddToPendingCount(1); // Completion of the left child "happens-before" completion of // the right child rightChild.AddToPendingCount(1); task.CompletionMap[leftChild] = rightChild; // If task is not on the left spine if (task.LeftPredecessor != null) { /* * Completion of left-predecessor, or left subtree, * "happens-before" completion of left-most leaf node of * right subtree. * The left child's pending count needs to be updated before * it is associated in the completion map, otherwise the * left child can complete prematurely and violate the * "happens-before" constraint. */ leftChild.AddToPendingCount(1); // Update association of left-predecessor to left-most // leaf node of right subtree if (task.CompletionMap.replace(task.LeftPredecessor, task, leftChild)) { // If replaced, adjust the pending count of the parent // to complete when its children complete task.AddToPendingCount(-1); } else { // Left-predecessor has already completed, parent's // pending count is adjusted by left-predecessor; // left child is ready to complete leftChild.AddToPendingCount(-1); } } ForEachOrderedTask <S, T> taskToFork; if (forkRight) { forkRight = false; rightSplit = leftSplit; task = leftChild; taskToFork = rightChild; } else { forkRight = true; task = rightChild; taskToFork = leftChild; } taskToFork.Fork(); } /* * Task's pending count is either 0 or 1. If 1 then the completion * map will contain a value that is task, and two calls to * tryComplete are required for completion, one below and one * triggered by the completion of task's left-predecessor in * onCompletion. Therefore there is no data race within the if * block. */ if (task.PendingCount > 0) { // Cannot complete just yet so buffer elements into a Node // for use when completion occurs //JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @SuppressWarnings("unchecked") java.util.function.IntFunction<T[]> generator = size -> (T[]) new Object[size]; //JAVA TO C# CONVERTER TODO TASK: Java lambdas satisfy functional interfaces, while .NET lambdas satisfy delegates - change the appropriate interface to a delegate: IntFunction <T[]> generator = size => (T[])new Object[size]; Node_Builder <T> nb = task.Helper.MakeNodeBuilder(task.Helper.ExactOutputSizeIfKnown(rightSplit), generator); task.Node = task.Helper.WrapAndCopyInto(nb, rightSplit).build(); task.Spliterator = null; } task.TryComplete(); }