com.epam.deltix.data.stream.PriorityQueue Maven / Gradle / Ivy
/*
* Copyright 2024 EPAM Systems, Inc
*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. 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 com.epam.deltix.data.stream;
import com.epam.deltix.streaming.MessageSource;
import javax.annotation.Nullable;
import java.io.PrintStream;
import java.util.Comparator;
/**
* Hand-optimized priority queue of MessageSource objects.
* Analogous to java.util.PriorityQueue <MessageSource <T>>
*/
public final class PriorityQueue {
/**
* Number of elements in the heap.
*/
private int mSize;
/**
* The heap represented by array. Root has the index of 1.
* Left child of node A is at A << 1. Right child of node
* A is at A << 1 + 1. Parent of node A is at A >> 1.
*/
private MessageSource[] heap;
private final Comparator comparator;
private final byte direction; // 1 for ascending and -1 for descending
public PriorityQueue(int capacity, boolean ascending, Comparator c) {
init (capacity);
this.comparator = c;
this.direction = (byte) (ascending ? 1 : -1);
}
public void dump (PrintStream ps) {
dump (ps, "", 1);
}
public void dump (PrintStream ps, String indent, int pos) {
MessageSource obj = getInternal (pos);
ps.println (indent + pos + ": " + obj);
int leftChildPos = pos << 1;
int rightChildPos = leftChildPos + 1;
if (leftChildPos <= mSize)
dump (ps, indent + " ", leftChildPos);
if (rightChildPos <= mSize)
dump (ps, indent + " ", rightChildPos);
}
// public void assertValid () {
// for (int pos = 1; pos <= mSize; pos++) {
// MessageSource obj = getInternal (pos);
//
// int leftChildPos = pos << 1;
// int rightChildPos = leftChildPos + 1;
//
// if (leftChildPos <= mSize) {
// MessageSource child = getInternal (leftChildPos);
//
// assert (child.getMessage ().getNanoTime () >= obj.getMessage ().getNanoTime ()) :
// "(L) child at " + leftChildPos + ": " + child + " < parent: " + obj + "; parent pos: " + pos;
// }
//
// if (rightChildPos <= mSize) {
// MessageSource child = getInternal (rightChildPos);
//
// assert (child.getMessage ().getNanoTime () >= obj.getMessage ().getNanoTime ()) :
// "(R) child at " + rightChildPos + ": " + child + " < parent: " + obj + "; parent pos: " + 1;
// }
// }
// }
@SuppressWarnings("unchecked")
public void init (int numObjects) {
heap = new MessageSource [numObjects + 1];
mSize = 0;
}
public void clear () {
mSize = 0;
}
public int size () {
return (mSize);
}
public boolean isEmpty () {
return (mSize == 0);
}
/**
* Spec: set heap at pos
to obj
,
* and percolate the element up if necessary.
*/
private int percUp (int pos, MessageSource obj) {
if (pos > 1) {
pos = findPosForElementInPercUp(pos, obj);
}
heap [pos] = obj;
return pos;
}
/**
* This code is moved to a separate method from {@link #percUp} to allow JIT not inline this method.
*/
private int findPosForElementInPercUp(int pos, MessageSource obj) {
T message = obj.getMessage();
// Cache fields
MessageSource[] heap = this.heap;
Comparator comparator = this.comparator;
byte direction = this.direction;
while (pos > 1) {
int parentPos = pos >> 1;
T parent = heap[parentPos].getMessage();
if (comparator.compare(parent, message) * direction <= 0)
break;
/**
* Percolate the parent down into the hole
*/
heap [pos] = heap [parentPos];
pos = parentPos;
}
return pos;
}
/**
* Spec: set heap at pos
to id
,
* and percolate the element down if necessary.
*/
private int percDown (int pos, MessageSource obj) {
if (pos * 2 <= mSize) {
pos = findPosForElementInPercDown(pos, obj);
}
/**
* Plug this hole with the last element.
*/
heap [pos] = obj;
return pos;
}
/**
* This code is moved to a separate method from {@link #percDown} to allow JIT not inline this method.
*/
private int findPosForElementInPercDown(int pos, MessageSource obj) {
T msg = obj.getMessage();
// Cache fields
int mSize = this.mSize;
Comparator comparator = this.comparator;
MessageSource[] heap = this.heap;
byte direction = this.direction;
for (; ; ) {
int leftChildPos = pos << 1;
if (leftChildPos > mSize)
break;
/**
* Find smallest child of the parent at pos.
*/
T left = heap[leftChildPos].getMessage();
int rightChildPos = leftChildPos + 1;
int smallestChildPos;
T smallest;
if (rightChildPos <= mSize) {
T right = heap[rightChildPos].getMessage();
if (comparator.compare(right, left) * direction < 0) {
smallestChildPos = rightChildPos;
smallest = right;
} else {
smallestChildPos = leftChildPos;
smallest = left;
}
} else {
smallestChildPos = leftChildPos;
smallest = left;
}
if (comparator.compare(msg, smallest) * direction <= 0)
break;
heap[pos] = heap[smallestChildPos];
pos = smallestChildPos;
}
return pos;
}
public void offer (MessageSource obj) {
final int currentCapacity = heap.length;
mSize++;
if (mSize + 1 >= currentCapacity) {
extendCapacity(currentCapacity);
}
/**
* Put the element at new leaf location and adjust the heap.
*/
percUp (mSize, obj);
}
@SuppressWarnings("unchecked")
private void extendCapacity(int currentCapacity) {
int newCapacity = currentCapacity * 2;
MessageSource[] newHeap = new MessageSource[newCapacity];
System.arraycopy(heap, 0, newHeap, 0, mSize);
heap = newHeap;
}
private int indexOfInternal (MessageSource obj) {
for (int ii = 1; ii <= mSize; ii++)
if (obj.equals (heap [ii]))
return (ii);
return (-1);
}
@SuppressWarnings ("unchecked")
private MessageSource getInternal (int pos) {
return heap [pos];
}
public MessageSource get (int idx) {
return (MessageSource) (getInternal (idx + 1));
}
private void removeInternal (int pos) {
/**
* We are removing element at pos, so we are going to have a hole there.
* Put the last element in the hole and adjust the heap.
*/
// ByteArrayOutputStream buf = new ByteArrayOutputStream();
// dump(new PrintStream(buf));
MessageSource last = getInternal (mSize);
heap [mSize] = null;
mSize--;
if (percDown(pos, last) == pos)
percUp(pos, last);
}
public boolean remove (MessageSource obj) {
int pos = indexOfInternal (obj);
if (pos > 0) {
removeInternal (pos);
return (true);
}
return (false);
}
public MessageSource peek () {
if (mSize == 0)
return (null);
return (getInternal (1));
}
@Nullable
public MessageSource poll () {
if (mSize == 0)
return (null);
MessageSource min = getInternal (1);
removeInternal (1);
return (min);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy