/work/obj-fuzz/dist/include/mozilla/Queue.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef mozilla_Queue_h |
8 | | #define mozilla_Queue_h |
9 | | |
10 | | #include "mozilla/MemoryReporting.h" |
11 | | |
12 | | namespace mozilla { |
13 | | |
14 | | // A queue implements a singly linked list of pages, each of which contains some |
15 | | // number of elements. Since the queue needs to store a "next" pointer, the |
16 | | // actual number of elements per page won't be quite as many as were requested. |
17 | | // |
18 | | // This class should only be used if it's valid to construct T elements from all |
19 | | // zeroes. The class also fails to call the destructor on items. However, it |
20 | | // will only destroy items after it has moved out their contents. The queue is |
21 | | // required to be empty when it is destroyed. |
22 | | template<class T, size_t RequestedItemsPerPage = 256> |
23 | | class Queue |
24 | | { |
25 | | public: |
26 | 74 | Queue() {} mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::Queue() Line | Count | Source | 26 | 62 | Queue() {} |
mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::Queue() Line | Count | Source | 26 | 12 | Queue() {} |
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::Queue() |
27 | | |
28 | | ~Queue() |
29 | 0 | { |
30 | 0 | MOZ_ASSERT(IsEmpty()); |
31 | 0 |
|
32 | 0 | if (mHead) { |
33 | 0 | free(mHead); |
34 | 0 | } |
35 | 0 | } Unexecuted instantiation: mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::~Queue() Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::~Queue() Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::~Queue() |
36 | | |
37 | | T& Push(T&& aElement) |
38 | 194 | { |
39 | 194 | if (!mHead) { |
40 | 19 | mHead = NewPage(); |
41 | 19 | MOZ_ASSERT(mHead); |
42 | 19 | |
43 | 19 | mTail = mHead; |
44 | 19 | mOffsetHead = 0; |
45 | 19 | mOffsetTail = 0; |
46 | 175 | } else if (mOffsetTail == ItemsPerPage) { |
47 | 0 | Page* page = NewPage(); |
48 | 0 | MOZ_ASSERT(page); |
49 | 0 |
|
50 | 0 | mTail->mNext = page; |
51 | 0 | mTail = page; |
52 | 0 | mOffsetTail = 0; |
53 | 0 | } |
54 | 194 | |
55 | 194 | T& eltLocation = mTail->mEvents[mOffsetTail]; |
56 | 194 | eltLocation = std::move(aElement); |
57 | 194 | ++mOffsetTail; |
58 | 194 | |
59 | 194 | return eltLocation; |
60 | 194 | } mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::Push(nsCOMPtr<nsIRunnable>&&) Line | Count | Source | 38 | 194 | { | 39 | 194 | if (!mHead) { | 40 | 19 | mHead = NewPage(); | 41 | 19 | MOZ_ASSERT(mHead); | 42 | 19 | | 43 | 19 | mTail = mHead; | 44 | 19 | mOffsetHead = 0; | 45 | 19 | mOffsetTail = 0; | 46 | 175 | } else if (mOffsetTail == ItemsPerPage) { | 47 | 0 | Page* page = NewPage(); | 48 | 0 | MOZ_ASSERT(page); | 49 | 0 |
| 50 | 0 | mTail->mNext = page; | 51 | 0 | mTail = page; | 52 | 0 | mOffsetTail = 0; | 53 | 0 | } | 54 | 194 | | 55 | 194 | T& eltLocation = mTail->mEvents[mOffsetTail]; | 56 | 194 | eltLocation = std::move(aElement); | 57 | 194 | ++mOffsetTail; | 58 | 194 | | 59 | 194 | return eltLocation; | 60 | 194 | } |
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::Push(mozilla::LabeledEventQueue::Epoch&&) Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::Push(mozilla::SchedulerGroup::EpochQueueEntry&&) |
61 | | |
62 | | bool IsEmpty() const |
63 | 82 | { |
64 | 82 | return !mHead || (mHead == mTail && mOffsetHead == mOffsetTail); |
65 | 82 | } mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::IsEmpty() const Line | Count | Source | 63 | 82 | { | 64 | 82 | return !mHead || (mHead == mTail && mOffsetHead == mOffsetTail); | 65 | 82 | } |
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::IsEmpty() const Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::IsEmpty() const |
66 | | |
67 | | T Pop() |
68 | 31 | { |
69 | 31 | MOZ_ASSERT(!IsEmpty()); |
70 | 31 | |
71 | 31 | MOZ_ASSERT(mOffsetHead < ItemsPerPage); |
72 | 31 | MOZ_ASSERT_IF(mHead == mTail, mOffsetHead <= mOffsetTail); |
73 | 31 | T result = std::move(mHead->mEvents[mOffsetHead++]); |
74 | 31 | |
75 | 31 | MOZ_ASSERT(mOffsetHead <= ItemsPerPage); |
76 | 31 | |
77 | 31 | // Check if mHead points to empty Page |
78 | 31 | if (mOffsetHead == ItemsPerPage) { |
79 | 0 | Page* dead = mHead; |
80 | 0 | mHead = mHead->mNext; |
81 | 0 | free(dead); |
82 | 0 | mOffsetHead = 0; |
83 | 0 | } |
84 | 31 | |
85 | 31 | return result; |
86 | 31 | } mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::Pop() Line | Count | Source | 68 | 31 | { | 69 | 31 | MOZ_ASSERT(!IsEmpty()); | 70 | 31 | | 71 | 31 | MOZ_ASSERT(mOffsetHead < ItemsPerPage); | 72 | 31 | MOZ_ASSERT_IF(mHead == mTail, mOffsetHead <= mOffsetTail); | 73 | 31 | T result = std::move(mHead->mEvents[mOffsetHead++]); | 74 | 31 | | 75 | 31 | MOZ_ASSERT(mOffsetHead <= ItemsPerPage); | 76 | 31 | | 77 | 31 | // Check if mHead points to empty Page | 78 | 31 | if (mOffsetHead == ItemsPerPage) { | 79 | 0 | Page* dead = mHead; | 80 | 0 | mHead = mHead->mNext; | 81 | 0 | free(dead); | 82 | 0 | mOffsetHead = 0; | 83 | 0 | } | 84 | 31 | | 85 | 31 | return result; | 86 | 31 | } |
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::Pop() Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::Pop() |
87 | | |
88 | | void FirstElementAssertions() const |
89 | 0 | { |
90 | 0 | MOZ_ASSERT(!IsEmpty()); |
91 | 0 | MOZ_ASSERT(mOffsetHead < ItemsPerPage); |
92 | 0 | MOZ_ASSERT_IF(mHead == mTail, mOffsetHead <= mOffsetTail); |
93 | 0 | } Unexecuted instantiation: mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::FirstElementAssertions() const Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::FirstElementAssertions() const Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::FirstElementAssertions() const |
94 | | |
95 | | T& FirstElement() |
96 | 0 | { |
97 | 0 | FirstElementAssertions(); |
98 | 0 | return mHead->mEvents[mOffsetHead]; |
99 | 0 | } Unexecuted instantiation: mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::FirstElement() Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::FirstElement() Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::FirstElement() |
100 | | |
101 | | const T& FirstElement() const |
102 | | { |
103 | | FirstElementAssertions(); |
104 | | return mHead->mEvents[mOffsetHead]; |
105 | | } |
106 | | |
107 | | void LastElementAssertions() const |
108 | 0 | { |
109 | 0 | MOZ_ASSERT(!IsEmpty()); |
110 | 0 | MOZ_ASSERT(mOffsetTail > 0); |
111 | 0 | MOZ_ASSERT(mOffsetTail <= ItemsPerPage); |
112 | 0 | MOZ_ASSERT_IF(mHead == mTail, mOffsetHead <= mOffsetTail); |
113 | 0 | } |
114 | | |
115 | | T& LastElement() |
116 | 0 | { |
117 | 0 | LastElementAssertions(); |
118 | 0 | return mTail->mEvents[mOffsetTail - 1]; |
119 | 0 | } |
120 | | |
121 | | const T& LastElement() const |
122 | | { |
123 | | LastElementAssertions(); |
124 | | return mTail->mEvents[mOffsetTail - 1]; |
125 | | } |
126 | | |
127 | | size_t Count() const |
128 | 0 | { |
129 | 0 | // It is obvious count is 0 when the queue is empty. |
130 | 0 | if (!mHead) { |
131 | 0 | return 0; |
132 | 0 | } |
133 | 0 | |
134 | 0 | /* How we count the number of events in the queue: |
135 | 0 | * 1. Let pageCount(x, y) denote the number of pages excluding the tail page |
136 | 0 | * where x is the index of head page and y is the index of the tail page. |
137 | 0 | * 2. Then we have pageCount(x, y) = y - x. |
138 | 0 | * |
139 | 0 | * Ex: pageCount(0, 0) = 0 where both head and tail pages point to page 0. |
140 | 0 | * pageCount(0, 1) = 1 where head points to page 0 and tail points page 1. |
141 | 0 | * |
142 | 0 | * 3. number of events = (ItemsPerPage * pageCount(x, y)) |
143 | 0 | * - (empty slots in head page) + (non-empty slots in tail page) |
144 | 0 | * = (ItemsPerPage * pageCount(x, y)) - mOffsetHead + mOffsetTail |
145 | 0 | */ |
146 | 0 | |
147 | 0 | int count = -mOffsetHead; |
148 | 0 |
|
149 | 0 | // Compute (ItemsPerPage * pageCount(x, y)) |
150 | 0 | for (Page* page = mHead; page != mTail; page = page->mNext) { |
151 | 0 | count += ItemsPerPage; |
152 | 0 | } |
153 | 0 |
|
154 | 0 | count += mOffsetTail; |
155 | 0 | MOZ_ASSERT(count >= 0); |
156 | 0 |
|
157 | 0 | return count; |
158 | 0 | } |
159 | | |
160 | | size_t ShallowSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const |
161 | 0 | { |
162 | 0 | size_t n = 0; |
163 | 0 | if (mHead) { |
164 | 0 | for (Page* page = mHead; page != mTail; page = page->mNext) { |
165 | 0 | n += aMallocSizeOf(page); |
166 | 0 | } |
167 | 0 | } |
168 | 0 | return n; |
169 | 0 | } Unexecuted instantiation: mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::ShallowSizeOfExcludingThis(unsigned long (*)(void const*)) const Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::ShallowSizeOfExcludingThis(unsigned long (*)(void const*)) const Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::ShallowSizeOfExcludingThis(unsigned long (*)(void const*)) const |
170 | | |
171 | | size_t ShallowSizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const |
172 | | { |
173 | | return aMallocSizeOf(this) + ShallowSizeOfExcludingThis(aMallocSizeOf); |
174 | | } |
175 | | |
176 | | private: |
177 | | static_assert((RequestedItemsPerPage & (RequestedItemsPerPage - 1)) == 0, |
178 | | "RequestedItemsPerPage should be a power of two to avoid heap slop."); |
179 | | |
180 | | // Since a Page must also contain a "next" pointer, we use one of the items to |
181 | | // store this pointer. If sizeof(T) > sizeof(Page*), then some space will be |
182 | | // wasted. So be it. |
183 | | static const size_t ItemsPerPage = RequestedItemsPerPage - 1; |
184 | | |
185 | | // Page objects are linked together to form a simple deque. |
186 | | struct Page |
187 | | { |
188 | | struct Page* mNext; |
189 | | T mEvents[ItemsPerPage]; |
190 | | }; |
191 | | |
192 | | static Page* NewPage() |
193 | 19 | { |
194 | 19 | return static_cast<Page*>(moz_xcalloc(1, sizeof(Page))); |
195 | 19 | } mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::NewPage() Line | Count | Source | 193 | 19 | { | 194 | 19 | return static_cast<Page*>(moz_xcalloc(1, sizeof(Page))); | 195 | 19 | } |
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::NewPage() Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::NewPage() |
196 | | |
197 | | Page* mHead = nullptr; |
198 | | Page* mTail = nullptr; |
199 | | |
200 | | uint16_t mOffsetHead = 0; // offset into mHead where next item is removed |
201 | | uint16_t mOffsetTail = 0; // offset into mTail where next item is added |
202 | | }; |
203 | | |
204 | | } // namespace mozilla |
205 | | |
206 | | #endif // mozilla_Queue_h |