Chromium Code Reviews| 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..5b33fda82806c27d1f21cb19880f63df7a77b6b4 |
| --- /dev/null |
| +++ b/cc/base/pyramid_sequence.cc |
| @@ -0,0 +1,1058 @@ |
| +// 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> |
| + |
| +namespace cc { |
| + |
| +namespace { |
| + |
| +int ClampNumberInForwardInterval(int number, |
| + int interval_start, |
| + int interval_end) { |
| + DCHECK_LE(interval_start, interval_end); |
| + if (number < interval_start) |
| + return interval_start; |
| + if (number > interval_end) |
| + return interval_end; |
| + return number; |
| +} |
| + |
| +int ClampNumberInBackwardInterval(int number, |
| + int interval_start, |
| + int interval_end) { |
| + DCHECK_GE(interval_start, interval_end); |
| + if (number > interval_start) |
| + return interval_start; |
| + if (number < interval_end) |
| + return interval_end; |
| + return number; |
| +} |
| + |
| +int LevelsToSkipAlongDirection(int levels) { |
| + return levels > 0 ? levels : 0; |
| +} |
| + |
| +int LevelsToSkipPerpendicularToDirection(int levels) { |
| + return levels >= 0 ? levels + 1 : 0; |
| +} |
| + |
| +enum class TilingCoverageDirection : uint8_t { |
| + RIGHT = 0, |
| + TOP_RIGHT, |
| + TOP, |
| + TOP_LEFT, |
| + LEFT, |
| + BOTTOM_LEFT, |
| + BOTTOM, |
| + BOTTOM_RIGHT |
| +}; |
| + |
| +// The pyramid sequence covers following 8 directions while iterating. |
| +// |
| +// TL T TR |
| +// L * R ---> |
| +// BL B BR |
| +// |
| +// The pyramid sequence can yeild better iteration order, if the positions of |
| +// its inlined level distance sequences are properly considered. Suppose primary |
| +// direction for coverage is right, then it can have inclination either to top |
| +// right or bottom right. This inclination is input by secondary direction. |
| +// The positions for right and inclined to bottom right (which is now considered |
| +// as default) is R, BR, TR, B, T, BL, TL, L. |
| +// This function returns the positions for different directions. |
|
prashant.n
2016/07/20 03:10:49
This function will play important role in giving b
|
| +TilingCoverageDirection* GetCoverageDirectionSequenceForDirections( |
| + TilingCoverageDirection primary_direction, |
| + TilingCoverageDirection secondary_direction) { |
| + switch (primary_direction) { |
| + case TilingCoverageDirection::RIGHT: |
| + switch (secondary_direction) { |
| + case TilingCoverageDirection::TOP_RIGHT: |
| + static TilingCoverageDirection right_top_right[] = { |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::LEFT}; |
| + return right_top_right; |
| + case TilingCoverageDirection::BOTTOM_RIGHT: |
| + static TilingCoverageDirection right_bottom_right[] = { |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::LEFT}; |
| + return right_bottom_right; |
| + default: |
| + NOTREACHED(); |
| + } |
| + break; |
| + |
| + case TilingCoverageDirection::TOP_RIGHT: |
| + switch (secondary_direction) { |
| + case TilingCoverageDirection::TOP: |
| + static TilingCoverageDirection top_right_top[] = { |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::BOTTOM_LEFT}; |
| + return top_right_top; |
| + case TilingCoverageDirection::RIGHT: |
| + static TilingCoverageDirection top_right_right[] = { |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::BOTTOM_LEFT}; |
| + return top_right_right; |
| + default: |
| + NOTREACHED(); |
| + } |
| + break; |
| + |
| + case TilingCoverageDirection::TOP: |
| + switch (secondary_direction) { |
| + case TilingCoverageDirection::TOP_RIGHT: |
| + static TilingCoverageDirection top_top_right[] = { |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::BOTTOM}; |
| + return top_top_right; |
| + case TilingCoverageDirection::TOP_LEFT: |
| + static TilingCoverageDirection top_top_left[] = { |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::BOTTOM}; |
| + return top_top_left; |
| + default: |
| + NOTREACHED(); |
| + } |
| + break; |
| + |
| + case TilingCoverageDirection::TOP_LEFT: |
| + switch (secondary_direction) { |
| + case TilingCoverageDirection::TOP: |
| + static TilingCoverageDirection top_left_top[] = { |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::BOTTOM_RIGHT}; |
| + return top_left_top; |
| + case TilingCoverageDirection::LEFT: |
| + static TilingCoverageDirection top_left_left[] = { |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::BOTTOM_RIGHT}; |
| + return top_left_left; |
| + default: |
| + NOTREACHED(); |
| + } |
| + break; |
| + |
| + case TilingCoverageDirection::LEFT: |
| + switch (secondary_direction) { |
| + case TilingCoverageDirection::TOP_LEFT: |
| + static TilingCoverageDirection left_top_left[] = { |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::RIGHT}; |
| + return left_top_left; |
| + case TilingCoverageDirection::BOTTOM_LEFT: |
| + static TilingCoverageDirection left_bottom_left[] = { |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::RIGHT}; |
| + return left_bottom_left; |
| + default: |
| + NOTREACHED(); |
| + } |
| + break; |
| + |
| + case TilingCoverageDirection::BOTTOM_LEFT: |
| + switch (secondary_direction) { |
| + case TilingCoverageDirection::LEFT: |
| + static TilingCoverageDirection bottom_left_left[] = { |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::TOP_RIGHT}; |
| + return bottom_left_left; |
| + case TilingCoverageDirection::BOTTOM: |
| + static TilingCoverageDirection bottom_left_bottom[] = { |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::TOP_RIGHT}; |
| + return bottom_left_bottom; |
| + default: |
| + NOTREACHED(); |
| + } |
| + break; |
| + |
| + case TilingCoverageDirection::BOTTOM: |
| + switch (secondary_direction) { |
| + case TilingCoverageDirection::BOTTOM_LEFT: |
| + static TilingCoverageDirection bottom_bottom_left[] = { |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::TOP}; |
| + return bottom_bottom_left; |
| + case TilingCoverageDirection::BOTTOM_RIGHT: |
| + static TilingCoverageDirection bottom_bottom_right[] = { |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::TOP_LEFT, |
| + TilingCoverageDirection::TOP}; |
| + return bottom_bottom_right; |
| + default: |
| + NOTREACHED(); |
| + } |
| + break; |
| + |
| + case TilingCoverageDirection::BOTTOM_RIGHT: |
| + switch (secondary_direction) { |
| + case TilingCoverageDirection::BOTTOM: |
| + static TilingCoverageDirection bottom_right_bottom[] = { |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::TOP_LEFT}; |
| + return bottom_right_bottom; |
| + case TilingCoverageDirection::RIGHT: |
| + static TilingCoverageDirection bottom_right_right[] = { |
| + TilingCoverageDirection::BOTTOM_RIGHT, |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::BOTTOM, |
| + TilingCoverageDirection::TOP_RIGHT, |
| + TilingCoverageDirection::BOTTOM_LEFT, |
| + TilingCoverageDirection::TOP, |
| + TilingCoverageDirection::LEFT, |
| + TilingCoverageDirection::TOP_LEFT}; |
| + return bottom_right_right; |
| + default: |
| + NOTREACHED(); |
| + } |
| + break; |
| + } |
| + |
| + return nullptr; |
| +} |
| + |
| +int GetPositionForDirection(TilingCoverageDirection* positions, |
| + TilingCoverageDirection direction) { |
| + for (int i = 0; i < 8; ++i) { |
| + if (positions[i] == direction) |
| + return i; |
| + } |
| + |
| + NOTREACHED(); |
| + return -1; |
| +} |
| + |
| +} // namespace |
| + |
| +// TriangularSequence implementation. |
| +TriangularSequence::TriangularSequence(std::string&& name, |
| + Type type, |
| + Interval&& interval, |
| + Interval&& interval_inflate_limit, |
| + int levels, |
| + int levels_to_skip, |
| + bool reverse) |
| + : name_(std::move(name)), |
| + type_(type), |
| + interval_(std::move(interval)), |
| + interval_inflate_limit_(std::move(interval_inflate_limit)), |
| + initial_interval_(interval_), |
| + levels_(levels), |
| + levels_traversed_(0), |
| + levels_limit_(levels), |
| + reverse_(reverse), |
| + within_bounds_(true), |
| + inflate_(nullptr), |
| + is_within_bounds_(nullptr) { |
| + DCHECK_GE(levels, 0); |
| + Init(type); |
| + (this->*inflate_)(levels_to_skip); |
| + |
| + if (reverse) { |
| + levels_limit_ = levels_traversed_; |
| + int last_level = levels - levels_to_skip - 1; |
| + (this->*inflate_)(last_level); |
| + } |
| +} |
| + |
| +TriangularSequence::TriangularSequence(const TriangularSequence& other) = |
| + default; |
| + |
| +TriangularSequence::TriangularSequence(TriangularSequence&& other) = default; |
| + |
| +TriangularSequence::~TriangularSequence() { |
| + inflate_ = nullptr; |
| + is_within_bounds_ = nullptr; |
| +} |
| + |
| +TriangularSequence& TriangularSequence::operator=( |
| + const TriangularSequence& other) = default; |
| + |
| +TriangularSequence& TriangularSequence::operator=(TriangularSequence&& other) = |
| + default; |
| + |
| +int TriangularSequence::GetInitialIntervalSpan() { |
| + return step_ == 1 ? initial_interval_.end - initial_interval_.start + 1 |
| + : initial_interval_.start - initial_interval_.end + 1; |
| +} |
| + |
| +int TriangularSequence::GetCurrentSequenceNumber() { |
| + DCHECK(inflate_); |
| + if (levels_traversed_ < levels_limit_ && !within_bounds_) |
| + (this->*inflate_)(1); |
| + |
| + return current_sequence_number_; |
| +} |
| + |
| +int TriangularSequence::GetReverseCurrentSequenceNumber() { |
| + DCHECK(inflate_); |
| + if (levels_traversed_ >= levels_limit_ && !within_bounds_) |
| + (this->*inflate_)(-1); |
| + |
| + return current_sequence_number_; |
| +} |
| + |
| +void TriangularSequence::Advance() { |
| + DCHECK(is_within_bounds_); |
| + current_sequence_number_ += step_; |
| + within_bounds_ = (this->*is_within_bounds_)(); |
| +} |
| + |
| +void TriangularSequence::Init(TriangularSequence::Type type) { |
| + switch (type) { |
| + case TriangularSequence::Type::FORWARD: |
| + inflate_ = &TriangularSequence::InflateForward; |
| + is_within_bounds_ = &TriangularSequence::IsWithinBoundsForward; |
| + step_ = reverse_ ? -1 : 1; |
| + break; |
| + case TriangularSequence::Type::BACKWARD: |
| + inflate_ = &TriangularSequence::InflateBackward; |
| + is_within_bounds_ = &TriangularSequence::IsWithinBoundsBackward; |
| + step_ = reverse_ ? 1 : -1; |
| + break; |
| + case TriangularSequence::Type::DIAGONAL_FORWARD: |
| + DCHECK_EQ(interval_.start, interval_.end); |
| + inflate_ = &TriangularSequence::InflateDiagonalForward; |
| + is_within_bounds_ = &TriangularSequence::IsWithinBoundsDiagonal; |
| + step_ = reverse_ ? -1 : 1; |
| + break; |
| + case TriangularSequence::Type::DIAGONAL_BACKWARD: |
| + DCHECK_EQ(interval_.start, interval_.end); |
| + inflate_ = &TriangularSequence::InflateDiagonalBackward; |
| + is_within_bounds_ = &TriangularSequence::IsWithinBoundsDiagonal; |
| + step_ = reverse_ ? 1 : -1; |
| + break; |
| + } |
| +} |
| + |
| +void TriangularSequence::Reset() { |
| + current_sequence_number_ = reverse_ ? interval_.end : interval_.start; |
| + within_bounds_ = true; |
| +} |
| + |
| +void TriangularSequence::InflateForward(int levels) { |
| + levels_traversed_ += levels; |
| + interval_.start = initial_interval_.start - levels_traversed_; |
| + interval_.end = initial_interval_.end + levels_traversed_; |
| + |
| + interval_.start = ClampNumberInForwardInterval(interval_.start, |
| + interval_inflate_limit_.start, |
| + interval_inflate_limit_.end); |
| + interval_.end = |
| + ClampNumberInForwardInterval(interval_.end, interval_inflate_limit_.start, |
| + interval_inflate_limit_.end); |
| + |
| + Reset(); |
| +} |
| + |
| +void TriangularSequence::InflateBackward(int levels) { |
| + levels_traversed_ += levels; |
| + interval_.start = initial_interval_.start + levels_traversed_; |
| + interval_.end = initial_interval_.end - levels_traversed_; |
| + interval_.start = ClampNumberInBackwardInterval(interval_.start, |
| + interval_inflate_limit_.start, |
| + interval_inflate_limit_.end); |
| + interval_.end = ClampNumberInBackwardInterval(interval_.end, |
| + interval_inflate_limit_.start, |
| + interval_inflate_limit_.end); |
| + |
| + Reset(); |
| +} |
| + |
| +void TriangularSequence::InflateDiagonalForward(int levels) { |
| + levels_traversed_ += levels; |
| + interval_.start = initial_interval_.start + levels_traversed_; |
| + interval_.end = initial_interval_.end + levels_traversed_; |
| + |
| + Reset(); |
| +} |
| + |
| +void TriangularSequence::InflateDiagonalBackward(int levels) { |
| + levels_traversed_ += levels; |
| + interval_.start = initial_interval_.start - levels_traversed_; |
| + interval_.end = initial_interval_.end - levels_traversed_; |
| + |
| + Reset(); |
| +} |
| + |
| +bool TriangularSequence::IsWithinBoundsForward() { |
| + DCHECK(reverse_ ? current_sequence_number_ <= interval_.end |
| + : current_sequence_number_ >= interval_.start); |
| + |
| + if (interval_.start == interval_.end || |
| + (reverse_ ? current_sequence_number_ < interval_.start |
| + : current_sequence_number_ > interval_.end)) |
| + return false; |
| + |
| + return true; |
| +} |
| + |
| +bool TriangularSequence::IsWithinBoundsBackward() { |
| + DCHECK(reverse_ ? current_sequence_number_ >= interval_.end |
| + : current_sequence_number_ <= interval_.start); |
| + |
| + if (interval_.start == interval_.end || |
| + (reverse_ ? current_sequence_number_ > interval_.start |
| + : current_sequence_number_ < interval_.end)) |
| + return false; |
| + |
| + return true; |
| +} |
| + |
| +bool TriangularSequence::IsWithinBoundsDiagonal() { |
| + DCHECK_EQ(interval_.start, interval_.end); |
| + if (current_sequence_number_ != interval_.start) |
| + return false; |
| + |
| + return true; |
| +} |
| + |
| +// LevelDistanceSequence implementation. |
| +LevelDistanceSequence::LevelDistanceSequence() |
| + : traversal_sequence_(TriangularSequence(std::string("dummy"), |
| + TriangularSequence::Type::FORWARD, |
| + TriangularSequence::Interval(0, 0), |
| + TriangularSequence::Interval(0, 0), |
| + 0, |
| + 0, |
| + false)), |
| + swapped_(false), |
| + reverse_(false), |
| + current_sequence_index_(-1), |
| + current_level_index_(-1) {} |
| + |
| +LevelDistanceSequence::LevelDistanceSequence( |
| + TriangularSequence&& traversal_sequence, |
| + TriangularSequence&& level_sequence, |
| + bool swapped, |
| + int levels_to_skip, |
| + int levels_delta, |
| + int distance, |
| + bool reverse) |
| + : traversal_sequence_(std::move(traversal_sequence)), |
| + swapped_(swapped), |
| + reverse_(reverse) { |
| + for (int i = levels_to_skip; i < level_sequence.GetInitialIntervalSpan(); |
| + ++i) { |
| + int d = distance * i; |
| + int l = level_sequence.GetCurrentSequenceNumber() + levels_delta; |
| + |
| + level_distances_.push_back(LevelDistance(l, d)); |
| + level_sequence.Advance(); |
| + } |
| + if (IsValid()) |
| + Reset(); |
| +} |
| + |
| +LevelDistanceSequence::LevelDistanceSequence( |
| + const LevelDistanceSequence& other) = default; |
| + |
| +LevelDistanceSequence::LevelDistanceSequence(LevelDistanceSequence&& other) = |
| + default; |
| + |
| +LevelDistanceSequence::~LevelDistanceSequence() { |
| + level_distances_.clear(); |
| +} |
| + |
| +LevelDistanceSequence& LevelDistanceSequence::operator=( |
| + const LevelDistanceSequence& other) = default; |
| + |
| +LevelDistanceSequence& LevelDistanceSequence::operator=( |
| + LevelDistanceSequence&& other) = default; |
| + |
| +int LevelDistanceSequence::GetCurrentIndexX() const { |
| + return swapped_ ? current_level_index_ : current_sequence_index_; |
| +} |
| + |
| +int LevelDistanceSequence::GetCurrentIndexY() const { |
| + return swapped_ ? current_sequence_index_ : current_level_index_; |
| +} |
| + |
| +int LevelDistanceSequence::GetMinimumDistance() const { |
| + DCHECK(!level_distances_.empty()); |
| + return level_distances_.front().distance; |
| +} |
| + |
| +int LevelDistanceSequence::GetMaximumDistance() const { |
| + DCHECK(!level_distances_.empty()); |
| + return level_distances_.back().distance; |
| +} |
| + |
| +bool LevelDistanceSequence::Advance() { |
| + traversal_sequence_.Advance(); |
| + if (!traversal_sequence_.is_within_bounds()) { |
| + level_distances_.erase(level_distances_.begin()); |
| + if (IsValid()) |
| + Reset(); |
| + |
| + return false; |
| + } |
| + |
| + current_sequence_index_ = traversal_sequence_.GetCurrentSequenceNumber(); |
| + return true; |
| +} |
| + |
| +bool LevelDistanceSequence::ReverseAdvance() { |
| + traversal_sequence_.Advance(); |
| + if (!traversal_sequence_.is_within_bounds()) { |
| + level_distances_.erase(level_distances_.end() - 1); |
| + if (IsValid()) |
| + Reset(); |
| + |
| + return false; |
| + } |
| + |
| + current_sequence_index_ = |
| + traversal_sequence_.GetReverseCurrentSequenceNumber(); |
| + return true; |
| +} |
| + |
| +void LevelDistanceSequence::Reset() { |
| + DCHECK(!level_distances_.empty()); |
| + if (reverse_) { |
| + current_sequence_index_ = |
| + traversal_sequence_.GetReverseCurrentSequenceNumber(); |
| + current_level_index_ = level_distances_.back().level; |
| + } else { |
| + current_sequence_index_ = traversal_sequence_.GetCurrentSequenceNumber(); |
| + current_level_index_ = level_distances_.front().level; |
| + } |
| +} |
| + |
| +// PyramidSequence implementation. |
| +PyramidSequence::PyramidSequence(bool reverse) |
| + : reverse_(reverse), |
| + current_level_distance_sequence_(nullptr), |
| + index_x_(-1), |
| + index_y_(-1) {} |
| + |
| +PyramidSequence::PyramidSequence(const PyramidSequence& other) = default; |
| + |
| +PyramidSequence::PyramidSequence(PyramidSequence&& other) = default; |
| + |
| +PyramidSequence::~PyramidSequence() { |
| + level_distance_sequences_.clear(); |
| + current_level_distance_sequence_ = nullptr; |
| +} |
| + |
| +PyramidSequence& PyramidSequence::operator=(const PyramidSequence& other) = |
| + default; |
| + |
| +PyramidSequence& PyramidSequence::operator=(PyramidSequence&& other) = default; |
| + |
| +bool PyramidSequence::IsTraversed() { |
| + if (!current_level_distance_sequence_) |
| + return true; |
| + |
| + return level_distance_sequences_.empty(); |
| +} |
| + |
| +void PyramidSequence::Init(int around_left, |
| + int around_right, |
| + int around_top, |
| + int around_bottom, |
| + int consider_left, |
| + int consider_right, |
| + int consider_top, |
| + int consider_bottom, |
| + int ignore_left, |
| + int ignore_right, |
| + int ignore_top, |
| + int ignore_bottom, |
| + int width, |
| + int height) { |
| + consider_left_ = consider_left; |
| + consider_right_ = consider_right; |
| + consider_top_ = consider_top; |
| + consider_bottom_ = consider_bottom; |
| + ignore_left_ = ignore_left; |
| + ignore_right_ = ignore_right; |
| + ignore_top_ = ignore_top; |
| + ignore_bottom_ = ignore_bottom; |
| + |
| + int left_levels = around_left - consider_left + 1; |
| + int right_levels = consider_right - around_right + 1; |
| + int top_levels = around_top - consider_top + 1; |
| + int bottom_levels = consider_bottom - around_bottom + 1; |
| + |
| + int skip_left_levels = around_left - consider_right; |
| + int skip_right_levels = consider_left - around_right; |
| + int skip_top_levels = around_top - consider_bottom; |
| + int skip_bottom_levels = consider_top - around_bottom; |
| + |
| + int skip_left_levels_perp = |
| + LevelsToSkipPerpendicularToDirection(skip_left_levels); |
| + int skip_right_levels_perp = |
| + LevelsToSkipPerpendicularToDirection(skip_right_levels); |
| + int skip_top_levels_perp = |
| + LevelsToSkipPerpendicularToDirection(skip_top_levels); |
| + int skip_bottom_levels_perp = |
| + LevelsToSkipPerpendicularToDirection(skip_bottom_levels); |
| + |
| + skip_left_levels = LevelsToSkipAlongDirection(skip_left_levels); |
| + skip_right_levels = LevelsToSkipAlongDirection(skip_right_levels); |
| + skip_top_levels = LevelsToSkipAlongDirection(skip_top_levels); |
| + skip_bottom_levels = LevelsToSkipAlongDirection(skip_bottom_levels); |
| + |
| + int diagonal_length = std::max(width, height); |
| + |
| + DCHECK(level_distance_sequences_.empty()); |
| + level_distance_sequences_.resize(8); |
| + // TODO(prashant.n): Implement direction of movement for this instead of |
| + // default right direction. http://crbug.com/629052. |
| + TilingCoverageDirection* positions = |
| + GetCoverageDirectionSequenceForDirections( |
| + TilingCoverageDirection::RIGHT, |
| + TilingCoverageDirection::BOTTOM_RIGHT); |
| + DCHECK(positions); |
| + |
| + // RIGHT seq |
| + if (right_levels > 0) { |
| + int start = around_bottom - 1; |
| + int end = around_top + 1; |
| + int skip_levels = |
| + std::max(skip_right_levels, |
| + std::max(skip_bottom_levels_perp, skip_top_levels_perp)); |
| + if (right_levels > skip_levels) { |
| + EmplaceAt( |
| + GetPositionForDirection(positions, TilingCoverageDirection::RIGHT), |
| + LevelDistanceSequence( |
| + TriangularSequence( |
| + std::string("r.seq"), TriangularSequence::Type::BACKWARD, |
| + TriangularSequence::Interval(start, end), |
| + TriangularSequence::Interval(consider_bottom, consider_top), |
| + right_levels, skip_levels, reverse_), |
| + TriangularSequence( |
| + std::string("r.lev"), TriangularSequence::Type::FORWARD, |
| + TriangularSequence::Interval(around_right, consider_right), |
| + TriangularSequence::Interval(consider_left, consider_right), |
| + 1, 0, false), |
| + true, skip_levels, skip_levels - skip_right_levels, width, |
| + reverse_)); |
| + } |
| + } |
| + |
| + // TOP_RIGHT seq |
| + if (right_levels > 0 && top_levels > 0) { |
| + int skip_levels = std::max(skip_right_levels, skip_top_levels); |
| + int diagonal_levels = std::min(right_levels, top_levels); |
| + if (diagonal_levels > skip_levels) { |
| + EmplaceAt( |
| + GetPositionForDirection(positions, |
| + TilingCoverageDirection::TOP_RIGHT), |
| + LevelDistanceSequence( |
| + TriangularSequence( |
| + std::string("tr.seq"), |
| + TriangularSequence::Type::DIAGONAL_FORWARD, |
| + TriangularSequence::Interval(around_right, around_right), |
| + TriangularSequence::Interval(consider_left, consider_right), |
| + diagonal_levels, skip_levels, reverse_), |
| + TriangularSequence( |
| + std::string("tr.lev"), TriangularSequence::Type::BACKWARD, |
| + TriangularSequence::Interval( |
| + around_top, around_top - diagonal_levels + 1), |
| + TriangularSequence::Interval(consider_bottom, consider_top), |
| + 1, 0, false), |
| + false, skip_levels, skip_levels - skip_top_levels, |
| + diagonal_length, reverse_)); |
| + } |
| + } |
| + |
| + // TOP seq |
| + if (top_levels > 0) { |
| + int start = around_right - 1; |
| + int end = around_left + 1; |
| + int skip_levels = |
| + std::max(skip_top_levels, |
| + std::max(skip_right_levels_perp, skip_left_levels_perp)); |
| + if (top_levels > skip_levels) { |
| + EmplaceAt( |
| + GetPositionForDirection(positions, TilingCoverageDirection::TOP), |
| + LevelDistanceSequence( |
| + TriangularSequence( |
| + std::string("t.seq"), TriangularSequence::Type::BACKWARD, |
| + TriangularSequence::Interval(start, end), |
| + TriangularSequence::Interval(consider_right, consider_left), |
| + top_levels, skip_levels, reverse_), |
| + TriangularSequence( |
| + std::string("t.lev"), TriangularSequence::Type::BACKWARD, |
| + TriangularSequence::Interval(around_top, consider_top), |
| + TriangularSequence::Interval(consider_bottom, consider_top), |
| + 1, 0, false), |
| + false, skip_levels, skip_levels - skip_top_levels, height, |
| + reverse_)); |
| + } |
| + } |
| + |
| + // TOP_LEFT seq |
| + if (top_levels > 0 && left_levels > 0) { |
| + int skip_levels = std::max(skip_top_levels, skip_left_levels); |
| + int diagonal_levels = std::min(top_levels, left_levels); |
| + if (diagonal_levels > skip_levels) { |
| + EmplaceAt( |
| + GetPositionForDirection(positions, TilingCoverageDirection::TOP_LEFT), |
| + LevelDistanceSequence( |
| + TriangularSequence( |
| + std::string("tl.seq"), |
| + TriangularSequence::Type::DIAGONAL_BACKWARD, |
| + TriangularSequence::Interval(around_left, around_left), |
| + TriangularSequence::Interval(consider_right, consider_left), |
| + diagonal_levels, skip_levels, reverse_), |
| + TriangularSequence( |
| + std::string("tl.lev"), TriangularSequence::Type::BACKWARD, |
| + TriangularSequence::Interval( |
| + around_top, around_top - diagonal_levels + 1), |
| + TriangularSequence::Interval(consider_bottom, consider_top), |
| + 1, 0, false), |
| + false, skip_levels, skip_levels - skip_top_levels, |
| + diagonal_length, reverse_)); |
| + } |
| + } |
| + |
| + // LEFT seq |
| + if (left_levels > 0) { |
| + int start = around_top + 1; |
| + int end = around_bottom - 1; |
| + int skip_levels = |
| + std::max(skip_left_levels, |
| + std::max(skip_top_levels_perp, skip_bottom_levels_perp)); |
| + if (left_levels > skip_levels) { |
| + EmplaceAt( |
| + GetPositionForDirection(positions, TilingCoverageDirection::LEFT), |
| + LevelDistanceSequence( |
| + TriangularSequence( |
| + std::string("l.seq"), TriangularSequence::Type::FORWARD, |
| + TriangularSequence::Interval(start, end), |
| + TriangularSequence::Interval(consider_top, consider_bottom), |
| + left_levels, skip_levels, reverse_), |
| + TriangularSequence( |
| + std::string("l.lev"), TriangularSequence::Type::BACKWARD, |
| + TriangularSequence::Interval(around_left, consider_left), |
| + TriangularSequence::Interval(consider_right, consider_left), |
| + 1, 0, false), |
| + true, skip_levels, skip_levels - skip_left_levels, width, |
| + reverse_)); |
| + } |
| + } |
| + |
| + // BOTTOM_LEFT seq |
| + if (left_levels > 0 && bottom_levels > 0) { |
| + int skip_levels = std::max(skip_left_levels, skip_bottom_levels); |
| + int diagonal_levels = std::min(left_levels, bottom_levels); |
| + if (diagonal_levels > skip_levels) { |
| + EmplaceAt( |
| + GetPositionForDirection(positions, |
| + TilingCoverageDirection::BOTTOM_LEFT), |
| + LevelDistanceSequence( |
| + TriangularSequence( |
| + std::string("bl.seq"), |
| + TriangularSequence::Type::DIAGONAL_BACKWARD, |
| + TriangularSequence::Interval(around_left, around_left), |
| + TriangularSequence::Interval(consider_right, consider_left), |
| + diagonal_levels, skip_levels, reverse_), |
| + TriangularSequence( |
| + std::string("bl.lev"), TriangularSequence::Type::FORWARD, |
| + TriangularSequence::Interval( |
| + around_bottom, around_bottom + diagonal_levels - 1), |
| + TriangularSequence::Interval(consider_top, consider_bottom), |
| + 1, 0, false), |
| + false, skip_levels, skip_levels - skip_bottom_levels, |
| + diagonal_length, reverse_)); |
| + } |
| + } |
| + |
| + // BOTTOM seq |
| + if (bottom_levels > 0) { |
| + int start = around_left + 1; |
| + int end = around_right - 1; |
| + int skip_levels = |
| + std::max(skip_bottom_levels, |
| + std::max(skip_left_levels_perp, skip_right_levels_perp)); |
| + if (bottom_levels > skip_levels) { |
| + EmplaceAt( |
| + GetPositionForDirection(positions, TilingCoverageDirection::BOTTOM), |
| + LevelDistanceSequence( |
| + TriangularSequence( |
| + std::string("b.seq"), TriangularSequence::Type::FORWARD, |
| + TriangularSequence::Interval(start, end), |
| + TriangularSequence::Interval(consider_left, consider_right), |
| + bottom_levels, skip_levels, reverse_), |
| + TriangularSequence( |
| + std::string("b.lev"), TriangularSequence::Type::FORWARD, |
| + TriangularSequence::Interval(around_bottom, consider_bottom), |
| + TriangularSequence::Interval(consider_top, consider_bottom), |
| + 1, 0, false), |
| + false, skip_levels, skip_levels - skip_bottom_levels, height, |
| + reverse_)); |
| + } |
| + } |
| + |
| + // BOTTOM_RIGHT seq |
| + if (bottom_levels > 0 && right_levels > 0) { |
| + int skip_levels = std::max(skip_bottom_levels, skip_right_levels); |
| + int diagonal_levels = std::min(bottom_levels, right_levels); |
| + if (diagonal_levels > skip_levels) { |
| + EmplaceAt( |
| + GetPositionForDirection(positions, |
| + TilingCoverageDirection::BOTTOM_RIGHT), |
| + LevelDistanceSequence( |
| + TriangularSequence( |
| + std::string("br.seq"), |
| + TriangularSequence::Type::DIAGONAL_FORWARD, |
| + TriangularSequence::Interval(around_right, around_right), |
| + TriangularSequence::Interval(consider_left, consider_right), |
| + diagonal_levels, skip_levels, reverse_), |
| + TriangularSequence( |
| + std::string("br.lev"), TriangularSequence::Type::FORWARD, |
| + TriangularSequence::Interval( |
| + around_bottom, around_bottom + diagonal_levels - 1), |
| + TriangularSequence::Interval(consider_top, consider_bottom), |
| + 1, 0, false), |
| + false, skip_levels, skip_levels - skip_bottom_levels, |
| + diagonal_length, reverse_)); |
| + } |
| + } |
| + |
| + current_level_distance_sequence_ = GetNextLevelDistanceSequence(); |
| + UpdateCurrent(); |
| +} |
| + |
| +void PyramidSequence::EmplaceAt( |
| + int position, |
| + LevelDistanceSequence&& level_distance_sequence) { |
| + LevelDistanceSequence::Iterator it = level_distance_sequences_.begin(); |
| + std::advance(it, position); |
| + level_distance_sequences_.emplace(it, std::move(level_distance_sequence)); |
| + LevelDistanceSequence::Iterator erase_it = level_distance_sequences_.begin(); |
| + std::advance(erase_it, position + 1); |
| + level_distance_sequences_.erase(erase_it); |
| +} |
| + |
| +void PyramidSequence::UpdateCurrent() { |
| + while (!IsTraversed()) { |
| + DCHECK(current_level_distance_sequence_->IsValid()); |
| + |
| + index_x_ = current_level_distance_sequence_->GetCurrentIndexX(); |
| + index_y_ = current_level_distance_sequence_->GetCurrentIndexY(); |
| + |
| + if (InConsiderRect() && !InIgnoreRect()) |
| + break; |
| + |
| + Advance(); |
| + } |
| +} |
| + |
| +bool PyramidSequence::InConsiderRect() const { |
| + return index_x_ >= consider_left_ && index_x_ <= consider_right_ && |
| + index_y_ >= consider_top_ && index_y_ <= consider_bottom_; |
| +} |
| + |
| +bool PyramidSequence::InIgnoreRect() const { |
| + return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ && |
| + index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_; |
| +} |
| + |
| +void PyramidSequence::RemoveEmptyLevelDistanceSequences() { |
| + level_distance_sequences_.erase( |
| + std::remove_if( |
| + level_distance_sequences_.begin(), level_distance_sequences_.end(), |
| + [](const LevelDistanceSequence& seq) { return !seq.IsValid(); }), |
| + level_distance_sequences_.end()); |
| +} |
| + |
| +// TopDownPyramidSequence implementation. |
| +TopDownPyramidSequence::TopDownPyramidSequence() : PyramidSequence(false) {} |
| + |
| +TopDownPyramidSequence::TopDownPyramidSequence( |
| + const TopDownPyramidSequence& other) = default; |
| + |
| +TopDownPyramidSequence::TopDownPyramidSequence(TopDownPyramidSequence&& other) = |
| + default; |
| + |
| +TopDownPyramidSequence::~TopDownPyramidSequence() {} |
| + |
| +TopDownPyramidSequence& TopDownPyramidSequence::operator=( |
| + const TopDownPyramidSequence& other) = default; |
| + |
| +TopDownPyramidSequence& TopDownPyramidSequence::operator=( |
| + TopDownPyramidSequence&& other) = default; |
| + |
| +void TopDownPyramidSequence::Advance() { |
| + if (IsTraversed()) |
| + return; |
| + |
| + if (!current_level_distance_sequence_->Advance()) |
| + current_level_distance_sequence_ = GetNextLevelDistanceSequence(); |
| +} |
| + |
| +LevelDistanceSequence* TopDownPyramidSequence::GetNextLevelDistanceSequence() { |
| + RemoveEmptyLevelDistanceSequences(); |
| + |
| + if (level_distance_sequences_.empty()) |
| + return nullptr; |
| + |
| + LevelDistanceSequence::Iterator min_distance_it = |
| + level_distance_sequences_.begin(); |
| + |
| + for (LevelDistanceSequence::Iterator it = level_distance_sequences_.begin(); |
| + it != level_distance_sequences_.end(); ++it) { |
| + int distance = it->GetMinimumDistance(); |
| + if (distance == 0) |
| + return &(*it); |
| + |
| + if (min_distance_it->GetMinimumDistance() > distance) |
| + min_distance_it = it; |
| + } |
| + |
| + return &(*min_distance_it); |
| +} |
| + |
| +// BottomUpPyramidSequence implementation. |
| +BottomUpPyramidSequence::BottomUpPyramidSequence() : PyramidSequence(true) {} |
| + |
| +BottomUpPyramidSequence::BottomUpPyramidSequence( |
| + const BottomUpPyramidSequence& other) |
| + : PyramidSequence(other) {} |
| + |
| +BottomUpPyramidSequence::BottomUpPyramidSequence( |
| + BottomUpPyramidSequence&& other) |
| + : PyramidSequence(std::move(other)) {} |
| + |
| +BottomUpPyramidSequence::~BottomUpPyramidSequence() {} |
| + |
| +BottomUpPyramidSequence& BottomUpPyramidSequence::operator=( |
| + const BottomUpPyramidSequence& other) { |
| + PyramidSequence::operator=(other); |
| + return *this; |
| +} |
| + |
| +BottomUpPyramidSequence& BottomUpPyramidSequence::operator=( |
| + BottomUpPyramidSequence&& other) { |
| + PyramidSequence::operator=(std::move(other)); |
| + return *this; |
| +} |
| + |
| +void BottomUpPyramidSequence::Advance() { |
| + if (IsTraversed()) |
| + return; |
| + |
| + if (!current_level_distance_sequence_->ReverseAdvance()) |
| + current_level_distance_sequence_ = GetNextLevelDistanceSequence(); |
| +} |
| + |
| +LevelDistanceSequence* BottomUpPyramidSequence::GetNextLevelDistanceSequence() { |
| + RemoveEmptyLevelDistanceSequences(); |
| + |
| + if (level_distance_sequences_.empty()) |
| + return nullptr; |
| + |
| + LevelDistanceSequence::ReverseIterator max_distance_it = |
| + level_distance_sequences_.rbegin(); |
| + |
| + for (LevelDistanceSequence::ReverseIterator it = |
| + level_distance_sequences_.rbegin(); |
| + it != level_distance_sequences_.rend(); ++it) { |
| + int distance = it->GetMaximumDistance(); |
| + |
| + if (max_distance_it->GetMaximumDistance() < distance) |
| + max_distance_it = it; |
| + } |
| + |
| + return &(*max_distance_it); |
| +} |
| + |
| +} // namespace cc |