Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(271)

Unified Diff: cc/base/pyramid_sequence.cc

Issue 2704303005: Pyramid sequence for testing
Patch Set: test4 Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/base/pyramid_sequence.h ('k') | cc/base/pyramid_sequence_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « cc/base/pyramid_sequence.h ('k') | cc/base/pyramid_sequence_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698