diff --git a/library/include/BitArray.h b/library/include/BitArray.h index 1469091d1..cfb859bd0 100644 --- a/library/include/BitArray.h +++ b/library/include/BitArray.h @@ -25,12 +25,14 @@ distribution. #pragma once #include "Pragma.h" #include "Export.h" +#include "Error.h" #include #include #include #include #include -//#include +#include +#include namespace DFHack { template @@ -232,4 +234,338 @@ namespace DFHack m_data[idx] = item; } }; + + template + struct DfLinkedList + { + class iterator; + class const_iterator; + + class proxy + { + L *cur; + friend struct DfLinkedList; + friend class iterator; + proxy(L *cur) : cur(cur) + { + CHECK_NULL_POINTER(cur); + } + public: + operator I *const &() const + { + return cur->item; + } + I *operator->() const + { + return cur->item; + } + proxy & operator=(I *const & item) + { + if (item) + { + CHECK_INVALID_ARGUMENT(item->dfhack_get_list_link() == nullptr); + item->dfhack_set_list_link(cur); + } + if (cur->item) + { + cur->item->dfhack_set_list_link(nullptr); + } + cur->item = item; + + return *this; + } + }; + + class iterator + { + L *root; + L *cur; + friend struct DfLinkedList; + friend class const_iterator; + iterator(L *root, L *cur) : root(root), cur(cur) {} + public: + using difference_type = void; + using value_type = I *; + using pointer = I **; + using reference = proxy; + using iterator_category = std::bidirectional_iterator_tag; + + iterator() : root(nullptr), cur(nullptr) {} + iterator(const iterator & other) : root(other.root), cur(other.cur) {} + + iterator & operator++() + { + CHECK_NULL_POINTER(root); + CHECK_NULL_POINTER(cur); + + cur = cur->next; + return *this; + } + iterator & operator--() + { + CHECK_NULL_POINTER(root); + + if (!cur) + { + // find end() - 1 + for (cur = root->next; cur && cur->next; cur = cur->next) + { + } + return *this; + } + + CHECK_NULL_POINTER(cur); + CHECK_NULL_POINTER(cur->prev); + + cur = cur->prev; + return *this; + } + iterator operator++(int) + { + iterator copy(*this); + ++*this; + return copy; + } + iterator operator--(int) + { + iterator copy(*this); + --*this; + return copy; + } + iterator & operator=(const iterator & other) + { + root = other.root; + cur = other.cur; + return *this; + } + + proxy operator*() + { + CHECK_NULL_POINTER(root); + CHECK_NULL_POINTER(cur); + + return proxy(cur); + } + + I *const & operator*() const + { + CHECK_NULL_POINTER(root); + CHECK_NULL_POINTER(cur); + + return cur->item; + } + + operator const_iterator() const + { + return const_iterator(*this); + } + bool operator==(const iterator & other) const + { + return root == other.root && cur == other.cur; + } + bool operator!=(const iterator & other) const + { + return !(*this == other); + } + }; + class const_iterator + { + iterator iter; + friend struct DfLinkedList; + public: + using difference_type = void; + using value_type = I *; + using pointer = I *const *; + using reference = I *const &; + using iterator_category = std::bidirectional_iterator_tag; + + const_iterator(const iterator & iter) : iter(iter) {} + const_iterator(const const_iterator & other) : iter(other.iter) {} + + const_iterator & operator++() + { + ++iter; + return *this; + } + const_iterator & operator--() + { + --iter; + return *this; + } + const_iterator operator++(int) + { + const_iterator copy(*this); + ++iter; + return copy; + } + const_iterator operator--(int) + { + const_iterator copy(*this); + --iter; + return copy; + } + const_iterator & operator=(const const_iterator & other) + { + iter = other.iter; + return *this; + } + I *const & operator*() const + { + return *iter; + } + bool operator==(const const_iterator & other) const + { + return iter == other.iter; + } + bool operator!=(const const_iterator & other) const + { + return iter != other.iter; + } + }; + + using value_type = I *; + using reference_type = proxy; + using difference_type = void; + using size_type = size_t; + + bool empty() const + { + return static_cast(this)->next == nullptr; + } + size_t size() const + { + size_t n = 0; + for (value_type const & i : *this) + n++; + return n; + } + + iterator begin() + { + return iterator(static_cast(this), static_cast(this)->next); + } + const_iterator begin() const + { + return const_iterator(const_cast *>(this)->begin()); + } + const_iterator cbegin() const + { + return begin(); + } + iterator end() + { + return iterator(static_cast(this), nullptr); + } + const_iterator end() const + { + return const_iterator(const_cast *>(this)->end()); + } + const_iterator cend() const + { + return end(); + } + + iterator erase(const_iterator pos) + { + auto root = static_cast(this); + CHECK_INVALID_ARGUMENT(pos.iter.root == root); + CHECK_NULL_POINTER(pos.iter.cur); + + auto link = pos.iter.cur; + auto next = link->next; + + if (link->prev) + { + link->prev->next = link->next; + } + else + { + root->next = link->next; + } + + if (link->next) + { + link->next->prev = link->prev; + } + + proxy p(link); + p = nullptr; + + delete link; + + return iterator(root, next); + } + iterator insert(const_iterator pos, I *const & item) + { + auto root = static_cast(this); + CHECK_INVALID_ARGUMENT(pos.iter.root == root); + + auto link = pos.iter.cur; + if (!link || !link->prev) + { + if (!link && root->next) + { + pos--; + return insert_after(pos, item); + } + + CHECK_INVALID_ARGUMENT(root->next == link); + push_front(item); + return begin(); + } + + auto newlink = new L(); + newlink->prev = link->prev; + newlink->next = link; + link->prev = newlink; + if (newlink->prev) + { + newlink->prev->next = newlink; + } + else if (link == root->next) + { + root->next = newlink; + } + newlink->item = nullptr; + proxy p(newlink); + p = item; + return iterator(root, newlink); + } + iterator insert_after(const_iterator pos, I *const & item) + { + auto root = static_cast(this); + CHECK_INVALID_ARGUMENT(pos.iter.root == root); + CHECK_NULL_POINTER(pos.iter.cur); + + auto link = pos.iter.cur; + auto next = link->next; + auto newlink = new L(); + newlink->prev = link; + newlink->next = next; + link->next = newlink; + if (next) + { + next->prev = newlink; + } + newlink->item = nullptr; + proxy p(newlink); + p= item; + return iterator(root, newlink); + } + void push_front(I *const & item) + { + auto root = static_cast(this); + auto link = new L(); + link->prev = nullptr; + if (root->next) + { + root->next->prev = link; + link->next = root->next; + } + link->item = nullptr; + proxy p(link); + p = item; + root->next = link; + } + }; } diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index 31a949df1..149ac47a0 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -439,6 +439,7 @@ namespace df using DFHack::enum_list_attr; using DFHack::BitArray; using DFHack::DfArray; + using DFHack::DfLinkedList; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" diff --git a/library/xml b/library/xml index f27ebae6a..372993c58 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f27ebae6aa8fb12c46217adec5a812cd49a905c8 +Subproject commit 372993c58851153320f3390119cdd2d97caef9db