
org.scijava.object.SortedObjectIndex Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scijava-common Show documentation
Show all versions of scijava-common Show documentation
SciJava Common is a shared library for SciJava software. It provides a plugin framework, with an extensible mechanism for service discovery, backed by its own annotation processor, so that plugins can be loaded dynamically. It is used by both ImageJ and SCIFIO.
/*
* #%L
* SciJava Common shared library for SciJava software.
* %%
* Copyright (C) 2009 - 2016 Board of Regents of the University of
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
* Institute of Molecular Cell Biology and Genetics.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.object;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Data structure for managing sorted lists of registered objects.
*
* This data structure is the same as a vanilla {@link ObjectIndex} except that
* each type list is kept in sorted order; hence, the items managed must
* implement the {@link Comparable} interface. When adding a single item (i.e.,
* with {@link #add(Object)}), a binary search is used to insert it in the
* correct position (O(log n) + O(n) time per item). When adding multiple items
* at once (i.e., with {@link #addAll(Collection)}), the items are appended and
* the list is then resorted (O(n log n) time for all items).
*
*
* @author Curtis Rueden
*/
public class SortedObjectIndex> extends
ObjectIndex
{
public SortedObjectIndex(final Class baseClass) {
super(baseClass);
}
// -- Collection methods --
@Override
public boolean contains(final Object o) {
final int index = findInList(o, getAll());
return index < 0;
}
@Override
public boolean containsAll(final Collection> c) {
for (final Object o : c) {
if (!contains(o)) return false;
}
return true;
}
@Override
public boolean addAll(final Collection extends E> c) {
if (c.size() > 1) {
mergeAfterSorting(c);
return c.size() > 0;
}
if (c.size() == 1) {
// add single item normally, to avoid resorting the lists
return add(c.iterator().next());
}
final boolean changed = super.addAll(c);
if (changed) sort();
return changed;
}
private void mergeAfterSorting(final Collection extends E> c) {
final List listToMerge = new ArrayList(c);
Collections.sort(listToMerge);
final Map, List> map = new HashMap, List>();
for (final E e : listToMerge) {
for (final Class> clazz : getTypes(getType(e))) {
final List list = retrieveList(clazz);
List list2 = map.get(clazz);
if (list2 == null) {
list2 = list.size() == 0 ? (List)list : new ArrayList();
map.put(clazz, list2);
}
list2.add(e);
}
}
for (final Entry, List> entry : map.entrySet()) {
final Class> clazz = entry.getKey();
final List into = retrieveList(clazz);
final List sorted = map.get(clazz);
if (into != sorted) mergeInto(sorted, into);
}
}
private void mergeInto(final List extends E> sorted, final List into) {
if (sorted == into) return;
final int count = sorted.size();
if (count == 0) return;
if (into.size() == 0) {
into.addAll(sorted);
return;
}
int index1 = into.size() - 1;
int index2 = sorted.size() - 1;
for (int i = 0; i < count; i++) into.add(null);
int writeIndex = into.size() - 1;
E e1 = into.get(index1);
E e2 = sorted.get(index2);
while (writeIndex > index1) {
if (e1.compareTo(e2) < 0) {
into.set(writeIndex--, e2);
if (--index2 < 0) break;
e2 = sorted.get(index2);
} else {
into.set(writeIndex--, e1);
if (--index1 < 0) break;
e1 = into.get(index1);
}
}
while (index2 >= 0) {
into.set(writeIndex--, sorted.get(index2--));
}
}
// -- Internal methods --
@Override
protected boolean addToList(final E obj, final List list,
final boolean batch)
{
if (batch) {
// adding multiple values; append to end of list, and sort afterward
return super.addToList(obj, list, batch);
}
// search for the correct location to insert the object
final int result = Collections.binarySearch(list, obj);
// NB: The objects' natural ordering may not be consistent with equals.
// Hence, the index reported may indicate a match with an unequal object
// (i.e., obj.compareTo(match) == 0 but !obj.equals(match)).
// But since we allow duplicate items in the index, this situation is fine;
// either way, we want to insert the object at the given point.
final int index = result < 0 ? -result - 1 : result;
// insert object at the appropriate location
list.add(index, obj);
return true;
}
// -- Helper methods --
private void sort() {
for (final List list : hoard.values()) {
Collections.sort(list);
}
}
private int findInList(final Object o, final List list) {
if (!getBaseClass().isAssignableFrom(o.getClass())) {
// wrong type
return list.size();
}
@SuppressWarnings("unchecked")
final E typedObj = (E) o;
return Collections.binarySearch(list, typedObj);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy