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:
58
main.cc
58
main.cc
@@ -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_; }
|
||||
@@ -67,7 +71,7 @@ namespace {
|
||||
/** Output the grid. */
|
||||
auto output() const -> void {
|
||||
std::string out(length_ * length_, '.');
|
||||
for (auto const& sq : squares_) {
|
||||
for (auto const &sq: squares_) {
|
||||
prettify_sq(out, sq);
|
||||
}
|
||||
for (size_t idx = 0; idx < length_ * length_; idx += length_) {
|
||||
@@ -76,17 +80,17 @@ namespace {
|
||||
}
|
||||
|
||||
private:
|
||||
auto set(std::string& s, size_t x, size_t y, char c) const noexcept -> void {
|
||||
auto set(std::string &s, size_t x, size_t y, char c) const noexcept -> void {
|
||||
assert(x < length_);
|
||||
assert(y < length_);
|
||||
assert(grid_[x + y * length_] != c);
|
||||
s[x + y * length_] = c;
|
||||
}
|
||||
|
||||
auto sq_x(Square const& sq) const noexcept -> size_t { return sq.pos() % length_; }
|
||||
auto sq_y(Square const& sq) const noexcept -> size_t { return sq.pos() / length_; }
|
||||
auto sq_x(Square const &sq) const noexcept -> size_t { return sq.pos() % length_; }
|
||||
auto sq_y(Square const &sq) const noexcept -> size_t { return sq.pos() / length_; }
|
||||
|
||||
auto prettify_sq(std::string& s, Square const &sq) const noexcept -> void {
|
||||
auto prettify_sq(std::string &s, Square const &sq) const noexcept -> void {
|
||||
switch (sq.length()) {
|
||||
case 1: set(s, sq_x(sq), sq_y(sq), '*');
|
||||
break;
|
||||
@@ -102,7 +106,7 @@ namespace {
|
||||
set(s, sq_x(sq), sq_y(sq) + n - 1, '+');
|
||||
set(s, sq_x(sq) + n - 1, sq_y(sq) + n - 1, '+');
|
||||
for (size_t i = 1; i < n - 1; ++i) {
|
||||
set(s, sq_x(sq) + i,sq_y(sq), '-');
|
||||
set(s, sq_x(sq) + i, sq_y(sq), '-');
|
||||
set(s, sq_x(sq) + i, sq_y(sq) + n - 1, '-');
|
||||
set(s, sq_x(sq), sq_y(sq) + i, '|');
|
||||
for (size_t j = 1; j < n - 1; ++j) {
|
||||
@@ -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
|
||||
@@ -181,7 +185,7 @@ namespace {
|
||||
* This means we only need to look for the first non-clear position along the
|
||||
* current row.
|
||||
*/
|
||||
auto const pos_x = pos % length_;
|
||||
auto const pos_x = pos % length_;
|
||||
auto const pos_y0 = pos - pos_x;
|
||||
auto b = pos;
|
||||
// Make sure we don't go looking in the next row.
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user