Index: cc/base/pyramid_sequence.cc |
diff --git a/cc/base/pyramid_sequence.cc b/cc/base/pyramid_sequence.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f0380020e7c631b5cb72c0dd692f3e94b9496cf6 |
--- /dev/null |
+++ b/cc/base/pyramid_sequence.cc |
@@ -0,0 +1,1069 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "cc/base/pyramid_sequence.h" |
+ |
+#include <algorithm> |
+#include <string> |
+ |
+#define ENUM_TO_INDEX(x) static_cast<unsigned int>(x) |
+ |
+namespace cc { |
+ |
+namespace { |
+ |
+int LevelsToSkipAlongDirection(int levels) { |
+ return levels > 0 ? levels : 0; |
+} |
+ |
+int LevelsToSkipCrossDirection(int levels) { |
+ return levels >= 0 ? levels + 1 : 0; |
+} |
+ |
+// The following function returns default coverage as spiral order {R, T, L, B}. |
+// TODO(prashant.n): Implement precedence in coverage directions instead of |
+// default spiral coverage. http://crbug.com/629052. |
+CoverageDirection* GetCoverageDirectionSequence() { |
+ static CoverageDirection |
+ spiral_coverage[ENUM_TO_INDEX(CoverageDirection::SIZE)] = { |
+ CoverageDirection::RIGHT, CoverageDirection::TOP, |
+ CoverageDirection::LEFT, CoverageDirection::BOTTOM}; |
+ return spiral_coverage; |
+} |
+ |
+int GetPositionForDirection(CoverageDirection* positions, |
+ CoverageDirection direction) { |
+ for (unsigned int i = 0; i < ENUM_TO_INDEX(CoverageDirection::SIZE); ++i) { |
+ if (positions[i] == direction) |
+ return i; |
+ } |
+ |
+ NOTREACHED(); |
+ return -1; |
+} |
+ |
+} // namespace |
+ |
+namespace internal { |
+ |
+// Interval implementation. |
+Interval::Iterator* Interval::Begin() { |
+ return new Iterator(this); |
+} |
+ |
+Interval::ReverseIterator* Interval::ReverseBegin() { |
+ return new ReverseIterator(this); |
+} |
+ |
+int Interval::GetSpan() const { |
+ return empty_ ? 0 : std::abs(end_ - start_) + 1; |
+} |
+ |
+int Interval::GetForwardClampedIndex(int index) const { |
+ DCHECK_LE(start_, end_); |
+ return (index < start_) ? start_ : ((index > end_) ? end_ : index); |
+} |
+ |
+int Interval::GetBackwardClampedIndex(int index) const { |
+ DCHECK_GE(start_, end_); |
+ return (index > start_) ? start_ : ((index < end_) ? end_ : index); |
+} |
+ |
+void Interval::ForwardClampTo(const Interval* other) { |
+ DCHECK_LE(start_, end_); |
+ DCHECK_LE(other->start_, other->end_); |
+ start_ = other->GetForwardClampedIndex(start_); |
+ end_ = other->GetForwardClampedIndex(end_); |
+} |
+ |
+void Interval::BackwardClampTo(const Interval* other) { |
+ DCHECK_GE(start_, end_); |
+ DCHECK_GE(other->start_, other->end_); |
+ start_ = other->GetBackwardClampedIndex(start_); |
+ end_ = other->GetBackwardClampedIndex(end_); |
+} |
+ |
+void Interval::ForwardInflate(int level, Interval* output) const { |
+ output->start_ = start_ - level; |
+ output->end_ = end_ + level; |
+} |
+ |
+void Interval::BackwardInflate(int level, Interval* output) const { |
+ output->start_ = start_ + level; |
+ output->end_ = end_ - level; |
+} |
+ |
+bool Interval::Contains(int index) const { |
+ return (start_ <= end_) ? (index >= start_ && index <= end_) |
+ : (index <= start_ && index >= end_); |
+} |
+ |
+bool Interval::Intersects(const Interval* interval) const { |
+ return interval->Contains(start_) || interval->Contains(end_); |
+} |
+ |
+void Interval::Intersect(const Interval* interval) { |
+ DCHECK(Intersects(interval)); |
+ DCHECK(((start_ <= end_) && (interval->start_ <= interval->end_)) || |
+ ((start_ >= end_) && (interval->start_ >= interval->end_))); |
+ |
+ bool forward_direction = (GetSpan() > interval->GetSpan()) |
+ ? (start_ <= end_) |
+ : (interval->start_ <= interval->end_); |
+ |
+ if (forward_direction) { |
+ start_ = std::max(start_, interval->start_); |
+ end_ = std::min(end_, interval->end_); |
+ } else { |
+ start_ = std::min(start_, interval->start_); |
+ end_ = std::max(end_, interval->end_); |
+ } |
+} |
+ |
+// Interval::IteratorBase implementation. |
+Interval::IteratorBase::IteratorBase(Interval* interval) |
+ : interval_(interval), within_bounds_(!interval->empty_), step_(0) {} |
+ |
+Interval::IteratorBase& Interval::IteratorBase::operator++() { |
+ current_index_ += step_; |
+ within_bounds_ = IsWithinBounds(); |
+ |
+ return *this; |
+} |
+ |
+// Interval::Iterator implementation. |
+Interval::Iterator::Iterator(Interval* interval) |
+ : Interval::IteratorBase(interval) { |
+ step_ = (interval_->start_ <= interval_->end_) ? 1 : -1; |
+ current_index_ = interval_->start_; |
+} |
+ |
+bool Interval::Iterator::IsWithinBounds() { |
+ if (step_ == 1) { |
+ DCHECK(current_index_ >= interval_->start_); |
+ |
+ if (interval_->start_ == interval_->end_ || |
+ current_index_ > interval_->end_) |
+ return false; |
+ |
+ return true; |
+ } else { |
+ DCHECK(current_index_ <= interval_->start_); |
+ |
+ if (interval_->start_ == interval_->end_ || |
+ current_index_ < interval_->end_) |
+ return false; |
+ |
+ return true; |
+ } |
+} |
+ |
+// Interval::ReverseIterator implementation. |
+Interval::ReverseIterator::ReverseIterator(Interval* interval) |
+ : Interval::IteratorBase(interval) { |
+ step_ = (interval_->start_ <= interval_->end_) ? -1 : 1; |
+ current_index_ = interval_->end_; |
+} |
+ |
+bool Interval::ReverseIterator::IsWithinBounds() { |
+ if (step_ == 1) { |
+ DCHECK(current_index_ >= interval_->end_); |
+ |
+ if (interval_->start_ == interval_->end_ || |
+ current_index_ > interval_->start_) |
+ return false; |
+ |
+ return true; |
+ } else { |
+ DCHECK(current_index_ <= interval_->end_); |
+ |
+ if (interval_->start_ == interval_->end_ || |
+ current_index_ < interval_->start_) |
+ return false; |
+ |
+ return true; |
+ } |
+} |
+ |
+// LinearSequence implementation. |
+LinearSequence::LinearSequence(bool forward_direction, |
+ std::unique_ptr<Interval> interval, |
+ std::unique_ptr<Interval> affinity_interval, |
+ std::unique_ptr<Interval> inflate_limit) |
+ : forward_direction_(forward_direction), |
+ interval_(std::move(interval)), |
+ inflate_limit_(std::move(inflate_limit)), |
+ affinity_interval_(std::move(affinity_interval)), |
+ initial_interval_(std::unique_ptr<Interval>( |
+ new Interval(interval_->start(), interval_->end()))) { |
+ TrisectInterval(); |
+} |
+ |
+LinearSequence::~LinearSequence() = default; |
+ |
+LinearSequence::Iterator* LinearSequence::Begin() { |
+ return new Iterator(this); |
+} |
+ |
+LinearSequence::ReverseIterator* LinearSequence::ReverseBegin() { |
+ return new ReverseIterator(this); |
+} |
+ |
+void LinearSequence::InflateToLevel(int level) { |
+ if (forward_direction_) { |
+ initial_interval_->ForwardInflate(level, interval_.get()); |
+ interval_->ForwardClampTo(inflate_limit_.get()); |
+ } else { |
+ initial_interval_->BackwardInflate(level, interval_.get()); |
+ interval_->BackwardClampTo(inflate_limit_.get()); |
+ } |
+ |
+ TrisectInterval(); |
+} |
+ |
+void LinearSequence::TrisectInterval() { |
+ if (interval_->IsEmpty()) { |
+ affinity_sub_interval_ = Interval(); |
+ before_sub_interval_ = Interval(); |
+ after_sub_interval_ = Interval(); |
+ return; |
+ } |
+ |
+ if (forward_direction_) { |
+ affinity_sub_interval_ = *(affinity_interval_.get()); |
+ if (affinity_sub_interval_.Intersects(interval_.get())) { |
+ affinity_sub_interval_.Intersect(interval_.get()); |
+ |
+ // Compute before sub-interval. |
+ if (affinity_sub_interval_.start() > interval_->start()) |
+ before_sub_interval_ = |
+ Interval(affinity_sub_interval_.start() - 1, interval_->start()); |
+ else if (affinity_sub_interval_.start() == interval_->start()) |
+ before_sub_interval_ = Interval(); |
+ |
+ // Compute after sub-interval. |
+ if (affinity_sub_interval_.end() < interval_->end()) |
+ after_sub_interval_ = |
+ Interval(affinity_sub_interval_.end() + 1, interval_->end()); |
+ else if (affinity_sub_interval_.end() == interval_->end()) |
+ after_sub_interval_ = Interval(); |
+ } else { |
+ // The affinity interval is either before or after the |interval_|. |
+ if (affinity_sub_interval_.end() < interval_->start()) { |
+ before_sub_interval_ = Interval(); |
+ after_sub_interval_ = *(interval_.get()); |
+ } else { |
+ after_sub_interval_ = Interval(); |
+ before_sub_interval_ = Interval(interval_->end(), interval_->start()); |
+ } |
+ |
+ affinity_sub_interval_ = Interval(); |
+ } |
+ } else { |
+ affinity_sub_interval_ = *(affinity_interval_.get()); |
+ if (affinity_sub_interval_.Intersects(interval_.get())) { |
+ affinity_sub_interval_.Intersect(interval_.get()); |
+ |
+ // Compute before sub-interval. |
+ if (affinity_sub_interval_.start() < interval_->start()) |
+ before_sub_interval_ = |
+ Interval(affinity_sub_interval_.start() + 1, interval_->start()); |
+ else if (affinity_sub_interval_.start() == interval_->start()) |
+ before_sub_interval_ = Interval(); |
+ |
+ // Compute after sub-interval. |
+ if (affinity_sub_interval_.end() > interval_->end()) |
+ after_sub_interval_ = |
+ Interval(affinity_sub_interval_.end() - 1, interval_->end()); |
+ else if (affinity_sub_interval_.end() == interval_->end()) |
+ after_sub_interval_ = Interval(); |
+ } else { |
+ // The affinity interval is either before or after the |interval_|. |
+ if (affinity_sub_interval_.end() > interval_->start()) { |
+ before_sub_interval_ = Interval(); |
+ after_sub_interval_ = *(interval_.get()); |
+ } else { |
+ after_sub_interval_ = Interval(); |
+ before_sub_interval_ = Interval(interval_->end(), interval_->start()); |
+ } |
+ |
+ affinity_sub_interval_ = Interval(); |
+ } |
+ } |
+} |
+ |
+// LinearSequence::IteratorBase implementation. |
+LinearSequence::IteratorBase::IteratorBase(LinearSequence* level_sequence) |
+ : level_sequence_(level_sequence), within_bounds_(true) {} |
+ |
+LinearSequence::IteratorBase::~IteratorBase() = default; |
+ |
+LinearSequence::IteratorBase& LinearSequence::IteratorBase::operator++() { |
+ if (within_bounds_) { |
+ ++(*(sub_interval_iterators_[ENUM_TO_INDEX( |
+ current_sub_interval_iterator_)])); |
+ current_sub_interval_iterator_ = GetCurrentSubIntervalIteratorType(); |
+ current_index_ = |
+ sub_interval_iterators_[ENUM_TO_INDEX(current_sub_interval_iterator_)] |
+ ->index(); |
+ within_bounds_ = IsWithinBounds(); |
+ } |
+ return *this; |
+} |
+ |
+bool LinearSequence::IteratorBase::IsWithinBounds() { |
+ return *(sub_interval_iterators_[ENUM_TO_INDEX( |
+ SubIntervalIteratorType::AFFINITY)]) || |
+ *(sub_interval_iterators_[ENUM_TO_INDEX( |
+ SubIntervalIteratorType::BEFORE)]) || |
+ *(sub_interval_iterators_[ENUM_TO_INDEX( |
+ SubIntervalIteratorType::AFTER)]); |
+} |
+ |
+// LinearSequence::Iterator implementation. |
+LinearSequence::Iterator::Iterator(LinearSequence* level_sequence) |
+ : LinearSequence::IteratorBase(level_sequence), before_first_(true) { |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::AFFINITY)] |
+ .reset(level_sequence_->affinity_sub_interval_.Begin()); |
+ |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::BEFORE)].reset( |
+ level_sequence_->before_sub_interval_.Begin()); |
+ |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::AFTER)].reset( |
+ level_sequence_->after_sub_interval_.Begin()); |
+ |
+ current_sub_interval_iterator_ = GetCurrentSubIntervalIteratorType(); |
+ current_index_ = |
+ sub_interval_iterators_[ENUM_TO_INDEX(current_sub_interval_iterator_)] |
+ ->index(); |
+} |
+ |
+LinearSequence::Iterator::~Iterator() = default; |
+ |
+LinearSequence::IteratorBase::SubIntervalIteratorType |
+LinearSequence::Iterator::GetCurrentSubIntervalIteratorType() { |
+ if (*(sub_interval_iterators_[ENUM_TO_INDEX( |
+ SubIntervalIteratorType::AFFINITY)])) |
+ return SubIntervalIteratorType::AFFINITY; |
+ |
+ if (before_first_) { |
+ before_first_ = false; |
+ if (*(sub_interval_iterators_[ENUM_TO_INDEX( |
+ SubIntervalIteratorType::BEFORE)])) |
+ return SubIntervalIteratorType::BEFORE; |
+ |
+ return SubIntervalIteratorType::AFTER; |
+ } else { |
+ before_first_ = true; |
+ if (*(sub_interval_iterators_[ENUM_TO_INDEX( |
+ SubIntervalIteratorType::AFTER)])) |
+ return SubIntervalIteratorType::AFTER; |
+ |
+ return SubIntervalIteratorType::BEFORE; |
+ } |
+} |
+ |
+// LinearSequence::ReverseIterator implementation. |
+LinearSequence::ReverseIterator::ReverseIterator(LinearSequence* level_sequence) |
+ : LinearSequence::IteratorBase(level_sequence), |
+ after_first_(true), |
+ before_sub_interval_span_( |
+ level_sequence_->before_sub_interval_.GetSpan()), |
+ after_sub_interval_span_(level_sequence_->after_sub_interval_.GetSpan()) { |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::AFFINITY)] |
+ .reset(level_sequence_->affinity_sub_interval_.ReverseBegin()); |
+ |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::BEFORE)].reset( |
+ level_sequence_->before_sub_interval_.ReverseBegin()); |
+ |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::AFTER)].reset( |
+ level_sequence_->after_sub_interval_.ReverseBegin()); |
+ |
+ current_sub_interval_iterator_ = GetCurrentSubIntervalIteratorType(); |
+ current_index_ = |
+ sub_interval_iterators_[ENUM_TO_INDEX(current_sub_interval_iterator_)] |
+ ->index(); |
+} |
+ |
+LinearSequence::ReverseIterator::~ReverseIterator() = default; |
+ |
+LinearSequence::IteratorBase::SubIntervalIteratorType |
+LinearSequence::ReverseIterator::GetCurrentSubIntervalIteratorType() { |
+ if (before_sub_interval_span_ > after_sub_interval_span_) { |
+ --before_sub_interval_span_; |
+ return SubIntervalIteratorType::BEFORE; |
+ } else if (before_sub_interval_span_ < after_sub_interval_span_) { |
+ --after_sub_interval_span_; |
+ return SubIntervalIteratorType::AFTER; |
+ } else { |
+ if (after_first_) { |
+ after_first_ = false; |
+ if (*(sub_interval_iterators_[ENUM_TO_INDEX( |
+ SubIntervalIteratorType::AFTER)])) |
+ return SubIntervalIteratorType::AFTER; |
+ |
+ if (*(sub_interval_iterators_[ENUM_TO_INDEX( |
+ SubIntervalIteratorType::BEFORE)])) |
+ return SubIntervalIteratorType::BEFORE; |
+ } else { |
+ after_first_ = true; |
+ if (*(sub_interval_iterators_[ENUM_TO_INDEX( |
+ SubIntervalIteratorType::BEFORE)])) |
+ return SubIntervalIteratorType::BEFORE; |
+ |
+ if (*(sub_interval_iterators_[ENUM_TO_INDEX( |
+ SubIntervalIteratorType::AFTER)])) |
+ return SubIntervalIteratorType::AFTER; |
+ } |
+ } |
+ |
+ return SubIntervalIteratorType::AFFINITY; |
+} |
+ |
+// TriangularSequence implementation. |
+TriangularSequence::TriangularSequence( |
+ CoverageDirection coverage_direction, |
+ std::unique_ptr<LinearSequence> traversal_sequence, |
+ std::unique_ptr<Interval> level_interval, |
+ bool should_swap_index_representation, |
+ int levels_to_skip, |
+ int distance) |
+ : coverage_direction_(coverage_direction), |
+ traversal_sequence_(std::move(traversal_sequence)), |
+ level_interval_(std::move(level_interval)), |
+ should_swap_index_representation_(should_swap_index_representation), |
+ levels_to_skip_(levels_to_skip), |
+ distance_(distance) {} |
+ |
+TriangularSequence::~TriangularSequence() = default; |
+ |
+TriangularSequence::Iterator* TriangularSequence::Begin() { |
+ return new Iterator(this); |
+} |
+ |
+TriangularSequence::ReverseIterator* TriangularSequence::ReverseBegin() { |
+ return new ReverseIterator(this); |
+} |
+ |
+// TriangularSequence::IteratorBase implementation. |
+TriangularSequence::IteratorBase::IteratorBase( |
+ TriangularSequence* triangular_sequence) |
+ : should_swap_index_representation_( |
+ triangular_sequence->should_swap_index_representation_) { |
+ DCHECK_NE(triangular_sequence->coverage_direction_, CoverageDirection::NONE); |
+ std::unique_ptr<Interval::Iterator> level_interval_it( |
+ triangular_sequence->level_interval_->Begin()); |
+ traversal_sequence_ = triangular_sequence->traversal_sequence_.get(); |
+ int span = triangular_sequence->level_interval_->GetSpan(); |
+ DCHECK_GE(span, triangular_sequence->levels_to_skip_); |
+ |
+ // Skip |levels_to_skip| levels in level interval. |
+ for (int i = 0; i < triangular_sequence->levels_to_skip_; ++i) |
+ ++(*level_interval_it); |
+ |
+ for (int i = triangular_sequence->levels_to_skip_; i < span; ++i) { |
+ level_distances_.push_back(LevelDistance( |
+ i, level_interval_it->index(), triangular_sequence->distance_ * i)); |
+ ++(*level_interval_it); |
+ } |
+} |
+ |
+TriangularSequence::IteratorBase::~IteratorBase() = default; |
+ |
+TriangularSequence::IteratorBase& TriangularSequence::IteratorBase:: |
+operator++() { |
+ Advance(); |
+ UpdateCurrent(); |
+ |
+ return *this; |
+} |
+ |
+// TriangularSequence::Iterator implementation. |
+TriangularSequence::Iterator::Iterator(TriangularSequence* triangular_sequence) |
+ : TriangularSequence::IteratorBase(triangular_sequence) { |
+ UpdateCurrent(); |
+} |
+ |
+int TriangularSequence::Iterator::GetNextDistance() const { |
+ DCHECK(*this); |
+ return level_distances_.front().distance; |
+} |
+ |
+void TriangularSequence::Iterator::Advance() { |
+ if (!*this) |
+ return; |
+ |
+ level_distances_.erase(level_distances_.begin()); |
+} |
+ |
+void TriangularSequence::Iterator::UpdateCurrent() { |
+ if (!*this) |
+ return; |
+ |
+ current_level_index_ = level_distances_.front().level_index; |
+ traversal_sequence_->InflateToLevel(level_distances_.front().interval_level); |
+} |
+ |
+// TriangularSequence::ReverseIterator implementation. |
+TriangularSequence::ReverseIterator::ReverseIterator( |
+ TriangularSequence* triangular_sequence) |
+ : TriangularSequence::IteratorBase(triangular_sequence) { |
+ UpdateCurrent(); |
+} |
+ |
+int TriangularSequence::ReverseIterator::GetNextDistance() const { |
+ DCHECK(!level_distances_.empty()); |
+ return level_distances_.back().distance; |
+} |
+ |
+void TriangularSequence::ReverseIterator::Advance() { |
+ if (!*this) |
+ return; |
+ |
+ level_distances_.erase(level_distances_.end() - 1); |
+} |
+ |
+void TriangularSequence::ReverseIterator::UpdateCurrent() { |
+ if (!*this) |
+ return; |
+ |
+ current_level_index_ = level_distances_.back().level_index; |
+ traversal_sequence_->InflateToLevel(level_distances_.back().interval_level); |
+} |
+ |
+// PyramidSequence implementation. |
+PyramidSequence::PyramidSequence(const IndexRect& around_index_rect, |
+ const IndexRect& consider_index_rect, |
+ const IndexRect& ignore_index_rect, |
+ int width, |
+ int height) |
+ : consider_index_rect_(consider_index_rect), |
+ ignore_index_rect_(ignore_index_rect) { |
+ // Compute center_index_rect and if it is valid (i.e. |around_index_rect| is |
+ // really around some index_rect) and both |consider_index_rect| and |
+ // |ignore_index_rect| are valid, then proceed, otherwise keep the pyramid |
+ // sequence empty. |
+ |
+ IndexRect center_index_rect(around_index_rect); |
+ center_index_rect.Inset(1, 1, 1, 1); |
+ if (!center_index_rect.is_valid() || !consider_index_rect.is_valid() || |
+ !ignore_index_rect.is_valid()) |
+ return; |
+ |
+ // Compute the max possible levels along all directions. |
+ int left_levels = around_index_rect.left() - consider_index_rect_.left() + 1; |
+ int right_levels = |
+ consider_index_rect_.right() - around_index_rect.right() + 1; |
+ int top_levels = around_index_rect.top() - consider_index_rect_.top() + 1; |
+ int bottom_levels = |
+ consider_index_rect_.bottom() - around_index_rect.bottom() + 1; |
+ |
+ // When center_index_rect and consider_index_rect are non-intersecting, then |
+ // we need to compute the levels to skip for avoiding traversal of levels |
+ // which do not fall in consider_index_rect. The pyramid sequence adds |
+ // diagonal indices to left and right directions and no diagonal indices for |
+ // top and bottom directions, so while considering skip levels for top/bottom, |
+ // we need to consider maximum of levels to skip "along" the top/bottom |
+ // directions and levels to skip "cross" left/right directions and for |
+ // considering skip levels for left/right, we need to consider maximum of |
+ // levels to skip "along" the left/right directions and levels to skip "along" |
+ // top/bottom directions. |
+ // Compute the levels to skip along and cross all directions. |
+ int skip_levels_along_left = |
+ around_index_rect.left() - consider_index_rect_.right(); |
+ int skip_levels_along_right = |
+ consider_index_rect_.left() - around_index_rect.right(); |
+ int skip_levels_along_top = |
+ around_index_rect.top() - consider_index_rect_.bottom(); |
+ int skip_levels_along_bottom = |
+ consider_index_rect_.top() - around_index_rect.bottom(); |
+ int skip_levels_cross_left = |
+ LevelsToSkipCrossDirection(skip_levels_along_left); |
+ int skip_levels_cross_right = |
+ LevelsToSkipCrossDirection(skip_levels_along_right); |
+ skip_levels_along_left = LevelsToSkipAlongDirection(skip_levels_along_left); |
+ skip_levels_along_right = LevelsToSkipAlongDirection(skip_levels_along_right); |
+ skip_levels_along_top = LevelsToSkipAlongDirection(skip_levels_along_top); |
+ skip_levels_along_bottom = |
+ LevelsToSkipAlongDirection(skip_levels_along_bottom); |
+ |
+ DCHECK(triangular_sequences_.empty()); |
+ triangular_sequences_.resize(ENUM_TO_INDEX(CoverageDirection::SIZE)); |
+ CoverageDirection* positions = GetCoverageDirectionSequence(); |
+ DCHECK(positions); |
+ |
+#define NEW_UNIQUE(type, val) std::unique_ptr<type>(new val) |
+ |
+ // Add triangular sequences for all directions. |
+ // RIGHT sequence. |
+ if (right_levels > 0) { |
+ int start = around_index_rect.bottom(); |
+ int end = around_index_rect.top(); |
+ int skip_levels = |
+ std::max(skip_levels_along_right, |
+ std::max(skip_levels_along_bottom, skip_levels_along_top)); |
+ if (right_levels > skip_levels) { |
+ EmplaceAt( |
+ GetPositionForDirection(positions, CoverageDirection::RIGHT), |
+ NEW_UNIQUE( |
+ TriangularSequence, |
+ TriangularSequence( |
+ CoverageDirection::RIGHT, |
+ NEW_UNIQUE( |
+ LinearSequence, |
+ LinearSequence( |
+ false, NEW_UNIQUE(Interval, Interval(start, end)), |
+ NEW_UNIQUE(Interval, |
+ Interval(center_index_rect.bottom(), |
+ center_index_rect.top())), |
+ NEW_UNIQUE(Interval, |
+ Interval(consider_index_rect_.bottom(), |
+ consider_index_rect_.top())))), |
+ NEW_UNIQUE(Interval, Interval(around_index_rect.right(), |
+ consider_index_rect_.right())), |
+ true, skip_levels, width))); |
+ } |
+ } |
+ |
+ // TOP sequence. |
+ if (top_levels > 0) { |
+ int start = around_index_rect.right() - 1; |
+ int end = around_index_rect.left() + 1; |
+ int skip_levels = |
+ std::max(skip_levels_along_top, |
+ std::max(skip_levels_cross_right, skip_levels_cross_left)); |
+ if (top_levels > skip_levels) { |
+ EmplaceAt( |
+ GetPositionForDirection(positions, CoverageDirection::TOP), |
+ NEW_UNIQUE( |
+ TriangularSequence, |
+ TriangularSequence( |
+ CoverageDirection::TOP, |
+ NEW_UNIQUE( |
+ LinearSequence, |
+ LinearSequence( |
+ false, NEW_UNIQUE(Interval, Interval(start, end)), |
+ NEW_UNIQUE(Interval, |
+ Interval(center_index_rect.right(), |
+ center_index_rect.left())), |
+ NEW_UNIQUE(Interval, |
+ Interval(consider_index_rect_.right(), |
+ consider_index_rect_.left())))), |
+ NEW_UNIQUE(Interval, Interval(around_index_rect.top(), |
+ consider_index_rect_.top())), |
+ false, skip_levels, height))); |
+ } |
+ } |
+ |
+ // LEFT sequence. |
+ if (left_levels > 0) { |
+ int start = around_index_rect.top(); |
+ int end = around_index_rect.bottom(); |
+ int skip_levels = |
+ std::max(skip_levels_along_left, |
+ std::max(skip_levels_along_top, skip_levels_along_bottom)); |
+ if (left_levels > skip_levels) { |
+ EmplaceAt( |
+ GetPositionForDirection(positions, CoverageDirection::LEFT), |
+ NEW_UNIQUE( |
+ TriangularSequence, |
+ TriangularSequence( |
+ CoverageDirection::LEFT, |
+ NEW_UNIQUE( |
+ LinearSequence, |
+ LinearSequence( |
+ true, NEW_UNIQUE(Interval, Interval(start, end)), |
+ NEW_UNIQUE(Interval, |
+ Interval(center_index_rect.top(), |
+ center_index_rect.bottom())), |
+ NEW_UNIQUE(Interval, |
+ Interval(consider_index_rect_.top(), |
+ consider_index_rect_.bottom())))), |
+ NEW_UNIQUE(Interval, Interval(around_index_rect.left(), |
+ consider_index_rect_.left())), |
+ true, skip_levels, width))); |
+ } |
+ } |
+ |
+ // BOTTOM sequence. |
+ if (bottom_levels > 0) { |
+ int start = around_index_rect.left() + 1; |
+ int end = around_index_rect.right() - 1; |
+ int skip_levels = |
+ std::max(skip_levels_along_bottom, |
+ std::max(skip_levels_cross_left, skip_levels_cross_right)); |
+ if (bottom_levels > skip_levels) { |
+ EmplaceAt( |
+ GetPositionForDirection(positions, CoverageDirection::BOTTOM), |
+ NEW_UNIQUE( |
+ TriangularSequence, |
+ TriangularSequence( |
+ CoverageDirection::BOTTOM, |
+ NEW_UNIQUE( |
+ LinearSequence, |
+ LinearSequence( |
+ true, NEW_UNIQUE(Interval, Interval(start, end)), |
+ NEW_UNIQUE(Interval, |
+ Interval(center_index_rect.left(), |
+ center_index_rect.right())), |
+ NEW_UNIQUE(Interval, |
+ Interval(consider_index_rect_.left(), |
+ consider_index_rect_.right())))), |
+ NEW_UNIQUE(Interval, Interval(around_index_rect.bottom(), |
+ consider_index_rect_.bottom())), |
+ false, skip_levels, height))); |
+ } |
+ } |
+ |
+ // Remove dummy triangular sequences. |
+ triangular_sequences_.erase( |
+ std::remove_if( |
+ triangular_sequences_.begin(), triangular_sequences_.end(), |
+ [](const std::unique_ptr<TriangularSequence>& triangular_sequence) { |
+ return triangular_sequence.get() == nullptr; |
+ }), |
+ triangular_sequences_.end()); |
+} |
+ |
+PyramidSequence::~PyramidSequence() = default; |
+ |
+PyramidSequence::Iterator* PyramidSequence::Begin() { |
+ return new Iterator(this); |
+} |
+ |
+PyramidSequence::ReverseIterator* PyramidSequence::ReverseBegin() { |
+ return new ReverseIterator(this); |
+} |
+ |
+void PyramidSequence::EmplaceAt( |
+ int position, |
+ std::unique_ptr<TriangularSequence> triangular_sequence) { |
+ triangular_sequences_[position] = std::move(triangular_sequence); |
+} |
+ |
+// PyramidSequence::IteratorBase implementation. |
+PyramidSequence::IteratorBase::IteratorBase( |
+ const IndexRect& consider_index_rect, |
+ const IndexRect& ignore_index_rect) |
+ : consider_index_rect_(consider_index_rect), |
+ ignore_index_rect_(ignore_index_rect), |
+ current_triangular_sequence_it_(nullptr) {} |
+ |
+PyramidSequence::IteratorBase::~IteratorBase() = default; |
+ |
+PyramidSequence::IteratorBase::operator bool() const { |
+ return current_triangular_sequence_it_ && !IsEmpty(); |
+} |
+ |
+PyramidSequence::IteratorBase& PyramidSequence::IteratorBase::operator++() { |
+ Advance(); |
+ UpdateCurrent(); |
+ |
+ return *this; |
+} |
+ |
+// PyramidSequence::Iterator implementation. |
+PyramidSequence::Iterator::Iterator(PyramidSequence* pyramid_sequence) |
+ : PyramidSequence::IteratorBase(pyramid_sequence->consider_index_rect_, |
+ pyramid_sequence->ignore_index_rect_) { |
+ for (TriangularSequence::Vector::iterator it = |
+ pyramid_sequence->triangular_sequences_.begin(); |
+ it != pyramid_sequence->triangular_sequences_.end(); ++it) { |
+ DCHECK(it->get()->coverage_direction() != CoverageDirection::NONE); |
+ triangular_sequence_iterators_.emplace_back(it->get()->Begin()); |
+ } |
+ |
+ current_triangular_sequence_it_ = GetNextTriangularSequenceIterator(); |
+ if (current_triangular_sequence_it_) { |
+ if (*current_triangular_sequence_it_) { |
+ current_traversal_sequence_iterator_ = |
+ current_triangular_sequence_it_->traversal_sequence()->Begin(); |
+ } |
+ |
+ UpdateCurrent(); |
+ } |
+} |
+ |
+PyramidSequence::Iterator::~Iterator() = default; |
+ |
+bool PyramidSequence::Iterator::IsEmpty() const { |
+ return triangular_sequence_iterators_.empty(); |
+} |
+ |
+void PyramidSequence::Iterator::Advance() { |
+ if (!*this) |
+ return; |
+ |
+ ++(*current_traversal_sequence_iterator_); |
+ if (!(*current_traversal_sequence_iterator_)) { |
+ ++(*current_triangular_sequence_it_); |
+ current_triangular_sequence_it_ = GetNextTriangularSequenceIterator(); |
+ if (current_triangular_sequence_it_) { |
+ current_traversal_sequence_iterator_ = |
+ current_triangular_sequence_it_->traversal_sequence()->Begin(); |
+ } |
+ } |
+} |
+ |
+void PyramidSequence::Iterator::UpdateCurrent() { |
+ while (*this) { |
+ if (*current_traversal_sequence_iterator_) { |
+ if (current_triangular_sequence_it_->is_index_representation_swapped()) { |
+ index_x_ = current_triangular_sequence_it_->level_index(); |
+ index_y_ = current_traversal_sequence_iterator_->index(); |
+ } else { |
+ index_x_ = current_traversal_sequence_iterator_->index(); |
+ index_y_ = current_triangular_sequence_it_->level_index(); |
+ } |
+ |
+ if (consider_index_rect_.Contains(index_x_, index_y_) && |
+ !ignore_index_rect_.Contains(index_x_, index_y_)) |
+ break; |
+ } |
+ |
+ Advance(); |
+ } |
+} |
+ |
+TriangularSequence::IteratorBase* |
+PyramidSequence::Iterator::GetNextTriangularSequenceIterator() { |
+ // Remove traversed TriangularSequence::Iterator(s). |
+ triangular_sequence_iterators_.erase( |
+ std::remove_if( |
+ triangular_sequence_iterators_.begin(), |
+ triangular_sequence_iterators_.end(), |
+ [](const std::unique_ptr<TriangularSequence::Iterator>& it) { |
+ return !(*(it.get())); |
+ }), |
+ triangular_sequence_iterators_.end()); |
+ |
+ if (triangular_sequence_iterators_.empty()) |
+ return nullptr; |
+ |
+ std::vector<std::unique_ptr<TriangularSequence::Iterator>>::iterator |
+ min_distance_it = triangular_sequence_iterators_.begin(); |
+ |
+ for (std::vector<std::unique_ptr<TriangularSequence::Iterator>>::iterator it = |
+ triangular_sequence_iterators_.begin(); |
+ it != triangular_sequence_iterators_.end(); ++it) { |
+ int distance = it->get()->GetNextDistance(); |
+ if (distance == 0) { |
+ min_distance_it = it; |
+ break; |
+ } |
+ |
+ if (min_distance_it->get()->GetNextDistance() > distance) |
+ min_distance_it = it; |
+ } |
+ |
+ return min_distance_it->get(); |
+} |
+ |
+// PyramidSequence::ReverseIterator implementation. |
+PyramidSequence::ReverseIterator::ReverseIterator( |
+ PyramidSequence* pyramid_sequence) |
+ : PyramidSequence::IteratorBase(pyramid_sequence->consider_index_rect_, |
+ pyramid_sequence->ignore_index_rect_) { |
+ for (TriangularSequence::Vector::iterator it = |
+ pyramid_sequence->triangular_sequences_.begin(); |
+ it != pyramid_sequence->triangular_sequences_.end(); ++it) { |
+ triangular_sequence_reverse_iterators_.emplace_back( |
+ it->get()->ReverseBegin()); |
+ } |
+ |
+ current_triangular_sequence_it_ = GetNextTriangularSequenceReverseIterator(); |
+ if (current_triangular_sequence_it_) { |
+ if (*current_triangular_sequence_it_) { |
+ current_traversal_sequence_reverse_iterator_ = |
+ current_triangular_sequence_it_->traversal_sequence()->ReverseBegin(); |
+ } |
+ UpdateCurrent(); |
+ } |
+} |
+ |
+PyramidSequence::ReverseIterator::~ReverseIterator() = default; |
+ |
+bool PyramidSequence::ReverseIterator::IsEmpty() const { |
+ return triangular_sequence_reverse_iterators_.empty(); |
+} |
+ |
+void PyramidSequence::ReverseIterator::Advance() { |
+ if (!*this) |
+ return; |
+ |
+ ++(*current_traversal_sequence_reverse_iterator_); |
+ if (!(*current_traversal_sequence_reverse_iterator_)) { |
+ ++(*current_triangular_sequence_it_); |
+ current_triangular_sequence_it_ = |
+ GetNextTriangularSequenceReverseIterator(); |
+ if (current_triangular_sequence_it_) { |
+ current_traversal_sequence_reverse_iterator_ = |
+ current_triangular_sequence_it_->traversal_sequence()->ReverseBegin(); |
+ } |
+ } |
+} |
+ |
+void PyramidSequence::ReverseIterator::UpdateCurrent() { |
+ while (*this) { |
+ if ((*current_traversal_sequence_reverse_iterator_)) { |
+ if (current_triangular_sequence_it_->is_index_representation_swapped()) { |
+ index_x_ = current_triangular_sequence_it_->level_index(); |
+ index_y_ = current_traversal_sequence_reverse_iterator_->index(); |
+ } else { |
+ index_x_ = current_traversal_sequence_reverse_iterator_->index(); |
+ index_y_ = current_triangular_sequence_it_->level_index(); |
+ } |
+ |
+ if (consider_index_rect_.Contains(index_x_, index_y_) && |
+ !ignore_index_rect_.Contains(index_x_, index_y_)) |
+ break; |
+ } |
+ |
+ Advance(); |
+ } |
+} |
+ |
+TriangularSequence::IteratorBase* |
+PyramidSequence::ReverseIterator::GetNextTriangularSequenceReverseIterator() { |
+ // Remove traversed TriangularSequence::ReverseIterator(s). |
+ triangular_sequence_reverse_iterators_.erase( |
+ std::remove_if( |
+ triangular_sequence_reverse_iterators_.begin(), |
+ triangular_sequence_reverse_iterators_.end(), |
+ [](const std::unique_ptr<TriangularSequence::ReverseIterator>& it) { |
+ return !(*(it.get())); |
+ }), |
+ triangular_sequence_reverse_iterators_.end()); |
+ |
+ if (triangular_sequence_reverse_iterators_.empty()) |
+ return nullptr; |
+ |
+ std::vector<std::unique_ptr<TriangularSequence::ReverseIterator>>:: |
+ reverse_iterator max_distance_it = |
+ triangular_sequence_reverse_iterators_.rbegin(); |
+ |
+ for (std::vector<std::unique_ptr<TriangularSequence::ReverseIterator>>:: |
+ reverse_iterator it = |
+ triangular_sequence_reverse_iterators_.rbegin(); |
+ it != triangular_sequence_reverse_iterators_.rend(); ++it) { |
+ int distance = it->get()->GetNextDistance(); |
+ |
+ if (max_distance_it->get()->GetNextDistance() < distance) |
+ max_distance_it = it; |
+ } |
+ |
+ return max_distance_it->get(); |
+} |
+ |
+} // namespace internal |
+ |
+PyramidSequence::PyramidSequence() {} |
+ |
+PyramidSequence::PyramidSequence(const IndexRect& around_index_rect, |
+ const IndexRect& consider_index_rect, |
+ const IndexRect& ignore_index_rect, |
+ int width, |
+ int height) |
+ : ptr_(new internal::PyramidSequence(around_index_rect, |
+ consider_index_rect, |
+ ignore_index_rect, |
+ width, |
+ height)) {} |
+ |
+PyramidSequence::PyramidSequence(const PyramidSequence& other) = default; |
+ |
+PyramidSequence::PyramidSequence(PyramidSequence&& other) = default; |
+ |
+PyramidSequence::~PyramidSequence() = default; |
+ |
+PyramidSequence& PyramidSequence::operator=(const PyramidSequence& other) = |
+ default; |
+ |
+PyramidSequence& PyramidSequence::operator=(PyramidSequence&& other) = default; |
+ |
+PyramidSequence::Iterator PyramidSequence::Begin() { |
+ return Iterator(ptr_->Begin()); |
+} |
+ |
+PyramidSequence::ReverseIterator PyramidSequence::ReverseBegin() { |
+ return ReverseIterator(ptr_->ReverseBegin()); |
+} |
+ |
+// iterator |
+PyramidSequence::Iterator::Iterator() {} |
+ |
+PyramidSequence::Iterator::Iterator(internal::PyramidSequence::Iterator* ptr) |
+ : ptr_(ptr) {} |
+ |
+PyramidSequence::Iterator::Iterator(const PyramidSequence::Iterator& other) = |
+ default; |
+ |
+PyramidSequence::Iterator::Iterator(PyramidSequence::Iterator&& other) = |
+ default; |
+ |
+PyramidSequence::Iterator::~Iterator() = default; |
+ |
+PyramidSequence::Iterator& PyramidSequence::Iterator::operator=( |
+ const PyramidSequence::Iterator& other) = default; |
+ |
+PyramidSequence::Iterator& PyramidSequence::Iterator::operator=( |
+ PyramidSequence::Iterator&& other) = default; |
+ |
+PyramidSequence::Iterator::operator bool() const { |
+ return *ptr_; |
+} |
+ |
+PyramidSequence::Iterator& PyramidSequence::Iterator::operator++() { |
+ ++(*ptr_); |
+ return *this; |
+} |
+ |
+int PyramidSequence::Iterator::index_x() const { |
+ return ptr_->index_x(); |
+} |
+ |
+int PyramidSequence::Iterator::index_y() const { |
+ return ptr_->index_y(); |
+} |
+ |
+// reverse |
+PyramidSequence::ReverseIterator::ReverseIterator() {} |
+ |
+PyramidSequence::ReverseIterator::ReverseIterator( |
+ internal::PyramidSequence::ReverseIterator* ptr) |
+ : ptr_(ptr) {} |
+ |
+PyramidSequence::ReverseIterator::ReverseIterator( |
+ const PyramidSequence::ReverseIterator& other) = default; |
+ |
+PyramidSequence::ReverseIterator::ReverseIterator( |
+ PyramidSequence::ReverseIterator&& other) = default; |
+ |
+PyramidSequence::ReverseIterator::~ReverseIterator() = default; |
+ |
+PyramidSequence::ReverseIterator& PyramidSequence::ReverseIterator::operator=( |
+ const PyramidSequence::ReverseIterator& other) = default; |
+ |
+PyramidSequence::ReverseIterator& PyramidSequence::ReverseIterator::operator=( |
+ PyramidSequence::ReverseIterator&& other) = default; |
+ |
+PyramidSequence::ReverseIterator::operator bool() const { |
+ return *ptr_; |
+} |
+ |
+PyramidSequence::ReverseIterator& PyramidSequence::ReverseIterator:: |
+operator++() { |
+ ++(*ptr_); |
+ return *this; |
+} |
+ |
+int PyramidSequence::ReverseIterator::index_x() const { |
+ return ptr_->index_x(); |
+} |
+ |
+int PyramidSequence::ReverseIterator::index_y() const { |
+ return ptr_->index_y(); |
+} |
+ |
+} // namespace cc |