summaryrefslogtreecommitdiff
path: root/lib/nes/common
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nes/common')
-rw-r--r--lib/nes/common/CMakeLists.txt1
-rw-r--r--lib/nes/common/list.hh130
2 files changed, 131 insertions, 0 deletions
diff --git a/lib/nes/common/CMakeLists.txt b/lib/nes/common/CMakeLists.txt
index 69ae435..553d468 100644
--- a/lib/nes/common/CMakeLists.txt
+++ b/lib/nes/common/CMakeLists.txt
@@ -3,4 +3,5 @@ target_sources(
PRIVATE
debug.hh
rgb.hh
+ list.hh
display.hh) \ No newline at end of file
diff --git a/lib/nes/common/list.hh b/lib/nes/common/list.hh
new file mode 100644
index 0000000..5f0d258
--- /dev/null
+++ b/lib/nes/common/list.hh
@@ -0,0 +1,130 @@
+#pragma once
+
+namespace nes
+{
+ /// An intrusive doubly-linked list.
+ template<typename T>
+ class list
+ {
+ public:
+ /// Base class of nodes in the list.
+ class node
+ {
+ friend list;
+
+ list* list_{ nullptr };
+ T* prev_{ nullptr };
+ T* next_{ nullptr };
+
+ public:
+ virtual ~node() = default;
+
+ node(node const&) = delete;
+ node(node&&) = delete;
+ auto operator=(node const&) -> node& = delete;
+ auto operator=(node&&) -> node& = delete;
+
+ protected:
+ explicit node() = default;
+ };
+
+ /// An iterator for the linked list.
+ class iterator
+ {
+ friend list;
+
+ T* current_{ nullptr };
+
+ public:
+ auto operator==(iterator const& other) -> bool { return current_ == other.current_; }
+ auto operator!=(iterator const& other) -> bool { return current_ != other.current_; }
+
+ auto operator*() -> T* { return current_; }
+
+ auto operator++() -> iterator&
+ {
+ if (current_)
+ {
+ node& current_node = *current_;
+ current_ = current_node.next_;
+ }
+ return *this;
+ }
+
+ auto operator++(int) -> iterator
+ {
+ auto res = *this;
+ ++*this;
+ return res;
+ }
+
+ private:
+ explicit iterator() = default;
+ explicit iterator(T* current)
+ : current_{ current }
+ {
+ }
+ };
+
+ private:
+ T* head_{ nullptr };
+ T* tail_{ nullptr };
+
+ public:
+ explicit list() = default;
+
+ ~list()
+ {
+ while (begin() != end()) { remove(begin()); }
+ }
+
+ list(list const&) = delete;
+ list(list&&) = delete;
+ auto operator=(list const&) -> list& = delete;
+ auto operator=(list&&) -> list& = delete;
+
+ auto begin() const -> iterator { return iterator{ head_ }; }
+ auto end() const -> iterator { return iterator{}; }
+
+ /// Add an item to the end of the list, removing it from any other list it may be in.
+ auto append(T& item) -> void
+ {
+ node& item_node = item;
+ if (item_node.list_) { item_node.list_->remove(item); }
+
+ item_node.list_ = this;
+ if (tail_)
+ {
+ item_node.prev_ = tail_;
+ tail_->next_ = &item;
+ }
+ else
+ {
+ head_ = &item;
+ }
+ tail_ = &item;
+ }
+
+ /// Remove an item from the list.
+ auto remove(T& item) -> void
+ {
+ node& item_node = item;
+ if (!item_node.list_) { return; }
+
+ if (head_ == &item) { head_ = item_node.next_; }
+ if (tail_ == &item) { tail_ = item_node.prev_; }
+ if (item_node.prev_) { item_node.prev_->next_ = item_node.next_; }
+ if (item_node.next_) { item_node.next_->prev_ = item_node.prev_; }
+
+ item_node.next_ = nullptr;
+ item_node.prev_ = nullptr;
+ item_node.list_ = nullptr;
+ }
+
+ /// Remove an item from the list by its iterator.
+ auto remove(iterator it) -> void
+ {
+ if (it != end()) { remove(**it); }
+ }
+ };
+} // namespace nes \ No newline at end of file