/* * Copyright (C) 2015 Francis Galiegue <fgaliegue@gmail.com> * * 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.github.fge.grappa.stack; import com.google.common.annotations.VisibleForTesting; import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; import java.util.Objects; /** * Base abstract implementation of a {@link ValueStack} * * @param <V> type parameter of this stack's values */ @ParametersAreNonnullByDefault public abstract class ValueStackBase<V> implements ValueStack<V> { @VisibleForTesting static final String NEGATIVE_INDEX = "index cannot be negative"; @VisibleForTesting static final String NOT_ENOUGH_ELEMENTS = "not enough elements in stack"; @VisibleForTesting static final String SWAP_BADARG = "argument to swap(...) must be >= 2"; @Override public final boolean isEmpty() { return size() == 0; } @Override public final void push(final V value) { push(0, value); } @Override public final void push(final int down, final V value) { /* * It is legal to append at the end! We must therefore check that the * index - 1 is strictly less than size, not the index itself */ if (down < 0) throw new IllegalArgumentException(NEGATIVE_INDEX); checkIndex(down - 1); Objects.requireNonNull(value); doPush(down, value); } /** * Push a value onto the stack at the given index * * <p>The value is guaranteed never to be null and the index is guaranteed * to be valid.</p> * * @param down the index * @param value the value */ protected abstract void doPush(int down, V value); @Nonnull @Override public final V pop() { return pop(0); } @Nonnull @Override public final V pop(final int down) { if (down < 0) throw new IllegalArgumentException(NEGATIVE_INDEX); checkIndex(down); return doPop(down); } @Nonnull @Override public final <T extends V> T popAs(final Class<T> type) { return type.cast(pop(0)); } @Nonnull @Override public final <T extends V> T popAs(final Class<T> type, final int down) { return type.cast(pop(down)); } /** * Removes the value from a given stack index * * <p>The index is guaranteed to be valid.</p> * * @param down the index * @return the value */ protected abstract V doPop(int down); @Nonnull @Override public final V peek() { return peek(0); } @Nonnull @Override public final V peek(final int down) { if (down < 0) throw new IllegalArgumentException(NEGATIVE_INDEX); checkIndex(down); return doPeek(down); } @Nonnull @Override public final <T extends V> T peekAs(final Class<T> type) { return type.cast(peek(0)); } @Nonnull @Override public final <T extends V> T peekAs(final Class<T> type, final int down) { return type.cast(peek(down)); } /** * Retrieves, witout removing, the value at the given stack indx * * <p>The index is guaranteed to be valid.</p> * * @param down the index * @return the value */ protected abstract V doPeek(final int down); @Override public final void poke(@Nonnull final V value) { poke(0, value); } @Override public final void poke(final int down, final V value) { if (down < 0) throw new IllegalArgumentException(NEGATIVE_INDEX); checkIndex(down); Objects.requireNonNull(value); doPoke(down, value); } /** * Replaces a value at a given stack index * * <p>The index is guaranteed to be valid and the value is guaranteed not to * be null.</p> * * @param down the index * @param value the value */ protected abstract void doPoke(final int down, final V value); @Override public final void swap(final int n) { if (n < 2) throw new IllegalArgumentException(SWAP_BADARG); /* * As for .push(n, value), we need to check for n - 1 here */ checkIndex(n - 1); doSwap(n); } @Override public final void swap() { swap(2); } /** * Reverses the order of the top n stack values * * <p>The number of values is guaranteed to be valid.</p> * * @param n the number of values to swap */ protected abstract void doSwap(final int n); /** * Duplicates the top value. Equivalent to push(peek()). */ @Override public final void dup() { checkIndex(0); doDup(); } protected abstract void doDup(); /** * Check whether the stack has enough elements to perform an operation * given an index in the stack * * @param index the index * * @throws IllegalStateException not enough elements in stack */ protected final void checkIndex(final int index) { if (index >= size()) throw new IllegalStateException(NOT_ENOUGH_ELEMENTS); } }