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 pos Position of closest corner to origin
|
||||||
* \param length Side length.
|
* \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;
|
Square(Square const &other) noexcept = default;
|
||||||
@@ -57,9 +57,13 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Results(Results const &other) noexcept = delete;
|
Results(Results const &other) noexcept = delete;
|
||||||
|
|
||||||
Results &operator=(Results const &other) noexcept = delete;
|
Results &operator=(Results const &other) noexcept = delete;
|
||||||
|
|
||||||
Results &operator=(Results &&other) noexcept = default;
|
Results &operator=(Results &&other) noexcept = default;
|
||||||
|
|
||||||
Results(Results &&other) noexcept = default;
|
Results(Results &&other) noexcept = default;
|
||||||
|
|
||||||
~Results() noexcept = default;
|
~Results() noexcept = default;
|
||||||
|
|
||||||
auto length() const noexcept -> size_t { return length_; }
|
auto length() const noexcept -> size_t { return length_; }
|
||||||
@@ -67,7 +71,7 @@ namespace {
|
|||||||
/** Output the grid. */
|
/** Output the grid. */
|
||||||
auto output() const -> void {
|
auto output() const -> void {
|
||||||
std::string out(length_ * length_, '.');
|
std::string out(length_ * length_, '.');
|
||||||
for (auto const& sq : squares_) {
|
for (auto const &sq: squares_) {
|
||||||
prettify_sq(out, sq);
|
prettify_sq(out, sq);
|
||||||
}
|
}
|
||||||
for (size_t idx = 0; idx < length_ * length_; idx += length_) {
|
for (size_t idx = 0; idx < length_ * length_; idx += length_) {
|
||||||
@@ -76,17 +80,17 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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(x < length_);
|
||||||
assert(y < length_);
|
assert(y < length_);
|
||||||
assert(grid_[x + y * length_] != c);
|
assert(grid_[x + y * length_] != c);
|
||||||
s[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_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_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()) {
|
switch (sq.length()) {
|
||||||
case 1: set(s, sq_x(sq), sq_y(sq), '*');
|
case 1: set(s, sq_x(sq), sq_y(sq), '*');
|
||||||
break;
|
break;
|
||||||
@@ -102,7 +106,7 @@ namespace {
|
|||||||
set(s, sq_x(sq), sq_y(sq) + n - 1, '+');
|
set(s, sq_x(sq), sq_y(sq) + n - 1, '+');
|
||||||
set(s, sq_x(sq) + n - 1, 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) {
|
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) + i, sq_y(sq) + n - 1, '-');
|
||||||
set(s, sq_x(sq), sq_y(sq) + i, '|');
|
set(s, sq_x(sq), sq_y(sq) + i, '|');
|
||||||
for (size_t j = 1; j < n - 1; ++j) {
|
for (size_t j = 1; j < n - 1; ++j) {
|
||||||
@@ -144,35 +148,35 @@ namespace {
|
|||||||
~Grid() noexcept = default;
|
~Grid() noexcept = default;
|
||||||
|
|
||||||
/** Get grid length */
|
/** Get grid length */
|
||||||
auto length() const noexcept -> size_t { return length_; }
|
|
||||||
auto end() const noexcept -> size_t { return grid_.size(); }
|
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. */
|
/** Add a square to the grid. */
|
||||||
auto add(Square const &sq) noexcept -> void {
|
auto add(Square const &sq) noexcept -> void {
|
||||||
for (auto i = pos_x(sq.pos()); i < pos_x(sq.pos()) + sq.length(); ++i) {
|
/* One would expect the fastest way to do this would be to have x be the
|
||||||
for (auto j = pos_y(sq.pos()); j < pos_y(sq.pos()) + sq.length(); ++j) {
|
* fastest increasing index so we stores [pos, pos + 1,..., pos+length, ...]
|
||||||
set(i, j, filled);
|
* 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. */
|
/** Clear a square from the grid. */
|
||||||
auto clear(Square const &sq) noexcept -> void {
|
auto clear(Square const &sq) noexcept -> void {
|
||||||
for (auto i = pos_x(sq.pos()); i < pos_x(sq.pos()) + sq.length(); ++i) {
|
for (auto x = 0; x < sq.length(); ++x) {
|
||||||
for (auto j = pos_y(sq.pos()); j < pos_y(sq.pos()) + sq.length(); ++j) {
|
for (auto y = sq.pos(); y < sq.pos() + sq.length() * length_; y += length_) {
|
||||||
set(i, j, empty);
|
grid_[x + y] = empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Get length of the largest square that fits at \a pos in the grid.
|
/** \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 {
|
auto largest_square(Pos pos, size_t n) const noexcept -> size_t {
|
||||||
assert(x(pos) < length_);
|
assert(pos < end());
|
||||||
assert(y(pos) < length_);
|
|
||||||
|
|
||||||
/* Because of how we walk through the grid (starting at 0,0 then increasing
|
/* 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
|
* 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
|
* This means we only need to look for the first non-clear position along the
|
||||||
* current row.
|
* current row.
|
||||||
*/
|
*/
|
||||||
auto const pos_x = pos % length_;
|
auto const pos_x = pos % length_;
|
||||||
auto const pos_y0 = pos - pos_x;
|
auto const pos_y0 = pos - pos_x;
|
||||||
auto b = pos;
|
auto b = pos;
|
||||||
// Make sure we don't go looking in the next row.
|
// Make sure we don't go looking in the next row.
|
||||||
@@ -192,15 +196,16 @@ namespace {
|
|||||||
}
|
}
|
||||||
// Check that this length fits vertically as well.
|
// Check that this length fits vertically as well.
|
||||||
auto const len = b - pos;
|
auto const len = b - pos;
|
||||||
auto const ye = std::min((pos / length_) + len, length_);
|
auto const pos_y = pos / length_;
|
||||||
return ye - pos_y(pos);
|
auto const ye = std::min(pos_y + len, length_);
|
||||||
|
return ye - pos_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the next position to check starting at pos.
|
/** Get the next position to check starting at pos.
|
||||||
*
|
*
|
||||||
* Returns grid_.length() if no more positions avaialble.
|
* 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 b = grid_.begin() + pos;
|
||||||
auto const p = std::find(b, grid_.end(), empty);
|
auto const p = std::find(b, grid_.end(), empty);
|
||||||
return p - grid_.begin();
|
return p - grid_.begin();
|
||||||
@@ -287,7 +292,10 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If there are no squares available of the current size try the next one.
|
// 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
|
/* Place a square of side length idx at pos, push this onto the stack and
|
||||||
* set up to look at the next position.
|
* set up to look at the next position.
|
||||||
|
|||||||
Reference in New Issue
Block a user