2020-07-28 23:01:43 +02:00
|
|
|
package org.warp.commonutils.type;
|
|
|
|
|
2020-09-22 19:17:48 +02:00
|
|
|
import it.unimi.dsi.fastutil.objects.Object2FloatMap;
|
|
|
|
import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap;
|
2020-07-28 23:01:43 +02:00
|
|
|
import java.lang.reflect.Array;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.PriorityQueue;
|
|
|
|
import java.util.Queue;
|
|
|
|
import java.util.function.Consumer;
|
2020-09-22 19:17:48 +02:00
|
|
|
import java.util.function.IntFunction;
|
2020-07-28 23:01:43 +02:00
|
|
|
import java.util.stream.Stream;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
|
|
|
|
public class FloatPriorityQueue<T> implements Queue<T> {
|
|
|
|
|
2020-09-22 19:17:48 +02:00
|
|
|
private final Object2FloatMap<T> contentValues;
|
2020-07-28 23:01:43 +02:00
|
|
|
private final Queue<ScoredValue<T>> internalQueue;
|
|
|
|
|
|
|
|
public static <T> FloatPriorityQueue<T> of() {
|
|
|
|
return new FloatPriorityQueue<T>(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static <T> FloatPriorityQueue<T> of(T value, float score) {
|
|
|
|
var pq = new FloatPriorityQueue<T>(1);
|
|
|
|
pq.offer(value);
|
|
|
|
return pq;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static <T> FloatPriorityQueue<T> of(ScoredValue<T> value) {
|
|
|
|
var pq = new FloatPriorityQueue<T>(1);
|
|
|
|
pq.offer(value);
|
|
|
|
return pq;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static <T> FloatPriorityQueue<T> of(ScoredValue<T>... values) {
|
|
|
|
var pq = new FloatPriorityQueue<T>(values.length);
|
|
|
|
for (ScoredValue<T> value : values) {
|
|
|
|
pq.offer(value);
|
|
|
|
}
|
|
|
|
return pq;
|
|
|
|
}
|
|
|
|
|
|
|
|
public FloatPriorityQueue(PriorityQueue<ScoredValue<T>> internalQueue) {
|
2020-09-22 19:17:48 +02:00
|
|
|
this(internalQueue.size());
|
|
|
|
for (ScoredValue<T> tScoredValue : internalQueue) {
|
|
|
|
add(tScoredValue.getValue(), tScoredValue.getScore());
|
|
|
|
}
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
2020-09-22 19:17:48 +02:00
|
|
|
private FloatPriorityQueue(Object2FloatMap<T> contentValues, Queue<ScoredValue<T>> internalQueue) {
|
|
|
|
this.contentValues = contentValues;
|
2020-07-28 23:01:43 +02:00
|
|
|
this.internalQueue = internalQueue;
|
|
|
|
}
|
|
|
|
|
|
|
|
public FloatPriorityQueue() {
|
2020-09-22 19:17:48 +02:00
|
|
|
this.contentValues = new Object2FloatOpenHashMap<>();
|
2020-07-28 23:01:43 +02:00
|
|
|
internalQueue = new PriorityQueue<>();
|
|
|
|
}
|
|
|
|
|
|
|
|
public FloatPriorityQueue(int initialCapacity) {
|
2020-09-22 19:17:48 +02:00
|
|
|
this.contentValues = new Object2FloatOpenHashMap<>(initialCapacity);
|
2020-07-28 23:01:43 +02:00
|
|
|
internalQueue = new PriorityQueue<>(Math.max(1, initialCapacity));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static <T> FloatPriorityQueue<T> synchronize(FloatPriorityQueue<T> queue) {
|
2020-09-22 19:17:48 +02:00
|
|
|
return new SynchronizedFloatPriorityQueue<T>(queue.contentValues, queue.internalQueue);
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static <T> FloatPriorityQueue<T> synchronizedPq(int initialCapacity) {
|
2020-09-22 19:17:48 +02:00
|
|
|
var pq = new FloatPriorityQueue<T>(initialCapacity);
|
|
|
|
return new SynchronizedFloatPriorityQueue<T>(pq.contentValues, pq.internalQueue);
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int size() {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
return internalQueue.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isEmpty() {
|
2020-09-22 21:28:56 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
return internalQueue.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean contains(Object o) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
return internalQueue.contains(ScoredValue.of(0, o));
|
|
|
|
}
|
|
|
|
|
|
|
|
@NotNull
|
|
|
|
@Override
|
|
|
|
public Iterator<T> iterator() {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
var it = internalQueue.iterator();
|
|
|
|
return new Iterator<T>() {
|
|
|
|
@Override
|
|
|
|
public boolean hasNext() {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
return it.hasNext();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public T next() {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
return getValueOrNull(it.next());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-09-22 19:17:48 +02:00
|
|
|
private static <T> T getValueOrNull(ScoredValue<T> scoredValue) {
|
2020-07-28 23:01:43 +02:00
|
|
|
if (scoredValue == null) {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
return scoredValue.getValue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@NotNull
|
|
|
|
@Override
|
|
|
|
public Object[] toArray() {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
return internalQueue.stream().map(FloatPriorityQueue::getValueOrNull).toArray(Object[]::new);
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@NotNull
|
|
|
|
@Override
|
|
|
|
public <T1> T1[] toArray(@NotNull T1[] a) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
return internalQueue
|
|
|
|
.stream()
|
2020-09-22 19:17:48 +02:00
|
|
|
.map(FloatPriorityQueue::getValueOrNull)
|
2020-07-28 23:01:43 +02:00
|
|
|
.toArray(i -> (T1[]) Array.newInstance(a.getClass().getComponentType(), i));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
@Override
|
|
|
|
public boolean add(T t) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
return offer(t, 0);
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean addTop(T t) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
if (contentValues.getFloat(t) == Integer.MAX_VALUE) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
if (contentValues.containsKey(t)) {
|
|
|
|
internalQueue.remove(ScoredValue.of(0, t));
|
|
|
|
}
|
|
|
|
contentValues.put(t, Integer.MAX_VALUE);
|
|
|
|
return internalQueue.add(ScoredValue.of(Integer.MAX_VALUE, t));
|
|
|
|
}
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean add(T t, float score) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
return offer(t, score);
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean remove(Object o) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
contentValues.removeFloat(o);
|
2020-07-28 23:01:43 +02:00
|
|
|
return internalQueue.remove(ScoredValue.of(0, o));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean containsAll(@NotNull Collection<?> c) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
for (Object o : c) {
|
|
|
|
//noinspection SuspiciousMethodCalls
|
|
|
|
if (!contentValues.containsKey(o)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean addAll(@NotNull Collection<? extends T> c) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
boolean added = false;
|
|
|
|
for (T t : c) {
|
|
|
|
added |= add(t);
|
|
|
|
}
|
|
|
|
return added;
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean removeAll(@NotNull Collection<?> c) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
boolean removed = false;
|
|
|
|
for (Object o : c) {
|
|
|
|
removed |= remove(o);
|
|
|
|
}
|
|
|
|
return removed;
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean retainAll(@NotNull Collection<?> c) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
return removeIf(item -> !c.contains(item));
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void clear() {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
contentValues.clear();
|
2020-07-28 23:01:43 +02:00
|
|
|
internalQueue.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean offer(T t) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
return offer(ScoredValue.of(0, t));
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean offer(T t, float score) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
return offer(ScoredValue.of(score, t));
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean offer(ScoredValue<T> value) {
|
2020-09-30 22:43:53 +02:00
|
|
|
int contentValuesSize = contentValues.size();
|
|
|
|
int internalQueueSize = internalQueue.size();
|
|
|
|
assert contentValuesSize == internalQueueSize;
|
2020-09-22 19:17:48 +02:00
|
|
|
|
|
|
|
boolean added = true;
|
|
|
|
float oldValue;
|
|
|
|
if (contentValues.containsKey(value.getValue())) {
|
|
|
|
internalQueue.remove(value);
|
|
|
|
oldValue = contentValues.getFloat(value.getValue());
|
|
|
|
added = false;
|
|
|
|
} else {
|
|
|
|
oldValue = 0f;
|
|
|
|
}
|
|
|
|
contentValues.put(value.getValue(), oldValue + value.getScore());
|
|
|
|
internalQueue.add(value);
|
|
|
|
return added;
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public T remove() {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
var val = internalQueue.remove();
|
|
|
|
if (val != null) {
|
|
|
|
contentValues.removeFloat(val.getValue());
|
|
|
|
}
|
|
|
|
return getValueOrNull(val);
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public T poll() {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
|
|
|
var val = internalQueue.poll();
|
|
|
|
|
|
|
|
if (val != null) {
|
|
|
|
contentValues.removeFloat(val.getValue());
|
|
|
|
}
|
|
|
|
return getValueOrNull(val);
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public T element() {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
return getValueOrNull(internalQueue.element());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public T peek() {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
return getValueOrNull(internalQueue.peek());
|
|
|
|
}
|
|
|
|
|
|
|
|
public void forEachItem(Consumer<ScoredValue<T>> action) {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
internalQueue.forEach(action);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Stream<ScoredValue<T>> streamItems() {
|
2020-09-22 19:17:48 +02:00
|
|
|
assert contentValues.size() == internalQueue.size();
|
2020-07-28 23:01:43 +02:00
|
|
|
return internalQueue.stream();
|
|
|
|
}
|
2020-09-22 19:17:48 +02:00
|
|
|
|
|
|
|
private static class SynchronizedFloatPriorityQueue<T> extends FloatPriorityQueue<T> {
|
|
|
|
|
|
|
|
public SynchronizedFloatPriorityQueue(Object2FloatMap<T> contentValues, Queue<ScoredValue<T>> internalQueue) {
|
|
|
|
super(contentValues, internalQueue);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized int size() {
|
|
|
|
return super.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean isEmpty() {
|
|
|
|
return super.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean contains(Object o) {
|
|
|
|
return super.contains(o);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized @NotNull Iterator<T> iterator() {
|
|
|
|
var it = super.iterator();
|
|
|
|
return new Iterator<T>() {
|
|
|
|
@Override
|
|
|
|
public boolean hasNext() {
|
|
|
|
synchronized (SynchronizedFloatPriorityQueue.this) {
|
|
|
|
return it.hasNext();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public T next() {
|
|
|
|
synchronized (SynchronizedFloatPriorityQueue.this) {
|
|
|
|
return it.next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized @NotNull Object[] toArray() {
|
|
|
|
return super.toArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized <T1> @NotNull T1[] toArray(@NotNull T1[] a) {
|
|
|
|
return super.toArray(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized <T1> T1[] toArray(IntFunction<T1[]> generator) {
|
|
|
|
//noinspection SuspiciousToArrayCall
|
|
|
|
return super.toArray(generator);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean add(T t, float score) {
|
|
|
|
return super.add(t, score);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean addTop(T t) {
|
|
|
|
return super.addTop(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean add(T t) {
|
|
|
|
return super.add(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean addAll(@NotNull Collection<? extends T> c) {
|
|
|
|
return super.addAll(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean remove(Object o) {
|
|
|
|
return super.remove(o);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean removeAll(@NotNull Collection<?> c) {
|
|
|
|
return super.removeAll(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean containsAll(@NotNull Collection<?> c) {
|
|
|
|
return super.containsAll(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean retainAll(@NotNull Collection<?> c) {
|
|
|
|
return super.retainAll(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized void clear() {
|
|
|
|
super.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean offer(T t) {
|
|
|
|
return super.offer(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean offer(T t, float score) {
|
|
|
|
return super.offer(t, score);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized boolean offer(ScoredValue<T> value) {
|
|
|
|
return super.offer(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized T remove() {
|
|
|
|
return super.remove();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized T poll() {
|
|
|
|
return super.poll();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized T element() {
|
|
|
|
return super.element();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized T peek() {
|
|
|
|
return super.peek();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized void forEachItem(Consumer<ScoredValue<T>> action) {
|
|
|
|
super.forEachItem(action);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public synchronized Stream<ScoredValue<T>> streamItems() {
|
|
|
|
return super.streamItems();
|
|
|
|
}
|
|
|
|
}
|
2020-07-28 23:01:43 +02:00
|
|
|
}
|