mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-25 22:30:49 +08:00
Provide a way to iterate over a const AnnotationList
This CL implements a const iterator to allow for iteration over a const AnnotationList. This way, the annotation list can passed as a const reference in search only situations. Change-Id: I53bd7871f3d914e7e7e627b6b464aa7fa79597f4 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4984053 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Andre Kempe <andre.kempe@arm.com>
This commit is contained in:
parent
c5e2b0313c
commit
c39206f699
@ -246,6 +246,14 @@ class Annotation {
|
||||
|
||||
std::atomic<Annotation*>& link_node() { return link_node_; }
|
||||
|
||||
Annotation* GetLinkNode(std::memory_order order = std::memory_order_seq_cst) {
|
||||
return link_node_.load(order);
|
||||
}
|
||||
const Annotation* GetLinkNode(
|
||||
std::memory_order order = std::memory_order_seq_cst) const {
|
||||
return link_node_.load(order);
|
||||
}
|
||||
|
||||
private:
|
||||
//! \brief Linked list next-node pointer. Accessed only by \sa AnnotationList.
|
||||
//!
|
||||
|
@ -77,7 +77,7 @@ Annotation* AnnotationList::Iterator::operator*() const {
|
||||
|
||||
AnnotationList::Iterator& AnnotationList::Iterator::operator++() {
|
||||
CHECK_NE(curr_, tail_);
|
||||
curr_ = curr_->link_node();
|
||||
curr_ = curr_->GetLinkNode();
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -86,12 +86,42 @@ bool AnnotationList::Iterator::operator==(
|
||||
return curr_ == other.curr_;
|
||||
}
|
||||
|
||||
AnnotationList::ConstIterator::ConstIterator(const Annotation* head,
|
||||
const Annotation* tail)
|
||||
: curr_(head), tail_(tail) {}
|
||||
|
||||
AnnotationList::ConstIterator::~ConstIterator() = default;
|
||||
|
||||
const Annotation* AnnotationList::ConstIterator::operator*() const {
|
||||
CHECK_NE(curr_, tail_);
|
||||
return curr_;
|
||||
}
|
||||
|
||||
AnnotationList::ConstIterator& AnnotationList::ConstIterator::operator++() {
|
||||
CHECK_NE(curr_, tail_);
|
||||
curr_ = curr_->GetLinkNode();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool AnnotationList::ConstIterator::operator==(
|
||||
const AnnotationList::ConstIterator& other) const {
|
||||
return curr_ == other.curr_;
|
||||
}
|
||||
|
||||
AnnotationList::Iterator AnnotationList::begin() {
|
||||
return Iterator(head_.link_node(), tail_pointer_);
|
||||
return Iterator(head_.GetLinkNode(), tail_pointer_);
|
||||
}
|
||||
|
||||
AnnotationList::ConstIterator AnnotationList::cbegin() const {
|
||||
return ConstIterator(head_.GetLinkNode(), tail_pointer_);
|
||||
}
|
||||
|
||||
AnnotationList::Iterator AnnotationList::end() {
|
||||
return Iterator(&tail_, tail_pointer_);
|
||||
}
|
||||
|
||||
AnnotationList::ConstIterator AnnotationList::cend() const {
|
||||
return ConstIterator(&tail_, tail_pointer_);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -80,11 +80,37 @@ class AnnotationList {
|
||||
// Copy and assign are required.
|
||||
};
|
||||
|
||||
//! \brief An InputIterator for iterating a const AnnotationList.
|
||||
class ConstIterator {
|
||||
public:
|
||||
~ConstIterator();
|
||||
|
||||
const Annotation* operator*() const;
|
||||
ConstIterator& operator++();
|
||||
bool operator==(const ConstIterator& other) const;
|
||||
bool operator!=(const ConstIterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class AnnotationList;
|
||||
ConstIterator(const Annotation* head, const Annotation* tail);
|
||||
|
||||
const Annotation* curr_;
|
||||
const Annotation* const tail_;
|
||||
|
||||
// Copy and assign are required.
|
||||
};
|
||||
|
||||
//! \brief Returns an iterator to the first element of the annotation list.
|
||||
Iterator begin();
|
||||
ConstIterator begin() const { return cbegin(); }
|
||||
ConstIterator cbegin() const;
|
||||
|
||||
//! \brief Returns an iterator past the last element of the annotation list.
|
||||
Iterator end();
|
||||
ConstIterator end() const { return cend(); }
|
||||
ConstIterator cend() const;
|
||||
|
||||
protected:
|
||||
#if BUILDFLAG(IS_IOS)
|
||||
|
@ -128,6 +128,100 @@ TEST_F(AnnotationList, DuplicateKeys) {
|
||||
EXPECT_EQ(1u, annotations.size());
|
||||
}
|
||||
|
||||
TEST_F(AnnotationList, IteratorSingleAnnotation) {
|
||||
ASSERT_EQ(annotations_.begin(), annotations_.end());
|
||||
ASSERT_EQ(annotations_.cbegin(), annotations_.cend());
|
||||
|
||||
one_.Set("1");
|
||||
|
||||
auto iterator = annotations_.begin();
|
||||
auto const_iterator = annotations_.cbegin();
|
||||
|
||||
ASSERT_NE(iterator, annotations_.end());
|
||||
ASSERT_NE(const_iterator, annotations_.cend());
|
||||
|
||||
EXPECT_EQ(*iterator, &one_);
|
||||
EXPECT_EQ(*const_iterator, &one_);
|
||||
|
||||
++iterator;
|
||||
++const_iterator;
|
||||
|
||||
EXPECT_EQ(iterator, annotations_.end());
|
||||
EXPECT_EQ(const_iterator, annotations_.cend());
|
||||
}
|
||||
|
||||
TEST_F(AnnotationList, IteratorMultipleAnnotationsInserted) {
|
||||
ASSERT_EQ(annotations_.begin(), annotations_.end());
|
||||
ASSERT_EQ(annotations_.cbegin(), annotations_.cend());
|
||||
|
||||
one_.Set("1");
|
||||
two_.Set("2");
|
||||
|
||||
// New annotations are inserted to the beginning of the list. Hence, |two_|
|
||||
// must be the first annotation, followed by |one_|.
|
||||
{
|
||||
auto iterator = annotations_.begin();
|
||||
auto const_iterator = annotations_.cbegin();
|
||||
|
||||
ASSERT_NE(iterator, annotations_.end());
|
||||
ASSERT_NE(const_iterator, annotations_.cend());
|
||||
|
||||
EXPECT_EQ(*iterator, &two_);
|
||||
EXPECT_EQ(*const_iterator, &two_);
|
||||
|
||||
++iterator;
|
||||
++const_iterator;
|
||||
|
||||
ASSERT_NE(iterator, annotations_.end());
|
||||
ASSERT_NE(const_iterator, annotations_.cend());
|
||||
|
||||
EXPECT_EQ(*iterator, &one_);
|
||||
EXPECT_EQ(*const_iterator, &one_);
|
||||
|
||||
++iterator;
|
||||
++const_iterator;
|
||||
|
||||
EXPECT_EQ(iterator, annotations_.end());
|
||||
EXPECT_EQ(const_iterator, annotations_.cend());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(AnnotationList, IteratorMultipleAnnotationsInsertedAndRemoved) {
|
||||
ASSERT_EQ(annotations_.begin(), annotations_.end());
|
||||
ASSERT_EQ(annotations_.cbegin(), annotations_.cend());
|
||||
|
||||
one_.Set("1");
|
||||
two_.Set("2");
|
||||
one_.Clear();
|
||||
two_.Clear();
|
||||
|
||||
// Even after clearing, Annotations are still inserted in the list and
|
||||
// reachable via the iterators.
|
||||
auto iterator = annotations_.begin();
|
||||
auto const_iterator = annotations_.cbegin();
|
||||
|
||||
ASSERT_NE(iterator, annotations_.end());
|
||||
ASSERT_NE(const_iterator, annotations_.cend());
|
||||
|
||||
EXPECT_EQ(*iterator, &two_);
|
||||
EXPECT_EQ(*const_iterator, &two_);
|
||||
|
||||
++iterator;
|
||||
++const_iterator;
|
||||
|
||||
ASSERT_NE(iterator, annotations_.end());
|
||||
ASSERT_NE(const_iterator, annotations_.cend());
|
||||
|
||||
EXPECT_EQ(*iterator, &one_);
|
||||
EXPECT_EQ(*const_iterator, &one_);
|
||||
|
||||
++iterator;
|
||||
++const_iterator;
|
||||
|
||||
EXPECT_EQ(iterator, annotations_.end());
|
||||
EXPECT_EQ(const_iterator, annotations_.cend());
|
||||
}
|
||||
|
||||
class RaceThread : public Thread {
|
||||
public:
|
||||
explicit RaceThread(test::AnnotationList* test) : Thread(), test_(test) {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user