github.com/searKing/golang/go@v1.2.74/util/function/consumer/sink/sink.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 sink 6 7 import ( 8 "github.com/searKing/golang/go/util/function/consumer" 9 ) 10 11 /** 12 * An extension of {@link Consumer} used to conduct values through the stages of 13 * a stream pipeline, with additional methods to manage size information, 14 * control flow, etc. Before calling the {@code accept()} method on a 15 * {@code Sink} for the first time, you must first call the {@code begin()} 16 * method to inform it that data is coming (optionally informing the sink how 17 * much data is coming), and after all data has been sent, you must call the 18 * {@code end()} method. After calling {@code end()}, you should not call 19 * {@code accept()} without again calling {@code begin()}. {@code Sink} also 20 * offers a mechanism by which the sink can cooperatively signal that it does 21 * not wish to receive any more data (the {@code cancellationRequested()} 22 * method), which a source can poll before sending more data to the 23 * {@code Sink}. 24 * 25 * <p>A sink may be in one of two states: an initial state and an active state. 26 * It starts out in the initial state; the {@code begin()} method transitions 27 * it to the active state, and the {@code end()} method transitions it back into 28 * the initial state, where it can be re-used. Data-accepting methods (such as 29 * {@code accept()} are only valid in the active state. 30 * 31 * @apiNote 32 * A stream pipeline consists of a source, zero or more intermediate stages 33 * (such as filtering or mapping), and a terminal stage, such as reduction or 34 * for-each. For concreteness, consider the pipeline: 35 * 36 * <pre>{@code 37 * int longestStringLengthStartingWithA 38 * = strings.stream() 39 * .filter(s -> s.startsWith("A")) 40 * .mapToInt(String::length) 41 * .max(); 42 * }</pre> 43 * 44 * <p>Here, we have three stages, filtering, mapping, and reducing. The 45 * filtering stage consumes strings and emits a subset of those strings; the 46 * mapping stage consumes strings and emits ints; the reduction stage consumes 47 * those ints and computes the maximal value. 48 * 49 * <p>A {@code Sink} instance is used to represent each stage of this pipeline, 50 * whether the stage accepts objects, ints, longs, or doubles. Sink has entry 51 * points for {@code accept(Object)}, {@code accept(int)}, etc, so that we do 52 * not need a specialized interface for each primitive specialization. (It 53 * might be called a "kitchen sink" for this omnivorous tendency.) The entry 54 * point to the pipeline is the {@code Sink} for the filtering stage, which 55 * sends some elements "Downstream" -- into the {@code Sink} for the mapping 56 * stage, which in turn sends integral values Downstream into the {@code Sink} 57 * for the reduction stage. The {@code Sink} implementations associated with a 58 * given stage is expected to know the data type for the next stage, and call 59 * the correct {@code accept} method on its Downstream {@code Sink}. Similarly, 60 * each stage must implement the correct {@code accept} method corresponding to 61 * the data type it accepts. 62 * 63 * <p>The specialized subtypes such as {@link Sink.OfInt} override 64 * {@code accept(Object)} to call the appropriate primitive specialization of 65 * {@code accept}, implement the appropriate primitive specialization of 66 * {@code Consumer}, and re-abstract the appropriate primitive specialization of 67 * {@code accept}. 68 * 69 * <p>The chaining subtypes such as {@link ChainedInt} not only implement 70 * {@code Sink.OfInt}, but also maintain a {@code Downstream} field which 71 * represents the Downstream {@code Sink}, and implement the methods 72 * {@code begin()}, {@code end()}, and {@code cancellationRequested()} to 73 * delegate to the Downstream {@code Sink}. Most implementations of 74 * intermediate operations will use these chaining wrappers. For example, the 75 * mapping stage in the above example would look like: 76 * 77 * <pre>{@code 78 * IntSink is = new Sink.AbstractChainedReferenceSink<U>(sink) { 79 * public void accept(U u) { 80 * Downstream.accept(mapper.applyAsInt(u)); 81 * } 82 * }; 83 * }</pre> 84 * 85 * <p>Here, we implement {@code Sink.AbstractChainedReferenceSink<U>}, meaning that we expect 86 * to receive elements of type {@code U} as input, and pass the Downstream sink 87 * to the constructor. Because the next stage expects to receive integers, we 88 * must call the {@code accept(int)} method when emitting values to the Downstream. 89 * The {@code accept()} method applies the mapping function from {@code U} to 90 * {@code int} and passes the resulting value to the Downstream {@code Sink}. 91 * 92 * @param <T> type of elements for value streams 93 * @since 1.8 94 */ 95 type Sink interface { 96 consumer.Consumer 97 98 /** 99 * Resets the sink state to receive a fresh data set. This must be called 100 * before sending any data to the sink. After calling {@link #end()}, 101 * you may call this method to reset the sink for another calculation. 102 * @param size The exact size of the data to be pushed Downstream, if 103 * known or {@code -1} if unknown or infinite. 104 * 105 * <p>Prior to this call, the sink must be in the initial state, and after 106 * this call it is in the active state. 107 */ 108 Begin(size int) 109 110 /** 111 * Indicates that all elements have been pushed. If the {@code Sink} is 112 * stateful, it should send any stored state Downstream at this time, and 113 * should clear any accumulated state (and associated resources). 114 * 115 * <p>Prior to this call, the sink must be in the active state, and after 116 * this call it is returned to the initial state. 117 */ 118 End() 119 120 /** 121 * Indicates that this {@code Sink} does not wish to receive any more data. 122 * 123 * @implSpec The default implementation always returns false. 124 * 125 * @return true if cancellation is requested 126 */ 127 CancellationRequested() bool 128 }