#ifndef PODIntervalTree_h
#define PODIntervalTree_h
#include "platform/PODArena.h"
#include "platform/PODInterval.h"
#include "platform/PODRedBlackTree.h"
#include "wtf/Assertions.h"
#include "wtf/Noncopyable.h"
#include "wtf/Vector.h"
namespace WebCore {
#ifndef NDEBUG
template<class T>
struct ValueToString;
#endif
template <class T, class UserData = void*>
class PODIntervalSearchAdapter {
public:
typedef PODInterval<T, UserData> IntervalType;
PODIntervalSearchAdapter(Vector<IntervalType>& result, const T& lowValue, const T& highValue)
: m_result(result)
, m_lowValue(lowValue)
, m_highValue(highValue)
{
}
const T& lowValue() const { return m_lowValue; }
const T& highValue() const { return m_highValue; }
void collectIfNeeded(const IntervalType& data) const
{
if (data.overlaps(m_lowValue, m_highValue))
m_result.append(data);
}
private:
Vector<IntervalType>& m_result;
T m_lowValue;
T m_highValue;
};
template<class T, class UserData = void*>
class PODIntervalTree FINAL : public PODRedBlackTree<PODInterval<T, UserData> > {
WTF_MAKE_NONCOPYABLE(PODIntervalTree);
public:
typedef PODInterval<T, UserData> IntervalType;
typedef PODIntervalSearchAdapter<T, UserData> IntervalSearchAdapterType;
PODIntervalTree(UninitializedTreeEnum unitializedTree)
: PODRedBlackTree<IntervalType>(unitializedTree)
{
init();
}
PODIntervalTree()
: PODRedBlackTree<IntervalType>()
{
init();
}
explicit PODIntervalTree(PassRefPtr<PODArena> arena)
: PODRedBlackTree<IntervalType>(arena)
{
init();
}
Vector<IntervalType> allOverlaps(const IntervalType& interval) const
{
Vector<IntervalType> result;
allOverlaps(interval, result);
return result;
}
void allOverlaps(const IntervalType& interval, Vector<IntervalType>& result) const
{
IntervalSearchAdapterType adapter(result, interval.low(), interval.high());
searchForOverlapsFrom<IntervalSearchAdapterType>(this->root(), adapter);
}
template <class AdapterType>
void allOverlapsWithAdapter(AdapterType& adapter) const
{
searchForOverlapsFrom<AdapterType>(this->root(), adapter);
}
static IntervalType createInterval(const T& low, const T& high, const UserData data = 0)
{
return IntervalType(low, high, data);
}
virtual bool checkInvariants() const OVERRIDE
{
if (!PODRedBlackTree<IntervalType>::checkInvariants())
return false;
if (!this->root())
return true;
return checkInvariantsFromNode(this->root(), 0);
}
private:
typedef typename PODRedBlackTree<IntervalType>::Node IntervalNode;
void init()
{
this->setNeedsFullOrderingComparisons(true);
}
template <class AdapterType>
void searchForOverlapsFrom(IntervalNode* node, AdapterType& adapter) const
{
if (!node)
return;
IntervalNode* left = node->left();
if (left
&& !(left->data().maxHigh() < adapter.lowValue()))
searchForOverlapsFrom<AdapterType>(left, adapter);
adapter.collectIfNeeded(node->data());
if (!(adapter.highValue() < node->data().low()))
searchForOverlapsFrom<AdapterType>(node->right(), adapter);
}
virtual bool updateNode(IntervalNode* node) OVERRIDE
{
const T* curMax = &node->data().high();
IntervalNode* left = node->left();
if (left) {
if (*curMax < left->data().maxHigh())
curMax = &left->data().maxHigh();
}
IntervalNode* right = node->right();
if (right) {
if (*curMax < right->data().maxHigh())
curMax = &right->data().maxHigh();
}
if (!(*curMax == node->data().maxHigh())) {
node->data().setMaxHigh(*curMax);
return true;
}
return false;
}
bool checkInvariantsFromNode(IntervalNode* node, T* currentMaxValue) const
{
T leftMaxValue(node->data().maxHigh());
T rightMaxValue(node->data().maxHigh());
IntervalNode* left = node->left();
IntervalNode* right = node->right();
if (left) {
if (!checkInvariantsFromNode(left, &leftMaxValue))
return false;
}
if (right) {
if (!checkInvariantsFromNode(right, &rightMaxValue))
return false;
}
if (!left && !right) {
if (currentMaxValue)
*currentMaxValue = node->data().high();
return (node->data().high() == node->data().maxHigh());
}
T localMaxValue(node->data().maxHigh());
if (!left || !right) {
if (left)
localMaxValue = leftMaxValue;
else
localMaxValue = rightMaxValue;
} else {
localMaxValue = (leftMaxValue < rightMaxValue) ? rightMaxValue : leftMaxValue;
}
if (localMaxValue < node->data().high())
localMaxValue = node->data().high();
if (!(localMaxValue == node->data().maxHigh())) {
#ifndef NDEBUG
String localMaxValueString = ValueToString<T>::string(localMaxValue);
WTF_LOG_ERROR("PODIntervalTree verification failed at node 0x%p: localMaxValue=%s and data=%s",
node, localMaxValueString.utf8().data(), node->data().toString().utf8().data());
#endif
return false;
}
if (currentMaxValue)
*currentMaxValue = localMaxValue;
return true;
}
};
#ifndef NDEBUG
template<class T, class UserData>
struct ValueToString<PODInterval<T, UserData> > {
static String string(const PODInterval<T, UserData>& interval)
{
return interval.toString();
}
};
#endif
}
#endif