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..4be597aa53391c68bd10a641aa494225535f9158 |
--- /dev/null |
+++ b/cc/base/pyramid_sequence.cc |
@@ -0,0 +1,1218 @@ |
+// 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 |
+ |
+// Interval implementation. |
+Interval::Iterator Interval::Begin() { |
+ return Iterator(this); |
+} |
+ |
+Interval::ReverseIterator Interval::ReverseBegin() { |
+ return 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_); |
+} |
+ |
+Interval Interval::GetForwardInflatedInterval(int level) const { |
+ return Interval(start_ - level, end_ + level); |
+} |
+ |
+Interval Interval::GetBackwardInflatedInterval(int level) const { |
+ return Interval(start_ + level, 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() : within_bounds_(false), step_(0) {} |
+ |
+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::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::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() {} |
+ |
+LinearSequence::LinearSequence(bool forward_direction, |
+ Interval interval, |
+ Interval affinity_interval, |
+ Interval inflate_limit) |
+ : forward_direction_(forward_direction), |
+ interval_(interval), |
+ inflate_limit_(inflate_limit), |
+ affinity_interval_(affinity_interval), |
+ initial_interval_(interval) { |
+ TrisectInterval(); |
+} |
+ |
+LinearSequence::LinearSequence(const LinearSequence& other) = default; |
+ |
+LinearSequence::LinearSequence(LinearSequence&& other) = default; |
+ |
+LinearSequence::~LinearSequence() = default; |
+ |
+LinearSequence& LinearSequence::operator=(const LinearSequence& other) = |
+ default; |
+ |
+LinearSequence& LinearSequence::operator=(LinearSequence&& other) = default; |
+ |
+LinearSequence::Iterator LinearSequence::Begin() { |
+ return Iterator(this); |
+} |
+ |
+LinearSequence::ReverseIterator LinearSequence::ReverseBegin() { |
+ return ReverseIterator(this); |
+} |
+ |
+void LinearSequence::InflateToLevel(int level) { |
+ if (forward_direction_) { |
+ interval_ = initial_interval_.GetForwardInflatedInterval(level); |
+ interval_.ForwardClampTo(inflate_limit_); |
+ } else { |
+ interval_ = initial_interval_.GetBackwardInflatedInterval(level); |
+ interval_.BackwardClampTo(inflate_limit_); |
+ } |
+ |
+ 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_; |
+ if (affinity_sub_interval_.Intersects(interval_)) { |
+ affinity_sub_interval_.Intersect(interval_); |
+ |
+ // 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_; |
+ } else { |
+ after_sub_interval_ = Interval(); |
+ before_sub_interval_ = Interval(interval_.end(), interval_.start()); |
+ } |
+ |
+ affinity_sub_interval_ = Interval(); |
+ } |
+ } else { |
+ affinity_sub_interval_ = affinity_interval_; |
+ if (affinity_sub_interval_.Intersects(interval_)) { |
+ affinity_sub_interval_.Intersect(interval_); |
+ |
+ // 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_; |
+ } else { |
+ after_sub_interval_ = Interval(); |
+ before_sub_interval_ = Interval(interval_.end(), interval_.start()); |
+ } |
+ |
+ affinity_sub_interval_ = Interval(); |
+ } |
+ } |
+} |
+ |
+// LinearSequence::IteratorBase implementation. |
+LinearSequence::IteratorBase::IteratorBase() : within_bounds_(false) {} |
+ |
+LinearSequence::IteratorBase::IteratorBase(LinearSequence* level_sequence) |
+ : level_sequence_(level_sequence), within_bounds_(true) {} |
+ |
+LinearSequence::IteratorBase::IteratorBase( |
+ const LinearSequence::IteratorBase& other) = default; |
+LinearSequence::IteratorBase::IteratorBase( |
+ LinearSequence::IteratorBase&& other) = default; |
+ |
+LinearSequence::IteratorBase::~IteratorBase() = default; |
+ |
+LinearSequence::IteratorBase& LinearSequence::IteratorBase::operator=( |
+ const LinearSequence::IteratorBase& other) = default; |
+LinearSequence::IteratorBase& LinearSequence::IteratorBase::operator=( |
+ LinearSequence::IteratorBase&& other) = 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; |
+} |
+ |
+// LinearSequence::Iterator implementation. |
+LinearSequence::Iterator::Iterator() {} |
+ |
+LinearSequence::Iterator::Iterator(LinearSequence* level_sequence) |
+ : LinearSequence::IteratorBase(level_sequence), |
+ affinity_sub_interval_iterator_( |
+ level_sequence_->affinity_sub_interval_.Begin()), |
+ before_sub_interval_iterator_( |
+ level_sequence_->before_sub_interval_.Begin()), |
+ after_sub_interval_iterator_( |
+ level_sequence_->after_sub_interval_.Begin()), |
+ before_first_(true) { |
+ Setup(); |
+ |
+ current_sub_interval_iterator_ = GetCurrentSubIntervalIteratorType(); |
+ current_index_ = |
+ sub_interval_iterators_[ENUM_TO_INDEX(current_sub_interval_iterator_)] |
+ ->index(); |
+} |
+ |
+LinearSequence::Iterator::Iterator(const LinearSequence::Iterator& other) |
+ : IteratorBase(other), |
+ affinity_sub_interval_iterator_(other.affinity_sub_interval_iterator_), |
+ before_sub_interval_iterator_(other.before_sub_interval_iterator_), |
+ after_sub_interval_iterator_(other.after_sub_interval_iterator_), |
+ before_first_(other.before_first_) { |
+ Setup(); |
+} |
+ |
+LinearSequence::Iterator::Iterator(LinearSequence::Iterator&& other) |
+ : IteratorBase(std::move(other)), |
+ affinity_sub_interval_iterator_( |
+ std::move(other.affinity_sub_interval_iterator_)), |
+ before_sub_interval_iterator_( |
+ std::move(other.before_sub_interval_iterator_)), |
+ after_sub_interval_iterator_( |
+ std::move(other.after_sub_interval_iterator_)), |
+ before_first_(other.before_first_) { |
+ Setup(); |
+} |
+ |
+LinearSequence::Iterator::~Iterator() = default; |
+ |
+LinearSequence::Iterator& LinearSequence::Iterator::operator=( |
+ const LinearSequence::Iterator& other) { |
+ IteratorBase::operator=(other); |
+ affinity_sub_interval_iterator_ = other.affinity_sub_interval_iterator_; |
+ before_sub_interval_iterator_ = other.before_sub_interval_iterator_; |
+ after_sub_interval_iterator_ = other.after_sub_interval_iterator_; |
+ before_first_ = other.before_first_; |
+ |
+ Setup(); |
+ |
+ return *this; |
+} |
+LinearSequence::Iterator& LinearSequence::Iterator::operator=( |
+ LinearSequence::Iterator&& other) { |
+ IteratorBase::operator=(std::move(other)); |
+ affinity_sub_interval_iterator_ = |
+ std::move(other.affinity_sub_interval_iterator_); |
+ before_sub_interval_iterator_ = |
+ std::move(other.before_sub_interval_iterator_); |
+ after_sub_interval_iterator_ = std::move(other.after_sub_interval_iterator_); |
+ before_first_ = other.before_first_; |
+ |
+ Setup(); |
+ |
+ return *this; |
+} |
+ |
+void LinearSequence::Iterator::Setup() { |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::AFFINITY)] = |
+ &affinity_sub_interval_iterator_; |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::BEFORE)] = |
+ &before_sub_interval_iterator_; |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::AFTER)] = |
+ &after_sub_interval_iterator_; |
+} |
+ |
+LinearSequence::IteratorBase::SubIntervalIteratorType |
+LinearSequence::Iterator::GetCurrentSubIntervalIteratorType() { |
+ if (affinity_sub_interval_iterator_) |
+ return SubIntervalIteratorType::AFFINITY; |
+ |
+ if (before_first_) { |
+ before_first_ = false; |
+ if (before_sub_interval_iterator_) |
+ return SubIntervalIteratorType::BEFORE; |
+ |
+ return SubIntervalIteratorType::AFTER; |
+ } else { |
+ before_first_ = true; |
+ if (after_sub_interval_iterator_) |
+ return SubIntervalIteratorType::AFTER; |
+ |
+ return SubIntervalIteratorType::BEFORE; |
+ } |
+} |
+ |
+bool LinearSequence::Iterator::IsWithinBounds() { |
+ return affinity_sub_interval_iterator_ || before_sub_interval_iterator_ || |
+ after_sub_interval_iterator_; |
+} |
+ |
+// LinearSequence::ReverseIterator implementation. |
+LinearSequence::ReverseIterator::ReverseIterator() {} |
+ |
+LinearSequence::ReverseIterator::ReverseIterator(LinearSequence* level_sequence) |
+ : LinearSequence::IteratorBase(level_sequence), |
+ affinity_sub_interval_reverse_iterator_( |
+ level_sequence_->affinity_sub_interval_.ReverseBegin()), |
+ before_sub_interval_reverse_iterator_( |
+ level_sequence_->before_sub_interval_.ReverseBegin()), |
+ after_sub_interval_reverse_iterator_( |
+ level_sequence_->after_sub_interval_.ReverseBegin()), |
+ after_first_(true), |
+ before_sub_interval_span_( |
+ level_sequence_->before_sub_interval_.GetSpan()), |
+ after_sub_interval_span_(level_sequence_->after_sub_interval_.GetSpan()) { |
+ Setup(); |
+ |
+ current_sub_interval_iterator_ = GetCurrentSubIntervalIteratorType(); |
+ current_index_ = |
+ sub_interval_iterators_[ENUM_TO_INDEX(current_sub_interval_iterator_)] |
+ ->index(); |
+} |
+ |
+LinearSequence::ReverseIterator::ReverseIterator( |
+ const LinearSequence::ReverseIterator& other) |
+ : IteratorBase(other), |
+ affinity_sub_interval_reverse_iterator_( |
+ other.affinity_sub_interval_reverse_iterator_), |
+ before_sub_interval_reverse_iterator_( |
+ other.before_sub_interval_reverse_iterator_), |
+ after_sub_interval_reverse_iterator_( |
+ other.after_sub_interval_reverse_iterator_), |
+ after_first_(other.after_first_), |
+ before_sub_interval_span_(other.before_sub_interval_span_), |
+ after_sub_interval_span_(other.after_sub_interval_span_) { |
+ Setup(); |
+} |
+ |
+LinearSequence::ReverseIterator::ReverseIterator( |
+ LinearSequence::ReverseIterator&& other) |
+ : IteratorBase(std::move(other)), |
+ affinity_sub_interval_reverse_iterator_( |
+ std::move(other.affinity_sub_interval_reverse_iterator_)), |
+ before_sub_interval_reverse_iterator_( |
+ std::move(other.before_sub_interval_reverse_iterator_)), |
+ after_sub_interval_reverse_iterator_( |
+ std::move(other.after_sub_interval_reverse_iterator_)), |
+ after_first_(other.after_first_), |
+ before_sub_interval_span_(other.before_sub_interval_span_), |
+ after_sub_interval_span_(other.after_sub_interval_span_) { |
+ Setup(); |
+} |
+ |
+LinearSequence::ReverseIterator::~ReverseIterator() = default; |
+ |
+LinearSequence::ReverseIterator& LinearSequence::ReverseIterator::operator=( |
+ const LinearSequence::ReverseIterator& other) { |
+ IteratorBase::operator=(other); |
+ affinity_sub_interval_reverse_iterator_ = |
+ other.affinity_sub_interval_reverse_iterator_; |
+ before_sub_interval_reverse_iterator_ = |
+ other.before_sub_interval_reverse_iterator_; |
+ after_sub_interval_reverse_iterator_ = |
+ other.after_sub_interval_reverse_iterator_; |
+ after_first_ = other.after_first_; |
+ before_sub_interval_span_ = other.before_sub_interval_span_; |
+ after_sub_interval_span_ = other.after_sub_interval_span_; |
+ |
+ Setup(); |
+ |
+ return *this; |
+} |
+LinearSequence::ReverseIterator& LinearSequence::ReverseIterator::operator=( |
+ LinearSequence::ReverseIterator&& other) { |
+ IteratorBase::operator=(std::move(other)); |
+ affinity_sub_interval_reverse_iterator_ = |
+ std::move(other.affinity_sub_interval_reverse_iterator_); |
+ before_sub_interval_reverse_iterator_ = |
+ std::move(other.before_sub_interval_reverse_iterator_); |
+ after_sub_interval_reverse_iterator_ = |
+ std::move(other.after_sub_interval_reverse_iterator_); |
+ after_first_ = other.after_first_; |
+ before_sub_interval_span_ = other.before_sub_interval_span_; |
+ after_sub_interval_span_ = other.after_sub_interval_span_; |
+ |
+ Setup(); |
+ |
+ return *this; |
+} |
+ |
+void LinearSequence::ReverseIterator::Setup() { |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::AFFINITY)] = |
+ &affinity_sub_interval_reverse_iterator_; |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::BEFORE)] = |
+ &before_sub_interval_reverse_iterator_; |
+ sub_interval_iterators_[ENUM_TO_INDEX(SubIntervalIteratorType::AFTER)] = |
+ &after_sub_interval_reverse_iterator_; |
+} |
+ |
+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 (after_sub_interval_reverse_iterator_) |
+ return SubIntervalIteratorType::AFTER; |
+ |
+ if (before_sub_interval_reverse_iterator_) |
+ return SubIntervalIteratorType::BEFORE; |
+ } else { |
+ after_first_ = true; |
+ if (before_sub_interval_reverse_iterator_) |
+ return SubIntervalIteratorType::BEFORE; |
+ |
+ if (after_sub_interval_reverse_iterator_) |
+ return SubIntervalIteratorType::AFTER; |
+ } |
+ } |
+ |
+ return SubIntervalIteratorType::AFFINITY; |
+} |
+ |
+bool LinearSequence::ReverseIterator::IsWithinBounds() { |
+ return affinity_sub_interval_reverse_iterator_ || |
+ before_sub_interval_reverse_iterator_ || |
+ after_sub_interval_reverse_iterator_; |
+} |
+ |
+// TriangularSequence implementation. |
+TriangularSequence::TriangularSequence() |
+ : coverage_direction_(CoverageDirection::NONE), |
+ traversal_sequence_(true, Interval(), Interval(), Interval()), |
+ level_interval_(), |
+ should_swap_index_representation_(false), |
+ levels_to_skip_(0), |
+ distance_(0) {} |
+ |
+TriangularSequence::TriangularSequence(CoverageDirection coverage_direction, |
+ LinearSequence&& traversal_sequence, |
+ 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(const TriangularSequence& other) = |
+ default; |
+ |
+TriangularSequence::TriangularSequence(TriangularSequence&& other) = default; |
+ |
+TriangularSequence::~TriangularSequence() {} |
+ |
+TriangularSequence& TriangularSequence::operator=( |
+ const TriangularSequence& other) = default; |
+ |
+TriangularSequence& TriangularSequence::operator=(TriangularSequence&& other) = |
+ default; |
+ |
+TriangularSequence::Iterator TriangularSequence::Begin() { |
+ return Iterator(this); |
+} |
+ |
+TriangularSequence::ReverseIterator TriangularSequence::ReverseBegin() { |
+ return ReverseIterator(this); |
+} |
+ |
+// TriangularSequence::IteratorBase implementation. |
+TriangularSequence::IteratorBase::IteratorBase() {} |
+ |
+TriangularSequence::IteratorBase::IteratorBase( |
+ TriangularSequence* triangular_sequence) |
+ : should_swap_index_representation_( |
+ triangular_sequence->should_swap_index_representation_) { |
+ DCHECK_NE(triangular_sequence->coverage_direction_, CoverageDirection::NONE); |
+ Interval::Iterator level_interval_it = |
+ triangular_sequence->level_interval_.Begin(); |
+ traversal_sequence_ = triangular_sequence->traversal_sequence_; |
+ 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( |
+ const TriangularSequence::IteratorBase& other) = default; |
+TriangularSequence::IteratorBase::IteratorBase( |
+ TriangularSequence::IteratorBase&& other) = default; |
+ |
+TriangularSequence::IteratorBase::~IteratorBase() = default; |
+ |
+TriangularSequence::IteratorBase& TriangularSequence::IteratorBase::operator=( |
+ const TriangularSequence::IteratorBase& other) = default; |
+TriangularSequence::IteratorBase& TriangularSequence::IteratorBase::operator=( |
+ TriangularSequence::IteratorBase&& other) = default; |
+ |
+TriangularSequence::IteratorBase& TriangularSequence::IteratorBase:: |
+operator++() { |
+ Advance(); |
+ UpdateCurrent(); |
+ |
+ return *this; |
+} |
+ |
+// TriangularSequence::Iterator implementation. |
+TriangularSequence::Iterator::Iterator() {} |
+ |
+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::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() |
+ : consider_index_rect_(-1, -1, -1, -1), |
+ ignore_index_rect_(-1, -1, -1, -1) {} |
+ |
+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); |
+ |
+ // 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), |
+ TriangularSequence( |
+ CoverageDirection::RIGHT, |
+ LinearSequence( |
+ false, Interval(start, end), |
+ Interval(center_index_rect.bottom(), center_index_rect.top()), |
+ Interval(consider_index_rect_.bottom(), |
+ consider_index_rect_.top())), |
+ 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), |
+ TriangularSequence( |
+ CoverageDirection::TOP, |
+ LinearSequence( |
+ false, Interval(start, end), |
+ Interval(center_index_rect.right(), center_index_rect.left()), |
+ Interval(consider_index_rect_.right(), |
+ consider_index_rect_.left())), |
+ 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), |
+ TriangularSequence( |
+ CoverageDirection::LEFT, |
+ LinearSequence( |
+ true, Interval(start, end), |
+ Interval(center_index_rect.top(), center_index_rect.bottom()), |
+ Interval(consider_index_rect_.top(), |
+ consider_index_rect_.bottom())), |
+ 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), |
+ TriangularSequence( |
+ CoverageDirection::BOTTOM, |
+ LinearSequence(true, Interval(start, end), |
+ Interval(center_index_rect.left(), |
+ center_index_rect.right()), |
+ Interval(consider_index_rect_.left(), |
+ consider_index_rect_.right())), |
+ 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 TriangularSequence& triangular_sequence) { |
+ return triangular_sequence.coverage_direction() == |
+ CoverageDirection::NONE; |
+ }), |
+ triangular_sequences_.end()); |
+} |
+ |
+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(this); |
+} |
+ |
+PyramidSequence::ReverseIterator PyramidSequence::ReverseBegin() { |
+ return ReverseIterator(this); |
+} |
+ |
+void PyramidSequence::EmplaceAt(int position, |
+ TriangularSequence&& triangular_sequence) { |
+ TriangularSequence::Vector::iterator it = triangular_sequences_.begin(); |
+ std::advance(it, position); |
+ triangular_sequences_.emplace(it, std::move(triangular_sequence)); |
+ TriangularSequence::Vector::iterator erase_it = triangular_sequences_.begin(); |
+ std::advance(erase_it, position + 1); |
+ triangular_sequences_.erase(erase_it); |
+} |
+ |
+// PyramidSequence::IteratorBase implementation. |
+PyramidSequence::IteratorBase::IteratorBase() |
+ : consider_index_rect_(-1, -1, -1, -1), |
+ ignore_index_rect_(-1, -1, -1, -1), |
+ current_triangular_sequence_it_(nullptr) {} |
+ |
+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( |
+ const PyramidSequence::IteratorBase& other) = default; |
+ |
+PyramidSequence::IteratorBase::IteratorBase( |
+ PyramidSequence::IteratorBase&& other) = default; |
+ |
+PyramidSequence::IteratorBase::~IteratorBase() = default; |
+ |
+PyramidSequence::IteratorBase& PyramidSequence::IteratorBase::operator=( |
+ const PyramidSequence::IteratorBase& other) = default; |
+ |
+PyramidSequence::IteratorBase& PyramidSequence::IteratorBase::operator=( |
+ PyramidSequence::IteratorBase&& other) = 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::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->coverage_direction() != CoverageDirection::NONE); |
+ triangular_sequence_iterators_.emplace_back(it->Begin()); |
+ } |
+ |
+ Setup(); |
+} |
+ |
+PyramidSequence::Iterator::Iterator(const PyramidSequence::Iterator& other) |
+ : IteratorBase(other), |
+ triangular_sequence_iterators_(other.triangular_sequence_iterators_) { |
+ Setup(); |
+} |
+ |
+PyramidSequence::Iterator::Iterator(PyramidSequence::Iterator&& other) |
+ : IteratorBase(std::move(other)), |
+ triangular_sequence_iterators_( |
+ std::move(other.triangular_sequence_iterators_)) { |
+ Setup(); |
+} |
+ |
+PyramidSequence::Iterator::~Iterator() = default; |
+ |
+PyramidSequence::Iterator& PyramidSequence::Iterator::operator=( |
+ const PyramidSequence::Iterator& other) { |
+ IteratorBase::operator=(other); |
+ triangular_sequence_iterators_ = other.triangular_sequence_iterators_; |
+ |
+ Setup(); |
+ |
+ return *this; |
+} |
+ |
+PyramidSequence::Iterator& PyramidSequence::Iterator::operator=( |
+ PyramidSequence::Iterator&& other) { |
+ IteratorBase::operator=(std::move(other)); |
+ triangular_sequence_iterators_ = |
+ std::move(other.triangular_sequence_iterators_); |
+ |
+ Setup(); |
+ |
+ return *this; |
+} |
+ |
+void PyramidSequence::Iterator::Setup() { |
+ 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(); |
+ } |
+} |
+ |
+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 TriangularSequence::Iterator& it) { return !it; }), |
+ triangular_sequence_iterators_.end()); |
+ |
+ if (triangular_sequence_iterators_.empty()) |
+ return nullptr; |
+ |
+ std::vector<TriangularSequence::Iterator>::iterator min_distance_it = |
+ triangular_sequence_iterators_.begin(); |
+ |
+ for (std::vector<TriangularSequence::Iterator>::iterator it = |
+ triangular_sequence_iterators_.begin(); |
+ it != triangular_sequence_iterators_.end(); ++it) { |
+ int distance = it->GetNextDistance(); |
+ if (distance == 0) { |
+ min_distance_it = it; |
+ break; |
+ } |
+ |
+ if (min_distance_it->GetNextDistance() > distance) |
+ min_distance_it = it; |
+ } |
+ |
+ return &(*min_distance_it); |
+} |
+ |
+// PyramidSequence::ReverseIterator implementation. |
+PyramidSequence::ReverseIterator::ReverseIterator() {} |
+ |
+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->ReverseBegin()); |
+ } |
+ |
+ Setup(); |
+} |
+ |
+PyramidSequence::ReverseIterator::ReverseIterator( |
+ const PyramidSequence::ReverseIterator& other) |
+ : IteratorBase(other), |
+ triangular_sequence_reverse_iterators_( |
+ other.triangular_sequence_reverse_iterators_) { |
+ Setup(); |
+} |
+ |
+PyramidSequence::ReverseIterator::ReverseIterator( |
+ PyramidSequence::ReverseIterator&& other) |
+ : IteratorBase(std::move(other)), |
+ triangular_sequence_reverse_iterators_( |
+ std::move(other.triangular_sequence_reverse_iterators_)) { |
+ Setup(); |
+} |
+ |
+PyramidSequence::ReverseIterator::~ReverseIterator() = default; |
+ |
+PyramidSequence::ReverseIterator& PyramidSequence::ReverseIterator::operator=( |
+ const PyramidSequence::ReverseIterator& other) { |
+ IteratorBase::operator=(other); |
+ triangular_sequence_reverse_iterators_ = |
+ other.triangular_sequence_reverse_iterators_; |
+ Setup(); |
+ return *this; |
+} |
+ |
+PyramidSequence::ReverseIterator& PyramidSequence::ReverseIterator::operator=( |
+ PyramidSequence::ReverseIterator&& other) { |
+ IteratorBase::operator=(std::move(other)); |
+ triangular_sequence_reverse_iterators_ = |
+ std::move(other.triangular_sequence_reverse_iterators_); |
+ Setup(); |
+ return *this; |
+} |
+ |
+void PyramidSequence::ReverseIterator::Setup() { |
+ 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(); |
+ } |
+} |
+ |
+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 TriangularSequence::ReverseIterator& it) { return !it; }), |
+ triangular_sequence_reverse_iterators_.end()); |
+ |
+ if (triangular_sequence_reverse_iterators_.empty()) |
+ return nullptr; |
+ |
+ std::vector<TriangularSequence::ReverseIterator>::reverse_iterator |
+ max_distance_it = triangular_sequence_reverse_iterators_.rbegin(); |
+ |
+ for (std::vector<TriangularSequence::ReverseIterator>::reverse_iterator it = |
+ triangular_sequence_reverse_iterators_.rbegin(); |
+ it != triangular_sequence_reverse_iterators_.rend(); ++it) { |
+ int distance = it->GetNextDistance(); |
+ |
+ if (max_distance_it->GetNextDistance() < distance) |
+ max_distance_it = it; |
+ } |
+ |
+ return &(*max_distance_it); |
+} |
+ |
+} // namespace cc |