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

com.metamx.common.guava.LimitedSequence Maven / Gradle / Ivy

There is a newer version: 1.3.8
Show newest version
/*
 * Copyright 2011 - 2015 Metamarkets Group Inc.
 *
 * Licensed 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 com.metamx.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.
 */
public class LimitedSequence extends YieldingSequenceBase
{
  private final Sequence baseSequence;
  private final int limit;

  public 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;

    public 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;

    public 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;
    }

    public boolean isInterruptYield()
    {
      return interruptYield;
    }

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy