All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.druid.java.util.common.guava.LimitedSequence Maven / Gradle / Ivy

There is a newer version: 0.12.3
Show newest version
/*
 * Licensed to Metamarkets Group Inc. (Metamarkets) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. Metamarkets licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package io.druid.java.util.common.guava;

import com.google.common.base.Preconditions;

import java.io.IOException;

/**
 * Limits the number of inputs from this sequence.  For example, if there are actually 100 things in the sequence
 * but the limit is set to 10, the Sequence will act as if it only had 10 things.
 */
final class LimitedSequence extends YieldingSequenceBase
{
  private final Sequence baseSequence;
  private final int limit;

  LimitedSequence(
      Sequence baseSequence,
      int limit
  )
  {
    Preconditions.checkNotNull(baseSequence);
    Preconditions.checkArgument(limit >= 0, "limit is negative");

    this.baseSequence = baseSequence;
    this.limit = limit;
  }

  @Override
  public  Yielder toYielder(OutType initValue, YieldingAccumulator accumulator)
  {
    final LimitedYieldingAccumulator limitedAccumulator = new LimitedYieldingAccumulator<>(
        accumulator
    );
    final Yielder subYielder = baseSequence.toYielder(initValue, limitedAccumulator);
    return new LimitedYielder<>(subYielder, limitedAccumulator);
  }

  private class LimitedYielder implements Yielder
  {
    private final Yielder subYielder;
    private final LimitedYieldingAccumulator limitedAccumulator;

    LimitedYielder(
        Yielder subYielder,
        LimitedYieldingAccumulator limitedAccumulator
    )
    {
      this.subYielder = subYielder;
      this.limitedAccumulator = limitedAccumulator;
    }

    @Override
    public OutType get()
    {
      return subYielder.get();
    }

    @Override
    public Yielder next(OutType initValue)
    {
      if (!limitedAccumulator.withinThreshold()) {
        return Yielders.done(initValue, subYielder);
      }

      Yielder next = subYielder.next(initValue);
      if (!limitedAccumulator.withinThreshold() && (!limitedAccumulator.yielded()
                                                    || limitedAccumulator.isInterruptYield())) {
        next = Yielders.done(next.get(), next);
      }
      return new LimitedYielder<>(next, limitedAccumulator);
    }

    @Override
    public boolean isDone()
    {
      return subYielder.isDone() || (
          !limitedAccumulator.withinThreshold() && (!limitedAccumulator.yielded()
                                                    || limitedAccumulator.isInterruptYield())
      );
    }

    @Override
    public void close() throws IOException
    {
      subYielder.close();
    }
  }

  private class LimitedYieldingAccumulator extends DelegatingYieldingAccumulator
  {
    int count;
    boolean interruptYield = false;

    LimitedYieldingAccumulator(YieldingAccumulator accumulator)
    {
      super(accumulator);
      count = 0;
    }

    @Override
    public OutType accumulate(OutType accumulated, T in)
    {
      ++count;

      if (!withinThreshold()) {
        // yield to interrupt the sequence
        interruptYield = true;
      }

      // if delegate yields as well we need to distinguish between the two yields
      final OutType retVal = super.accumulate(accumulated, in);
      if (yielded() && interruptYield) {
        interruptYield = false;
      }
      if (interruptYield) {
        yield();
      }

      return retVal;
    }

    boolean isInterruptYield()
    {
      return interruptYield;
    }

    private boolean withinThreshold()
    {
      return count < limit;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy