[tint] Support iteration while adding to BlockAllocator
Remove reverse iterators - they weren't used, and looked broken.
Bug: chromium:1487321, oss-fuzz:62750
Change-Id: I05c19ee3ea1233bab07890254d3a9b01c3eb2be0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/153981
Reviewed-by: James Price <jrprice@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Commit-Queue: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/utils/memory/block_allocator.h b/src/tint/utils/memory/block_allocator.h
index 2ee1296..978950a 100644
--- a/src/tint/utils/memory/block_allocator.h
+++ b/src/tint/utils/memory/block_allocator.h
@@ -40,6 +40,7 @@
std::array<T*, kMax> ptrs;
Pointers* next;
Pointers* prev;
+ size_t count;
};
/// Block is linked list of memory blocks.
@@ -48,7 +49,7 @@
/// Note: We're not using std::aligned_storage here as this warns / errors on MSVC.
struct alignas(BLOCK_ALIGNMENT) Block {
uint8_t data[BLOCK_SIZE];
- Block* next;
+ Block* next = nullptr;
};
// Forward declaration
@@ -56,7 +57,7 @@
class TView;
/// An iterator for the objects owned by the BlockAllocator.
- template <bool IS_CONST, bool FORWARD>
+ template <bool IS_CONST>
class TIterator {
using PointerTy = std::conditional_t<IS_CONST, const T*, T*>;
@@ -76,10 +77,12 @@
/// Progress the iterator forward one element
/// @returns this iterator
TIterator& operator++() {
- if (FORWARD) {
- ProgressForward();
- } else {
- ProgressBackwards();
+ if (ptrs != nullptr) {
+ ++idx;
+ if (idx >= ptrs->count) {
+ idx = 0;
+ ptrs = ptrs->next;
+ }
}
return *this;
}
@@ -87,44 +90,27 @@
/// Progress the iterator backwards one element
/// @returns this iterator
TIterator& operator--() {
- if (FORWARD) {
- ProgressBackwards();
- } else {
- ProgressForward();
+ if (ptrs != nullptr) {
+ if (idx == 0) {
+ ptrs = ptrs->prev;
+ idx = ptrs->count - 1;
+ }
+ --idx;
}
return *this;
}
/// @returns the pointer to the object at the current iterator position
- PointerTy operator*() const { return ptrs ? ptrs->ptrs[idx] : nullptr; }
+ PointerTy operator*() const { return ptrs->ptrs[idx]; }
private:
friend TView<IS_CONST>; // Keep internal iterator impl private.
explicit TIterator(const Pointers* p, size_t i) : ptrs(p), idx(i) {}
- /// Progresses the iterator forwards
- void ProgressForward() {
- if (ptrs != nullptr) {
- ++idx;
- if (idx == Pointers::kMax) {
- idx = 0;
- ptrs = ptrs->next;
- }
- }
- }
- /// Progresses the iterator backwards
- void ProgressBackwards() {
- if (ptrs != nullptr) {
- if (idx == 0) {
- idx = Pointers::kMax - 1;
- ptrs = ptrs->prev;
- }
- --idx;
- }
- }
-
- const Pointers* ptrs;
- size_t idx;
+ /// The current Pointers
+ const Pointers* ptrs = nullptr;
+ /// The current index within #ptrs
+ size_t idx = 0;
};
/// View provides begin() and end() methods for looping over the objects owned by the
@@ -133,26 +119,12 @@
class TView {
public:
/// @returns an iterator to the beginning of the view
- TIterator<IS_CONST, true> begin() const {
- return TIterator<IS_CONST, true>{allocator_->data.pointers.root, 0};
+ TIterator<IS_CONST> begin() const {
+ return TIterator<IS_CONST>{allocator_->data.pointers.root, 0};
}
/// @returns an iterator to the end of the view
- TIterator<IS_CONST, true> end() const {
- return allocator_->data.pointers.current_index >= Pointers::kMax
- ? TIterator<IS_CONST, true>{nullptr, 0}
- : TIterator<IS_CONST, true>{allocator_->data.pointers.current,
- allocator_->data.pointers.current_index};
- }
-
- /// @returns an iterator to the beginning of the view
- TIterator<IS_CONST, false> rbegin() const { return TIterator<IS_CONST, false>{nullptr, 0}; }
-
- /// @returns an iterator to the end of the view
- TIterator<IS_CONST, false> rend() const {
- return TIterator<IS_CONST, false>{allocator_->data.pointers.current,
- allocator_->data.pointers.current_index};
- }
+ TIterator<IS_CONST> end() const { return TIterator<IS_CONST>{nullptr, 0}; }
private:
friend BlockAllocator; // For BlockAllocator::operator View()
@@ -162,16 +134,10 @@
public:
/// A forward-iterator type over the objects of the BlockAllocator
- using Iterator = TIterator</* const */ false, /* forward */ true>;
+ using Iterator = TIterator</* const */ false>;
/// An immutable forward-iterator type over the objects of the BlockAllocator
- using ConstIterator = TIterator</* const */ true, /* forward */ true>;
-
- /// A reverse-iterator type over the objects of the BlockAllocator
- using ReverseIterator = TIterator</* const */ false, /* forward */ false>;
-
- /// An immutable reverse-iterator type over the objects of the BlockAllocator
- using ReverseConstIterator = TIterator</* const */ true, /* forward */ false>;
+ using ConstIterator = TIterator</* const */ true>;
/// View provides begin() and end() methods for looping over the objects owned by the
/// BlockAllocator.
@@ -287,7 +253,7 @@
void AddObjectPointer(T* ptr) {
auto& pointers = data.pointers;
- if (pointers.current_index >= Pointers::kMax) {
+ if (!pointers.current || pointers.current->count == Pointers::kMax) {
auto* prev_pointers = pointers.current;
pointers.current = Allocate<Pointers>();
if (!pointers.current) {
@@ -295,7 +261,7 @@
}
pointers.current->next = nullptr;
pointers.current->prev = prev_pointers;
- pointers.current_index = 0;
+ pointers.current->count = 0;
if (prev_pointers) {
prev_pointers->next = pointers.current;
@@ -304,7 +270,7 @@
}
}
- pointers.current->ptrs[pointers.current_index++] = ptr;
+ pointers.current->ptrs[pointers.current->count++] = ptr;
}
struct {
@@ -326,10 +292,6 @@
/// The current (end) Pointers structure of the pointers linked list.
/// AddObjectPointer() adds to this structure.
Pointers* current = nullptr;
- /// The array index in #current for the next append.
- /// Initialized with Pointers::kMax so that the first append triggers a allocation of
- /// the Pointers structure.
- size_t current_index = Pointers::kMax;
} pointers;
size_t count = 0;
diff --git a/src/tint/utils/memory/block_allocator_test.cc b/src/tint/utils/memory/block_allocator_test.cc
index d6da564..821e150 100644
--- a/src/tint/utils/memory/block_allocator_test.cc
+++ b/src/tint/utils/memory/block_allocator_test.cc
@@ -14,6 +14,8 @@
#include "src/tint/utils/memory/block_allocator.h"
+#include <vector>
+
#include "gtest/gtest.h"
namespace tint {
@@ -160,5 +162,30 @@
}
}
+TEST_F(BlockAllocatorTest, AddWhileIterating) {
+ using Allocator = BlockAllocator<size_t>;
+
+ Allocator allocator;
+ for (int i = 0; i < 20; i++) {
+ allocator.Create(allocator.Count());
+
+ std::vector<size_t*> seen;
+ for (auto* j : allocator.Objects()) {
+ if (*j % 3 == 0) {
+ allocator.Create(allocator.Count());
+ }
+ seen.push_back(j);
+ }
+
+ // Check that iteration-while-adding saw the same list of objects as an
+ // iteration-without-adding.
+ size_t n = 0;
+ for (auto* obj : allocator.Objects()) {
+ ASSERT_TRUE(n < seen.size());
+ EXPECT_EQ(seen[n++], obj);
+ }
+ }
+}
+
} // namespace
} // namespace tint