Skip to content

Commit

Permalink
JIT: Add priority queue implementation (dotnet#109319)
Browse files Browse the repository at this point in the history
  • Loading branch information
amanasifkhalid authored Oct 29, 2024
1 parent 8f8ac8e commit 8886107
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/coreclr/jit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ set( JIT_HEADERS
opcode.h
optcse.h
phase.h
priorityqueue.h
promotion.h
rangecheck.h
rationalize.h
Expand Down
121 changes: 121 additions & 0 deletions src/coreclr/jit/priorityqueue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

//
// PriorityQueue: A priority queue implemented as a max-heap

template <typename T, typename Compare>
class PriorityQueue
{
private:
jitstd::vector<T> data;
Compare comp;

#ifdef DEBUG
// Returns true only if each element has a higher priority than its children.
bool VerifyMaxHeap() const
{
for (size_t i = 0; i < data.size(); i++)
{
const size_t leftChild = (2 * i) + 1;
const size_t rightChild = leftChild + 1;

if (rightChild < data.size())
{
if (comp(data[i], data[leftChild]) || comp(data[i], data[rightChild]))
{
return false;
}
}
else if (leftChild < data.size())
{
if (comp(data[i], data[leftChild]))
{
return false;
}
}
}

return true;
}
#endif // DEBUG

public:
PriorityQueue(const jitstd::allocator<T>& allocator, const Compare& compare)
: data(allocator)
, comp(compare)
{
}

const T& Top() const
{
assert(!data.empty());
return data.front();
}

bool Empty() const
{
return data.empty();
}

// Insert new element at the back of the vector.
// Then, while the new element has a higher priority than its parent, move the element up.
void Push(const T& value)
{
size_t i = data.size();
data.push_back(value);

auto getParent = [](const size_t i) -> size_t {
return (i - 1) / 2;
};

// Instead of swapping the new value with its parent, copy the parent value to the correct location,
// and write the new value once.
for (size_t parent = getParent(i); (i != 0) && comp(data[parent], value); i = parent, parent = getParent(i))
{
data[i] = data[parent];
}

data[i] = value;
// assert(VerifyMaxHeap());
}

// Remove and return the root element.
// To efficiently pop from the back of the vector, we will look for a new position for the last element.
T Pop()
{
assert(!data.empty());

auto getLeftChild = [](const size_t i) -> size_t {
return (2 * i) + 1;
};

const T root = data.front();
const T& lastElem = data.back();
const size_t size = data.size() - 1;
size_t i = 0;

// Instead of swapping 'lastElem' with its highest-priority child, copy the child to the parent position.
// Once we've found a position for 'lastElem', we will write to it once.
for (size_t maxChild = getLeftChild(i); maxChild < size; i = maxChild, maxChild = getLeftChild(i))
{
const size_t rightChild = maxChild + 1;
maxChild = ((rightChild < size) && comp(data[maxChild], data[rightChild])) ? rightChild : maxChild;

if (comp(lastElem, data[maxChild]))
{
data[i] = data[maxChild];
}
else
{
break;
}
}

data[i] = lastElem;
data.pop_back();

// assert(VerifyMaxHeap());
return root;
}
};

0 comments on commit 8886107

Please sign in to comment.