dlx iterators

This commit is contained in:
Eric Mertens 2022-11-21 14:14:20 -08:00
parent 43cf5942bc
commit b053686349
2 changed files with 46 additions and 54 deletions

View File

@ -6,14 +6,16 @@
namespace dlx { namespace dlx {
template <Cell* Cell::* direction> struct CellView; template <Cell* Cell::* direction> struct CellView;
template <Cell* Cell::* direction> struct CellIterator;
struct Cell { struct Cell {
Cell *U, *D, *L, *R; Cell *U, *D, *L, *R;
std::size_t n; std::size_t n;
union { union {
Cell* c; Cell* c; // pointer to column cell belongs to
std::size_t s; std::size_t s; // number of elements in column
}; };
auto LR_self() -> void; auto LR_self() -> void;
@ -28,44 +30,34 @@ struct Cell {
auto LR_insert(Cell* k) -> void; auto LR_insert(Cell* k) -> void;
auto UD_insert(Cell* k) -> void; auto UD_insert(Cell* k) -> void;
auto CoverCol() -> void; auto CoverCol() -> void;
auto UncoverCol() -> void; auto UncoverCol() -> void;
auto rightwards() -> CellView<&Cell::R>; auto rightwards() -> CellView<&Cell::R>;
auto leftwards() -> CellView<&Cell::L>; auto leftwards() -> CellView<&Cell::L>;
auto upwards() -> CellView<&Cell::U>; auto upwards() -> CellView<&Cell::U>;
auto downwards() -> CellView<&Cell::D>; auto downwards() -> CellView<&Cell::D>;
static auto ColNew() -> Cell*;
auto ColAdd(std::size_t row_id) -> Cell*; auto ColAdd(std::size_t row_id) -> Cell*;
static Cell* ColNew(); };
template <Cell* Cell::* direction>
struct CellIterator {
Cell* cell;
auto operator==(CellIterator const&) const -> bool = default;
auto operator* () const -> Cell& { return *cell; }
auto operator->() const -> Cell* { return cell; }
auto operator++() -> CellIterator& { cell = cell->*direction; return *this; }
}; };
template <Cell* Cell::* direction> template <Cell* Cell::* direction>
struct CellView { struct CellView {
Cell* cell; Cell* cell;
auto begin() const -> CellIterator<direction> { return CellIterator<direction>{cell->*direction}; }
auto operator==(CellView const&) const -> bool = default; auto end() const -> CellIterator<direction> { return CellIterator<direction>{cell}; };
auto begin() const -> CellView;
auto end() const -> CellView;
auto operator*() -> Cell*;
auto operator++() -> CellView&;
}; };
template <Cell* Cell::* direction>
auto CellView<direction>::begin() const -> CellView { return {cell->*direction}; }
template <Cell* Cell::* direction>
auto CellView<direction>::end() const -> CellView { return {cell}; }
template <Cell* Cell::* direction>
auto CellView<direction>::operator*() -> Cell* { return cell; }
template <Cell* Cell::* direction>
auto CellView<direction>::operator++() -> CellView& {
cell = cell->*direction;
return *this;
}
auto Cell::LR_self() -> void { L = R = this; } auto Cell::LR_self() -> void { L = R = this; }
auto Cell::UD_self() -> void { U = D = this; } auto Cell::UD_self() -> void { U = D = this; }
auto Cell::LR_delete() -> void { L->R = R; R->L = L; } auto Cell::LR_delete() -> void { L->R = R; R->L = L; }
@ -95,19 +87,19 @@ auto Cell::ColAdd(std::size_t row_id) -> Cell*
auto Cell::CoverCol() -> void { auto Cell::CoverCol() -> void {
LR_delete(); LR_delete();
for (auto const i : downwards()) { for (auto & i : downwards()) {
for (auto const j : i->rightwards()) { for (auto & j : i.rightwards()) {
j->UD_delete(); j.UD_delete();
j->c->s--; j.c->s--;
} }
} }
} }
auto Cell::UncoverCol() -> void { auto Cell::UncoverCol() -> void {
for (auto const i : upwards()) { for (auto & i : upwards()) {
for (auto const j : i->leftwards()) { for (auto & j : i.leftwards()) {
j->c->s++; j.c->s++;
j->UD_restore(); j.UD_restore();
} }
} }
LR_restore(); LR_restore();
@ -198,8 +190,8 @@ auto Dlx::Set(std::size_t row, std::size_t col) -> void {
// Ignore duplicates. // Ignore duplicates.
if (r->c->n == col) return; if (r->c->n == col) return;
for (auto const cursor : r->rightwards()) { for (auto const& cursor : r->rightwards()) {
if (cursor->c->n == col) return; if (cursor.c->n == col) return;
} }
// Otherwise insert at end of LR list. // Otherwise insert at end of LR list.
@ -209,8 +201,8 @@ auto Dlx::Set(std::size_t row, std::size_t col) -> void {
auto Dlx::PickRow(std::size_t i) -> void { auto Dlx::PickRow(std::size_t i) -> void {
if (auto r = rtab_.at(i)) { if (auto r = rtab_.at(i)) {
r->c->CoverCol(); r->c->CoverCol();
for (auto const j : r->rightwards()) { for (auto & j : r->rightwards()) {
j->c->CoverCol(); j.c->CoverCol();
} }
} }
} }
@ -219,9 +211,9 @@ auto Dlx::RemoveRow(std::size_t i) -> void {
if (auto & r = rtab_.at(i)) { if (auto & r = rtab_.at(i)) {
r->UD_delete(); r->UD_delete();
r->c->s--; r->c->s--;
for (auto const j : r->rightwards()) { for (auto & j : r->rightwards()) {
j->UD_delete(); j.UD_delete();
j->c->s--; j.c->s--;
} }
r = nullptr; r = nullptr;
} }
@ -240,9 +232,9 @@ auto Dlx::Solve(
} }
auto s = c->s; auto s = c->s;
for (auto const i : root_->rightwards()) { for (auto & i : root_->rightwards()) {
if (i->s < s) { if (i.s < s) {
s = (c = i)->s; s = (c = &i)->s;
} }
} }
@ -251,15 +243,15 @@ auto Dlx::Solve(
} }
c->CoverCol(); c->CoverCol();
for (auto const r : c->downwards()) { for (auto & r : c->downwards()) {
if (try_cb(c->n, s, r->n)) [[unlikely]] return true; if (try_cb(c->n, s, r.n)) [[unlikely]] return true;
for (auto const j : r->rightwards()) { for (auto & j : r.rightwards()) {
j->c->CoverCol(); j.c->CoverCol();
} }
if (self(self)) [[unlikely]] return true; if (self(self)) [[unlikely]] return true;
if (undo_cb()) [[unlikely]] return true; if (undo_cb()) [[unlikely]] return true;
for (auto const j : r->leftwards()) { for (auto & j : r.leftwards()) {
j->c->UncoverCol(); j.c->UncoverCol();
} }
} }
c->UncoverCol(); c->UncoverCol();