blob: 9eebb638309f98facf9096459ade8cfdc87161c4 [file] [log] [blame]
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PODIntervalTree_h
#define PODIntervalTree_h
#include "platform/PODArena.h"
#include "platform/PODInterval.h"
#include "platform/PODRedBlackTree.h"
#include "platform/wtf/Assertions.h"
#include "platform/wtf/Noncopyable.h"
#include "platform/wtf/Vector.h"
namespace blink {
#ifndef NDEBUG
template <class T>
struct ValueToString;
#endif
template <class T, class UserData = void*>
class PODIntervalSearchAdapter {
DISALLOW_NEW();
public:
typedef PODInterval<T, UserData> IntervalType;
PODIntervalSearchAdapter(Vector<IntervalType>& result,
const T& low_value,
const T& high_value)
: result_(result), low_value_(low_value), high_value_(high_value) {}
const T& LowValue() const { return low_value_; }
const T& HighValue() const { return high_value_; }
void CollectIfNeeded(const IntervalType& data) const {
if (data.Overlaps(low_value_, high_value_))
result_.push_back(data);
}
private:
Vector<IntervalType>& result_;
T low_value_;
T high_value_;
};
// An interval tree, which is a form of augmented red-black tree. It
// supports efficient (O(lg n)) insertion, removal and querying of
// intervals in the tree.
template <class T, class UserData = void*>
class PODIntervalTree final : public PODRedBlackTree<PODInterval<T, UserData>> {
WTF_MAKE_NONCOPYABLE(PODIntervalTree);
public:
// Typedef to reduce typing when declaring intervals to be stored in
// this tree.
typedef PODInterval<T, UserData> IntervalType;
typedef PODIntervalSearchAdapter<T, UserData> IntervalSearchAdapterType;
PODIntervalTree(UninitializedTreeEnum unitialized_tree)
: PODRedBlackTree<IntervalType>(unitialized_tree) {
Init();
}
PODIntervalTree() : PODRedBlackTree<IntervalType>() { Init(); }
explicit PODIntervalTree(scoped_refptr<PODArena> arena)
: PODRedBlackTree<IntervalType>(arena) {
Init();
}
// Returns all intervals in the tree which overlap the given query
// interval. The returned intervals are sorted by increasing low
// endpoint.
Vector<IntervalType> AllOverlaps(const IntervalType& interval) const {
Vector<IntervalType> result;
AllOverlaps(interval, result);
return result;
}
// Returns all intervals in the tree which overlap the given query
// interval. The returned intervals are sorted by increasing low
// endpoint.
void AllOverlaps(const IntervalType& interval,
Vector<IntervalType>& result) const {
// Explicit dereference of "this" required because of
// inheritance rules in template classes.
IntervalSearchAdapterType adapter(result, interval.Low(), interval.High());
SearchForOverlapsFrom<IntervalSearchAdapterType>(this->Root(), adapter);
}
template <class AdapterType>
void AllOverlapsWithAdapter(AdapterType& adapter) const {
// Explicit dereference of "this" required because of
// inheritance rules in template classes.
SearchForOverlapsFrom<AdapterType>(this->Root(), adapter);
}
// Helper to create interval objects.
static IntervalType CreateInterval(const T& low,
const T& high,
const UserData data = nullptr) {
return IntervalType(low, high, data);
}
bool CheckInvariants() const override {
if (!PODRedBlackTree<IntervalType>::CheckInvariants())
return false;
if (!this->Root())
return true;
return CheckInvariantsFromNode(this->Root(), nullptr);
}
private:
typedef typename PODRedBlackTree<IntervalType>::Node IntervalNode;
// Initializes the tree.
void Init() {
// Explicit dereference of "this" required because of
// inheritance rules in template classes.
this->SetNeedsFullOrderingComparisons(true);
}
// Starting from the given node, adds all overlaps with the given
// interval to the result vector. The intervals are sorted by
// increasing low endpoint.
template <class AdapterType>
DISABLE_CFI_PERF void SearchForOverlapsFrom(IntervalNode* node,
AdapterType& adapter) const {
if (!node)
return;
// Because the intervals are sorted by left endpoint, inorder
// traversal produces results sorted as desired.
// See whether we need to traverse the left subtree.
IntervalNode* left = node->Left();
if (left
// This is phrased this way to avoid the need for operator
// <= on type T.
&& !(left->Data().MaxHigh() < adapter.LowValue()))
SearchForOverlapsFrom<AdapterType>(left, adapter);
// Check for overlap with current node.
adapter.CollectIfNeeded(node->Data());
// See whether we need to traverse the right subtree.
// This is phrased this way to avoid the need for operator <=
// on type T.
if (!(adapter.HighValue() < node->Data().Low()))
SearchForOverlapsFrom<AdapterType>(node->Right(), adapter);
}
bool UpdateNode(IntervalNode* node) override {
// Would use const T&, but need to reassign this reference in this
// function.
const T* cur_max = &node->Data().High();
IntervalNode* left = node->Left();
if (left) {
if (*cur_max < left->Data().MaxHigh())
cur_max = &left->Data().MaxHigh();
}
IntervalNode* right = node->Right();
if (right) {
if (*cur_max < right->Data().MaxHigh())
cur_max = &right->Data().MaxHigh();
}
// This is phrased like this to avoid needing operator!= on type T.
if (!(*cur_max == node->Data().MaxHigh())) {
node->Data().SetMaxHigh(*cur_max);
return true;
}
return false;
}
bool CheckInvariantsFromNode(IntervalNode* node, T* current_max_value) const {
// These assignments are only done in order to avoid requiring
// a default constructor on type T.
T left_max_value(node->Data().MaxHigh());
T right_max_value(node->Data().MaxHigh());
IntervalNode* left = node->Left();
IntervalNode* right = node->Right();
if (left) {
if (!CheckInvariantsFromNode(left, &left_max_value))
return false;
}
if (right) {
if (!CheckInvariantsFromNode(right, &right_max_value))
return false;
}
if (!left && !right) {
// Base case.
if (current_max_value)
*current_max_value = node->Data().High();
return (node->Data().High() == node->Data().MaxHigh());
}
T local_max_value(node->Data().MaxHigh());
if (!left || !right) {
if (left)
local_max_value = left_max_value;
else
local_max_value = right_max_value;
} else {
local_max_value =
(left_max_value < right_max_value) ? right_max_value : left_max_value;
}
if (local_max_value < node->Data().High())
local_max_value = node->Data().High();
if (!(local_max_value == node->Data().MaxHigh())) {
#ifndef NDEBUG
String local_max_value_string =
ValueToString<T>::ToString(local_max_value);
DLOG(ERROR) << "PODIntervalTree verification failed at node " << node
<< ": localMaxValue=" << local_max_value_string
<< " and data=" << node->Data().ToString();
#endif
return false;
}
if (current_max_value)
*current_max_value = local_max_value;
return true;
}
};
#ifndef NDEBUG
// Support for printing PODIntervals at the PODRedBlackTree level.
template <class T, class UserData>
struct ValueToString<PODInterval<T, UserData>> {
static String ToString(const PODInterval<T, UserData>& interval) {
return interval.ToString();
}
};
#endif
} // namespace blink
#endif // PODIntervalTree_h