| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "cc/base/pyramid_sequence.h" | 
|  | 6 | 
|  | 7 #include <algorithm> | 
|  | 8 #include <string> | 
|  | 9 | 
|  | 10 namespace cc { | 
|  | 11 | 
|  | 12 namespace { | 
|  | 13 | 
|  | 14 int ClampNumberInForwardInterval(int number, int start_limit, int end_limit) { | 
|  | 15   DCHECK_LE(start_limit, end_limit); | 
|  | 16   if (number < start_limit) | 
|  | 17     return start_limit; | 
|  | 18   if (number > end_limit) | 
|  | 19     return end_limit; | 
|  | 20   return number; | 
|  | 21 } | 
|  | 22 | 
|  | 23 int ClampNumberInBackwardInterval(int number, int start_limit, int end_limit) { | 
|  | 24   DCHECK_GE(start_limit, end_limit); | 
|  | 25   if (number > start_limit) | 
|  | 26     return start_limit; | 
|  | 27   if (number < end_limit) | 
|  | 28     return end_limit; | 
|  | 29   return number; | 
|  | 30 } | 
|  | 31 | 
|  | 32 int LevelsToSkipAlongDirection(int levels) { | 
|  | 33   return levels > 0 ? levels : 0; | 
|  | 34 } | 
|  | 35 | 
|  | 36 int LevelsToSkipPerpendicularToDirection(int levels) { | 
|  | 37   return levels >= 0 ? levels + 1 : 0; | 
|  | 38 } | 
|  | 39 | 
|  | 40 enum class CoverageDirection : uint8_t { | 
|  | 41   RIGHT = 0, | 
|  | 42   TOP_RIGHT, | 
|  | 43   TOP, | 
|  | 44   TOP_LEFT, | 
|  | 45   LEFT, | 
|  | 46   BOTTOM_LEFT, | 
|  | 47   BOTTOM, | 
|  | 48   BOTTOM_RIGHT | 
|  | 49 }; | 
|  | 50 | 
|  | 51 // The pyramid sequence covers following 8 directions while iterating. | 
|  | 52 //   TL  T  TR | 
|  | 53 //    L  *   R | 
|  | 54 //   BL  B  BR | 
|  | 55 // | 
|  | 56 // where - | 
|  | 57 //   R  = right | 
|  | 58 //   TR = top right | 
|  | 59 //   T  = top | 
|  | 60 //   TL = top left | 
|  | 61 //   L  = left | 
|  | 62 //   BL = bottom left | 
|  | 63 //   B  = bottom | 
|  | 64 //   BR = bottom right | 
|  | 65 // | 
|  | 66 // The following function returns the spiral order {R, TR, T, TL, L, BL, B, BR}. | 
|  | 67 CoverageDirection* GetCoverageDirectionSequence() { | 
|  | 68   static CoverageDirection right_top_right[8] = { | 
|  | 69       CoverageDirection::RIGHT,  CoverageDirection::TOP_RIGHT, | 
|  | 70       CoverageDirection::TOP,    CoverageDirection::TOP_LEFT, | 
|  | 71       CoverageDirection::LEFT,   CoverageDirection::BOTTOM_LEFT, | 
|  | 72       CoverageDirection::BOTTOM, CoverageDirection::BOTTOM_RIGHT}; | 
|  | 73   return right_top_right; | 
|  | 74 } | 
|  | 75 | 
|  | 76 int GetPositionForDirection(CoverageDirection* positions, | 
|  | 77                             CoverageDirection direction) { | 
|  | 78   for (int i = 0; i < 8; ++i) { | 
|  | 79     if (positions[i] == direction) | 
|  | 80       return i; | 
|  | 81   } | 
|  | 82 | 
|  | 83   NOTREACHED(); | 
|  | 84   return -1; | 
|  | 85 } | 
|  | 86 | 
|  | 87 }  // namespace | 
|  | 88 | 
|  | 89 // Interval implementation. | 
|  | 90 Interval::Interval(Type type, | 
|  | 91                    int start, | 
|  | 92                    int end, | 
|  | 93                    int start_inflate_limit, | 
|  | 94                    int end_inflate_limit, | 
|  | 95                    bool reverse_order) | 
|  | 96     : start_(start), | 
|  | 97       end_(end), | 
|  | 98       initial_start_(start), | 
|  | 99       initial_end_(end), | 
|  | 100       start_inflate_limit_(start_inflate_limit), | 
|  | 101       end_inflate_limit_(end_inflate_limit), | 
|  | 102       reverse_order_(reverse_order), | 
|  | 103       within_bounds_(true), | 
|  | 104       inflate_to_level_ptr_(nullptr), | 
|  | 105       is_within_bounds_ptr_(nullptr) { | 
|  | 106   Init(type); | 
|  | 107   Reset(); | 
|  | 108 } | 
|  | 109 | 
|  | 110 Interval::Interval(const Interval& other) = default; | 
|  | 111 | 
|  | 112 Interval::Interval(Interval&& other) = default; | 
|  | 113 | 
|  | 114 Interval::~Interval() { | 
|  | 115   inflate_to_level_ptr_ = nullptr; | 
|  | 116   is_within_bounds_ptr_ = nullptr; | 
|  | 117 } | 
|  | 118 | 
|  | 119 Interval& Interval::operator=(const Interval& other) = default; | 
|  | 120 | 
|  | 121 Interval& Interval::operator=(Interval&& other) = default; | 
|  | 122 | 
|  | 123 Interval& Interval::operator++() { | 
|  | 124   DCHECK(is_within_bounds_ptr_); | 
|  | 125   current_index_ += step_; | 
|  | 126   within_bounds_ = (this->*is_within_bounds_ptr_)(); | 
|  | 127 | 
|  | 128   return *this; | 
|  | 129 } | 
|  | 130 | 
|  | 131 void Interval::InflateToLevel(int level) { | 
|  | 132   DCHECK(inflate_to_level_ptr_); | 
|  | 133   (this->*inflate_to_level_ptr_)(level); | 
|  | 134 } | 
|  | 135 | 
|  | 136 int Interval::GetSpan() { | 
|  | 137   return std::abs(end_ - start_) + 1; | 
|  | 138 } | 
|  | 139 | 
|  | 140 void Interval::Init(Interval::Type type) { | 
|  | 141   switch (type) { | 
|  | 142     case Interval::Type::FORWARD: | 
|  | 143       inflate_to_level_ptr_ = &Interval::InflateToLevelForward; | 
|  | 144       is_within_bounds_ptr_ = &Interval::IsWithinBoundsForward; | 
|  | 145       step_ = reverse_order_ ? -1 : 1; | 
|  | 146       break; | 
|  | 147     case Interval::Type::BACKWARD: | 
|  | 148       inflate_to_level_ptr_ = &Interval::InflateToLevelBackward; | 
|  | 149       is_within_bounds_ptr_ = &Interval::IsWithinBoundsBackward; | 
|  | 150       step_ = reverse_order_ ? 1 : -1; | 
|  | 151       break; | 
|  | 152     case Interval::Type::DIAGONAL_FORWARD: | 
|  | 153       DCHECK_EQ(start_, end_); | 
|  | 154       inflate_to_level_ptr_ = &Interval::InflateToLevelDiagonalForward; | 
|  | 155       is_within_bounds_ptr_ = &Interval::IsWithinBoundsDiagonal; | 
|  | 156       step_ = reverse_order_ ? -1 : 1; | 
|  | 157       break; | 
|  | 158     case Interval::Type::DIAGONAL_BACKWARD: | 
|  | 159       DCHECK_EQ(start_, end_); | 
|  | 160       inflate_to_level_ptr_ = &Interval::InflateToLevelDiagonalBackward; | 
|  | 161       is_within_bounds_ptr_ = &Interval::IsWithinBoundsDiagonal; | 
|  | 162       step_ = reverse_order_ ? 1 : -1; | 
|  | 163       break; | 
|  | 164   } | 
|  | 165 } | 
|  | 166 | 
|  | 167 void Interval::Reset() { | 
|  | 168   current_index_ = reverse_order_ ? end_ : start_; | 
|  | 169   within_bounds_ = true; | 
|  | 170 } | 
|  | 171 | 
|  | 172 void Interval::InflateToLevelForward(int level) { | 
|  | 173   start_ = initial_start_ - level; | 
|  | 174   end_ = initial_end_ + level; | 
|  | 175 | 
|  | 176   start_ = ClampNumberInForwardInterval(start_, start_inflate_limit_, | 
|  | 177                                         end_inflate_limit_); | 
|  | 178   end_ = ClampNumberInForwardInterval(end_, start_inflate_limit_, | 
|  | 179                                       end_inflate_limit_); | 
|  | 180 | 
|  | 181   Reset(); | 
|  | 182 } | 
|  | 183 | 
|  | 184 void Interval::InflateToLevelBackward(int level) { | 
|  | 185   start_ = initial_start_ + level; | 
|  | 186   end_ = initial_end_ - level; | 
|  | 187   start_ = ClampNumberInBackwardInterval(start_, start_inflate_limit_, | 
|  | 188                                          end_inflate_limit_); | 
|  | 189   end_ = ClampNumberInBackwardInterval(end_, start_inflate_limit_, | 
|  | 190                                        end_inflate_limit_); | 
|  | 191 | 
|  | 192   Reset(); | 
|  | 193 } | 
|  | 194 | 
|  | 195 void Interval::InflateToLevelDiagonalForward(int level) { | 
|  | 196   start_ = initial_start_ + level; | 
|  | 197   end_ = initial_end_ + level; | 
|  | 198 | 
|  | 199   Reset(); | 
|  | 200 } | 
|  | 201 | 
|  | 202 void Interval::InflateToLevelDiagonalBackward(int level) { | 
|  | 203   start_ = initial_start_ - level; | 
|  | 204   end_ = initial_end_ - level; | 
|  | 205 | 
|  | 206   Reset(); | 
|  | 207 } | 
|  | 208 | 
|  | 209 bool Interval::IsWithinBoundsForward() { | 
|  | 210   DCHECK(reverse_order_ ? current_index_ <= end_ : current_index_ >= start_); | 
|  | 211 | 
|  | 212   if (start_ == end_ || | 
|  | 213       (reverse_order_ ? current_index_ < start_ : current_index_ > end_)) | 
|  | 214     return false; | 
|  | 215 | 
|  | 216   return true; | 
|  | 217 } | 
|  | 218 | 
|  | 219 bool Interval::IsWithinBoundsBackward() { | 
|  | 220   DCHECK(reverse_order_ ? current_index_ >= end_ : current_index_ <= start_); | 
|  | 221 | 
|  | 222   if (start_ == end_ || | 
|  | 223       (reverse_order_ ? current_index_ > start_ : current_index_ < end_)) | 
|  | 224     return false; | 
|  | 225 | 
|  | 226   return true; | 
|  | 227 } | 
|  | 228 | 
|  | 229 bool Interval::IsWithinBoundsDiagonal() { | 
|  | 230   DCHECK_EQ(start_, end_); | 
|  | 231   if (current_index_ != start_) | 
|  | 232     return false; | 
|  | 233 | 
|  | 234   return true; | 
|  | 235 } | 
|  | 236 | 
|  | 237 // TriangularSequence implementation. | 
|  | 238 TriangularSequence::TriangularSequence() | 
|  | 239     : name_(std::string("dummy")), | 
|  | 240       traversal_interval_(Interval::Type::FORWARD, 0, 0, 0, 0, false), | 
|  | 241       swapped_(false), | 
|  | 242       reverse_order_(false), | 
|  | 243       current_level_index_(-1) {} | 
|  | 244 | 
|  | 245 TriangularSequence::TriangularSequence(std::string&& name, | 
|  | 246                                        Interval&& traversal_interval, | 
|  | 247                                        Interval&& level_interval, | 
|  | 248                                        bool swapped, | 
|  | 249                                        int levels_to_skip, | 
|  | 250                                        int distance, | 
|  | 251                                        bool reverse_order) | 
|  | 252     : name_(std::move(name)), | 
|  | 253       traversal_interval_(std::move(traversal_interval)), | 
|  | 254       swapped_(swapped), | 
|  | 255       reverse_order_(reverse_order) { | 
|  | 256   int span = level_interval.GetSpan(); | 
|  | 257   DCHECK_GE(span, levels_to_skip); | 
|  | 258 | 
|  | 259   // Skip |levels_to_skip| levels in level interval. | 
|  | 260   for (int i = 0; i < levels_to_skip; ++i) | 
|  | 261     ++level_interval; | 
|  | 262 | 
|  | 263   for (int i = levels_to_skip; i < span; ++i) { | 
|  | 264     level_distances_.push_back( | 
|  | 265         LevelDistance(i, level_interval.index(), distance * i)); | 
|  | 266     ++level_interval; | 
|  | 267   } | 
|  | 268 | 
|  | 269   UpdateCurrent(); | 
|  | 270 } | 
|  | 271 | 
|  | 272 TriangularSequence::TriangularSequence(const TriangularSequence& other) = | 
|  | 273     default; | 
|  | 274 | 
|  | 275 TriangularSequence::TriangularSequence(TriangularSequence&& other) = default; | 
|  | 276 | 
|  | 277 TriangularSequence::~TriangularSequence() { | 
|  | 278   level_distances_.clear(); | 
|  | 279 } | 
|  | 280 | 
|  | 281 TriangularSequence& TriangularSequence::operator=( | 
|  | 282     const TriangularSequence& other) = default; | 
|  | 283 | 
|  | 284 TriangularSequence& TriangularSequence::operator=(TriangularSequence&& other) = | 
|  | 285     default; | 
|  | 286 | 
|  | 287 TriangularSequence& TriangularSequence::operator++() { | 
|  | 288   Advance(); | 
|  | 289   UpdateCurrent(); | 
|  | 290 | 
|  | 291   return *this; | 
|  | 292 } | 
|  | 293 | 
|  | 294 int TriangularSequence::GetMinimumDistance() const { | 
|  | 295   DCHECK(!level_distances_.empty()); | 
|  | 296   return level_distances_.front().distance; | 
|  | 297 } | 
|  | 298 | 
|  | 299 int TriangularSequence::GetMaximumDistance() const { | 
|  | 300   DCHECK(!level_distances_.empty()); | 
|  | 301   return level_distances_.back().distance; | 
|  | 302 } | 
|  | 303 | 
|  | 304 void TriangularSequence::Advance() { | 
|  | 305   if (!*this) | 
|  | 306     return; | 
|  | 307 | 
|  | 308   if (reverse_order_) | 
|  | 309     level_distances_.erase(level_distances_.end() - 1); | 
|  | 310   else | 
|  | 311     level_distances_.erase(level_distances_.begin()); | 
|  | 312 } | 
|  | 313 | 
|  | 314 void TriangularSequence::UpdateCurrent() { | 
|  | 315   if (!*this) | 
|  | 316     return; | 
|  | 317 | 
|  | 318   if (reverse_order_) { | 
|  | 319     current_level_index_ = level_distances_.back().level_index; | 
|  | 320     traversal_interval_.InflateToLevel(level_distances_.back().interval_level); | 
|  | 321   } else { | 
|  | 322     current_level_index_ = level_distances_.front().level_index; | 
|  | 323     traversal_interval_.InflateToLevel(level_distances_.front().interval_level); | 
|  | 324   } | 
|  | 325 } | 
|  | 326 | 
|  | 327 // PyramidSequence implementation. | 
|  | 328 PyramidSequence::PyramidSequence(bool reverse_order) | 
|  | 329     : reverse_order_(reverse_order), | 
|  | 330       current_triangular_sequence_(nullptr), | 
|  | 331       index_x_(-1), | 
|  | 332       index_y_(-1) {} | 
|  | 333 | 
|  | 334 PyramidSequence::PyramidSequence(const PyramidSequence& other) = default; | 
|  | 335 | 
|  | 336 PyramidSequence::PyramidSequence(PyramidSequence&& other) = default; | 
|  | 337 | 
|  | 338 PyramidSequence::~PyramidSequence() { | 
|  | 339   triangular_sequences_.clear(); | 
|  | 340   current_triangular_sequence_ = nullptr; | 
|  | 341 } | 
|  | 342 | 
|  | 343 PyramidSequence& PyramidSequence::operator=(const PyramidSequence& other) = | 
|  | 344     default; | 
|  | 345 | 
|  | 346 PyramidSequence& PyramidSequence::operator=(PyramidSequence&& other) = default; | 
|  | 347 | 
|  | 348 void PyramidSequence::Init(int around_left, | 
|  | 349                            int around_right, | 
|  | 350                            int around_top, | 
|  | 351                            int around_bottom, | 
|  | 352                            int consider_left, | 
|  | 353                            int consider_right, | 
|  | 354                            int consider_top, | 
|  | 355                            int consider_bottom, | 
|  | 356                            int ignore_left, | 
|  | 357                            int ignore_right, | 
|  | 358                            int ignore_top, | 
|  | 359                            int ignore_bottom, | 
|  | 360                            int width, | 
|  | 361                            int height) { | 
|  | 362   consider_left_ = consider_left; | 
|  | 363   consider_right_ = consider_right; | 
|  | 364   consider_top_ = consider_top; | 
|  | 365   consider_bottom_ = consider_bottom; | 
|  | 366   ignore_left_ = ignore_left; | 
|  | 367   ignore_right_ = ignore_right; | 
|  | 368   ignore_top_ = ignore_top; | 
|  | 369   ignore_bottom_ = ignore_bottom; | 
|  | 370 | 
|  | 371   int left_levels = around_left - consider_left + 1; | 
|  | 372   int right_levels = consider_right - around_right + 1; | 
|  | 373   int top_levels = around_top - consider_top + 1; | 
|  | 374   int bottom_levels = consider_bottom - around_bottom + 1; | 
|  | 375 | 
|  | 376   int skip_left_levels = around_left - consider_right; | 
|  | 377   int skip_right_levels = consider_left - around_right; | 
|  | 378   int skip_top_levels = around_top - consider_bottom; | 
|  | 379   int skip_bottom_levels = consider_top - around_bottom; | 
|  | 380 | 
|  | 381   int skip_left_levels_perp = | 
|  | 382       LevelsToSkipPerpendicularToDirection(skip_left_levels); | 
|  | 383   int skip_right_levels_perp = | 
|  | 384       LevelsToSkipPerpendicularToDirection(skip_right_levels); | 
|  | 385   int skip_top_levels_perp = | 
|  | 386       LevelsToSkipPerpendicularToDirection(skip_top_levels); | 
|  | 387   int skip_bottom_levels_perp = | 
|  | 388       LevelsToSkipPerpendicularToDirection(skip_bottom_levels); | 
|  | 389 | 
|  | 390   skip_left_levels = LevelsToSkipAlongDirection(skip_left_levels); | 
|  | 391   skip_right_levels = LevelsToSkipAlongDirection(skip_right_levels); | 
|  | 392   skip_top_levels = LevelsToSkipAlongDirection(skip_top_levels); | 
|  | 393   skip_bottom_levels = LevelsToSkipAlongDirection(skip_bottom_levels); | 
|  | 394 | 
|  | 395   int diagonal_distance = std::max(width, height); | 
|  | 396 | 
|  | 397   DCHECK(triangular_sequences_.empty()); | 
|  | 398   triangular_sequences_.resize(8); | 
|  | 399   // TODO(prashant.n): Implement precedence in coverage directions instead of | 
|  | 400   // default right direction. http://crbug.com/629052. | 
|  | 401   CoverageDirection* positions = GetCoverageDirectionSequence(); | 
|  | 402   DCHECK(positions); | 
|  | 403 | 
|  | 404   // RIGHT sequence. | 
|  | 405   if (right_levels > 0) { | 
|  | 406     int start = around_bottom - 1; | 
|  | 407     int end = around_top + 1; | 
|  | 408     int skip_levels = | 
|  | 409         std::max(skip_right_levels, | 
|  | 410                  std::max(skip_bottom_levels_perp, skip_top_levels_perp)); | 
|  | 411     if (right_levels > skip_levels) { | 
|  | 412       EmplaceAt( | 
|  | 413           GetPositionForDirection(positions, CoverageDirection::RIGHT), | 
|  | 414           TriangularSequence( | 
|  | 415               std::string("r.seq"), | 
|  | 416               Interval(Interval::Type::BACKWARD, start, end, consider_bottom, | 
|  | 417                        consider_top, reverse_order_), | 
|  | 418               Interval(Interval::Type::FORWARD, around_right, consider_right, | 
|  | 419                        consider_left, consider_right, false), | 
|  | 420               true, skip_levels, width, reverse_order_)); | 
|  | 421     } | 
|  | 422   } | 
|  | 423 | 
|  | 424   // TOP_RIGHT sequence. | 
|  | 425   if (right_levels > 0 && top_levels > 0) { | 
|  | 426     int skip_levels = std::max(skip_right_levels, skip_top_levels); | 
|  | 427     int diagonal_levels = std::min(right_levels, top_levels); | 
|  | 428     if (diagonal_levels > skip_levels) { | 
|  | 429       EmplaceAt( | 
|  | 430           GetPositionForDirection(positions, CoverageDirection::TOP_RIGHT), | 
|  | 431           TriangularSequence(std::string("tr.seq"), | 
|  | 432                              Interval(Interval::Type::DIAGONAL_FORWARD, | 
|  | 433                                       around_right, around_right, consider_left, | 
|  | 434                                       consider_right, reverse_order_), | 
|  | 435                              Interval(Interval::Type::BACKWARD, around_top, | 
|  | 436                                       around_top - diagonal_levels + 1, | 
|  | 437                                       consider_bottom, consider_top, false), | 
|  | 438                              false, skip_levels, diagonal_distance, | 
|  | 439                              reverse_order_)); | 
|  | 440     } | 
|  | 441   } | 
|  | 442 | 
|  | 443   // TOP sequence. | 
|  | 444   if (top_levels > 0) { | 
|  | 445     int start = around_right - 1; | 
|  | 446     int end = around_left + 1; | 
|  | 447     int skip_levels = | 
|  | 448         std::max(skip_top_levels, | 
|  | 449                  std::max(skip_right_levels_perp, skip_left_levels_perp)); | 
|  | 450     if (top_levels > skip_levels) { | 
|  | 451       EmplaceAt(GetPositionForDirection(positions, CoverageDirection::TOP), | 
|  | 452                 TriangularSequence( | 
|  | 453                     std::string("t.seq"), | 
|  | 454                     Interval(Interval::Type::BACKWARD, start, end, | 
|  | 455                              consider_right, consider_left, reverse_order_), | 
|  | 456                     Interval(Interval::Type::BACKWARD, around_top, consider_top, | 
|  | 457                              consider_bottom, consider_top, false), | 
|  | 458                     false, skip_levels, height, reverse_order_)); | 
|  | 459     } | 
|  | 460   } | 
|  | 461 | 
|  | 462   // TOP_LEFT sequence. | 
|  | 463   if (top_levels > 0 && left_levels > 0) { | 
|  | 464     int skip_levels = std::max(skip_top_levels, skip_left_levels); | 
|  | 465     int diagonal_levels = std::min(top_levels, left_levels); | 
|  | 466     if (diagonal_levels > skip_levels) { | 
|  | 467       EmplaceAt(GetPositionForDirection(positions, CoverageDirection::TOP_LEFT), | 
|  | 468                 TriangularSequence( | 
|  | 469                     std::string("tl.seq"), | 
|  | 470                     Interval(Interval::Type::DIAGONAL_BACKWARD, around_left, | 
|  | 471                              around_left, consider_right, consider_left, | 
|  | 472                              reverse_order_), | 
|  | 473                     Interval(Interval::Type::BACKWARD, around_top, | 
|  | 474                              around_top - diagonal_levels + 1, consider_bottom, | 
|  | 475                              consider_top, false), | 
|  | 476                     false, skip_levels, diagonal_distance, reverse_order_)); | 
|  | 477     } | 
|  | 478   } | 
|  | 479 | 
|  | 480   // LEFT sequence. | 
|  | 481   if (left_levels > 0) { | 
|  | 482     int start = around_top + 1; | 
|  | 483     int end = around_bottom - 1; | 
|  | 484     int skip_levels = | 
|  | 485         std::max(skip_left_levels, | 
|  | 486                  std::max(skip_top_levels_perp, skip_bottom_levels_perp)); | 
|  | 487     if (left_levels > skip_levels) { | 
|  | 488       EmplaceAt( | 
|  | 489           GetPositionForDirection(positions, CoverageDirection::LEFT), | 
|  | 490           TriangularSequence( | 
|  | 491               std::string("l.seq"), | 
|  | 492               Interval(Interval::Type::FORWARD, start, end, consider_top, | 
|  | 493                        consider_bottom, reverse_order_), | 
|  | 494               Interval(Interval::Type::BACKWARD, around_left, consider_left, | 
|  | 495                        consider_right, consider_left, false), | 
|  | 496               true, skip_levels, width, reverse_order_)); | 
|  | 497     } | 
|  | 498   } | 
|  | 499 | 
|  | 500   // BOTTOM_LEFT sequence. | 
|  | 501   if (left_levels > 0 && bottom_levels > 0) { | 
|  | 502     int skip_levels = std::max(skip_left_levels, skip_bottom_levels); | 
|  | 503     int diagonal_levels = std::min(left_levels, bottom_levels); | 
|  | 504     if (diagonal_levels > skip_levels) { | 
|  | 505       EmplaceAt( | 
|  | 506           GetPositionForDirection(positions, CoverageDirection::BOTTOM_LEFT), | 
|  | 507           TriangularSequence(std::string("bl.seq"), | 
|  | 508                              Interval(Interval::Type::DIAGONAL_BACKWARD, | 
|  | 509                                       around_left, around_left, consider_right, | 
|  | 510                                       consider_left, reverse_order_), | 
|  | 511                              Interval(Interval::Type::FORWARD, around_bottom, | 
|  | 512                                       around_bottom + diagonal_levels - 1, | 
|  | 513                                       consider_top, consider_bottom, false), | 
|  | 514                              false, skip_levels, diagonal_distance, | 
|  | 515                              reverse_order_)); | 
|  | 516     } | 
|  | 517   } | 
|  | 518 | 
|  | 519   // BOTTOM sequence. | 
|  | 520   if (bottom_levels > 0) { | 
|  | 521     int start = around_left + 1; | 
|  | 522     int end = around_right - 1; | 
|  | 523     int skip_levels = | 
|  | 524         std::max(skip_bottom_levels, | 
|  | 525                  std::max(skip_left_levels_perp, skip_right_levels_perp)); | 
|  | 526     if (bottom_levels > skip_levels) { | 
|  | 527       EmplaceAt( | 
|  | 528           GetPositionForDirection(positions, CoverageDirection::BOTTOM), | 
|  | 529           TriangularSequence( | 
|  | 530               std::string("b.seq"), | 
|  | 531               Interval(Interval::Type::FORWARD, start, end, consider_left, | 
|  | 532                        consider_right, reverse_order_), | 
|  | 533               Interval(Interval::Type::FORWARD, around_bottom, consider_bottom, | 
|  | 534                        consider_top, consider_bottom, false), | 
|  | 535               false, skip_levels, height, reverse_order_)); | 
|  | 536     } | 
|  | 537   } | 
|  | 538 | 
|  | 539   // BOTTOM_RIGHT sequence. | 
|  | 540   if (bottom_levels > 0 && right_levels > 0) { | 
|  | 541     int skip_levels = std::max(skip_bottom_levels, skip_right_levels); | 
|  | 542     int diagonal_levels = std::min(bottom_levels, right_levels); | 
|  | 543     if (diagonal_levels > skip_levels) { | 
|  | 544       EmplaceAt( | 
|  | 545           GetPositionForDirection(positions, CoverageDirection::BOTTOM_RIGHT), | 
|  | 546           TriangularSequence(std::string("br.seq"), | 
|  | 547                              Interval(Interval::Type::DIAGONAL_FORWARD, | 
|  | 548                                       around_right, around_right, consider_left, | 
|  | 549                                       consider_right, reverse_order_), | 
|  | 550                              Interval(Interval::Type::FORWARD, around_bottom, | 
|  | 551                                       around_bottom + diagonal_levels - 1, | 
|  | 552                                       consider_top, consider_bottom, false), | 
|  | 553                              false, skip_levels, diagonal_distance, | 
|  | 554                              reverse_order_)); | 
|  | 555     } | 
|  | 556   } | 
|  | 557 | 
|  | 558   current_triangular_sequence_ = GetNextTriangularSequence(); | 
|  | 559   if (current_triangular_sequence_) { | 
|  | 560     if (*current_triangular_sequence_) | 
|  | 561       current_traversal_interval_ = | 
|  | 562           current_triangular_sequence_->traversal_interval(); | 
|  | 563     UpdateCurrent(); | 
|  | 564   } | 
|  | 565 } | 
|  | 566 | 
|  | 567 PyramidSequence::operator bool() const { | 
|  | 568   return current_triangular_sequence_ && !triangular_sequences_.empty(); | 
|  | 569 } | 
|  | 570 | 
|  | 571 PyramidSequence& PyramidSequence::operator++() { | 
|  | 572   Advance(); | 
|  | 573   UpdateCurrent(); | 
|  | 574 | 
|  | 575   return *this; | 
|  | 576 } | 
|  | 577 | 
|  | 578 void PyramidSequence::EmplaceAt(int position, | 
|  | 579                                 TriangularSequence&& triangular_sequence) { | 
|  | 580   TriangularSequence::Iterator it = triangular_sequences_.begin(); | 
|  | 581   std::advance(it, position); | 
|  | 582   triangular_sequences_.emplace(it, std::move(triangular_sequence)); | 
|  | 583   TriangularSequence::Iterator erase_it = triangular_sequences_.begin(); | 
|  | 584   std::advance(erase_it, position + 1); | 
|  | 585   triangular_sequences_.erase(erase_it); | 
|  | 586 } | 
|  | 587 | 
|  | 588 void PyramidSequence::Advance() { | 
|  | 589   if (!*this) | 
|  | 590     return; | 
|  | 591 | 
|  | 592   ++(*current_traversal_interval_); | 
|  | 593   if (!*current_traversal_interval_) { | 
|  | 594     ++(*current_triangular_sequence_); | 
|  | 595     current_triangular_sequence_ = GetNextTriangularSequence(); | 
|  | 596     if (current_triangular_sequence_) { | 
|  | 597       current_traversal_interval_ = | 
|  | 598           current_triangular_sequence_->traversal_interval(); | 
|  | 599     } | 
|  | 600   } | 
|  | 601 } | 
|  | 602 | 
|  | 603 void PyramidSequence::UpdateCurrent() { | 
|  | 604   while (*this) { | 
|  | 605     if (current_traversal_interval_ && (*current_traversal_interval_)) { | 
|  | 606       if (current_triangular_sequence_->is_swapped()) { | 
|  | 607         index_x_ = current_triangular_sequence_->level_index(); | 
|  | 608         index_y_ = current_traversal_interval_->index(); | 
|  | 609       } else { | 
|  | 610         index_x_ = current_traversal_interval_->index(); | 
|  | 611         index_y_ = current_triangular_sequence_->level_index(); | 
|  | 612       } | 
|  | 613 | 
|  | 614       if (InConsiderRect() && !InIgnoreRect()) | 
|  | 615         break; | 
|  | 616     } | 
|  | 617 | 
|  | 618     Advance(); | 
|  | 619   } | 
|  | 620 } | 
|  | 621 | 
|  | 622 void PyramidSequence::RemoveEmptyTriangularSequences() { | 
|  | 623   triangular_sequences_.erase( | 
|  | 624       std::remove_if(triangular_sequences_.begin(), triangular_sequences_.end(), | 
|  | 625                      [](const TriangularSequence& seq) { return !seq; }), | 
|  | 626       triangular_sequences_.end()); | 
|  | 627 } | 
|  | 628 | 
|  | 629 bool PyramidSequence::InConsiderRect() const { | 
|  | 630   return index_x_ >= consider_left_ && index_x_ <= consider_right_ && | 
|  | 631          index_y_ >= consider_top_ && index_y_ <= consider_bottom_; | 
|  | 632 } | 
|  | 633 | 
|  | 634 bool PyramidSequence::InIgnoreRect() const { | 
|  | 635   return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ && | 
|  | 636          index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_; | 
|  | 637 } | 
|  | 638 | 
|  | 639 // TopDownPyramidSequence implementation. | 
|  | 640 TopDownPyramidSequence::TopDownPyramidSequence() : PyramidSequence(false) {} | 
|  | 641 | 
|  | 642 TopDownPyramidSequence::TopDownPyramidSequence( | 
|  | 643     const TopDownPyramidSequence& other) = default; | 
|  | 644 | 
|  | 645 TopDownPyramidSequence::TopDownPyramidSequence(TopDownPyramidSequence&& other) = | 
|  | 646     default; | 
|  | 647 | 
|  | 648 TopDownPyramidSequence::~TopDownPyramidSequence() {} | 
|  | 649 | 
|  | 650 TopDownPyramidSequence& TopDownPyramidSequence::operator=( | 
|  | 651     const TopDownPyramidSequence& other) = default; | 
|  | 652 | 
|  | 653 TopDownPyramidSequence& TopDownPyramidSequence::operator=( | 
|  | 654     TopDownPyramidSequence&& other) = default; | 
|  | 655 | 
|  | 656 TriangularSequence* TopDownPyramidSequence::GetNextTriangularSequence() { | 
|  | 657   RemoveEmptyTriangularSequences(); | 
|  | 658 | 
|  | 659   if (triangular_sequences_.empty()) | 
|  | 660     return nullptr; | 
|  | 661 | 
|  | 662   TriangularSequence::Iterator min_distance_it = triangular_sequences_.begin(); | 
|  | 663 | 
|  | 664   for (TriangularSequence::Iterator it = triangular_sequences_.begin(); | 
|  | 665        it != triangular_sequences_.end(); ++it) { | 
|  | 666     int distance = it->GetMinimumDistance(); | 
|  | 667     if (distance == 0) | 
|  | 668       return &(*it); | 
|  | 669 | 
|  | 670     if (min_distance_it->GetMinimumDistance() > distance) | 
|  | 671       min_distance_it = it; | 
|  | 672   } | 
|  | 673 | 
|  | 674   return &(*min_distance_it); | 
|  | 675 } | 
|  | 676 | 
|  | 677 // BottomUpPyramidSequence implementation. | 
|  | 678 BottomUpPyramidSequence::BottomUpPyramidSequence() : PyramidSequence(true) {} | 
|  | 679 | 
|  | 680 BottomUpPyramidSequence::BottomUpPyramidSequence( | 
|  | 681     const BottomUpPyramidSequence& other) | 
|  | 682     : PyramidSequence(other) {} | 
|  | 683 | 
|  | 684 BottomUpPyramidSequence::BottomUpPyramidSequence( | 
|  | 685     BottomUpPyramidSequence&& other) | 
|  | 686     : PyramidSequence(std::move(other)) {} | 
|  | 687 | 
|  | 688 BottomUpPyramidSequence::~BottomUpPyramidSequence() {} | 
|  | 689 | 
|  | 690 BottomUpPyramidSequence& BottomUpPyramidSequence::operator=( | 
|  | 691     const BottomUpPyramidSequence& other) { | 
|  | 692   PyramidSequence::operator=(other); | 
|  | 693   return *this; | 
|  | 694 } | 
|  | 695 | 
|  | 696 BottomUpPyramidSequence& BottomUpPyramidSequence::operator=( | 
|  | 697     BottomUpPyramidSequence&& other) { | 
|  | 698   PyramidSequence::operator=(std::move(other)); | 
|  | 699   return *this; | 
|  | 700 } | 
|  | 701 | 
|  | 702 TriangularSequence* BottomUpPyramidSequence::GetNextTriangularSequence() { | 
|  | 703   RemoveEmptyTriangularSequences(); | 
|  | 704 | 
|  | 705   if (triangular_sequences_.empty()) | 
|  | 706     return nullptr; | 
|  | 707 | 
|  | 708   TriangularSequence::ReverseIterator max_distance_it = | 
|  | 709       triangular_sequences_.rbegin(); | 
|  | 710 | 
|  | 711   for (TriangularSequence::ReverseIterator it = triangular_sequences_.rbegin(); | 
|  | 712        it != triangular_sequences_.rend(); ++it) { | 
|  | 713     int distance = it->GetMaximumDistance(); | 
|  | 714 | 
|  | 715     if (max_distance_it->GetMaximumDistance() < distance) | 
|  | 716       max_distance_it = it; | 
|  | 717   } | 
|  | 718 | 
|  | 719   return &(*max_distance_it); | 
|  | 720 } | 
|  | 721 | 
|  | 722 }  // namespace cc | 
| OLD | NEW | 
|---|