diff --git a/src/util/dlist.h b/src/util/dlist.h index 7efe5bb53..e8be4cda5 100644 --- a/src/util/dlist.h +++ b/src/util/dlist.h @@ -17,9 +17,11 @@ Revision History: --*/ #pragma once +#include +template class dll_iterator; -template +template class dll_base { T* m_next { nullptr }; T* m_prev { nullptr }; @@ -27,6 +29,8 @@ public: T* prev() { return m_prev; } T* next() { return m_next; } + T const* prev() const { return m_prev; } + T const* next() const { return m_next; } void init(T* t) { m_next = t; @@ -105,11 +109,10 @@ public: return true; } - - static bool contains(T* list, T* elem) { + static bool contains(T const* list, T const* elem) { if (!list) return false; - T* first = list; + T const* first = list; do { if (list == elem) return true; @@ -120,5 +123,59 @@ public: } }; +template +class dll_iterator { + T const* m_elem; + bool m_first; + dll_iterator(T const* elem, bool first): m_elem(elem), m_first(first) { } +public: + static dll_iterator mk_begin(T const* elem) { + // Setting first==(bool)elem makes this also work for elem==nullptr; + // but we can't implement top-level begin/end for pointers because it clashes with the definition for arrays. + return {elem, (bool)elem}; + } + + static dll_iterator mk_end(T const* elem) { + return {elem, false}; + } + + // using value_type = T; + // using pointer = T const*; + // using reference = T const&; + // using iterator_category = std::input_iterator_tag; + + dll_iterator& operator++() { + m_elem = m_elem->next(); + m_first = false; + return *this; + } + + T const& operator*() const { + return *m_elem; + } + + bool operator==(dll_iterator const& other) const { + return m_elem == other.m_elem && m_first == other.m_first; + } + + bool operator!=(dll_iterator const& other) const { + return !operator==(other); + } +}; + +template < typename T + , typename U = std::enable_if_t, T>> // should only match if T actually inherits from dll_base + > +dll_iterator begin(T const& elem) { + return dll_iterator::mk_begin(&elem); +} + +template < typename T + , typename U = std::enable_if_t, T>> // should only match if T actually inherits from dll_base + > +dll_iterator end(T const& elem) +{ + return dll_iterator::mk_end(&elem); +}