Skip to content

Commit

Permalink
support to work with sub-collections
Browse files Browse the repository at this point in the history
  • Loading branch information
vagabondkjo committed Mar 25, 2024
1 parent 644ea6f commit b401006
Show file tree
Hide file tree
Showing 2 changed files with 233 additions and 34 deletions.
210 changes: 176 additions & 34 deletions src/smart_contracts/qpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -5072,6 +5072,157 @@ namespace QPI
return NULL_INDEX;
}

// Return elementIndex of first element in priority queue of pov,
// and ignore elements with priority greater than maxPriority
sint64 _headIndex(const sint64 povIndex, const sint64 maxPriority) const
{
const auto& pov = _povs[povIndex];
// quick check pov's size
if (pov.population == 0)
{
return NULL_INDEX;
}
// quick check head/tail
if (_elements[pov.headIndex].priority <= maxPriority)
{
return pov.headIndex;
}
if (_elements[pov.tailIndex].priority > maxPriority)
{
return NULL_INDEX;
}
// search index of parent element if any
sint64 idx = _searchElement(pov.bstRootIndex, maxPriority);
if (_elements[idx].priority > maxPriority)
{
return NULL_INDEX;
}
if (_elements[idx].priority < maxPriority)
{
return idx;
}
// iterating until the first element's has same priority
while (idx != NULL_INDEX)
{
sint64 prevIdx = _previousElementIndex(idx);
if (prevIdx == NULL_INDEX || _elements[prevIdx].priority != maxPriority)
{
break;
}
idx = prevIdx;
}
return idx;
}

// Return elementIndex of last element in priority queue of pov,
// and ignore elements with priority less than minPriority
sint64 _tailIndex(const sint64 povIndex, const sint64 minPriority) const
{
const auto& pov = _povs[povIndex];
// quick check pov's size
if (pov.population == 0)
{
return NULL_INDEX;
}
// quick check head/tail
if (_elements[pov.headIndex].priority < minPriority)
{
return NULL_INDEX;
}
if (_elements[pov.tailIndex].priority >= minPriority)
{
return pov.tailIndex;
}
// search index of parent element if any
sint64 idx = _searchElement(pov.bstRootIndex, minPriority);
if (_elements[idx].priority > minPriority)
{
sint64 nextIdx = _nextElementIndex(idx);
if (nextIdx != NULL_INDEX &&
_elements[nextIdx].priority == minPriority)
{
// continue iterating until the last element's has same priority below
idx = nextIdx;
}
else
{
return idx;
}
}
else if (_elements[idx].priority < minPriority)
{
auto priority = _elements[idx].priority;
while (idx != NULL_INDEX)
{
sint64 prevIdx = _previousElementIndex(idx);
if (prevIdx == NULL_INDEX)
{
break;
}
if (_elements[prevIdx].priority > minPriority)
{
if (priority < minPriority)
{
idx = prevIdx;
}
break;
}
idx = prevIdx;
priority = _elements[idx].priority;
}
return idx;
}
// iterating until the last element's has same priority
while (idx != NULL_INDEX)
{
sint64 nextIdx = _nextElementIndex(idx);
if (nextIdx == NULL_INDEX || _elements[nextIdx].priority != minPriority)
{
break;
}
idx = nextIdx;
}
return idx;
}

// Return index of parent element to insert a priority
sint64 _searchElement(const sint64 bstRootIndex,
const sint64 priority, int* pIterationsCount = nullptr) const
{
sint64 idx = bstRootIndex;
while (idx != NULL_INDEX)
{
if (pIterationsCount)
{
*pIterationsCount += 1;
}
auto& curElement = _elements[idx];
if (curElement.priority > priority)
{
if (curElement.bstRightIndex != NULL_INDEX)
{
idx = curElement.bstRightIndex;
}
else
{
return idx;
}
}
else
{
if (curElement.bstLeftIndex != NULL_INDEX)
{
idx = curElement.bstLeftIndex;
}
else
{
return idx;
}
}
}
return NULL_INDEX;
}

