All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jlib.collection.CachingList Maven / Gradle / Ivy

/*
 * jlib - Open Source Java Library
 *
 *     www.jlib.org
 *
 *
 *     Copyright 2005-2018 Igor Akkerman
 *
 *     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.jlib.collection;

import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Spliterator;
import java.util.function.UnaryOperator;

import lombok.NonNull;
import lombok.RequiredArgsConstructor;

/**
 * 

* {@link List} caching the index of the last {@link Item} looked up using {@link #indexOf(Object)} and * returning it by a subsequent call to {@link #get(int)} for the same index. The other methods are delegated to the * {@link List} specified to the constructor. *

*

* Note that if the index of the requested {@link Item} is changed in the delegate {@link List} between the calls to * {@link #indexOf(Object)} and {@link #get(int)}, the former, now wrong, index will be returned by the latter * call. This also happens when the {@link Item} is removed from the delegate {@link List}. *

*

* As in all jlib classes, {@code null} {@link Item}s are not permitted and cause undefined behaviour, * such as {@link RuntimeException}s or invalid results. Hence, a {@link CachingList} may not be used on delegate * {@link List}s containing {@code null} {@link Item}s. *

*

* The key idea behind this proxy is to be able to use the following idiom without worrying about performance issues due * to multiple lookups: *

*
 * if (list.contains(item)) {
 *     itemIndex = list.indexOf(item);
 *     // commands with index
 * }
 * else {
 *     // commands with no item
 * }
*

* Instead, many developers use the following technique which enforces comparing the result with {@code -1}. This is a * discouraged code style and less readable: *

*
 * // dicouraged by clean coders
 * itemIndex = list.indexOf(item);
 * if (itemIndex != -1) {
 *     // commands with index
 * }
 * else {
 *     // commands with no index
 * }
* * @param * type of the values * * @author Igor Akkerman */ @RequiredArgsConstructor public final class CachingList implements List { /** delegate {@link List} */ private final List delegate; /** last looked up index; -1 if unset (for performance reasons) */ private int lastLookedUpItemIndex; /** last looked up {@link Item}; {@code null} if unset (for performance reasons) */ private /* @Nullable */ Object lastLookedUpItem; @Override public boolean contains(final /* @Nullable */ Object item) { return indexOf(item) != - 1; } @Override @NonNull public Iterator iterator() { return delegate.iterator(); } @Override @NonNull public Object[] toArray() { return delegate.toArray(); } @Override @NonNull @SuppressWarnings("SuspiciousToArrayCall") public ArrayItem[] toArray(@NonNull final ArrayItem[] array) { return delegate.toArray(array); } @Override public boolean add(final Item item) { return delegate.add(item); } @Override public boolean remove(final Object item) { return delegate.remove(item); } @Override public boolean containsAll(@NonNull final Collection items) { return delegate.containsAll(items); } @Override public boolean addAll(@NonNull final Collection items) { return delegate.addAll(items); } @Override public boolean addAll(final int index, @NonNull final Collection items) { return delegate.addAll(index, items); } @Override public boolean removeAll(@NonNull final Collection items) { return delegate.removeAll(items); } @Override public boolean retainAll(@NonNull final Collection items) { return delegate.retainAll(items); } @Override public void replaceAll(final UnaryOperator operator) { delegate.replaceAll(operator); } @Override public void sort(final Comparator items) { delegate.sort(items); } @Override @SuppressWarnings("ObjectEquality") public int indexOf(final /* @Nullable */ Object item) { if (item == lastLookedUpItem) return lastLookedUpItemIndex; @SuppressWarnings("ConstantConditions") final int itemIndex = delegate.indexOf(item); lastLookedUpItem = item; lastLookedUpItemIndex = itemIndex; return itemIndex; } @Override public int lastIndexOf(final Object o) { return delegate.lastIndexOf(o); } @Override @NonNull public ListIterator listIterator() { return delegate.listIterator(); } @Override @NonNull public ListIterator listIterator(final int index) { return delegate.listIterator(index); } @Override @NonNull public List subList(final int fromIndex, final int toIndex) { return delegate.subList(fromIndex, toIndex); } @Override public Spliterator spliterator() { return delegate.spliterator(); } @Override public Item remove(final int index) { if (index == lastLookedUpItemIndex) clearLastLookedUpIndex(); return delegate.remove(index); } @Override public void clear() { clearLastLookedUpIndex(); delegate.clear(); } @Override @SuppressWarnings({ "EqualsWhichDoesntCheckParameterClass", "EqualsBetweenInconvertibleTypes" }) public boolean equals(final Object object) { return delegate.equals(object); } @Override public int hashCode() { return delegate.hashCode(); } @Override public Item get(final int index) { return delegate.get(index); } @Override public Item set(final int index, final Item element) { return delegate.set(index, element); } @Override public void add(final int index, final Item element) { delegate.add(index, element); } /** * Clears the last looked up contained Key and Item. */ @SuppressWarnings({ "AssignmentToNull", "ConstantConditions" }) private void clearLastLookedUpIndex() { lastLookedUpItem = null; lastLookedUpItemIndex = - 1; } @Override public int size() { return delegate.size(); } @Override public boolean isEmpty() { return delegate.isEmpty(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy