#ifndef MRT_CARTESIAN_TREE_H
#define MRT_CARTESIAN_TREE_H
#include <cstddef>
#include <cstdint>
#include "Base/LogFile.h"
#include "Base/Panic.h"
#include "LocalDeque.h"
#if defined(MRT_DEBUG)
#define DEBUG_CARTESIAN_TREE
#endif
#ifdef DEBUG_CARTESIAN_TREE
#define CTREE_ASSERT(cond, msg) MRT_ASSERT(cond, msg)
#define CTREE_CHECK_PARENT_AND_LCHILD(n) CheckParentAndLeftChild(n)
#define CTREE_CHECK_PARENT_AND_RCHILD(n) CheckParentAndRightChild(n)
#else
#define CTREE_ASSERT(cond, msg) (void(0))
#define CTREE_CHECK_PARENT_AND_LCHILD(n) (void(0))
#define CTREE_CHECK_PARENT_AND_RCHILD(n) (void(0))
#endif
namespace MapleRuntime {
class CartesianTree {
public:
using Index = uint32_t;
using Count = uint32_t;
CartesianTree() = default;
~CartesianTree() = default;
void Init(size_t memoryBlockCount)
{
size_t nodeCount = (memoryBlockCount >> 1) + 1;
size_t nativeSize = (nodeCount + 7) * AllocUtilRndUp(sizeof(Node), alignof(Node));
nodeAllocator.Init(ALLOCUTIL_PAGE_RND_UP(nativeSize));
size_t dequeSize = nodeCount * sizeof(Node*);
sud.Init(ALLOCUTIL_PAGE_RND_UP(dequeSize));
traversalSud.Init(sud.GetMemMap());
}
void Fini() noexcept
{
ClearTree();
sud.Fini();
nodeAllocator.Fini();
}
void ClearTree()
{
CartesianTree::Iterator it(*this);
Node* node = it.Next();
while (node != nullptr) {
DeleteNode(node);
node = it.Next();
}
root = nullptr;
totalCount = 0;
}
Count GetTotalCount() const { return totalCount; }
void IncTotalCount(Count cnt) { totalCount += cnt; }
void DecTotalCount(Count cnt)
{
if (totalCount < cnt) {
LOG(RTLOG_FATAL, "CartesianTree::DecTotalCount() Should not execute here, abort.");
}
totalCount -= cnt;
}
bool MergeInsert(Index idx, Count num, bool refreshRegionInfo)
{
if (root == nullptr) {
root = new (nodeAllocator.Allocate()) Node(idx, num, refreshRegionInfo);
CTREE_ASSERT(root != nullptr, "failed to allocate a new node");
IncTotalCount(num);
return true;
}
if (num == 0) {
return false;
}
return MergeInsertInternal(idx, num, refreshRegionInfo);
}
bool TakeUnits(Count num, Index& idx, bool refreshRegionInfo = true)
{
if (root == nullptr || num == 0) {
return false;
}
return TakeUnitsImpl(num, idx, refreshRegionInfo);
}
bool TakeUnitsLowAddr(Count num, Index& idx, bool refreshRegionInfo = true)
{
if (root == nullptr || num == 0) {
return false;
}
return TakeUnitsLowAddrImpl(num, idx, refreshRegionInfo);
}
struct Node {
Node(Index idx, Count num, bool refreshRegionInfo) : l(nullptr), r(nullptr), index(idx), count(num)
{
if (refreshRegionInfo) {
RefreshFreeRegionInfo();
}
}
~Node()
{
l = nullptr;
r = nullptr;
}
inline Index GetIndex() const { return index; }
inline Count GetCount() const { return count; }
inline void IncCount(Count num, bool refreshRegionInfo)
{
count += num;
if (refreshRegionInfo && count > 0) {
RefreshFreeRegionInfo();
}
}
inline void ClearCount() { count = 0; }
inline void UpdateNode(Index idx, Count cnt, bool refreshRegionInfo)
{
index = idx;
count = cnt;
if (refreshRegionInfo && cnt > 0) {
RefreshFreeRegionInfo();
}
}
inline bool IsProperNode() const
{
Count leftCount = l == nullptr ? 0 : l->GetCount();
Count rightCount = r == nullptr ? 0 : r->GetCount();
return (count >= leftCount && count >= rightCount);
}
void RefreshFreeRegionInfo();
void ReleaseMemory();
Node* l;
Node* r;
private:
Index index;
Count count;
};
class Iterator {
public:
explicit Iterator(CartesianTree& tree) : localQueue(tree.traversalSud)
{
if (tree.root != nullptr) {
localQueue.Push(tree.root);
}
}
~Iterator() = default;
inline Node* Next()
{
if (localQueue.Empty()) {
return nullptr;
}
Node* front = localQueue.Front();
if (front->r != nullptr) {
localQueue.Push(front->r);
}
if (front->l != nullptr) {
localQueue.Push(front->l);
}
localQueue.PopFront();
return front;
}
private:
LocalDeque<Node*> localQueue;
};
class ForwardIterator {
public:
explicit ForwardIterator(CartesianTree& tree) : localQueue(tree.sud)
{
if (tree.root != nullptr) {
localQueue.Push(&tree.root);
}
}
~ForwardIterator() = default;
inline Node** Next()
{
if (localQueue.Empty()) {
return nullptr;
}
Node** topElement = localQueue.Front();
Node* node = *topElement;
if (node->r != nullptr) {
localQueue.Push(&node->r);
}
if (node->l != nullptr) {
localQueue.Push(&node->l);
}
localQueue.PopFront();
return topElement;
}
private:
LocalDeque<Node**> localQueue;
};
inline bool Empty() const { return root == nullptr; }
inline const Node* RootNode() const { return root; }
size_t GetNodeCount() const;
void ReleaseRootNode()
{
root->ReleaseMemory();
RemoveNode(root);
}
using RTAllocator = RTAllocatorT<sizeof(Node), alignof(Node)>;
#ifdef DEBUG_CARTESIAN_TREE
void DumpTree(const char* msg) const;
#endif
private:
Count totalCount = 0u;
Node* root = nullptr;
SingleUseDeque<Node**> sud;
SingleUseDeque<Node*> traversalSud;
RTAllocator nodeAllocator;
void DeleteNode(Node* n) noexcept
{
if (n == nullptr) {
return;
}
nodeAllocator.Deallocate(n);
}
enum class MergeResult {
MERGE_SUCCESS = 0,
MERGE_MISS,
MERGE_ERROR
};
MergeResult MergeAt(Node& n, Index idx, Count num, bool refreshRegionInfo)
{
Index endIdx = idx + num;
if (idx == n.GetIndex() + n.GetCount()) {
return MergeToRight(n, endIdx, num, refreshRegionInfo);
}
if (endIdx == n.GetIndex()) {
return MergeToLeft(n, idx, num, refreshRegionInfo);
}
return MergeResult::MERGE_MISS;
}
MergeResult MergeToRight(Node& n, Index endIdx, Count num, bool refreshRegionInfo)
{
Node* parent = &n;
Node* nearest = n.r;
while (nearest != nullptr) {
if (nearest->GetIndex() == endIdx) {
if (nearest->l != nullptr) {
CTREE_ASSERT(false, "merging failed case 1");
return MergeResult::MERGE_ERROR;
}
break;
} else if (nearest->GetIndex() < endIdx) {
CTREE_ASSERT(false, "merging failed case 2");
return MergeResult::MERGE_ERROR;
} else {
parent = nearest;
nearest = nearest->l;
}
}
n.IncCount(num, refreshRegionInfo);
IncTotalCount(num);
if (nearest != nullptr) {
n.IncCount(nearest->GetCount(), refreshRegionInfo);
if (parent == &n) {
n.r = nearest->r;
} else {
parent->l = nearest->r;
}
nodeAllocator.Deallocate(nearest);
}
CTREE_CHECK_PARENT_AND_RCHILD(&n);
return MergeResult::MERGE_SUCCESS;
}
MergeResult MergeToLeft(Node& n, Index startIdx, Count num, bool refreshRegionInfo)
{
Node* parent = &n;
Node* nearest = n.l;
while (nearest != nullptr) {
if (nearest->GetIndex() + nearest->GetCount() == startIdx) {
if (nearest->r != nullptr) {
CTREE_ASSERT(false, "merging failed case 3");
return MergeResult::MERGE_ERROR;
}
break;
} else if (nearest->GetIndex() + nearest->GetCount() > startIdx) {
CTREE_ASSERT(false, "merging failed case 4");
return MergeResult::MERGE_ERROR;
} else {
parent = nearest;
nearest = nearest->r;
}
}
n.UpdateNode(startIdx, n.GetCount() + num, refreshRegionInfo);
IncTotalCount(num);
if (nearest != nullptr) {
if (parent == &n) {
n.l = nearest->l;
} else {
parent->r = nearest->l;
}
n.UpdateNode(nearest->GetIndex(), n.GetCount() + nearest->GetCount(), refreshRegionInfo);
nodeAllocator.Deallocate(nearest);
}
CTREE_CHECK_PARENT_AND_LCHILD(&n);
return MergeResult::MERGE_SUCCESS;
}
bool MergeInsertInternal(Index idx, Count num, bool refreshRegionInfo);
inline Node* RotateLeftChild(Node& n) const
{
Node* newRoot = n.l;
n.l = newRoot->r;
newRoot->r = &n;
return newRoot;
}
inline Node* RotateRightChild(Node& n) const
{
Node* newRoot = n.r;
n.r = newRoot->l;
newRoot->l = &n;
return newRoot;
}
bool TakeUnitsImpl(Count num, Index& idx, bool refershRegionInfo);
Node** FindBestFitLowAddrPtr(Node** nodePtr, Count num, Node** best);
bool TakeUnitsLowAddrImpl(Count num, Index& idx, bool refreshRegionInfo);
bool AllocateLowestAddressFromNode(Node*& node, Count count, Index& index);
ATTR_NO_INLINE Node* LowerNode(Node* n)
{
CTREE_ASSERT(n, "lowering node failed");
Node* tmp = nullptr;
if (n->l != nullptr && n->l->GetCount() > n->GetCount()) {
if (n->r != nullptr && n->r->GetCount() > n->l->GetCount()) {
tmp = RotateRightChild(*n);
tmp->l = LowerNode(tmp->l);
CTREE_CHECK_PARENT_AND_LCHILD(tmp);
return tmp;
} else {
tmp = RotateLeftChild(*n);
tmp->r = LowerNode(tmp->r);
CTREE_CHECK_PARENT_AND_RCHILD(tmp);
return tmp;
}
}
if (n->r != nullptr && n->r->GetCount() > n->GetCount()) {
tmp = RotateRightChild(*n);
tmp->l = LowerNode(tmp->l);
CTREE_CHECK_PARENT_AND_LCHILD(tmp);
return tmp;
}
return n;
}
Node*& LowerImproperNodeOnce(Node*& n) const
{
CTREE_ASSERT(n, "failed to lower node once");
if (n->l != nullptr) {
if (n->r != nullptr && n->r->GetCount() >= n->l->GetCount()) {
Node* newRoot = RotateRightChild(*n);
CTREE_CHECK_PARENT_AND_LCHILD(newRoot);
n = newRoot;
return newRoot->l;
}
Node* newRoot = RotateLeftChild(*n);
CTREE_CHECK_PARENT_AND_RCHILD(newRoot);
n = newRoot;
return newRoot->r;
}
if (n->r != nullptr) {
Node* newRoot = RotateRightChild(*n);
CTREE_CHECK_PARENT_AND_LCHILD(newRoot);
n = newRoot;
return newRoot->l;
}
return n;
}
Node*& MaintainHeapPropertyForZeroNode(Node*& n) const
{
Node** nodePtr = &n;
while ((*nodePtr)->l != nullptr || (*nodePtr)->r != nullptr) {
nodePtr = &LowerImproperNodeOnce(*nodePtr);
}
return *nodePtr;
}
void MaintainHeapPropertyForNonZeroNode(Node*& n) const
{
Node** nodePtr = &n;
while (!(**nodePtr).IsProperNode()) {
nodePtr = &LowerImproperNodeOnce(*nodePtr);
}
}
void RemoveZeroNode(Node*& n)
{
Node*& nodeRef = MaintainHeapPropertyForZeroNode(n);
CHECK_DETAIL((nodeRef->l == nullptr && nodeRef->r == nullptr), "UNEXPECT");
nodeAllocator.Deallocate(nodeRef);
nodeRef = nullptr;
}
void RemoveNode(Node*& n)
{
DecTotalCount(n->GetCount());
n->ClearCount();
RemoveZeroNode(n);
}
void LowerNonZeroNode(Node*& n) const { MaintainHeapPropertyForNonZeroNode(n); }
#ifdef DEBUG_CARTESIAN_TREE
inline void CheckParentAndLeftChild(const Node* n) const
{
if (n != nullptr) {
const Node* l = n->l;
if (l != nullptr) {
CTREE_ASSERT((n->GetIndex() > (l->GetIndex() + l->GetCount())), "left child overlapped with parent");
CTREE_ASSERT((n->GetCount() >= l->GetCount()), "left child bigger than parent");
}
}
}
inline void CheckParentAndRightChild(const Node* n) const
{
if (n != nullptr) {
const Node* r = n->r;
if (r != nullptr) {
CTREE_ASSERT(((n->GetIndex() + n->GetCount()) < r->GetIndex()), "right child overlapped with parent");
CTREE_ASSERT((n->GetCount() >= r->GetCount()), "right child bigger than parent");
}
}
}
inline void CheckNode(const Node* n) const
{
CheckParentAndLeftChild(n);
CheckParentAndRightChild(n);
}
void VerifyTree()
{
Count total = 0;
CartesianTree::Iterator it(*this);
Node* node = it.Next();
while (node != nullptr) {
total += node->GetCount();
CheckNode(node);
node = it.Next();
}
if (total != GetTotalCount()) {
DLOG(REGION, "c-tree %p total unit count %u (expect %u)", this, GetTotalCount(), total);
DumpTree("internal error tree");
LOG(RTLOG_FATAL, "CartesianTree::VerifyTree() Should not execute here, abort.");
}
}
#endif
};
}
#endif