/* * (C) Copyright 2017 Pantheon Technologies, s.r.o. and others. * * 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 org.opendaylight.yangtools.triemap; import static org.opendaylight.yangtools.triemap.Constants.MAX_DEPTH; import java.util.Iterator; import java.util.Map.Entry; import java.util.NoSuchElementException; /** * Abstract base class for iterators supporting {@link AbstractEntrySet} subclasses. * * @author Robert Varga * * @param <K> the type of entry keys * @param <V> the type of entry values */ abstract class AbstractIterator<K, V> implements Iterator<Entry<K, V>> { private final BasicNode[][] nodeStack = new BasicNode[MAX_DEPTH][]; private final int[] positionStack = new int[MAX_DEPTH]; private final TrieMap<K, V> map; private LNodeEntries<K, V> lnode; private EntryNode<K, V> current; private int depth = -1; AbstractIterator(final ImmutableTrieMap<K, V> map) { this.map = map; readin(map.RDCSS_READ_ROOT()); } @Override public final boolean hasNext() { return current != null || lnode != null; } @Override public final Entry<K, V> next() { final Entry<K, V> entry; // Check LNode iterator first if (lnode != null) { entry = lnode; lnode = lnode.next(); if (lnode == null) { advance(); } } else { entry = current; advance(); } if (entry == null) { throw new NoSuchElementException(); } return wrapEntry(entry); } /** * Wrap entry so it can be presented to the user. * * @param entry An immutable entry, guaranteed to be non-null * @return Wrapped entry, may not be null */ abstract Entry<K, V> wrapEntry(Entry<K, V> entry); /** * Read the contents of an INode's main node. * * @param in INode to be read. */ private void readin(final INode<K, V> in) { final MainNode<K, V> m = in.gcasRead(map); if (m instanceof CNode) { // Enter the next level final CNode<K, V> cn = (CNode<K, V>) m; depth++; nodeStack[depth] = cn.array; positionStack[depth] = -1; advance(); } else if (m instanceof TNode) { current = (TNode<K, V>) m; } else if (m instanceof LNode) { lnode = ((LNode<K, V>) m).entries(); } else if (m == null) { current = null; } } private void advance() { if (depth >= 0) { int npos = positionStack[depth] + 1; if (npos < nodeStack[depth].length) { positionStack [depth] = npos; BasicNode elem = nodeStack[depth][npos]; if (elem instanceof SNode) { current = (SNode<K, V>) elem; } else if (elem instanceof INode) { readin((INode<K, V>) elem); } } else { depth -= 1; advance(); } } else { current = null; } } }