/*
* $Id$
* This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc
*
* Copyright (c) 2000-2012 Stephane GALLAND.
* Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
* Universite de Technologie de Belfort-Montbeliard.
* Copyright (c) 2013-2016 The original authors, and other authors.
*
* 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.arakhne.afc.util;
import java.util.Comparator;
import java.util.List;
import java.util.NavigableSet;
import org.eclipse.xtext.xbase.lib.Pure;
/**
* Utilities on lists.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 0.4
*/
public final class ListUtil {
private ListUtil() {
//
}
/** Remove the given element from the list using a dichotomic algorithm.
*
* <p>This function ensure that the comparator is invoked as: <code>comparator(data, dataAlreadyInList)</code>.
*
* @param <E> is the type of the elements in the list.
* @param list is the list to change.
* @param comparator is the comparator of elements.
* @param data is the data to remove.
* @return the index at which the element was removed in the list; or
* <code>-1</code> if the element was not removed.
*/
public static <E> int remove(List<E> list, Comparator<? super E> comparator, E data) {
assert list != null;
assert comparator != null;
assert data != null;
int first = 0;
int last = list.size() - 1;
while (last >= first) {
final int center = (first + last) / 2;
final E dt = list.get(center);
final int cmpR = comparator.compare(data, dt);
if (cmpR == 0) {
list.remove(center);
return center;
} else if (cmpR < 0) {
last = center - 1;
} else {
first = center + 1;
}
}
return -1;
}
/** Add the given element in the main list using a dichotomic algorithm.
*
* <p>This function ensure that the comparator is invoked as: <code>comparator(data, dataAlreadyInList)</code>.
*
* @param <E> is the type of the elements in the list.
* @param list is the list to change.
* @param comparator is the comparator of elements.
* @param data is the data to insert.
* @param allowMultipleOccurencesOfSameValue indicates if multiple
* occurrences of the same value are allowed in the list.
* @param allowReplacement indicates if the given {@code elt} may replace
* the found element.
* @return the index where the element was inserted, or <code>-1</code>
* if the element was not inserted.
*/
public static <E> int add(List<E> list, Comparator<? super E> comparator, E data,
boolean allowMultipleOccurencesOfSameValue, boolean allowReplacement) {
assert list != null;
assert comparator != null;
assert data != null;
int first = 0;
int last = list.size() - 1;
while (last >= first) {
final int center = (first + last) / 2;
final E dt = list.get(center);
final int cmpR = comparator.compare(data, dt);
if (cmpR == 0 && !allowMultipleOccurencesOfSameValue) {
if (allowReplacement) {
list.set(center, data);
return center;
}
return -1;
}
if (cmpR < 0) {
last = center - 1;
} else {
first = center + 1;
}
}
list.add(first, data);
return first;
}
/** Replies if the given element is inside the list, using a dichotomic algorithm.
*
* <p>This function ensure that the comparator is invoked as: <code>comparator(data, dataAlreadyInList)</code>.
*
* @param <E> is the type of the elements in the list.
* @param list is the list to explore.
* @param comparator is the comparator of elements.
* @param data is the data to search for.
* @return <code>true</code> if the data is inside the list, otherwise <code>false</code>
*/
@Pure
public static <E> boolean contains(List<E> list, Comparator<? super E> comparator, E data) {
assert list != null;
assert comparator != null;
assert data != null;
int first = 0;
int last = list.size() - 1;
while (last >= first) {
final int center = (first + last) / 2;
final E dt = list.get(center);
final int cmpR = comparator.compare(data, dt);
if (cmpR == 0) {
return true;
} else if (cmpR < 0) {
last = center - 1;
} else {
first = center + 1;
}
}
return false;
}
/** Replies the index of the given data in the given list according to a
* dichotomic search algorithm. Order between objects
* is given by {@code comparator}.
*
* <p>This function assumes that the given list is sorted
* according to the given comparator.
* A dichotomic algorithm is used.
*
* @param <T> is the type of the data to search for.
* @param list is the list inside which the element should be searched.
* @param comparator is the comparator used to sort the list.
* @param elt is the element to search for.
* @return the index at which the element is, or <code>-1</code> if
* the element was not found.
*/
@Pure
public static <T> int indexOf(List<T> list, Comparator<? super T> comparator, T elt) {
try {
assert comparator != null;
assert list != null;
if (elt == null) {
return -1;
}
int first = 0;
int last = list.size() - 1;
while (last >= first) {
int center = (first + last) / 2;
final T indata = list.get(center);
final int cmp = comparator.compare(elt, indata);
if (cmp == 0) {
do {
--center;
}
while (center >= 0 && comparator.compare(elt, list.get(center)) == 0);
return center + 1;
} else if (cmp < 0) {
last = center - 1;
} else {
first = center + 1;
}
}
} catch (AssertionError e) {
throw e;
} catch (Throwable exception) {
//
}
return -1;
}
/** Replies the last index of the given data in the given list according to a
* dichotomic search algorithm. Order between objects
* is given by {@code comparator}.
*
* <p>This function assumes that the given list is sorted
* according to the given comparator.
* A dichotomic algorithm is used.
*
* @param <T> is the type of the data to search for.
* @param list is the list inside which the element should be searched.
* @param comparator is the comparator used to sort the list.
* @param elt is the element to search for.
* @return the last index at which the element is, or <code>-1</code> if
* the element was not found.
*/
@Pure
public static <T> int lastIndexOf(List<T> list, Comparator<? super T> comparator, T elt) {
try {
assert comparator != null;
assert list != null;
if (elt == null) {
return -1;
}
int first = 0;
int last = list.size() - 1;
while (last >= first) {
int c = (first + last) / 2;
final T indata = list.get(c);
final int cmp = comparator.compare(elt, indata);
if (cmp == 0) {
do {
++c;
}
while (c < list.size() && comparator.compare(elt, list.get(c)) == 0);
return c - 1;
} else if (cmp < 0) {
last = c - 1;
} else {
first = c + 1;
}
}
} catch (AssertionError e) {
throw e;
} catch (Throwable exception) {
//
}
return -1;
}
/** Replies the index at which the given element may
* be added in a sorted list.
*
* <p>This function assumes that the given list is sorted
* according to the given comparator.
* A dichotomic algorithm is used.
*
* <p>This function assumes that the given {@code elt}
* may appear many times in the list.
*
* @param <T> is the type of the elements.
* @param comparator is the comparator used to sort the list.
* @param elt is the element to add in.
* @param list is the list inside which the element should be added.
* @return the index at which the element may be added.
*/
@Pure
public static <T> int getInsertionIndex(List<T> list, Comparator<? super T> comparator, T elt) {
return getInsertionIndex(list, comparator, elt, true);
}
/** Replies the index at which the given element may
* be added in a sorted list.
*
* <p>This function assumes that the given list is sorted
* according to the given comparator.
* A dichotomic algorithm is used.
*
* <p>This function assumes that the given {@code elt}
* may appear many times in the list.
*
* @param <T> is the type of the elements.
* @param comparator is the comparator used to sort the list.
* @param elt is the element to add in.
* @param list is the list inside which the element should be added.
* @param allowMultiple indicates if the given {@code elt} may appear
* many times in the list, or not.
* @return the index at which the element may be added.
*/
@Pure
public static <T> int getInsertionIndex(List<T> list, Comparator<? super T> comparator, T elt, boolean allowMultiple) {
try {
assert comparator != null;
assert list != null;
if (elt == null) {
return -1;
}
int first = 0;
int last = list.size() - 1;
while (last >= first) {
final int center = (first + last) / 2;
final T indata = list.get(center);
final int comparison = comparator.compare(elt, indata);
if (!allowMultiple && comparison == 0) {
return -1;
}
if (comparison < 0) {
last = center - 1;
} else {
first = center + 1;
}
}
return first;
} catch (AssertionError e) {
throw e;
} catch (Throwable exception) {
return -1;
}
}
/**
* Returns the index of the leastest element in this list greater than or equal to
* the given element, or <code>-1</code> if there is no such element.
*
* <p>This function assumes that the given list is sorted
* according to the given comparator.
* A dichotomic algorithm is used.
*
* @param <T> is the type of the data to search for.
* @param list is the list inside which the element should be searched.
* @param comparator is the comparator used to sort the list.
* @param elt is the value to match.
* @return the index of leastest element greater than or equal to {@code elt}, or
* <code>-1</code> if there is no such element.
* @see NavigableSet#ceiling(Object)
*/
@Pure
public static <T> int ceilingIndex(List<T> list, Comparator<? super T> comparator, T elt) {
try {
assert comparator != null;
assert list != null;
if (elt == null) {
return -1;
}
int first = 0;
int last = list.size() - 1;
while (last >= first) {
int c = (first + last) / 2;
final T indata = list.get(c);
final int cmp = comparator.compare(elt, indata);
if (cmp == 0) {
do {
--c;
}
while (c >= 0 && comparator.compare(elt, list.get(c)) == 0);
return c + 1;
} else if (cmp < 0) {
last = c - 1;
} else {
first = c + 1;
}
}
if (first >= list.size()) {
first = -1;
}
return first;
} catch (AssertionError e) {
throw e;
} catch (Throwable exception) {
return -1;
}
}
/**
* Returns the index of the greatest element in this list less than or equal to
* the given element, or <code>-1</code> if there is no such element.
*
* <p>This function assumes that the given list is sorted
* according to the given comparator.
* A dichotomic algorithm is used.
*
* @param <T> is the type of the data to search for.
* @param list is the list inside which the element should be searched.
* @param comparator is the comparator used to sort the list.
* @param elt is the value to match.
* @return the index of greatest element less than or equal to {@code elt}, or
* <code>-1</code> if there is no such element.
* @see NavigableSet#floor(Object)
*/
@Pure
public static <T> int floorIndex(List<T> list, Comparator<? super T> comparator, T elt) {
try {
assert comparator != null;
assert list != null;
if (elt == null) {
return -1;
}
int first = 0;
int last = list.size() - 1;
while (last >= first) {
int center = (first + last) / 2;
final T indata = list.get(center);
final int cmp = comparator.compare(elt, indata);
if (cmp == 0) {
do {
++center;
}
while (center < list.size() && comparator.compare(elt, list.get(center)) == 0);
return center - 1;
} else if (cmp < 0) {
last = center - 1;
} else {
first = center + 1;
}
}
return last;
} catch (AssertionError e) {
throw e;
} catch (Throwable exception) {
return -1;
}
}
/**
* Returns the index of the least element in this list strictly greater
* than the given element, or <code>-1</code> if there is no such element.
*
* <p>This function assumes that the given list is sorted
* according to the given comparator.
* A dichotomic algorithm is used.
*
* @param <T> is the type of the data to search for.
* @param list is the list inside which the element should be searched.
* @param comparator is the comparator used to sort the list.
* @param elt is the value to match.
* @return the index of least element strictly greater than to {@code elt}, or
* <code>-1</code> if there is no such element.
* @see NavigableSet#higher(Object)
*/
@Pure
public static <T> int higherIndex(List<T> list, Comparator<? super T> comparator, T elt) {
try {
assert comparator != null;
assert list != null;
if (elt == null) {
return -1;
}
int first = 0;
int last = list.size() - 1;
while (last >= first) {
final int center = (first + last) / 2;
final T indata = list.get(center);
final int cmp = comparator.compare(elt, indata);
if (cmp < 0) {
last = center - 1;
} else {
first = center + 1;
}
}
++last;
if (last >= list.size()) {
last = -1;
}
return last;
} catch (AssertionError e) {
throw e;
} catch (Throwable exception) {
return -1;
}
}
/**
* Returns the index of the greatest element in this list strictly lower
* than the given element, or <code>-1</code> if there is no such element.
*
* <p>This function assumes that the given list is sorted
* according to the given comparator.
* A dichotomic algorithm is used.
*
* @param <T> is the type of the data to search for.
* @param list is the list inside which the element should be searched.
* @param comparator is the comparator used to sort the list.
* @param elt is the value to match.
* @return the index of greater element strictly lower than to {@code elt}, or
* <code>-1</code> if there is no such element.
* @see NavigableSet#lower(Object)
*/
@Pure
public static <T> int lowerIndex(List<T> list, Comparator<? super T> comparator, T elt) {
try {
assert comparator != null;
assert list != null;
if (elt == null) {
return -1;
}
int first = 0;
int last = list.size() - 1;
while (last >= first) {
final int center = (first + last) / 2;
final T indata = list.get(center);
final int cmp = comparator.compare(elt, indata);
if (cmp <= 0) {
last = center - 1;
} else {
first = center + 1;
}
}
return last;
} catch (AssertionError e) {
throw e;
} catch (Throwable exception) {
return -1;
}
}
}