intrusive_list: Interface changes

- Remove the root pointer from iterators.

This is unnecessary, since the only way to get a valid iterator is
either from a node itself (it transiently becomes an iterator via the
underlying interface), or through the iterator interface for the list.
This should also result in better code generation, as each increment or
decrement of an iterator is now branchless.

- Remove iterator_to

This is actually a pretty dangerous function, since it would immediately
create an iterator into the list using the given item, even if it's not
actually part of the list. This was only left around due to lack of
type handling around constructors.

- Add other overloads for erase() and remove()

Now handles iterators, pointers, and references.
This commit is contained in:
Lioncash 2016-08-26 15:38:59 -04:00 committed by MerryMage
parent d164184b1e
commit f2bf795876
2 changed files with 107 additions and 44 deletions

View file

@ -42,7 +42,7 @@ static Xbyak::Address MJitStateCpsr() {
} }
static void EraseInstruction(IR::Block& block, IR::Inst* inst) { static void EraseInstruction(IR::Block& block, IR::Inst* inst) {
block.Instructions().erase(block.Instructions().iterator_to(*inst)); block.Instructions().erase(inst);
} }
EmitX64::BlockDescriptor EmitX64::Emit(IR::Block& block) { EmitX64::BlockDescriptor EmitX64::Emit(IR::Block& block) {

View file

@ -22,21 +22,33 @@ template <typename T> class IntrusiveListIterator;
template <typename T> template <typename T>
class IntrusiveListNode { class IntrusiveListNode {
public: public:
void UnlinkFromList() { bool IsSentinel() const {
prev->next = next; return is_sentinel;
next->prev = prev;
#if !defined(NDEBUG)
next = prev = nullptr;
#endif
} }
private: protected:
IntrusiveListNode* next = nullptr;
IntrusiveListNode* prev = nullptr;
bool is_sentinel = false;
friend class IntrusiveList<T>; friend class IntrusiveList<T>;
friend class IntrusiveListIterator<T>; friend class IntrusiveListIterator<T>;
friend class IntrusiveListIterator<const T>; friend class IntrusiveListIterator<const T>;
};
IntrusiveListNode* next = this; template <typename T>
IntrusiveListNode* prev = this; class IntrusiveListSentinel final : public IntrusiveListNode<T>
{
using IntrusiveListNode<T>::next;
using IntrusiveListNode<T>::prev;
using IntrusiveListNode<T>::is_sentinel;
public:
IntrusiveListSentinel() {
next = this;
prev = this;
is_sentinel = true;
}
}; };
template <typename T> template <typename T>
@ -61,15 +73,19 @@ public:
IntrusiveListIterator(const IntrusiveListIterator& other) = default; IntrusiveListIterator(const IntrusiveListIterator& other) = default;
IntrusiveListIterator& operator=(const IntrusiveListIterator& other) = default; IntrusiveListIterator& operator=(const IntrusiveListIterator& other) = default;
IntrusiveListIterator(node_pointer list_root, node_pointer node) : root(list_root), node(node) { explicit IntrusiveListIterator(node_pointer list_node) : node(list_node) {
}
explicit IntrusiveListIterator(pointer data) : node(data) {
}
explicit IntrusiveListIterator(reference data) : node(&data) {
} }
IntrusiveListIterator& operator++() { IntrusiveListIterator& operator++() {
node = node == root ? node : node->next; node = node->next;
return *this; return *this;
} }
IntrusiveListIterator& operator--() { IntrusiveListIterator& operator--() {
node = node->prev == root ? node : node->prev; node = node->prev;
return *this; return *this;
} }
IntrusiveListIterator operator++(int) { IntrusiveListIterator operator++(int) {
@ -84,19 +100,17 @@ public:
} }
bool operator==(const IntrusiveListIterator& other) const { bool operator==(const IntrusiveListIterator& other) const {
DEBUG_ASSERT(root == other.root);
return node == other.node; return node == other.node;
} }
bool operator!=(const IntrusiveListIterator& other) const { bool operator!=(const IntrusiveListIterator& other) const {
return !(*this == other); return !operator==(other);
} }
reference operator*() const { reference operator*() const {
DEBUG_ASSERT(node != root); DEBUG_ASSERT(!node->IsSentinel());
return static_cast<T&>(*node); return static_cast<reference>(*node);
} }
pointer operator->() const { pointer operator->() const {
DEBUG_ASSERT(node != root);
return std::addressof(operator*()); return std::addressof(operator*());
} }
@ -106,7 +120,6 @@ public:
private: private:
friend class IntrusiveList<T>; friend class IntrusiveList<T>;
node_pointer root = nullptr;
node_pointer node = nullptr; node_pointer node = nullptr;
}; };
@ -150,7 +163,7 @@ public:
existing_node->prev->next = new_node; existing_node->prev->next = new_node;
existing_node->prev = new_node; existing_node->prev = new_node;
return iterator(root.get(), new_node); return iterator(new_node);
} }
/** /**
@ -201,11 +214,47 @@ public:
} }
/** /**
* Removes node from list * Removes a node from this list
* @param node Node to remove from list. * @param node An iterator that points to the node to remove from list.
*/ */
void remove(reference node) { pointer remove(iterator& it) {
node.UnlinkFromList(); DEBUG_ASSERT(it != end());
pointer node = &*it++;
node->prev->next = node->next;
node->next->prev = node->prev;
#if !defined(NDEBUG)
node->next = nullptr;
node->prev = nullptr;
#endif
return node;
}
/**
* Removes a node from this list
* @param node A constant iterator that points to the node to remove from list.
*/
pointer remove(const iterator& it) {
iterator copy = it;
return remove(it);
}
/**
* Removes a node from this list.
* @param node A pointer to the node to remove.
*/
pointer remove(pointer node) {
return remove(iterator(node));
}
/**
* Removes a node from this list.
* @param node A reference to the node to remove.
*/
pointer remove(reference node) {
return remove(iterator(node));
} }
/** /**
@ -261,12 +310,12 @@ public:
} }
// Iterator interface // Iterator interface
iterator begin() { return iterator(root.get(), root->next); } iterator begin() { return iterator(root->next); }
const_iterator begin() const { return const_iterator(root.get(), root->next); } const_iterator begin() const { return const_iterator(root->next); }
const_iterator cbegin() const { return begin(); } const_iterator cbegin() const { return begin(); }
iterator end() { return iterator(root.get(), root.get()); } iterator end() { return iterator(root.get()); }
const_iterator end() const { return const_iterator(root.get(), root.get()); } const_iterator end() const { return const_iterator(root.get()); }
const_iterator cend() const { return end(); } const_iterator cend() const { return end(); }
reverse_iterator rbegin() { return reverse_iterator(end()); } reverse_iterator rbegin() { return reverse_iterator(end()); }
@ -277,17 +326,31 @@ public:
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
const_reverse_iterator crend() const { return rend(); } const_reverse_iterator crend() const { return rend(); }
iterator iterator_to(reference item) { return iterator(root.get(), &item); } /**
const_iterator iterator_to(reference item) const { return const_iterator(root.get(), &item); } * Erases a node from the list, indicated by an iterator.
* @param it The iterator that points to the node to erase.
*/
iterator erase(iterator it) { iterator erase(iterator it) {
DEBUG_ASSERT(it.root == root.get() && it.node != it.root); remove(it);
IntrusiveListNode<T>* to_remove = it.node;
++it;
to_remove->UnlinkFromList();
return it; return it;
} }
/**
* Erases a node from this list.
* @param node A pointer to the node to erase from this list.
*/
iterator erase(pointer node) {
return erase(iterator(node));
}
/**
* Erases a node from this list.
* @param node A reference to the node to erase from this list.
*/
iterator erase(reference node) {
return erase(iterator(node));
}
/** /**
* Exchanges contents of this list with another list instance. * Exchanges contents of this list with another list instance.
* @param other The other list to swap with. * @param other The other list to swap with.
@ -297,7 +360,7 @@ public:
} }
private: private:
std::shared_ptr<IntrusiveListNode<T>> root = std::make_shared<IntrusiveListNode<T>>(); std::shared_ptr<IntrusiveListNode<T>> root = std::make_shared<IntrusiveListSentinel<T>>();
}; };
/** /**