CachedStack.java
package Hoot.Runtime.Values;
import java.util.*;
import static Hoot.Runtime.Functions.Utils.*;
/**
* Caches items on a thread scoped stack.
* @param <T> item type
*
* @author nik <nikboyd@sonic.net>
* @see "Copyright 2010,2021 Nikolas S Boyd."
* @see "Permission is granted to copy this work provided this copyright statement is retained in all copies."
*/
public class CachedStack<T extends Cacheable<T>> {
private final ThreadLocal<Stack<T>> cache = new ThreadLocal<>();
private Stack<T> cacheStack() { cache.set(new Stack<>()); return cache.get(); }
public Stack<T> cachedStack() { return itemOr(() -> cacheStack(), cache.get()); }
public T pop() { return hasItems() ? cachedStack().pop() : defaultItem(); }
public T top() { return hasItems() ? cachedStack().peek() : defaultItem(); }
public T popIfTop(T item) { if (hasTop(item)) cachedStack().pop(); return item; }
public boolean hasTop(Cacheable item) { return hasOne(item) && hasItems() && top() == item; }
public T push(T item) {
if (hasNone(item) || item.isDefault()) return item;
item.stackIndex(stackDepth()); cachedStack().push(item); return item; }
public T priorItem(T item) {
return (item.isBottom() || !item.onStack()) ?
defaultItem() : cachedStack().get(item.prior()); }
public boolean hasItems() { return 0 < stackDepth(); }
public boolean isEmpty() { return stackDepth() < 1; }
public int stackDepth() { return cachedStack().size(); }
private T defaultItem = null;
public T defaultItem() { return this.defaultItem; }
public CachedStack defaultIfEmpty(T item) { this.defaultItem = item; return this; }
} // CachedStack<T>