/*
* Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.yangtools.yang.parser.stmt.reactor;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.Iterators;
import java.util.AbstractCollection;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.function.Consumer;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
/**
* Simple integer-to-StatementContextBase map optimized for size and restricted in scope of operations. It does not
* implement {@link java.util.Map} for simplicity's sake.
*
*
* Unlike other collections, this view does not detect concurrent modification. Iteration is performed in order of
* increasing offset. In face of concurrent modification, number of elements returned through iteration may not match
* the size reported via {@link Collection#size()}.
*
* @author Robert Varga
*/
abstract class StatementMap extends AbstractCollection> {
private static final class Empty extends StatementMap {
private static final Iterator> EMPTY_ITERATOR;
static {
// This may look weird, but we really want to return two Iterator implementations from StatementMap, so that
// users have to deal with bimorphic invocation. Note that we want to invoke hasNext() here, as we want to
// initialize state to AbstractIterator.endOfData().
final Iterator> it = new Regular(0).iterator();
verify(!it.hasNext());
EMPTY_ITERATOR = it;
}
@Override
AbstractResumedStatement, ?, ?> get(final int index) {
return null;
}
@Override
StatementMap put(final int index, final AbstractResumedStatement, ?, ?> obj) {
return index == 0 ? new Singleton(obj) : new Regular(index, obj);
}
@Override
public int size() {
return 0;
}
@Override
StatementMap ensureCapacity(final int expectedLimit) {
return expectedLimit < 2 ? this : new Regular(expectedLimit);
}
@Override
public void forEach(final Consumer super AbstractResumedStatement, ?, ?>> action) {
// No-op
}
@Override
public Iterator> iterator() {
return EMPTY_ITERATOR;
}
}
private static final class Regular extends StatementMap {
private AbstractResumedStatement, ?, ?>[] elements;
private int size;
Regular(final int expectedLimit) {
elements = new AbstractResumedStatement, ?, ?>[expectedLimit];
}
Regular(final int index, final AbstractResumedStatement, ?, ?> object) {
this(index + 1, index, object);
}
Regular(final AbstractResumedStatement, ?, ?> object0, final int index,
final AbstractResumedStatement, ?, ?> object) {
this(index + 1, 0, object0);
elements[index] = requireNonNull(object);
size = 2;
}
Regular(final int expectedLimit, final int index, final AbstractResumedStatement, ?, ?> object) {
this(expectedLimit);
elements[index] = requireNonNull(object);
size = 1;
}
@Override
AbstractResumedStatement, ?, ?> get(final int index) {
return index >= elements.length ? null : elements[index];
}
@Override
StatementMap put(final int index, final AbstractResumedStatement, ?, ?> obj) {
if (index < elements.length) {
checkArgument(elements[index] == null);
} else {
// FIXME: detect linear growth
elements = Arrays.copyOf(elements, index + 1);
}
elements[index] = requireNonNull(obj);
size++;
return this;
}
@Override
public int size() {
return size;
}
@Override
StatementMap ensureCapacity(final int expectedLimit) {
if (elements.length < expectedLimit) {
elements = Arrays.copyOf(elements, expectedLimit);
}
return this;
}
@Override
public Iterator> iterator() {
return new AbstractIterator<>() {
private int nextOffset = 0;
@Override
protected AbstractResumedStatement, ?, ?> computeNext() {
while (nextOffset < elements.length) {
final AbstractResumedStatement, ?, ?> ret = elements[nextOffset++];
if (ret != null) {
return ret;
}
}
return endOfData();
}
};
}
}
private static final class Singleton extends StatementMap {
private final AbstractResumedStatement, ?, ?> object;
Singleton(final AbstractResumedStatement, ?, ?> object) {
this.object = requireNonNull(object);
}
@Override
AbstractResumedStatement, ?, ?> get(final int index) {
return index == 0 ? object : null;
}
@Override
StatementMap put(final int index, final AbstractResumedStatement, ?, ?> obj) {
checkArgument(index != 0);
return new Regular(this.object, index, obj);
}
@Override
public int size() {
return 1;
}
@Override
StatementMap ensureCapacity(final int expectedLimit) {
return expectedLimit < 2 ? this : new Regular(expectedLimit, 0, object);
}
@Override
public Iterator> iterator() {
return Iterators.singletonIterator(object);
}
}
private static final StatementMap EMPTY = new Empty();
static StatementMap empty() {
return EMPTY;
}
/**
* Return the statement context at specified index.
*
* @param index Element index, must be non-negative
* @return Requested element or null if there is no element at that index
*/
abstract @Nullable AbstractResumedStatement, ?, ?> get(int index);
/**
* Add a statement at specified index.
*
* @param index Element index, must be non-negative
* @param obj Object to store
* @return New statement map
* @throws IllegalArgumentException if the index is already occupied
*/
abstract @NonNull StatementMap put(int index, @NonNull AbstractResumedStatement, ?, ?> obj);
abstract @NonNull StatementMap ensureCapacity(int expectedLimit);
}