Modules/Containers/public/IntervalTree.hpp
2024-11-24 22:41:13 +03:00

88 lines
No EOL
2.5 KiB
C++

#pragma once
#include "Tree.hpp"
namespace tp {
template <typename tType>
class IntervalKey {
public:
IntervalKey() = default;
IntervalKey(tType start, tType end) {
mStart = start;
mEnd = end;
}
inline bool descentRight(const IntervalKey& in) const {
if (in.mStart != mStart) return in.mStart > mStart;
return in.mEnd > mEnd;
}
inline bool descentLeft(const IntervalKey& in) const {
if (in.mStart != mStart) return in.mStart < mStart;
return in.mEnd < mEnd;
}
inline bool exactNode(const IntervalKey& in) const { return in.mStart == mStart && in.mEnd == mEnd; }
inline const IntervalKey& getFindKey() const { return *this; }
inline const IntervalKey& keyInRightSubtree(const IntervalKey& in) const { return in; }
inline const IntervalKey& keyInLeftSubtree(const IntervalKey& in) const { return in; }
template <typename tTreeNodeType>
inline void updateTreeCacheCallBack(const tTreeNodeType& node) {
mMax = 0;
if (node.mRight && node.mRight->key.mMax > mMax) mMax = node.mRight->key.mMax;
if (node.mLeft && node.mLeft->key.mMax > mMax) mMax = node.mLeft->key.mMax;
if (mMax < mEnd) mMax = mEnd;
}
public:
tType mStart = tType();
tType mEnd = tType();
tType mMax = tType();
};
template <typename tType, typename tData>
class IntervalTree : public AvlTree<IntervalKey<tType>, tData> {
typedef AvlTree<IntervalKey<tType>, tData>::Node Node;
public:
IntervalTree() = default;
template <typename tFunctor>
ualni forEachIntersection(tType start, tType end, tFunctor functor) const {
ualni debug = 0;
forEachIntersectionUtil(this->head(), start, end, functor, debug);
return debug;
}
private:
template <typename tFunctor>
void forEachIntersectionUtil(const Node* node, tType start, tType end, tFunctor functor, ualni& debug) const {
if (node == nullptr) return;
debug++;
// If 'start' is to the right of the rightmost point of any interval
// in this node and all children, there won't be any matches.
if (start > node->key.mMax) return;
// Search left children
forEachIntersectionUtil(node->mLeft, start, end, functor, debug);
// Check this node
if (start <= node->key.mEnd && end >= node->key.mStart) {
functor(node->key.mStart, node->key.mEnd, node->data);
}
// If end is to the left of the start of this interval,
// then it can't be in any child to the right.
if (end < node->key.mStart) return;
// Otherwise, search right children
forEachIntersectionUtil(node->mRight, start, end, functor, debug);
}
};
}