Make add and clear use indices.

This is the last commit of the workstream and we
have a ~10% speed improvement.
This commit is contained in:
2025-09-04 11:27:49 +02:00
parent f1445b7544
commit ff43ba5287

44
main.cc
View File

@@ -26,7 +26,7 @@ namespace {
* \param pos Position of closest corner to origin
* \param length Side length.
*/
Square(Pos const &pos, size_t const length) noexcept : pos_(pos), length_(length) {
Square(Pos pos, size_t const length) noexcept : pos_(pos), length_(length) {
}
Square(Square const &other) noexcept = default;
@@ -57,9 +57,13 @@ namespace {
}
Results(Results const &other) noexcept = delete;
Results &operator=(Results const &other) noexcept = delete;
Results &operator=(Results &&other) noexcept = default;
Results(Results &&other) noexcept = default;
~Results() noexcept = default;
auto length() const noexcept -> size_t { return length_; }
@@ -144,35 +148,35 @@ namespace {
~Grid() noexcept = default;
/** Get grid length */
auto length() const noexcept -> size_t { return length_; }
auto end() const noexcept -> size_t { return grid_.size(); }
auto pos_x(Pos const& pos) const noexcept -> size_t { return pos % length_; }
auto pos_y(Pos const& pos) const noexcept -> size_t { return pos / length_; }
/** Add a square to the grid. */
auto add(Square const &sq) noexcept -> void {
for (auto i = pos_x(sq.pos()); i < pos_x(sq.pos()) + sq.length(); ++i) {
for (auto j = pos_y(sq.pos()); j < pos_y(sq.pos()) + sq.length(); ++j) {
set(i, j, filled);
/* One would expect the fastest way to do this would be to have x be the
* fastest increasing index so we stores [pos, pos + 1,..., pos+length, ...]
* But experimentation tells us this isn't so, and storing
* [pos, pos + length, ..., pos + 1, ...] is faster!
*/
for (auto x = 0; x < sq.length(); ++x) {
for (auto y = sq.pos(); y < sq.pos() + sq.length() * length_; y += length_) {
grid_[x + y] = filled;
}
}
}
/** Clear a square from the grid. */
auto clear(Square const &sq) noexcept -> void {
for (auto i = pos_x(sq.pos()); i < pos_x(sq.pos()) + sq.length(); ++i) {
for (auto j = pos_y(sq.pos()); j < pos_y(sq.pos()) + sq.length(); ++j) {
set(i, j, empty);
for (auto x = 0; x < sq.length(); ++x) {
for (auto y = sq.pos(); y < sq.pos() + sq.length() * length_; y += length_) {
grid_[x + y] = empty;
}
}
}
/** \brief Get length of the largest square that fits at \a pos in the grid.
*/
auto largest_square(Pos const &pos, size_t n) const noexcept -> size_t {
assert(x(pos) < length_);
assert(y(pos) < length_);
auto largest_square(Pos pos, size_t n) const noexcept -> size_t {
assert(pos < end());
/* Because of how we walk through the grid (starting at 0,0 then increasing
* x followed by y) we can assume that if the position (b, y) is clear
@@ -192,15 +196,16 @@ namespace {
}
// Check that this length fits vertically as well.
auto const len = b - pos;
auto const ye = std::min((pos / length_) + len, length_);
return ye - pos_y(pos);
auto const pos_y = pos / length_;
auto const ye = std::min(pos_y + len, length_);
return ye - pos_y;
}
/** Get the next position to check starting at pos.
*
* Returns grid_.length() if no more positions avaialble.
*/
auto next_pos(Pos const &pos) const noexcept -> Pos {
auto next_pos(Pos pos) const noexcept -> Pos {
auto const b = grid_.begin() + pos;
auto const p = std::find(b, grid_.end(), empty);
return p - grid_.begin();
@@ -287,7 +292,10 @@ namespace {
}
// If there are no squares available of the current size try the next one.
if (avail_sqs[idx] == 0) { --idx; continue; }
if (avail_sqs[idx] == 0) {
--idx;
continue;
}
/* Place a square of side length idx at pos, push this onto the stack and
* set up to look at the next position.