github.com/searKing/golang/go@v1.2.74/container/stream/op/terminal/abstract_pipeline.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 terminal 6 7 import ( 8 "context" 9 "runtime" 10 11 "github.com/searKing/golang/go/error/exception" 12 "github.com/searKing/golang/go/util/class" 13 "github.com/searKing/golang/go/util/optional" 14 "github.com/searKing/golang/go/util/spliterator" 15 ) 16 17 const ( 18 MsgStreamLinked = "stream has already been operated upon or closed" 19 MsgConsumed = "source already consumed or closed" 20 ) 21 22 var ( 23 ParallelTargetSize = runtime.GOMAXPROCS(-1) 24 ) 25 26 /** 27 * Abstract base class for "pipeline" classes, which are the core 28 * implementations of the Stream interface and its primitive specializations. 29 * Manages construction and evaluation of stream pipelines. 30 * 31 * <p>An {@code AbstractPipeline} represents an initial portion of a stream 32 * pipeline, encapsulating a stream source and zero or more intermediate 33 * operations. The individual {@code AbstractPipeline} objects are often 34 * referred to as <em>stages</em>, where each stage describes either the stream 35 * source or an intermediate operation. 36 * 37 * <p>A concrete intermediate stage is generally built from an 38 * {@code AbstractPipeline}, a shape-specific pipeline class which extends it 39 * (e.g., {@code IntPipeline}) which is also abstract, and an operation-specific 40 * concrete class which extends that. {@code AbstractPipeline} contains most of 41 * the mechanics of evaluating the pipeline, and implements methods that will be 42 * used by the operation; the shape-specific classes add helper methods for 43 * dealing with collection of results into the appropriate shape-specific 44 * containers. 45 * 46 * <p>After chaining a new intermediate operation, or executing a terminal 47 * operation, the stream is considered to be consumed, and no more intermediate 48 * or terminal operations are permitted on this stream instance. 49 * 50 * @implNote 51 * <p>For sequential streams, and parallel streams without 52 * <a href="package-summary.html#StreamOps">stateful intermediate 53 * operations</a>, parallel streams, pipeline evaluation is done in a single 54 * pass that "jams" all the operations together. For parallel streams with 55 * stateful operations, execution is divided into segments, where each 56 * stateful operations marks the end of a segment, and each segment is 57 * evaluated separately and the result used as the input to the next 58 * segment. In all cases, the source data is not consumed until a terminal 59 * operation begins. 60 * 61 * @param <E_IN> type of input elements 62 * @param <E_OUT> type of output elements 63 * @param <S> type of the subclass implementing {@code BaseStream} 64 * @since 1.8 65 */ 66 type AbstractPipeline struct { 67 class.Class 68 /** 69 * True if pipeline is parallel, otherwise the pipeline is sequential; only 70 * valid for the source stage. 71 */ 72 parallel bool 73 74 /** 75 * True if this pipeline has been linked or consumed 76 */ 77 linkedOrConsumed bool 78 79 /** Target split size, common to all tasks in a computation */ 80 targetSize int // may be lazily initialized 81 } 82 83 func (p *AbstractPipeline) IsParallel() bool { 84 return p.parallel 85 } 86 87 func (p *AbstractPipeline) SetParallel(parallel bool) { 88 p.parallel = parallel 89 } 90 91 func (p *AbstractPipeline) IsLinkedOrConsumed() bool { 92 return p.linkedOrConsumed 93 } 94 95 func (p *AbstractPipeline) SetLinkedOrConsumed(linkedOrConsumed bool) { 96 p.linkedOrConsumed = linkedOrConsumed 97 } 98 99 /** 100 * Returns the targetSize, initializing it via the supplied 101 * size estimate if not already initialized. 102 */ 103 func (p *AbstractPipeline) GetTargetSize(sizeEstimate int) int { 104 if p.targetSize == 0 { 105 p.targetSize = p.SuggestTargetSize(sizeEstimate) 106 } 107 return p.targetSize 108 } 109 110 func (p *AbstractPipeline) SetTargetSize(targetSize int) { 111 p.targetSize = targetSize 112 } 113 114 /** 115 * Returns a suggested target leaf size based on the initial size estimate. 116 * 117 * @return suggested target leaf size 118 */ 119 func (p *AbstractPipeline) SuggestTargetSize(sizeEstimate int) int { 120 est := sizeEstimate / ParallelTargetSize 121 if est > 0 { 122 return est 123 } 124 return 1 125 } 126 127 // Terminal evaluation methods 128 129 /** 130 * Evaluate the pipeline with a terminal operation to produce a result. 131 * 132 * @param <R> the type of result 133 * @param terminalOp the terminal operation to be applied to the pipeline. 134 * @return the result 135 */ 136 func (p *AbstractPipeline) Evaluate(ctx context.Context, terminalOp Operation, split spliterator.Spliterator) optional.Optional { 137 if p.IsLinkedOrConsumed() { 138 panic(exception.NewIllegalStateException1(MsgStreamLinked)) 139 } 140 p.SetLinkedOrConsumed(true) 141 defer p.SetLinkedOrConsumed(false) 142 143 if p.IsParallel() { 144 return terminalOp.EvaluateParallel(ctx, split) 145 } 146 return terminalOp.EvaluateSequential(ctx, split) 147 }