OLD | NEW |
1 /* | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. | 2 // Use of this source code is governed by a BSD-style license that can be |
3 * Copyright (C) 2009 Google Inc. All rights reserved. | 3 // found in the LICENSE file. |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions | |
7 * are met: | |
8 * | |
9 * 1. Redistributions of source code must retain the above copyright | |
10 * notice, this list of conditions and the following disclaimer. | |
11 * 2. Redistributions in binary form must reproduce the above copyright | |
12 * notice, this list of conditions and the following disclaimer in the | |
13 * documentation and/or other materials provided with the distribution. | |
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
15 * its contributors may be used to endorse or promote products derived | |
16 * from this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 */ | |
29 | 4 |
30 #ifndef WTF_Deque_h | 5 #include "platform/wtf/Deque.h" |
31 #define WTF_Deque_h | |
32 | 6 |
33 // FIXME: Could move what Vector and Deque share into a separate file. | 7 // The contents of this header was moved to platform/wtf as part of |
34 // Deque doesn't actually use Vector. | 8 // WTF migration project. See the following post for details: |
35 | 9 // https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gY
CAAJ |
36 #include "wtf/Vector.h" | |
37 #include <iterator> | |
38 | |
39 namespace WTF { | |
40 | |
41 template <typename T, size_t inlineCapacity, typename Allocator> | |
42 class DequeIteratorBase; | |
43 template <typename T, size_t inlineCapacity, typename Allocator> | |
44 class DequeIterator; | |
45 template <typename T, size_t inlineCapacity, typename Allocator> | |
46 class DequeConstIterator; | |
47 | |
48 template <typename T, | |
49 size_t inlineCapacity = 0, | |
50 typename Allocator = PartitionAllocator> | |
51 class Deque : public ConditionalDestructor<Deque<T, INLINE_CAPACITY, Allocator>, | |
52 (INLINE_CAPACITY == 0) && | |
53 Allocator::isGarbageCollected> { | |
54 USE_ALLOCATOR(Deque, Allocator); | |
55 | |
56 public: | |
57 typedef DequeIterator<T, inlineCapacity, Allocator> iterator; | |
58 typedef DequeConstIterator<T, inlineCapacity, Allocator> const_iterator; | |
59 typedef std::reverse_iterator<iterator> reverse_iterator; | |
60 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; | |
61 | |
62 Deque(); | |
63 Deque(const Deque&); | |
64 Deque& operator=(const Deque&); | |
65 Deque(Deque&&); | |
66 Deque& operator=(Deque&&); | |
67 | |
68 void finalize(); | |
69 void finalizeGarbageCollectedObject() { finalize(); } | |
70 | |
71 void swap(Deque&); | |
72 | |
73 size_t size() const { | |
74 return m_start <= m_end ? m_end - m_start | |
75 : m_end + m_buffer.capacity() - m_start; | |
76 } | |
77 bool isEmpty() const { return m_start == m_end; } | |
78 | |
79 iterator begin() { return iterator(this, m_start); } | |
80 iterator end() { return iterator(this, m_end); } | |
81 const_iterator begin() const { return const_iterator(this, m_start); } | |
82 const_iterator end() const { return const_iterator(this, m_end); } | |
83 reverse_iterator rbegin() { return reverse_iterator(end()); } | |
84 reverse_iterator rend() { return reverse_iterator(begin()); } | |
85 const_reverse_iterator rbegin() const { | |
86 return const_reverse_iterator(end()); | |
87 } | |
88 const_reverse_iterator rend() const { | |
89 return const_reverse_iterator(begin()); | |
90 } | |
91 | |
92 T& front() { | |
93 DCHECK_NE(m_start, m_end); | |
94 return m_buffer.buffer()[m_start]; | |
95 } | |
96 const T& front() const { | |
97 DCHECK_NE(m_start, m_end); | |
98 return m_buffer.buffer()[m_start]; | |
99 } | |
100 T takeFirst(); | |
101 | |
102 T& back() { | |
103 DCHECK_NE(m_start, m_end); | |
104 return *(--end()); | |
105 } | |
106 const T& back() const { | |
107 DCHECK_NE(m_start, m_end); | |
108 return *(--end()); | |
109 } | |
110 T takeLast(); | |
111 | |
112 T& at(size_t i) { | |
113 RELEASE_ASSERT(i < size()); | |
114 size_t right = m_buffer.capacity() - m_start; | |
115 return i < right ? m_buffer.buffer()[m_start + i] | |
116 : m_buffer.buffer()[i - right]; | |
117 } | |
118 const T& at(size_t i) const { | |
119 RELEASE_ASSERT(i < size()); | |
120 size_t right = m_buffer.capacity() - m_start; | |
121 return i < right ? m_buffer.buffer()[m_start + i] | |
122 : m_buffer.buffer()[i - right]; | |
123 } | |
124 | |
125 T& operator[](size_t i) { return at(i); } | |
126 const T& operator[](size_t i) const { return at(i); } | |
127 | |
128 template <typename U> | |
129 void push_front(U&&); | |
130 void erase(iterator&); | |
131 void erase(const_iterator&); | |
132 | |
133 // STL compatibility. | |
134 template <typename U> | |
135 void push_back(U&&); | |
136 void pop_back(); | |
137 void pop_front(); | |
138 bool empty() const { return isEmpty(); } | |
139 template <typename... Args> | |
140 void emplace_back(Args&&...); | |
141 template <typename... Args> | |
142 void emplace_front(Args&&...); | |
143 | |
144 void clear(); | |
145 | |
146 template <typename VisitorDispatcher> | |
147 void trace(VisitorDispatcher); | |
148 | |
149 static_assert(!std::is_polymorphic<T>::value || | |
150 !VectorTraits<T>::canInitializeWithMemset, | |
151 "Cannot initialize with memset if there is a vtable"); | |
152 static_assert(Allocator::isGarbageCollected || | |
153 !AllowsOnlyPlacementNew<T>::value || | |
154 !IsTraceable<T>::value, | |
155 "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that " | |
156 "have trace methods into an off-heap Deque"); | |
157 static_assert(Allocator::isGarbageCollected || | |
158 !IsPointerToGarbageCollectedType<T>::value, | |
159 "Cannot put raw pointers to garbage-collected classes into a " | |
160 "Deque. Use HeapDeque<Member<T>> instead."); | |
161 | |
162 private: | |
163 friend class DequeIteratorBase<T, inlineCapacity, Allocator>; | |
164 | |
165 class BackingBuffer : public VectorBuffer<T, INLINE_CAPACITY, Allocator> { | |
166 WTF_MAKE_NONCOPYABLE(BackingBuffer); | |
167 | |
168 private: | |
169 using Base = VectorBuffer<T, INLINE_CAPACITY, Allocator>; | |
170 using Base::m_size; | |
171 | |
172 public: | |
173 BackingBuffer() : Base() {} | |
174 explicit BackingBuffer(size_t capacity) : Base(capacity) {} | |
175 | |
176 void setSize(size_t size) { m_size = size; } | |
177 }; | |
178 | |
179 typedef VectorTypeOperations<T> TypeOperations; | |
180 typedef DequeIteratorBase<T, inlineCapacity, Allocator> IteratorBase; | |
181 | |
182 void erase(size_t position); | |
183 void destroyAll(); | |
184 void expandCapacityIfNeeded(); | |
185 void expandCapacity(); | |
186 | |
187 BackingBuffer m_buffer; | |
188 unsigned m_start; | |
189 unsigned m_end; | |
190 }; | |
191 | |
192 template <typename T, size_t inlineCapacity, typename Allocator> | |
193 class DequeIteratorBase { | |
194 DISALLOW_NEW(); | |
195 | |
196 protected: | |
197 DequeIteratorBase(); | |
198 DequeIteratorBase(const Deque<T, inlineCapacity, Allocator>*, size_t); | |
199 DequeIteratorBase(const DequeIteratorBase&); | |
200 DequeIteratorBase& operator=(const DequeIteratorBase<T, 0, Allocator>&); | |
201 ~DequeIteratorBase(); | |
202 | |
203 void assign(const DequeIteratorBase& other) { *this = other; } | |
204 | |
205 void increment(); | |
206 void decrement(); | |
207 | |
208 T* before() const; | |
209 T* after() const; | |
210 | |
211 bool isEqual(const DequeIteratorBase&) const; | |
212 | |
213 private: | |
214 Deque<T, inlineCapacity, Allocator>* m_deque; | |
215 unsigned m_index; | |
216 | |
217 friend class Deque<T, inlineCapacity, Allocator>; | |
218 }; | |
219 | |
220 template <typename T, | |
221 size_t inlineCapacity = 0, | |
222 typename Allocator = PartitionAllocator> | |
223 class DequeIterator : public DequeIteratorBase<T, inlineCapacity, Allocator> { | |
224 private: | |
225 typedef DequeIteratorBase<T, inlineCapacity, Allocator> Base; | |
226 typedef DequeIterator<T, inlineCapacity, Allocator> Iterator; | |
227 | |
228 public: | |
229 typedef ptrdiff_t difference_type; | |
230 typedef T value_type; | |
231 typedef T* pointer; | |
232 typedef T& reference; | |
233 typedef std::bidirectional_iterator_tag iterator_category; | |
234 | |
235 DequeIterator(Deque<T, inlineCapacity, Allocator>* deque, size_t index) | |
236 : Base(deque, index) {} | |
237 | |
238 DequeIterator(const Iterator& other) : Base(other) {} | |
239 DequeIterator& operator=(const Iterator& other) { | |
240 Base::assign(other); | |
241 return *this; | |
242 } | |
243 | |
244 T& operator*() const { return *Base::after(); } | |
245 T* operator->() const { return Base::after(); } | |
246 | |
247 bool operator==(const Iterator& other) const { return Base::isEqual(other); } | |
248 bool operator!=(const Iterator& other) const { return !Base::isEqual(other); } | |
249 | |
250 Iterator& operator++() { | |
251 Base::increment(); | |
252 return *this; | |
253 } | |
254 // postfix ++ intentionally omitted | |
255 Iterator& operator--() { | |
256 Base::decrement(); | |
257 return *this; | |
258 } | |
259 // postfix -- intentionally omitted | |
260 }; | |
261 | |
262 template <typename T, | |
263 size_t inlineCapacity = 0, | |
264 typename Allocator = PartitionAllocator> | |
265 class DequeConstIterator | |
266 : public DequeIteratorBase<T, inlineCapacity, Allocator> { | |
267 private: | |
268 typedef DequeIteratorBase<T, inlineCapacity, Allocator> Base; | |
269 typedef DequeConstIterator<T, inlineCapacity, Allocator> Iterator; | |
270 typedef DequeIterator<T, inlineCapacity, Allocator> NonConstIterator; | |
271 | |
272 public: | |
273 typedef ptrdiff_t difference_type; | |
274 typedef T value_type; | |
275 typedef const T* pointer; | |
276 typedef const T& reference; | |
277 typedef std::bidirectional_iterator_tag iterator_category; | |
278 | |
279 DequeConstIterator(const Deque<T, inlineCapacity, Allocator>* deque, | |
280 size_t index) | |
281 : Base(deque, index) {} | |
282 | |
283 DequeConstIterator(const Iterator& other) : Base(other) {} | |
284 DequeConstIterator(const NonConstIterator& other) : Base(other) {} | |
285 DequeConstIterator& operator=(const Iterator& other) { | |
286 Base::assign(other); | |
287 return *this; | |
288 } | |
289 DequeConstIterator& operator=(const NonConstIterator& other) { | |
290 Base::assign(other); | |
291 return *this; | |
292 } | |
293 | |
294 const T& operator*() const { return *Base::after(); } | |
295 const T* operator->() const { return Base::after(); } | |
296 | |
297 bool operator==(const Iterator& other) const { return Base::isEqual(other); } | |
298 bool operator!=(const Iterator& other) const { return !Base::isEqual(other); } | |
299 | |
300 Iterator& operator++() { | |
301 Base::increment(); | |
302 return *this; | |
303 } | |
304 // postfix ++ intentionally omitted | |
305 Iterator& operator--() { | |
306 Base::decrement(); | |
307 return *this; | |
308 } | |
309 // postfix -- intentionally omitted | |
310 }; | |
311 | |
312 template <typename T, size_t inlineCapacity, typename Allocator> | |
313 inline Deque<T, inlineCapacity, Allocator>::Deque() : m_start(0), m_end(0) {} | |
314 | |
315 template <typename T, size_t inlineCapacity, typename Allocator> | |
316 inline Deque<T, inlineCapacity, Allocator>::Deque(const Deque& other) | |
317 : m_buffer(other.m_buffer.capacity()), | |
318 m_start(other.m_start), | |
319 m_end(other.m_end) { | |
320 const T* otherBuffer = other.m_buffer.buffer(); | |
321 if (m_start <= m_end) { | |
322 TypeOperations::uninitializedCopy(otherBuffer + m_start, | |
323 otherBuffer + m_end, | |
324 m_buffer.buffer() + m_start); | |
325 } else { | |
326 TypeOperations::uninitializedCopy(otherBuffer, otherBuffer + m_end, | |
327 m_buffer.buffer()); | |
328 TypeOperations::uninitializedCopy(otherBuffer + m_start, | |
329 otherBuffer + m_buffer.capacity(), | |
330 m_buffer.buffer() + m_start); | |
331 } | |
332 } | |
333 | |
334 template <typename T, size_t inlineCapacity, typename Allocator> | |
335 inline Deque<T, inlineCapacity, Allocator>& | |
336 Deque<T, inlineCapacity, Allocator>::operator=(const Deque& other) { | |
337 Deque<T> copy(other); | |
338 swap(copy); | |
339 return *this; | |
340 } | |
341 | |
342 template <typename T, size_t inlineCapacity, typename Allocator> | |
343 inline Deque<T, inlineCapacity, Allocator>::Deque(Deque&& other) | |
344 : m_start(0), m_end(0) { | |
345 swap(other); | |
346 } | |
347 | |
348 template <typename T, size_t inlineCapacity, typename Allocator> | |
349 inline Deque<T, inlineCapacity, Allocator>& | |
350 Deque<T, inlineCapacity, Allocator>::operator=(Deque&& other) { | |
351 swap(other); | |
352 return *this; | |
353 } | |
354 | |
355 template <typename T, size_t inlineCapacity, typename Allocator> | |
356 inline void Deque<T, inlineCapacity, Allocator>::destroyAll() { | |
357 if (m_start <= m_end) { | |
358 TypeOperations::destruct(m_buffer.buffer() + m_start, | |
359 m_buffer.buffer() + m_end); | |
360 m_buffer.clearUnusedSlots(m_buffer.buffer() + m_start, | |
361 m_buffer.buffer() + m_end); | |
362 } else { | |
363 TypeOperations::destruct(m_buffer.buffer(), m_buffer.buffer() + m_end); | |
364 m_buffer.clearUnusedSlots(m_buffer.buffer(), m_buffer.buffer() + m_end); | |
365 TypeOperations::destruct(m_buffer.buffer() + m_start, | |
366 m_buffer.buffer() + m_buffer.capacity()); | |
367 m_buffer.clearUnusedSlots(m_buffer.buffer() + m_start, | |
368 m_buffer.buffer() + m_buffer.capacity()); | |
369 } | |
370 } | |
371 | |
372 // Off-GC-heap deques: Destructor should be called. | |
373 // On-GC-heap deques: Destructor should be called for inline buffers (if any) | |
374 // but destructor shouldn't be called for vector backing since it is managed by | |
375 // the traced GC heap. | |
376 template <typename T, size_t inlineCapacity, typename Allocator> | |
377 inline void Deque<T, inlineCapacity, Allocator>::finalize() { | |
378 if (!INLINE_CAPACITY && !m_buffer.buffer()) | |
379 return; | |
380 if (!isEmpty() && | |
381 !(Allocator::isGarbageCollected && m_buffer.hasOutOfLineBuffer())) | |
382 destroyAll(); | |
383 | |
384 m_buffer.destruct(); | |
385 } | |
386 | |
387 template <typename T, size_t inlineCapacity, typename Allocator> | |
388 inline void Deque<T, inlineCapacity, Allocator>::swap(Deque& other) { | |
389 typename BackingBuffer::OffsetRange thisHole; | |
390 if (m_start <= m_end) { | |
391 m_buffer.setSize(m_end); | |
392 thisHole.begin = 0; | |
393 thisHole.end = m_start; | |
394 } else { | |
395 m_buffer.setSize(m_buffer.capacity()); | |
396 thisHole.begin = m_end; | |
397 thisHole.end = m_start; | |
398 } | |
399 typename BackingBuffer::OffsetRange otherHole; | |
400 if (other.m_start <= other.m_end) { | |
401 other.m_buffer.setSize(other.m_end); | |
402 otherHole.begin = 0; | |
403 otherHole.end = other.m_start; | |
404 } else { | |
405 other.m_buffer.setSize(other.m_buffer.capacity()); | |
406 otherHole.begin = other.m_end; | |
407 otherHole.end = other.m_start; | |
408 } | |
409 | |
410 m_buffer.swapVectorBuffer(other.m_buffer, thisHole, otherHole); | |
411 | |
412 std::swap(m_start, other.m_start); | |
413 std::swap(m_end, other.m_end); | |
414 } | |
415 | |
416 template <typename T, size_t inlineCapacity, typename Allocator> | |
417 inline void Deque<T, inlineCapacity, Allocator>::clear() { | |
418 destroyAll(); | |
419 m_start = 0; | |
420 m_end = 0; | |
421 m_buffer.deallocateBuffer(m_buffer.buffer()); | |
422 m_buffer.resetBufferPointer(); | |
423 } | |
424 | |
425 template <typename T, size_t inlineCapacity, typename Allocator> | |
426 inline void Deque<T, inlineCapacity, Allocator>::expandCapacityIfNeeded() { | |
427 if (m_start) { | |
428 if (m_end + 1 != m_start) | |
429 return; | |
430 } else if (m_end) { | |
431 if (m_end != m_buffer.capacity() - 1) | |
432 return; | |
433 } else if (m_buffer.capacity()) { | |
434 return; | |
435 } | |
436 | |
437 expandCapacity(); | |
438 } | |
439 | |
440 template <typename T, size_t inlineCapacity, typename Allocator> | |
441 void Deque<T, inlineCapacity, Allocator>::expandCapacity() { | |
442 size_t oldCapacity = m_buffer.capacity(); | |
443 T* oldBuffer = m_buffer.buffer(); | |
444 size_t newCapacity = | |
445 std::max(static_cast<size_t>(16), oldCapacity + oldCapacity / 4 + 1); | |
446 if (m_buffer.expandBuffer(newCapacity)) { | |
447 if (m_start <= m_end) { | |
448 // No adjustments to be done. | |
449 } else { | |
450 size_t newStart = m_buffer.capacity() - (oldCapacity - m_start); | |
451 TypeOperations::moveOverlapping(oldBuffer + m_start, | |
452 oldBuffer + oldCapacity, | |
453 m_buffer.buffer() + newStart); | |
454 m_buffer.clearUnusedSlots(oldBuffer + m_start, | |
455 oldBuffer + std::min(oldCapacity, newStart)); | |
456 m_start = newStart; | |
457 } | |
458 return; | |
459 } | |
460 m_buffer.allocateBuffer(newCapacity); | |
461 if (m_start <= m_end) { | |
462 TypeOperations::move(oldBuffer + m_start, oldBuffer + m_end, | |
463 m_buffer.buffer() + m_start); | |
464 m_buffer.clearUnusedSlots(oldBuffer + m_start, oldBuffer + m_end); | |
465 } else { | |
466 TypeOperations::move(oldBuffer, oldBuffer + m_end, m_buffer.buffer()); | |
467 m_buffer.clearUnusedSlots(oldBuffer, oldBuffer + m_end); | |
468 size_t newStart = m_buffer.capacity() - (oldCapacity - m_start); | |
469 TypeOperations::move(oldBuffer + m_start, oldBuffer + oldCapacity, | |
470 m_buffer.buffer() + newStart); | |
471 m_buffer.clearUnusedSlots(oldBuffer + m_start, oldBuffer + oldCapacity); | |
472 m_start = newStart; | |
473 } | |
474 m_buffer.deallocateBuffer(oldBuffer); | |
475 } | |
476 | |
477 template <typename T, size_t inlineCapacity, typename Allocator> | |
478 inline T Deque<T, inlineCapacity, Allocator>::takeFirst() { | |
479 T oldFirst = std::move(front()); | |
480 pop_front(); | |
481 return oldFirst; | |
482 } | |
483 | |
484 template <typename T, size_t inlineCapacity, typename Allocator> | |
485 inline T Deque<T, inlineCapacity, Allocator>::takeLast() { | |
486 T oldLast = std::move(back()); | |
487 pop_back(); | |
488 return oldLast; | |
489 } | |
490 | |
491 template <typename T, size_t inlineCapacity, typename Allocator> | |
492 template <typename U> | |
493 inline void Deque<T, inlineCapacity, Allocator>::push_back(U&& value) { | |
494 expandCapacityIfNeeded(); | |
495 T* newElement = &m_buffer.buffer()[m_end]; | |
496 if (m_end == m_buffer.capacity() - 1) | |
497 m_end = 0; | |
498 else | |
499 ++m_end; | |
500 new (NotNull, newElement) T(std::forward<U>(value)); | |
501 } | |
502 | |
503 template <typename T, size_t inlineCapacity, typename Allocator> | |
504 template <typename U> | |
505 inline void Deque<T, inlineCapacity, Allocator>::push_front(U&& value) { | |
506 expandCapacityIfNeeded(); | |
507 if (!m_start) | |
508 m_start = m_buffer.capacity() - 1; | |
509 else | |
510 --m_start; | |
511 new (NotNull, &m_buffer.buffer()[m_start]) T(std::forward<U>(value)); | |
512 } | |
513 | |
514 template <typename T, size_t inlineCapacity, typename Allocator> | |
515 template <typename... Args> | |
516 inline void Deque<T, inlineCapacity, Allocator>::emplace_back(Args&&... args) { | |
517 expandCapacityIfNeeded(); | |
518 T* newElement = &m_buffer.buffer()[m_end]; | |
519 if (m_end == m_buffer.capacity() - 1) | |
520 m_end = 0; | |
521 else | |
522 ++m_end; | |
523 new (NotNull, newElement) T(std::forward<Args>(args)...); | |
524 } | |
525 | |
526 template <typename T, size_t inlineCapacity, typename Allocator> | |
527 template <typename... Args> | |
528 inline void Deque<T, inlineCapacity, Allocator>::emplace_front(Args&&... args) { | |
529 expandCapacityIfNeeded(); | |
530 if (!m_start) | |
531 m_start = m_buffer.capacity() - 1; | |
532 else | |
533 --m_start; | |
534 new (NotNull, &m_buffer.buffer()[m_start]) T(std::forward<Args>(args)...); | |
535 } | |
536 | |
537 template <typename T, size_t inlineCapacity, typename Allocator> | |
538 inline void Deque<T, inlineCapacity, Allocator>::pop_front() { | |
539 DCHECK(!isEmpty()); | |
540 TypeOperations::destruct(&m_buffer.buffer()[m_start], | |
541 &m_buffer.buffer()[m_start + 1]); | |
542 m_buffer.clearUnusedSlots(&m_buffer.buffer()[m_start], | |
543 &m_buffer.buffer()[m_start + 1]); | |
544 if (m_start == m_buffer.capacity() - 1) | |
545 m_start = 0; | |
546 else | |
547 ++m_start; | |
548 } | |
549 | |
550 template <typename T, size_t inlineCapacity, typename Allocator> | |
551 inline void Deque<T, inlineCapacity, Allocator>::pop_back() { | |
552 DCHECK(!isEmpty()); | |
553 if (!m_end) | |
554 m_end = m_buffer.capacity() - 1; | |
555 else | |
556 --m_end; | |
557 TypeOperations::destruct(&m_buffer.buffer()[m_end], | |
558 &m_buffer.buffer()[m_end + 1]); | |
559 m_buffer.clearUnusedSlots(&m_buffer.buffer()[m_end], | |
560 &m_buffer.buffer()[m_end + 1]); | |
561 } | |
562 | |
563 template <typename T, size_t inlineCapacity, typename Allocator> | |
564 inline void Deque<T, inlineCapacity, Allocator>::erase(iterator& it) { | |
565 erase(it.m_index); | |
566 } | |
567 | |
568 template <typename T, size_t inlineCapacity, typename Allocator> | |
569 inline void Deque<T, inlineCapacity, Allocator>::erase(const_iterator& it) { | |
570 erase(it.m_index); | |
571 } | |
572 | |
573 template <typename T, size_t inlineCapacity, typename Allocator> | |
574 inline void Deque<T, inlineCapacity, Allocator>::erase(size_t position) { | |
575 if (position == m_end) | |
576 return; | |
577 | |
578 T* buffer = m_buffer.buffer(); | |
579 TypeOperations::destruct(&buffer[position], &buffer[position + 1]); | |
580 | |
581 // Find which segment of the circular buffer contained the remove element, | |
582 // and only move elements in that part. | |
583 if (position >= m_start) { | |
584 TypeOperations::moveOverlapping(buffer + m_start, buffer + position, | |
585 buffer + m_start + 1); | |
586 m_buffer.clearUnusedSlots(buffer + m_start, buffer + m_start + 1); | |
587 m_start = (m_start + 1) % m_buffer.capacity(); | |
588 } else { | |
589 TypeOperations::moveOverlapping(buffer + position + 1, buffer + m_end, | |
590 buffer + position); | |
591 m_buffer.clearUnusedSlots(buffer + m_end - 1, buffer + m_end); | |
592 m_end = (m_end - 1 + m_buffer.capacity()) % m_buffer.capacity(); | |
593 } | |
594 } | |
595 | |
596 template <typename T, size_t inlineCapacity, typename Allocator> | |
597 inline DequeIteratorBase<T, inlineCapacity, Allocator>::DequeIteratorBase() | |
598 : m_deque(0) {} | |
599 | |
600 template <typename T, size_t inlineCapacity, typename Allocator> | |
601 inline DequeIteratorBase<T, inlineCapacity, Allocator>::DequeIteratorBase( | |
602 const Deque<T, inlineCapacity, Allocator>* deque, | |
603 size_t index) | |
604 : m_deque(const_cast<Deque<T, inlineCapacity, Allocator>*>(deque)), | |
605 m_index(index) {} | |
606 | |
607 template <typename T, size_t inlineCapacity, typename Allocator> | |
608 inline DequeIteratorBase<T, inlineCapacity, Allocator>::DequeIteratorBase( | |
609 const DequeIteratorBase& other) | |
610 : m_deque(other.m_deque), m_index(other.m_index) {} | |
611 | |
612 template <typename T, size_t inlineCapacity, typename Allocator> | |
613 inline DequeIteratorBase<T, inlineCapacity, Allocator>& | |
614 DequeIteratorBase<T, inlineCapacity, Allocator>::operator=( | |
615 const DequeIteratorBase<T, 0, Allocator>& other) { | |
616 m_deque = other.m_deque; | |
617 m_index = other.m_index; | |
618 return *this; | |
619 } | |
620 | |
621 template <typename T, size_t inlineCapacity, typename Allocator> | |
622 inline DequeIteratorBase<T, inlineCapacity, Allocator>::~DequeIteratorBase() {} | |
623 | |
624 template <typename T, size_t inlineCapacity, typename Allocator> | |
625 inline bool DequeIteratorBase<T, inlineCapacity, Allocator>::isEqual( | |
626 const DequeIteratorBase& other) const { | |
627 return m_index == other.m_index; | |
628 } | |
629 | |
630 template <typename T, size_t inlineCapacity, typename Allocator> | |
631 inline void DequeIteratorBase<T, inlineCapacity, Allocator>::increment() { | |
632 DCHECK_NE(m_index, m_deque->m_end); | |
633 DCHECK(m_deque->m_buffer.capacity()); | |
634 if (m_index == m_deque->m_buffer.capacity() - 1) | |
635 m_index = 0; | |
636 else | |
637 ++m_index; | |
638 } | |
639 | |
640 template <typename T, size_t inlineCapacity, typename Allocator> | |
641 inline void DequeIteratorBase<T, inlineCapacity, Allocator>::decrement() { | |
642 DCHECK_NE(m_index, m_deque->m_start); | |
643 DCHECK(m_deque->m_buffer.capacity()); | |
644 if (!m_index) | |
645 m_index = m_deque->m_buffer.capacity() - 1; | |
646 else | |
647 --m_index; | |
648 } | |
649 | |
650 template <typename T, size_t inlineCapacity, typename Allocator> | |
651 inline T* DequeIteratorBase<T, inlineCapacity, Allocator>::after() const { | |
652 RELEASE_ASSERT(m_index != m_deque->m_end); | |
653 return &m_deque->m_buffer.buffer()[m_index]; | |
654 } | |
655 | |
656 template <typename T, size_t inlineCapacity, typename Allocator> | |
657 inline T* DequeIteratorBase<T, inlineCapacity, Allocator>::before() const { | |
658 RELEASE_ASSERT(m_index != m_deque->m_start); | |
659 if (!m_index) | |
660 return &m_deque->m_buffer.buffer()[m_deque->m_buffer.capacity() - 1]; | |
661 return &m_deque->m_buffer.buffer()[m_index - 1]; | |
662 } | |
663 | |
664 // This is only called if the allocator is a HeapAllocator. It is used when | |
665 // visiting during a tracing GC. | |
666 template <typename T, size_t inlineCapacity, typename Allocator> | |
667 template <typename VisitorDispatcher> | |
668 void Deque<T, inlineCapacity, Allocator>::trace(VisitorDispatcher visitor) { | |
669 DCHECK(Allocator::isGarbageCollected) << "Garbage collector must be enabled."; | |
670 const T* bufferBegin = m_buffer.buffer(); | |
671 const T* end = bufferBegin + m_end; | |
672 if (IsTraceableInCollectionTrait<VectorTraits<T>>::value) { | |
673 if (m_start <= m_end) { | |
674 for (const T* bufferEntry = bufferBegin + m_start; bufferEntry != end; | |
675 bufferEntry++) | |
676 Allocator::template trace<VisitorDispatcher, T, VectorTraits<T>>( | |
677 visitor, *const_cast<T*>(bufferEntry)); | |
678 } else { | |
679 for (const T* bufferEntry = bufferBegin; bufferEntry != end; | |
680 bufferEntry++) | |
681 Allocator::template trace<VisitorDispatcher, T, VectorTraits<T>>( | |
682 visitor, *const_cast<T*>(bufferEntry)); | |
683 const T* bufferEnd = m_buffer.buffer() + m_buffer.capacity(); | |
684 for (const T* bufferEntry = bufferBegin + m_start; | |
685 bufferEntry != bufferEnd; bufferEntry++) | |
686 Allocator::template trace<VisitorDispatcher, T, VectorTraits<T>>( | |
687 visitor, *const_cast<T*>(bufferEntry)); | |
688 } | |
689 } | |
690 if (m_buffer.hasOutOfLineBuffer()) { | |
691 Allocator::markNoTracing(visitor, m_buffer.buffer()); | |
692 Allocator::registerBackingStoreReference(visitor, m_buffer.bufferSlot()); | |
693 } | |
694 } | |
695 | |
696 template <typename T, size_t inlineCapacity, typename Allocator> | |
697 inline void swap(Deque<T, inlineCapacity, Allocator>& a, | |
698 Deque<T, inlineCapacity, Allocator>& b) { | |
699 a.swap(b); | |
700 } | |
701 | |
702 } // namespace WTF | |
703 | |
704 using WTF::Deque; | |
705 | |
706 #endif // WTF_Deque_h | |
OLD | NEW |