mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-05 22:23:29 +00:00
Adds iterators and a check to avoid segfault when removing node in LinkedList.
Bug: dawn:628 Change-Id: I1250ffe303155004572c2476ec357daa78b7bb3b Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/65860 Commit-Queue: Loko Kung <lokokung@google.com> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
34206ec07b
commit
6fd28ba4cb
@ -2,7 +2,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// This file is a copy of Chromium's /src/base/containers/linked_list.h
|
// This file is a copy of Chromium's /src/base/containers/linked_list.h with the following
|
||||||
|
// modifications:
|
||||||
|
// - Added iterators for ranged based iterations
|
||||||
|
// - Added in list check before removing node to prevent segfault, now returns true iff removed
|
||||||
|
|
||||||
#ifndef COMMON_LINKED_LIST_H
|
#ifndef COMMON_LINKED_LIST_H
|
||||||
#define COMMON_LINKED_LIST_H
|
#define COMMON_LINKED_LIST_H
|
||||||
@ -43,6 +46,11 @@
|
|||||||
// ...
|
// ...
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
// for (LinkNode<MyNodeType*> node : list) {
|
||||||
|
// MyNodeType* value = node->value();
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
// Or to iterate the linked list backwards:
|
// Or to iterate the linked list backwards:
|
||||||
//
|
//
|
||||||
// for (LinkNode<MyNodeType>* node = list.tail();
|
// for (LinkNode<MyNodeType>* node = list.tail();
|
||||||
@ -125,14 +133,18 @@ class LinkNode {
|
|||||||
return this->next_ != nullptr;
|
return this->next_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove |this| from the linked list.
|
// Remove |this| from the linked list. Returns true iff removed from a list.
|
||||||
void RemoveFromList() {
|
bool RemoveFromList() {
|
||||||
|
if (!IsInList()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
this->previous_->next_ = this->next_;
|
this->previous_->next_ = this->next_;
|
||||||
this->next_->previous_ = this->previous_;
|
this->next_->previous_ = this->previous_;
|
||||||
// next() and previous() return non-null if and only this node is not in any
|
// next() and previous() return non-null if and only this node is not in any list.
|
||||||
// list.
|
|
||||||
this->next_ = nullptr;
|
this->next_ = nullptr;
|
||||||
this->previous_ = nullptr;
|
this->previous_ = nullptr;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkNode<T>* previous() const {
|
LinkNode<T>* previous() const {
|
||||||
@ -197,4 +209,44 @@ class LinkedList {
|
|||||||
private:
|
private:
|
||||||
LinkNode<T> root_;
|
LinkNode<T> root_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class LinkedListIterator {
|
||||||
|
public:
|
||||||
|
LinkedListIterator(LinkNode<T>* node) : current_(node), next_(node->next()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// We keep an early reference to the next node in the list so that even if the current element
|
||||||
|
// is modified or removed from the list, we have a valid next node.
|
||||||
|
LinkedListIterator<T> const& operator++() {
|
||||||
|
current_ = next_;
|
||||||
|
next_ = current_->next();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const LinkedListIterator<T>& other) const {
|
||||||
|
return current_ != other.current_;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkNode<T>* operator*() const {
|
||||||
|
return current_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LinkNode<T>* current_;
|
||||||
|
LinkNode<T>* next_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
LinkedListIterator<T> begin(LinkedList<T>& l) {
|
||||||
|
return LinkedListIterator<T>(l.head());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free end function does't use LinkedList<T>::end because of it's const nature. Instead we wrap
|
||||||
|
// around from tail.
|
||||||
|
template <typename T>
|
||||||
|
LinkedListIterator<T> end(LinkedList<T>& l) {
|
||||||
|
return LinkedListIterator<T>(l.tail()->next());
|
||||||
|
}
|
||||||
|
|
||||||
#endif // COMMON_LINKED_LIST_H
|
#endif // COMMON_LINKED_LIST_H
|
||||||
|
@ -19,6 +19,10 @@ class Node : public LinkNode<Node> {
|
|||||||
return id_;
|
return id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_id(int id) {
|
||||||
|
id_ = id;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int id_;
|
int id_;
|
||||||
};
|
};
|
||||||
@ -360,6 +364,27 @@ TEST(LinkedList, IsInList) {
|
|||||||
EXPECT_FALSE(n.IsInList());
|
EXPECT_FALSE(n.IsInList());
|
||||||
list.Append(&n);
|
list.Append(&n);
|
||||||
EXPECT_TRUE(n.IsInList());
|
EXPECT_TRUE(n.IsInList());
|
||||||
n.RemoveFromList();
|
EXPECT_TRUE(n.RemoveFromList());
|
||||||
EXPECT_FALSE(n.IsInList());
|
EXPECT_FALSE(n.IsInList());
|
||||||
|
EXPECT_FALSE(n.RemoveFromList());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LinkedList, RangeBasedModify) {
|
||||||
|
LinkedList<Node> list;
|
||||||
|
|
||||||
|
Node n1(1);
|
||||||
|
Node n2(2);
|
||||||
|
list.Append(&n1);
|
||||||
|
list.Append(&n2);
|
||||||
|
|
||||||
|
for (LinkNode<Node>* node : list) {
|
||||||
|
node->value()->set_id(node->value()->id() + 1);
|
||||||
|
}
|
||||||
|
const int expected[] = {2, 3};
|
||||||
|
ExpectListContents(list, 2, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LinkedList, RangeBasedEndIsEnd) {
|
||||||
|
LinkedList<Node> list;
|
||||||
|
EXPECT_EQ(list.end(), *end(list));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user