github.com/searKing/golang/go@v1.2.74/container/stream/op/find/task.go (about)

     1  // Copyright 2020 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package find
     6  
     7  import (
     8  	"context"
     9  
    10  	"github.com/searKing/golang/go/container/stream/op/terminal"
    11  	"github.com/searKing/golang/go/util/spliterator"
    12  )
    13  
    14  type FindTask struct {
    15  	terminal.TODOShortCircuitTask
    16  
    17  	op FindOp
    18  	// true if find first
    19  	// false if find any
    20  	mustFindFirst bool
    21  }
    22  
    23  /**
    24   * Constructor for root tasks.
    25   *
    26   * @param helper the {@code PipelineHelper} describing the stream pipeline
    27   *               up to this operation
    28   * @param spliterator the {@code Spliterator} describing the source for this
    29   *                    pipeline
    30   */
    31  func (task *FindTask) WithSpliterator(op FindOp, spliterator spliterator.Spliterator) *FindTask {
    32  	task.TODOShortCircuitTask.WithSpliterator(spliterator)
    33  	task.op = op
    34  	task.mustFindFirst = op.mustFindFirst
    35  	task.SetDerived(task)
    36  	return task
    37  }
    38  
    39  /**
    40   * Constructor for non-root nodes.
    41   *
    42   * @param parent parent task in the computation tree
    43   * @param spliterator the {@code Spliterator} for the portion of the
    44   *                    computation tree described by this task
    45   */
    46  func (task *FindTask) WithParent(parent *FindTask, spliterator spliterator.Spliterator) *FindTask {
    47  	task.TODOShortCircuitTask.WithParent(parent, spliterator)
    48  	task.op = parent.op
    49  	task.mustFindFirst = parent.mustFindFirst
    50  	task.SetDerived(task)
    51  	return task
    52  }
    53  
    54  func (task *FindTask) MakeChild(spliterator spliterator.Spliterator) terminal.Task {
    55  	child := &FindTask{}
    56  	return child.WithParent(task, spliterator)
    57  }
    58  
    59  func (task *FindTask) foundResult(answer terminal.Sink) {
    60  	if task.IsLeftmostNode() {
    61  		task.ShortCircuit(answer)
    62  		return
    63  	}
    64  	task.CancelLaterNodes()
    65  }
    66  
    67  func (task *FindTask) DoLeaf(ctx context.Context) terminal.Sink {
    68  	result := terminal.WrapAndCopyInto(ctx, task.op.MakeSink(), task.GetSpliterator())
    69  	if !task.mustFindFirst {
    70  		if result != nil && result.Get().IsPresent() {
    71  			task.ShortCircuit(result)
    72  		}
    73  		return nil
    74  	}
    75  	if result != nil && result.Get().IsPresent() {
    76  		task.foundResult(result)
    77  		return result
    78  	}
    79  	return nil
    80  }
    81  
    82  func (task *FindTask) OnCompletion(caller terminal.Task) {
    83  	if task.mustFindFirst {
    84  		child := task.LeftChild()
    85  		var p terminal.Task
    86  		for child != p {
    87  			result := child.GetLocalResult()
    88  			if result != nil && task.op.presentPredicate.Test(result.Get().Get()) {
    89  				task.SetLocalResult(result)
    90  				task.foundResult(result)
    91  				break
    92  			}
    93  
    94  			p = child
    95  			child = task.RightChild()
    96  		}
    97  	}
    98  	// GC spliterator, left and right child
    99  	task.TODOShortCircuitTask.OnCompletion(caller)
   100  }