| 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 |