#include #include #include template struct Item { using value_type = T; using const_reference = const T&; T value; Item* next = nullptr; Item* emplace(const_reference value) { auto item = new Item{value, next}; next = item; return item; } void visit(std::function visitor) const { visitor(value); if (next != nullptr) { next->visit(visitor); } } Item* tail() { for (auto at = this; at != nullptr; at = at->next) { if (at->next == nullptr) { return at; } } return nullptr; } }; using IntItem = Item; template void dump(const Item* head) { head->visit([](const T& value) { fmt::print(" {}", value); }); fmt::print("\n"); } template std::string to_string(const Item* head) { std::stringstream w; head->visit([&w](const T& value) { w << " " << value; }); return w.str(); } template Item* make_list(std::initializer_list items) { // TODO(michaelh): change to take an initialiser list. auto first = new Item{1}; auto at = first; for (const auto& i : items) { at = at->emplace(i); } return first; } template Item* filter(Item* head, std::function predicate) { // TODO(michaelh): std::function doesn't match. // TODO(michaelh): how can you mark the return as not-null? auto at = &head; for (auto at = &head; *at != nullptr;) { if (predicate((*at)->value)) { *at = (*at)->next; } else { at = &(*at)->next; } } fmt::print("\n"); return head; }