Skip to content

Commit de32acf

Browse files
derekxu16Commit Queue
authored andcommitted
[VM] Introduce ListQueue class
TEST=list_queue_test.cc Change-Id: Ie85055475f35a9fdc4f31e61d5f1f5d04eb707a8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/420220 Reviewed-by: Ben Konyi <[email protected]> Commit-Queue: Derek Xu <[email protected]>
1 parent 7427e65 commit de32acf

File tree

4 files changed

+151
-0
lines changed

4 files changed

+151
-0
lines changed

runtime/bin/builtin_impl_sources.gni

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ builtin_impl_tests = [
6464
"eventhandler_test.cc",
6565
"file_test.cc",
6666
"hashmap_test.cc",
67+
"list_queue_test.cc",
6768
"priority_heap_test.cc",
6869
"snapshot_utils_test.cc",
6970
"test_utils.cc",

runtime/bin/list_queue_test.cc

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
#include <vector>
6+
7+
#include "platform/list_queue.h"
8+
#include "vm/unit_test.h"
9+
10+
namespace dart {
11+
12+
void ExpectContentsToBe(const ListQueue<intptr_t>& actual,
13+
const std::vector<intptr_t>& expected) {
14+
intptr_t i = 0;
15+
actual.ForEach([&expected, &i](intptr_t actual_element) {
16+
EXPECT(actual_element == expected[i]);
17+
++i;
18+
});
19+
}
20+
21+
VM_UNIT_TEST_CASE(ListQueue_PublicMethods) {
22+
ListQueue<intptr_t> l;
23+
intptr_t front = -1;
24+
25+
l.PushBack(1);
26+
ExpectContentsToBe(l, {1});
27+
EXPECT(l.Length() == 1);
28+
29+
front = l.PopFront();
30+
EXPECT(front == 1);
31+
ExpectContentsToBe(l, {});
32+
EXPECT(l.Length() == 0);
33+
34+
l.PushBack(2);
35+
ExpectContentsToBe(l, {2});
36+
EXPECT(l.Length() == 1);
37+
38+
l.PushBack(3);
39+
ExpectContentsToBe(l, {2, 3});
40+
EXPECT(l.Length() == 2);
41+
42+
front = l.PopFront();
43+
EXPECT(front == 2);
44+
ExpectContentsToBe(l, {3});
45+
EXPECT(l.Length() == 1);
46+
47+
l.PushBack(4);
48+
ExpectContentsToBe(l, {3, 4});
49+
EXPECT(l.Length() == 2);
50+
}
51+
52+
VM_UNIT_TEST_CASE(ListQueue_Grow) {
53+
const intptr_t kInitialCapacity = ListQueue<intptr_t>::kInitialCapacity;
54+
55+
ListQueue<intptr_t> l;
56+
l.PushBack(1);
57+
ExpectContentsToBe(l, {1});
58+
l.PopFront();
59+
ExpectContentsToBe(l, {});
60+
61+
// Force |l| to grow by adding more than |kInitialCapacity| elements to it.
62+
for (intptr_t i = 0; i <= kInitialCapacity + 3; ++i) {
63+
l.PushBack(123);
64+
}
65+
66+
ExpectContentsToBe(l, std::vector<intptr_t>(kInitialCapacity + 4, 123));
67+
}
68+
69+
} // namespace dart

runtime/platform/list_queue.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
#ifndef RUNTIME_PLATFORM_LIST_QUEUE_H_
6+
#define RUNTIME_PLATFORM_LIST_QUEUE_H_
7+
8+
#include <functional>
9+
#include <memory>
10+
#include <utility>
11+
12+
#include "platform/assert.h"
13+
#include "platform/globals.h"
14+
15+
// A queue backed by a circular buffer similar to dart:collection's ListQueue.
16+
template <typename T>
17+
class ListQueue {
18+
public:
19+
static constexpr intptr_t kInitialCapacity = 64;
20+
21+
ListQueue()
22+
: buffer_(std::make_unique<T[]>(kInitialCapacity)),
23+
capacity_(kInitialCapacity) {}
24+
25+
void PushBack(T&& element) {
26+
buffer_[tail_] = std::move(element);
27+
tail_ = (tail_ + 1) % capacity_;
28+
if (head_ == tail_) {
29+
Grow();
30+
}
31+
++length_;
32+
}
33+
34+
T&& PopFront() {
35+
ASSERT(head_ != tail_);
36+
T&& element = std::move(buffer_[head_]);
37+
head_ = (head_ + 1) % capacity_;
38+
--length_;
39+
return std::move(element);
40+
}
41+
42+
// The number of elements currently in the queue.
43+
intptr_t Length() { return length_; }
44+
45+
void ForEach(std::function<void(const T&)> callback) const {
46+
for (intptr_t i = head_; i != tail_; i = (i + 1) % capacity_) {
47+
callback(buffer_[i]);
48+
}
49+
}
50+
51+
private:
52+
std::unique_ptr<T[]> buffer_;
53+
intptr_t capacity_;
54+
intptr_t length_ = 0;
55+
intptr_t head_ = 0;
56+
intptr_t tail_ = 0;
57+
58+
void Grow() {
59+
intptr_t split = capacity_ - head_;
60+
61+
intptr_t new_capacity = capacity_ << 1;
62+
std::unique_ptr<T[]> new_buffer = std::make_unique<T[]>(new_capacity);
63+
64+
for (intptr_t i = 0; i < split; ++i) {
65+
new_buffer[i] = std::move(buffer_[head_ + i]);
66+
}
67+
for (intptr_t i = split; i < split + head_; ++i) {
68+
new_buffer[i] = std::move(buffer_[i - split]);
69+
}
70+
71+
head_ = 0;
72+
tail_ = capacity_;
73+
buffer_.swap(new_buffer);
74+
capacity_ = new_capacity;
75+
}
76+
77+
DISALLOW_COPY_AND_ASSIGN(ListQueue);
78+
};
79+
80+
#endif // RUNTIME_PLATFORM_LIST_QUEUE_H_

runtime/platform/platform_sources.gni

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ platform_sources = [
1818
"growable_array.h",
1919
"hashmap.cc",
2020
"hashmap.h",
21+
"list_queue.h",
2122
"lockers.h",
2223
"memory_sanitizer.h",
2324
"safe_stack.h",

0 commit comments

Comments
 (0)