// Add element to priority queue, return elementIndex of new element
sint64 _addPovElement(const sint64 povIndex, const T value, const sint64 priority)
{
Expand All @@ -5089,40 +5240,19 @@ namespace QPI
else
{
int iterations_count = 0;
sint64 idx = pov.bstRootIndex;
while (idx != NULL_INDEX)
sint64 parentIdx = _searchElement(pov.bstRootIndex, priority, &iterations_count);
if (_elements[parentIdx].priority > priority)
{
iterations_count++;
auto& curElement = _elements[idx];
if (_elements[idx].priority > priority)
{
if (curElement.bstRightIndex != NULL_INDEX)
{
idx = curElement.bstRightIndex;
}
else
{
curElement.bstRightIndex = newElementIdx;
newElement.bstParentIndex = idx;
pov.population++;
break;
}
}
else
{
if (curElement.bstLeftIndex != NULL_INDEX)
{
idx = curElement.bstLeftIndex;
}
else
{
curElement.bstLeftIndex = newElementIdx;
newElement.bstParentIndex = idx;
pov.population++;
break;
}
}
_elements[parentIdx].bstRightIndex = newElementIdx;
}
else
{
_elements[parentIdx].bstLeftIndex = newElementIdx;
}
newElement.bstParentIndex = parentIdx;
pov.population++;


if (_elements[pov.headIndex].priority < priority)
{
pov.headIndex = newElementIdx;
Expand Down Expand Up @@ -5605,7 +5735,13 @@ namespace QPI
// Return elementIndex of first element with priority <= maxPriority in priority queue of pov (or NULL_INDEX if pov is unknown).
sint64 headIndex(const id& pov, sint64 maxPriority) const
{
return NULL_INDEX; // TODO: Implement
const sint64 povIndex = _povIndex(pov);
if (povIndex < 0)
{
return NULL_INDEX;
}

return _headIndex(povIndex, maxPriority);
}

// Return elementIndex of next element in priority queue (or NULL_INDEX if this is the last element).
Expand Down Expand Up @@ -5776,7 +5912,13 @@ namespace QPI
// Return elementIndex of last element with priority >= minPriority in priority queue of pov (or NULL_INDEX if pov is unknown).
sint64 tailIndex(const id& pov, sint64 minPriority) const
{
return NULL_INDEX; // TODO: Implement
const sint64 povIndex = _povIndex(pov);
if (povIndex < 0)
{
return NULL_INDEX;
}

return _tailIndex(povIndex, minPriority);
}
};

Expand Down
57 changes: 57 additions & 0 deletions test/qpi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,63 @@ TEST(TestCoreQPI, CollectionOneRemoveLastHeadTail) {
checkPriorityQueue(coll, pov, print);
}

TEST(TestCoreQPI, CollectionSubCollections) {
QPI::id pov(1, 2, 3, 4);

QPI::collection<size_t, 512> coll;
coll.reset();

std::vector<QPI::sint64> priorities = {
44, 22, 88, 111, 55, 56, 11, 55, 55, 54, 66, 77, 99
};

for (size_t i = 0; i < priorities.size(); i++)
{
coll.add(pov, i, priorities[i]);
}
checkPriorityQueue(coll, pov, false);

// sorted priorities: 111, 99, 88, 77, 66, .... 44, 22, 11

// test head/tail
auto headIdx = coll.headIndex(pov);
EXPECT_EQ(coll.priority(headIdx), 111);
auto tailIdx = coll.tailIndex(pov);
EXPECT_EQ(coll.priority(tailIdx), 11);

// test prev/next
auto idx = coll.prevElementIndex(tailIdx);
idx = coll.prevElementIndex(idx);
EXPECT_EQ(coll.priority(idx), 44);
idx = coll.nextElementIndex(headIdx);
idx = coll.nextElementIndex(idx);
EXPECT_EQ(coll.priority(idx), 88);

// test sub-collection's head
headIdx = coll.headIndex(pov, 100);
EXPECT_EQ(coll.priority(headIdx), 99);
headIdx = coll.headIndex(pov, 99);
EXPECT_EQ(coll.priority(headIdx), 99);

// test sub-collection's head: duplicated priorites
headIdx = coll.headIndex(pov, 55);
EXPECT_EQ(coll.priority(headIdx), 55);
idx = coll.prevElementIndex(headIdx);
EXPECT_EQ(coll.priority(idx), 56);

// test sub-collection's tail
tailIdx = coll.tailIndex(pov, 33);
EXPECT_EQ(coll.priority(tailIdx), 44);
tailIdx = coll.tailIndex(pov, 44);
EXPECT_EQ(coll.priority(tailIdx), 44);

// test sub-collection's tail: duplicated priorites
tailIdx = coll.tailIndex(pov, 55);
EXPECT_EQ(coll.priority(tailIdx), 55);
idx = coll.nextElementIndex(tailIdx);
EXPECT_EQ(coll.priority(idx), 54);
}

template <unsigned long long capacity>
void testCollectionCleanupPseudoRandom(int povs, int seed)
{
Expand Down

0 comments on commit b401006

Please sign in to comment.