diff --git a/dlx/include/dlx.hpp b/dlx/include/dlx.hpp index 15c81e0..986a3ac 100644 --- a/dlx/include/dlx.hpp +++ b/dlx/include/dlx.hpp @@ -7,30 +7,9 @@ namespace dlx { +struct Cell; + class Dlx final { - - struct Cell { - Cell *U, *D, *L, *R; - std::size_t n; - union { - Cell* c; - std::size_t s; - }; - - auto LR_self() -> void; - auto UD_self() -> void; - auto LR_delete() -> void; - auto UD_delete() -> void; - auto UD_restore() -> void; - auto LR_restore() -> void; - auto LR_insert(Cell* k) -> void; - auto UD_insert(Cell* k) -> void; - auto CoverCol() -> void; - auto UncoverCol() -> void; - auto ColAdd(std::size_t row_id) -> Cell*; - static Cell* ColNew(); - }; - std::vector ctab_; std::vector rtab_; Cell* root_; diff --git a/dlx/src/dlx.cpp b/dlx/src/dlx.cpp index a764eda..f93fe10 100644 --- a/dlx/src/dlx.cpp +++ b/dlx/src/dlx.cpp @@ -6,16 +6,76 @@ namespace dlx { -auto Dlx::Cell::LR_self() -> void { L = R = this; } -auto Dlx::Cell::UD_self() -> void { U = D = this; } -auto Dlx::Cell::LR_delete() -> void { L->R = R; R->L = L; } -auto Dlx::Cell::UD_delete() -> void { U->D = D; D->U = U; } -auto Dlx::Cell::UD_restore() -> void { U->D = D->U = this; } -auto Dlx::Cell::LR_restore() -> void { L->R = R->L = this; } -auto Dlx::Cell::LR_insert(Cell* k) -> void { L = k->L; R = k; k->L = k->L->R = this; } -auto Dlx::Cell::UD_insert(Cell* k) -> void { U = k->U, D = k, k->U = k->U->D = this; } +template struct CellView; -auto Dlx::Cell::ColNew() -> Dlx::Cell* +struct Cell { + Cell *U, *D, *L, *R; + std::size_t n; + union { + Cell* c; + std::size_t s; + }; + + auto LR_self() -> void; + auto UD_self() -> void; + + auto LR_delete() -> void; + auto UD_delete() -> void; + + auto UD_restore() -> void; + auto LR_restore() -> void; + + auto LR_insert(Cell* k) -> void; + auto UD_insert(Cell* k) -> void; + + auto CoverCol() -> void; + auto UncoverCol() -> void; + + auto rightwards() -> CellView<&Cell::R>; + auto leftwards() -> CellView<&Cell::L>; + auto upwards() -> CellView<&Cell::U>; + auto downwards() -> CellView<&Cell::D>; + + auto ColAdd(std::size_t row_id) -> Cell*; + static Cell* ColNew(); +}; + +template +struct CellView { + Cell* cell; + + auto operator==(CellView const&) const -> bool = default; + auto begin() const -> CellView; + auto end() const -> CellView; + auto operator*() -> Cell*; + auto operator++() -> CellView&; +}; + +template +auto CellView::begin() const -> CellView { return {cell->*direction}; } + +template +auto CellView::end() const -> CellView { return {cell}; } + +template +auto CellView::operator*() -> Cell* { return cell; } + +template +auto CellView::operator++() -> CellView& { + cell = cell->*direction; + return *this; +} + +auto Cell::LR_self() -> void { L = R = this; } +auto Cell::UD_self() -> void { U = D = this; } +auto Cell::LR_delete() -> void { L->R = R; R->L = L; } +auto Cell::UD_delete() -> void { U->D = D; D->U = U; } +auto Cell::UD_restore() -> void { U->D = D->U = this; } +auto Cell::LR_restore() -> void { L->R = R->L = this; } +auto Cell::LR_insert(Cell* k) -> void { L = k->L; R = k; k->L = k->L->R = this; } +auto Cell::UD_insert(Cell* k) -> void { U = k->U, D = k, k->U = k->U->D = this; } + +auto Cell::ColNew() -> Cell* { auto c = new Cell; c->UD_self(); @@ -23,7 +83,7 @@ auto Dlx::Cell::ColNew() -> Dlx::Cell* return c; } -auto Dlx::Cell::ColAdd(std::size_t row_id) -> Cell* +auto Cell::ColAdd(std::size_t row_id) -> Cell* { auto n = new Cell; n->n = row_id; @@ -33,19 +93,19 @@ auto Dlx::Cell::ColAdd(std::size_t row_id) -> Cell* return n; } -auto Dlx::Cell::CoverCol() -> void { +auto Cell::CoverCol() -> void { LR_delete(); - for (auto i = D; i != this; i = i->D) { - for (auto j = i->R; j != i; j = j->R) { + for (auto const i : downwards()) { + for (auto const j : i->rightwards()) { j->UD_delete(); j->c->s--; } } } -auto Dlx::Cell::UncoverCol() -> void { - for (auto i = U; i != this; i = i->U) { - for (auto j = i->L; j != i; j = j->L) { +auto Cell::UncoverCol() -> void { + for (auto const i : upwards()) { + for (auto const j : i->leftwards()) { j->c->s++; j->UD_restore(); } @@ -53,7 +113,10 @@ auto Dlx::Cell::UncoverCol() -> void { LR_restore(); } - +auto Cell::rightwards() -> CellView<&Cell::R> { return CellView<&Cell::R>{this}; } +auto Cell::leftwards() -> CellView<&Cell::L> { return CellView<&Cell::L>{this}; } +auto Cell::upwards() -> CellView<&Cell::U> { return CellView<&Cell::U>{this}; } +auto Cell::downwards() -> CellView<&Cell::D> { return CellView<&Cell::D>{this}; } Dlx::Dlx() { root_ = Cell::ColNew(); @@ -63,16 +126,18 @@ Dlx::Dlx() { Dlx::~Dlx() { for (auto const row : rtab_) { if (row) { - Cell* next; - for (auto cursor = row->R; cursor != row; cursor = next) { - next = cursor->R; - delete cursor; + auto cursor = row->R; + // manual iteration because we have to save next _before_ deleting cursor + while (cursor != row) { + auto tmp = cursor; + cursor = cursor->R; + delete tmp; } delete row; } } for (auto const col : ctab_) { - if (col) { delete col; } + delete col; } delete root_; } @@ -118,13 +183,12 @@ auto Dlx::MarkOptional(std::size_t col) -> void { c->LR_self(); } - auto Dlx::Set(std::size_t row, std::size_t col) -> void { AllocRow(row); AllocCol(col); - auto c = ctab_[col]; + auto c = ctab_[col]; auto & r = rtab_[row]; - + if (!r) { r = c->ColAdd(row); r->LR_self(); @@ -134,7 +198,7 @@ auto Dlx::Set(std::size_t row, std::size_t col) -> void { // Ignore duplicates. if (r->c->n == col) return; - for (auto cursor = r->R; cursor != r; cursor = cursor->R) { + for (auto const cursor : r->rightwards()) { if (cursor->c->n == col) return; } @@ -145,7 +209,7 @@ auto Dlx::Set(std::size_t row, std::size_t col) -> void { auto Dlx::PickRow(std::size_t i) -> void { if (auto r = rtab_.at(i)) { r->c->CoverCol(); - for (auto j = r->R; j != r; j = j->R) { + for (auto const j : r->rightwards()) { j->c->CoverCol(); } } @@ -155,7 +219,7 @@ auto Dlx::RemoveRow(std::size_t i) -> void { if (auto & r = rtab_.at(i)) { r->UD_delete(); r->c->s--; - for (auto j = r->R; j != r; j = j->R) { + for (auto const j : r->rightwards()) { j->UD_delete(); j->c->s--; } @@ -177,10 +241,10 @@ auto Dlx::Solve( } auto s = std::numeric_limits::max(); - for (auto i = root_->R; i != root_; i = i->R) { + for (auto const i : root_->rightwards()) { if (i->s < s) { s = (c = i)->s; - + if (s == 0) { stuck_cb(c->n); return; @@ -189,14 +253,14 @@ auto Dlx::Solve( } c->CoverCol(); - for (auto r = c->D; r != c; r = r->D) { + for (auto const r : c->downwards()) { try_cb(c->n, s, r->n); - for (auto j = r->R; j != r; j = j->R) { + for (auto const j : r->rightwards()) { j->c->CoverCol(); } self(self); undo_cb(); - for (auto j = r->L; j != r; j=j->L) { + for (auto const j : r->leftwards()) { j->c->UncoverCol(); } }