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  }