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

org.scijava.object.SortedObjectIndex Maven / Gradle / Ivy

/*
 * #%L
 * SciJava Common shared library for SciJava software.
 * %%
 * Copyright (C) 2009 - 2017 Board of Regents of the University of
 * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck
 * Institute of Molecular Cell Biology and Genetics, University of
 * Konstanz, and KNIME GmbH.
 * %%
 * 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 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; } // -- 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); } private void mergeAfterSorting(final Collection c) { final List listToMerge = new ArrayList<>(c); Collections.sort(listToMerge); final Map, List> map = new HashMap<>(); 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 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--)); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy