/* * 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 com.google.common.base.Preconditions; import com.google.common.collect.AbstractIterator; import com.google.common.collect.ImmutableList; import java.util.AbstractCollection; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.function.Consumer; import javax.annotation.Nonnull; import javax.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. * * @author Robert Varga */ abstract class StatementMap { private static final class Empty extends StatementMap { @Override StatementContextBase<?, ?, ?> get(final int index) { return null; } @Override StatementMap put(final int index, final StatementContextBase<?, ?, ?> object) { return index == 0 ? new Singleton(object) : new Regular(index, object); } @Override Collection<StatementContextBase<?, ?, ?>> values() { return ImmutableList.of(); } } private static final class Regular extends StatementMap { private StatementContextBase<?, ?, ?>[] elements; Regular(final int index, final StatementContextBase<?, ?, ?> object) { elements = new StatementContextBase<?, ?, ?>[index + 1]; elements[index] = Preconditions.checkNotNull(object); } Regular(final StatementContextBase<?, ?, ?> object0, final int index, final StatementContextBase<?, ?, ?> object) { elements = new StatementContextBase<?, ?, ?>[index + 1]; elements[0] = Preconditions.checkNotNull(object0); elements[index] = Preconditions.checkNotNull(object); } @Override StatementContextBase<?, ?, ?> get(final int index) { if (index >= elements.length) { return null; } return elements[index]; } @Override StatementMap put(final int index, final StatementContextBase<?, ?, ?> object) { if (index < elements.length) { Preconditions.checkArgument(elements[index] == null); } else { elements = Arrays.copyOf(elements, index + 1); } elements[index] = Preconditions.checkNotNull(object); return this; } @Override Collection<StatementContextBase<?, ?, ?>> values() { return new RegularAsCollection<>(elements); } } private static final class RegularAsCollection<T> extends AbstractCollection<T> { private final T[] elements; RegularAsCollection(final T[] elements) { this.elements = Preconditions.checkNotNull(elements); } @Override public void forEach(final Consumer<? super T> action) { for (T e : elements) { if (e != null) { action.accept(e); } } } @Override public boolean isEmpty() { // This has a single-use and when it is instantiated, we know to have at least two items return false; } @Override public Iterator<T> iterator() { return new AbstractIterator<T>() { private int nextOffset = 0; @Override protected T computeNext() { while (nextOffset < elements.length) { final T ret = elements[nextOffset++]; if (ret != null) { return ret; } } return endOfData(); } }; } @Override public int size() { // Optimized for non-sparse case int nulls = 0; for (T e : elements) { if (e == null) { nulls++; } } return elements.length - nulls; } } private static final class Singleton extends StatementMap { private final StatementContextBase<?, ?, ?> object; Singleton(final StatementContextBase<?, ?, ?> object) { this.object = Preconditions.checkNotNull(object); } @Override StatementContextBase<?, ?, ?> get(final int index) { return index == 0 ? object : null; } @Override StatementMap put(final int index, final StatementContextBase<?, ?, ?> object) { Preconditions.checkArgument(index != 0); return new Regular(this.object, index, object); } @Override Collection<StatementContextBase<?, ?, ?>> values() { return ImmutableList.of(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 StatementContextBase<?, ?, ?> get(int index); /** * Add a statement at specified index. * * @param index Element index, must be non-negative * @param object Object to store * @return New statement map * @throws IllegalArgumentException if the index is already occupied */ abstract @Nonnull StatementMap put(int index, @Nonnull StatementContextBase<?, ?, ?> object); /** * Return a read-only view of the elements in this map. Unlike other maps, 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()}. * * @return Read-only view of available statements. */ abstract @Nonnull Collection<StatementContextBase<?, ?, ?>> values(); }