Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Side by Side Diff: third_party/WebKit/Source/wtf/Vector.h

Issue 2769603002: Move files in wtf/ to platform/wtf/ (Part 8). (Closed)
Patch Set: Rebase. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be
3 * 3 // found in the LICENSE file.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 */
20 4
21 #ifndef WTF_Vector_h 5 #include "platform/wtf/Vector.h"
22 #define WTF_Vector_h
23 6
24 #include "wtf/Alignment.h" 7 // The contents of this header was moved to platform/wtf as part of
25 #include "wtf/ConditionalDestructor.h" 8 // WTF migration project. See the following post for details:
26 #include "wtf/ContainerAnnotations.h" 9 // https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gY CAAJ
27 #include "wtf/Noncopyable.h"
28 #include "wtf/NotFound.h"
29 #include "wtf/StdLibExtras.h"
30 #include "wtf/VectorTraits.h"
31 #include "wtf/allocator/PartitionAllocator.h"
32 #include <algorithm>
33 #include <initializer_list>
34 #include <iterator>
35 #include <string.h>
36 #include <utility>
37
38 // For ASAN builds, disable inline buffers completely as they cause various
39 // issues.
40 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER
41 #define INLINE_CAPACITY 0
42 #else
43 #define INLINE_CAPACITY inlineCapacity
44 #endif
45
46 namespace WTF {
47
48 #if defined(MEMORY_SANITIZER_INITIAL_SIZE)
49 static const size_t kInitialVectorSize = 1;
50 #else
51 #ifndef WTF_VECTOR_INITIAL_SIZE
52 #define WTF_VECTOR_INITIAL_SIZE 4
53 #endif
54 static const size_t kInitialVectorSize = WTF_VECTOR_INITIAL_SIZE;
55 #endif
56
57 template <typename T, size_t inlineBuffer, typename Allocator>
58 class Deque;
59
60 //
61 // Vector Traits
62 //
63
64 // Bunch of traits for Vector are defined here, with which you can customize
65 // Vector's behavior. In most cases the default traits are appropriate, so you
66 // usually don't have to specialize those traits by yourself.
67 //
68 // The behavior of the implementation below can be controlled by VectorTraits.
69 // If you want to change the behavior of your type, take a look at VectorTraits
70 // (defined in VectorTraits.h), too.
71
72 template <bool needsDestruction, typename T>
73 struct VectorDestructor;
74
75 template <typename T>
76 struct VectorDestructor<false, T> {
77 STATIC_ONLY(VectorDestructor);
78 static void destruct(T*, T*) {}
79 };
80
81 template <typename T>
82 struct VectorDestructor<true, T> {
83 STATIC_ONLY(VectorDestructor);
84 static void destruct(T* begin, T* end) {
85 for (T* cur = begin; cur != end; ++cur)
86 cur->~T();
87 }
88 };
89
90 template <bool unusedSlotsMustBeZeroed, typename T>
91 struct VectorUnusedSlotClearer;
92
93 template <typename T>
94 struct VectorUnusedSlotClearer<false, T> {
95 STATIC_ONLY(VectorUnusedSlotClearer);
96 static void clear(T*, T*) {}
97 #if DCHECK_IS_ON()
98 static void checkCleared(const T*, const T*) {}
99 #endif
100 };
101
102 template <typename T>
103 struct VectorUnusedSlotClearer<true, T> {
104 STATIC_ONLY(VectorUnusedSlotClearer);
105 static void clear(T* begin, T* end) {
106 memset(reinterpret_cast<void*>(begin), 0, sizeof(T) * (end - begin));
107 }
108
109 #if DCHECK_IS_ON()
110 static void checkCleared(const T* begin, const T* end) {
111 const unsigned char* unusedArea =
112 reinterpret_cast<const unsigned char*>(begin);
113 const unsigned char* endAddress =
114 reinterpret_cast<const unsigned char*>(end);
115 DCHECK_GE(endAddress, unusedArea);
116 for (int i = 0; i < endAddress - unusedArea; ++i)
117 DCHECK(!unusedArea[i]);
118 }
119 #endif
120 };
121
122 template <bool canInitializeWithMemset, typename T>
123 struct VectorInitializer;
124
125 template <typename T>
126 struct VectorInitializer<false, T> {
127 STATIC_ONLY(VectorInitializer);
128 static void initialize(T* begin, T* end) {
129 for (T* cur = begin; cur != end; ++cur)
130 new (NotNull, cur) T;
131 }
132 };
133
134 template <typename T>
135 struct VectorInitializer<true, T> {
136 STATIC_ONLY(VectorInitializer);
137 static void initialize(T* begin, T* end) {
138 memset(begin, 0,
139 reinterpret_cast<char*>(end) - reinterpret_cast<char*>(begin));
140 }
141 };
142
143 template <bool canMoveWithMemcpy, typename T>
144 struct VectorMover;
145
146 template <typename T>
147 struct VectorMover<false, T> {
148 STATIC_ONLY(VectorMover);
149 static void move(T* src, T* srcEnd, T* dst) {
150 while (src != srcEnd) {
151 new (NotNull, dst) T(std::move(*src));
152 src->~T();
153 ++dst;
154 ++src;
155 }
156 }
157 static void moveOverlapping(T* src, T* srcEnd, T* dst) {
158 if (src > dst) {
159 move(src, srcEnd, dst);
160 } else {
161 T* dstEnd = dst + (srcEnd - src);
162 while (src != srcEnd) {
163 --srcEnd;
164 --dstEnd;
165 new (NotNull, dstEnd) T(std::move(*srcEnd));
166 srcEnd->~T();
167 }
168 }
169 }
170 static void swap(T* src, T* srcEnd, T* dst) {
171 std::swap_ranges(src, srcEnd, dst);
172 }
173 };
174
175 template <typename T>
176 struct VectorMover<true, T> {
177 STATIC_ONLY(VectorMover);
178 static void move(const T* src, const T* srcEnd, T* dst) {
179 if (LIKELY(dst && src))
180 memcpy(dst, src, reinterpret_cast<const char*>(srcEnd) -
181 reinterpret_cast<const char*>(src));
182 }
183 static void moveOverlapping(const T* src, const T* srcEnd, T* dst) {
184 if (LIKELY(dst && src))
185 memmove(dst, src, reinterpret_cast<const char*>(srcEnd) -
186 reinterpret_cast<const char*>(src));
187 }
188 static void swap(T* src, T* srcEnd, T* dst) {
189 std::swap_ranges(reinterpret_cast<char*>(src),
190 reinterpret_cast<char*>(srcEnd),
191 reinterpret_cast<char*>(dst));
192 }
193 };
194
195 template <bool canCopyWithMemcpy, typename T>
196 struct VectorCopier;
197
198 template <typename T>
199 struct VectorCopier<false, T> {
200 STATIC_ONLY(VectorCopier);
201 template <typename U>
202 static void uninitializedCopy(const U* src, const U* srcEnd, T* dst) {
203 while (src != srcEnd) {
204 new (NotNull, dst) T(*src);
205 ++dst;
206 ++src;
207 }
208 }
209 };
210
211 template <typename T>
212 struct VectorCopier<true, T> {
213 STATIC_ONLY(VectorCopier);
214 static void uninitializedCopy(const T* src, const T* srcEnd, T* dst) {
215 if (LIKELY(dst && src))
216 memcpy(dst, src, reinterpret_cast<const char*>(srcEnd) -
217 reinterpret_cast<const char*>(src));
218 }
219 template <typename U>
220 static void uninitializedCopy(const U* src, const U* srcEnd, T* dst) {
221 VectorCopier<false, T>::uninitializedCopy(src, srcEnd, dst);
222 }
223 };
224
225 template <bool canFillWithMemset, typename T>
226 struct VectorFiller;
227
228 template <typename T>
229 struct VectorFiller<false, T> {
230 STATIC_ONLY(VectorFiller);
231 static void uninitializedFill(T* dst, T* dstEnd, const T& val) {
232 while (dst != dstEnd) {
233 new (NotNull, dst) T(val);
234 ++dst;
235 }
236 }
237 };
238
239 template <typename T>
240 struct VectorFiller<true, T> {
241 STATIC_ONLY(VectorFiller);
242 static void uninitializedFill(T* dst, T* dstEnd, const T& val) {
243 static_assert(sizeof(T) == sizeof(char), "size of type should be one");
244 #if COMPILER(GCC) && defined(_FORTIFY_SOURCE)
245 if (!__builtin_constant_p(dstEnd - dst) || (!(dstEnd - dst)))
246 memset(dst, val, dstEnd - dst);
247 #else
248 memset(dst, val, dstEnd - dst);
249 #endif
250 }
251 };
252
253 template <bool canCompareWithMemcmp, typename T>
254 struct VectorComparer;
255
256 template <typename T>
257 struct VectorComparer<false, T> {
258 STATIC_ONLY(VectorComparer);
259 static bool compare(const T* a, const T* b, size_t size) {
260 DCHECK(a);
261 DCHECK(b);
262 return std::equal(a, a + size, b);
263 }
264 };
265
266 template <typename T>
267 struct VectorComparer<true, T> {
268 STATIC_ONLY(VectorComparer);
269 static bool compare(const T* a, const T* b, size_t size) {
270 DCHECK(a);
271 DCHECK(b);
272 return memcmp(a, b, sizeof(T) * size) == 0;
273 }
274 };
275
276 template <typename T>
277 struct VectorElementComparer {
278 STATIC_ONLY(VectorElementComparer);
279 template <typename U>
280 static bool compareElement(const T& left, const U& right) {
281 return left == right;
282 }
283 };
284
285 template <typename T>
286 struct VectorElementComparer<std::unique_ptr<T>> {
287 STATIC_ONLY(VectorElementComparer);
288 template <typename U>
289 static bool compareElement(const std::unique_ptr<T>& left, const U& right) {
290 return left.get() == right;
291 }
292 };
293
294 // A collection of all the traits used by Vector. This is basically an
295 // implementation detail of Vector, and you probably don't want to change this.
296 // If you want to customize Vector's behavior, you should specialize
297 // VectorTraits instead (defined in VectorTraits.h).
298 template <typename T>
299 struct VectorTypeOperations {
300 STATIC_ONLY(VectorTypeOperations);
301 static void destruct(T* begin, T* end) {
302 VectorDestructor<VectorTraits<T>::needsDestruction, T>::destruct(begin,
303 end);
304 }
305
306 static void initialize(T* begin, T* end) {
307 VectorInitializer<VectorTraits<T>::canInitializeWithMemset, T>::initialize(
308 begin, end);
309 }
310
311 static void move(T* src, T* srcEnd, T* dst) {
312 VectorMover<VectorTraits<T>::canMoveWithMemcpy, T>::move(src, srcEnd, dst);
313 }
314
315 static void moveOverlapping(T* src, T* srcEnd, T* dst) {
316 VectorMover<VectorTraits<T>::canMoveWithMemcpy, T>::moveOverlapping(
317 src, srcEnd, dst);
318 }
319
320 static void swap(T* src, T* srcEnd, T* dst) {
321 VectorMover<VectorTraits<T>::canMoveWithMemcpy, T>::swap(src, srcEnd, dst);
322 }
323
324 static void uninitializedCopy(const T* src, const T* srcEnd, T* dst) {
325 VectorCopier<VectorTraits<T>::canCopyWithMemcpy, T>::uninitializedCopy(
326 src, srcEnd, dst);
327 }
328
329 static void uninitializedFill(T* dst, T* dstEnd, const T& val) {
330 VectorFiller<VectorTraits<T>::canFillWithMemset, T>::uninitializedFill(
331 dst, dstEnd, val);
332 }
333
334 static bool compare(const T* a, const T* b, size_t size) {
335 return VectorComparer<VectorTraits<T>::canCompareWithMemcmp, T>::compare(
336 a, b, size);
337 }
338
339 template <typename U>
340 static bool compareElement(const T& left, U&& right) {
341 return VectorElementComparer<T>::compareElement(left,
342 std::forward<U>(right));
343 }
344 };
345
346 //
347 // VectorBuffer
348 //
349
350 // VectorBuffer is an implementation detail of Vector and Deque. It manages
351 // Vector's underlying buffer, and does operations like allocation or
352 // expansion.
353 //
354 // Not meant for general consumption.
355
356 template <typename T, bool hasInlineCapacity, typename Allocator>
357 class VectorBufferBase {
358 WTF_MAKE_NONCOPYABLE(VectorBufferBase);
359 DISALLOW_NEW();
360
361 public:
362 void allocateBuffer(size_t newCapacity) {
363 DCHECK(newCapacity);
364 DCHECK_LE(newCapacity,
365 Allocator::template maxElementCountInBackingStore<T>());
366 size_t sizeToAllocate = allocationSize(newCapacity);
367 if (hasInlineCapacity)
368 m_buffer =
369 Allocator::template allocateInlineVectorBacking<T>(sizeToAllocate);
370 else
371 m_buffer = Allocator::template allocateVectorBacking<T>(sizeToAllocate);
372 m_capacity = sizeToAllocate / sizeof(T);
373 }
374
375 void allocateExpandedBuffer(size_t newCapacity) {
376 DCHECK(newCapacity);
377 size_t sizeToAllocate = allocationSize(newCapacity);
378 if (hasInlineCapacity)
379 m_buffer =
380 Allocator::template allocateInlineVectorBacking<T>(sizeToAllocate);
381 else
382 m_buffer =
383 Allocator::template allocateExpandedVectorBacking<T>(sizeToAllocate);
384 m_capacity = sizeToAllocate / sizeof(T);
385 }
386
387 size_t allocationSize(size_t capacity) const {
388 return Allocator::template quantizedSize<T>(capacity);
389 }
390
391 T* buffer() { return m_buffer; }
392 const T* buffer() const { return m_buffer; }
393 size_t capacity() const { return m_capacity; }
394
395 void clearUnusedSlots(T* from, T* to) {
396 // If the vector backing is garbage-collected and needs tracing or
397 // finalizing, we clear out the unused slots so that the visitor or the
398 // finalizer does not cause a problem when visiting the unused slots.
399 VectorUnusedSlotClearer<
400 Allocator::isGarbageCollected &&
401 (VectorTraits<T>::needsDestruction ||
402 IsTraceableInCollectionTrait<VectorTraits<T>>::value),
403 T>::clear(from, to);
404 }
405
406 void checkUnusedSlots(const T* from, const T* to) {
407 #if DCHECK_IS_ON() && !defined(ANNOTATE_CONTIGUOUS_CONTAINER)
408 VectorUnusedSlotClearer<
409 Allocator::isGarbageCollected &&
410 (VectorTraits<T>::needsDestruction ||
411 IsTraceableInCollectionTrait<VectorTraits<T>>::value),
412 T>::checkCleared(from, to);
413 #endif
414 }
415
416 // |end| is exclusive, a la STL.
417 struct OffsetRange final {
418 OffsetRange() : begin(0), end(0) {}
419 explicit OffsetRange(size_t begin, size_t end) : begin(begin), end(end) {
420 DCHECK_LE(begin, end);
421 }
422 bool empty() const { return begin == end; }
423 size_t begin;
424 size_t end;
425 };
426
427 protected:
428 VectorBufferBase() : m_buffer(nullptr), m_capacity(0) {}
429
430 VectorBufferBase(T* buffer, size_t capacity)
431 : m_buffer(buffer), m_capacity(capacity) {}
432
433 T* m_buffer;
434 unsigned m_capacity;
435 unsigned m_size;
436 };
437
438 template <typename T,
439 size_t inlineCapacity,
440 typename Allocator = PartitionAllocator>
441 class VectorBuffer;
442
443 template <typename T, typename Allocator>
444 class VectorBuffer<T, 0, Allocator>
445 : protected VectorBufferBase<T, false, Allocator> {
446 private:
447 using Base = VectorBufferBase<T, false, Allocator>;
448
449 public:
450 using OffsetRange = typename Base::OffsetRange;
451
452 VectorBuffer() {}
453
454 explicit VectorBuffer(size_t capacity) {
455 // Calling malloc(0) might take a lock and may actually do an allocation
456 // on some systems.
457 if (capacity)
458 allocateBuffer(capacity);
459 }
460
461 void destruct() {
462 deallocateBuffer(m_buffer);
463 m_buffer = nullptr;
464 }
465
466 void deallocateBuffer(T* bufferToDeallocate) {
467 Allocator::freeVectorBacking(bufferToDeallocate);
468 }
469
470 bool expandBuffer(size_t newCapacity) {
471 size_t sizeToAllocate = allocationSize(newCapacity);
472 if (Allocator::expandVectorBacking(m_buffer, sizeToAllocate)) {
473 m_capacity = sizeToAllocate / sizeof(T);
474 return true;
475 }
476 return false;
477 }
478
479 inline bool shrinkBuffer(size_t newCapacity) {
480 DCHECK_LT(newCapacity, capacity());
481 size_t sizeToAllocate = allocationSize(newCapacity);
482 if (Allocator::shrinkVectorBacking(m_buffer, allocationSize(capacity()),
483 sizeToAllocate)) {
484 m_capacity = sizeToAllocate / sizeof(T);
485 return true;
486 }
487 return false;
488 }
489
490 void resetBufferPointer() {
491 m_buffer = nullptr;
492 m_capacity = 0;
493 }
494
495 // See the other specialization for the meaning of |thisHole| and |otherHole|.
496 // They are irrelevant in this case.
497 void swapVectorBuffer(VectorBuffer<T, 0, Allocator>& other,
498 OffsetRange thisHole,
499 OffsetRange otherHole) {
500 static_assert(VectorTraits<T>::canSwapUsingCopyOrMove,
501 "Cannot swap HeapVectors of TraceWrapperMembers.");
502
503 std::swap(m_buffer, other.m_buffer);
504 std::swap(m_capacity, other.m_capacity);
505 std::swap(m_size, other.m_size);
506 }
507
508 using Base::allocateBuffer;
509 using Base::allocationSize;
510
511 using Base::buffer;
512 using Base::capacity;
513
514 using Base::clearUnusedSlots;
515 using Base::checkUnusedSlots;
516
517 bool hasOutOfLineBuffer() const {
518 // When inlineCapacity is 0 we have an out of line buffer if we have a
519 // buffer.
520 return buffer();
521 }
522
523 T** bufferSlot() { return &m_buffer; }
524
525 protected:
526 using Base::m_size;
527
528 private:
529 using Base::m_buffer;
530 using Base::m_capacity;
531 };
532
533 template <typename T, size_t inlineCapacity, typename Allocator>
534 class VectorBuffer : protected VectorBufferBase<T, true, Allocator> {
535 WTF_MAKE_NONCOPYABLE(VectorBuffer);
536
537 private:
538 using Base = VectorBufferBase<T, true, Allocator>;
539
540 public:
541 using OffsetRange = typename Base::OffsetRange;
542
543 VectorBuffer() : Base(inlineBuffer(), inlineCapacity) {}
544
545 explicit VectorBuffer(size_t capacity)
546 : Base(inlineBuffer(), inlineCapacity) {
547 if (capacity > inlineCapacity)
548 Base::allocateBuffer(capacity);
549 }
550
551 void destruct() {
552 deallocateBuffer(m_buffer);
553 m_buffer = nullptr;
554 }
555
556 NEVER_INLINE void reallyDeallocateBuffer(T* bufferToDeallocate) {
557 Allocator::freeInlineVectorBacking(bufferToDeallocate);
558 }
559
560 void deallocateBuffer(T* bufferToDeallocate) {
561 if (UNLIKELY(bufferToDeallocate != inlineBuffer()))
562 reallyDeallocateBuffer(bufferToDeallocate);
563 }
564
565 bool expandBuffer(size_t newCapacity) {
566 DCHECK_GT(newCapacity, inlineCapacity);
567 if (m_buffer == inlineBuffer())
568 return false;
569
570 size_t sizeToAllocate = allocationSize(newCapacity);
571 if (Allocator::expandInlineVectorBacking(m_buffer, sizeToAllocate)) {
572 m_capacity = sizeToAllocate / sizeof(T);
573 return true;
574 }
575 return false;
576 }
577
578 inline bool shrinkBuffer(size_t newCapacity) {
579 DCHECK_LT(newCapacity, capacity());
580 if (newCapacity <= inlineCapacity) {
581 // We need to switch to inlineBuffer. Vector::shrinkCapacity will
582 // handle it.
583 return false;
584 }
585 DCHECK_NE(m_buffer, inlineBuffer());
586 size_t newSize = allocationSize(newCapacity);
587 if (!Allocator::shrinkInlineVectorBacking(
588 m_buffer, allocationSize(capacity()), newSize))
589 return false;
590 m_capacity = newSize / sizeof(T);
591 return true;
592 }
593
594 void resetBufferPointer() {
595 m_buffer = inlineBuffer();
596 m_capacity = inlineCapacity;
597 }
598
599 void allocateBuffer(size_t newCapacity) {
600 // FIXME: This should DCHECK(!m_buffer) to catch misuse/leaks.
601 if (newCapacity > inlineCapacity)
602 Base::allocateBuffer(newCapacity);
603 else
604 resetBufferPointer();
605 }
606
607 void allocateExpandedBuffer(size_t newCapacity) {
608 if (newCapacity > inlineCapacity)
609 Base::allocateExpandedBuffer(newCapacity);
610 else
611 resetBufferPointer();
612 }
613
614 size_t allocationSize(size_t capacity) const {
615 if (capacity <= inlineCapacity)
616 return m_inlineBufferSize;
617 return Base::allocationSize(capacity);
618 }
619
620 // Swap two vector buffers, both of which have the same non-zero inline
621 // capacity.
622 //
623 // If the data is in an out-of-line buffer, we can just pass the pointers
624 // across the two buffers. If the data is in an inline buffer, we need to
625 // either swap or move each element, depending on whether each slot is
626 // occupied or not.
627 //
628 // Further complication comes from the fact that VectorBuffer is also used as
629 // the backing store of a Deque. Deque allocates the objects like a ring
630 // buffer, so there may be a "hole" (unallocated region) in the middle of the
631 // buffer. This function assumes elements in a range [m_buffer, m_buffer +
632 // m_size) are all allocated except for elements within |thisHole|. The same
633 // applies for |other.m_buffer| and |otherHole|.
634 void swapVectorBuffer(VectorBuffer<T, inlineCapacity, Allocator>& other,
635 OffsetRange thisHole,
636 OffsetRange otherHole) {
637 using TypeOperations = VectorTypeOperations<T>;
638
639 static_assert(VectorTraits<T>::canSwapUsingCopyOrMove,
640 "Cannot swap HeapVectors of TraceWrapperMembers.");
641
642 if (buffer() != inlineBuffer() && other.buffer() != other.inlineBuffer()) {
643 // The easiest case: both buffers are non-inline. We just need to swap the
644 // pointers.
645 std::swap(m_buffer, other.m_buffer);
646 std::swap(m_capacity, other.m_capacity);
647 std::swap(m_size, other.m_size);
648 return;
649 }
650
651 Allocator::enterGCForbiddenScope();
652
653 // Otherwise, we at least need to move some elements from one inline buffer
654 // to another.
655 //
656 // Terminology: "source" is a place from which elements are copied, and
657 // "destination" is a place to which elements are copied. thisSource or
658 // otherSource can be empty (represented by nullptr) when this range or
659 // other range is in an out-of-line buffer.
660 //
661 // We first record which range needs to get moved and where elements in such
662 // a range will go. Elements in an inline buffer will go to the other
663 // buffer's inline buffer. Elements in an out-of-line buffer won't move,
664 // because we can just swap pointers of out-of-line buffers.
665 T* thisSourceBegin = nullptr;
666 size_t thisSourceSize = 0;
667 T* thisDestinationBegin = nullptr;
668 if (buffer() == inlineBuffer()) {
669 thisSourceBegin = buffer();
670 thisSourceSize = m_size;
671 thisDestinationBegin = other.inlineBuffer();
672 if (!thisHole.empty()) { // Sanity check.
673 DCHECK_LT(thisHole.begin, thisHole.end);
674 DCHECK_LE(thisHole.end, thisSourceSize);
675 }
676 } else {
677 // We don't need the hole information for an out-of-line buffer.
678 thisHole.begin = thisHole.end = 0;
679 }
680 T* otherSourceBegin = nullptr;
681 size_t otherSourceSize = 0;
682 T* otherDestinationBegin = nullptr;
683 if (other.buffer() == other.inlineBuffer()) {
684 otherSourceBegin = other.buffer();
685 otherSourceSize = other.m_size;
686 otherDestinationBegin = inlineBuffer();
687 if (!otherHole.empty()) {
688 DCHECK_LT(otherHole.begin, otherHole.end);
689 DCHECK_LE(otherHole.end, otherSourceSize);
690 }
691 } else {
692 otherHole.begin = otherHole.end = 0;
693 }
694
695 // Next, we mutate members and do other bookkeeping. We do pointer swapping
696 // (for out-of-line buffers) here if we can. From now on, don't assume
697 // buffer() or capacity() maintains their original values.
698 std::swap(m_capacity, other.m_capacity);
699 if (thisSourceBegin &&
700 !otherSourceBegin) { // Our buffer is inline, theirs is not.
701 DCHECK_EQ(buffer(), inlineBuffer());
702 DCHECK_NE(other.buffer(), other.inlineBuffer());
703 ANNOTATE_DELETE_BUFFER(m_buffer, inlineCapacity, m_size);
704 m_buffer = other.buffer();
705 other.m_buffer = other.inlineBuffer();
706 std::swap(m_size, other.m_size);
707 ANNOTATE_NEW_BUFFER(other.m_buffer, inlineCapacity, other.m_size);
708 } else if (!thisSourceBegin &&
709 otherSourceBegin) { // Their buffer is inline, ours is not.
710 DCHECK_NE(buffer(), inlineBuffer());
711 DCHECK_EQ(other.buffer(), other.inlineBuffer());
712 ANNOTATE_DELETE_BUFFER(other.m_buffer, inlineCapacity, other.m_size);
713 other.m_buffer = buffer();
714 m_buffer = inlineBuffer();
715 std::swap(m_size, other.m_size);
716 ANNOTATE_NEW_BUFFER(m_buffer, inlineCapacity, m_size);
717 } else { // Both buffers are inline.
718 DCHECK(thisSourceBegin);
719 DCHECK(otherSourceBegin);
720 DCHECK_EQ(buffer(), inlineBuffer());
721 DCHECK_EQ(other.buffer(), other.inlineBuffer());
722 ANNOTATE_CHANGE_SIZE(m_buffer, inlineCapacity, m_size, other.m_size);
723 ANNOTATE_CHANGE_SIZE(other.m_buffer, inlineCapacity, other.m_size,
724 m_size);
725 std::swap(m_size, other.m_size);
726 }
727
728 // We are ready to move elements. We determine an action for each "section",
729 // which is a contiguous range such that all elements in the range are
730 // treated similarly.
731 size_t sectionBegin = 0;
732 while (sectionBegin < inlineCapacity) {
733 // To determine the end of this section, we list up all the boundaries
734 // where the "occupiedness" may change.
735 size_t sectionEnd = inlineCapacity;
736 if (thisSourceBegin && sectionBegin < thisSourceSize)
737 sectionEnd = std::min(sectionEnd, thisSourceSize);
738 if (!thisHole.empty() && sectionBegin < thisHole.begin)
739 sectionEnd = std::min(sectionEnd, thisHole.begin);
740 if (!thisHole.empty() && sectionBegin < thisHole.end)
741 sectionEnd = std::min(sectionEnd, thisHole.end);
742 if (otherSourceBegin && sectionBegin < otherSourceSize)
743 sectionEnd = std::min(sectionEnd, otherSourceSize);
744 if (!otherHole.empty() && sectionBegin < otherHole.begin)
745 sectionEnd = std::min(sectionEnd, otherHole.begin);
746 if (!otherHole.empty() && sectionBegin < otherHole.end)
747 sectionEnd = std::min(sectionEnd, otherHole.end);
748
749 DCHECK_LT(sectionBegin, sectionEnd);
750
751 // Is the |sectionBegin|-th element of |thisSource| occupied?
752 bool thisOccupied = false;
753 if (thisSourceBegin && sectionBegin < thisSourceSize) {
754 // Yes, it's occupied, unless the position is in a hole.
755 if (thisHole.empty() || sectionBegin < thisHole.begin ||
756 sectionBegin >= thisHole.end)
757 thisOccupied = true;
758 }
759 bool otherOccupied = false;
760 if (otherSourceBegin && sectionBegin < otherSourceSize) {
761 if (otherHole.empty() || sectionBegin < otherHole.begin ||
762 sectionBegin >= otherHole.end)
763 otherOccupied = true;
764 }
765
766 if (thisOccupied && otherOccupied) {
767 // Both occupied; swap them. In this case, one's destination must be the
768 // other's source (i.e. both ranges are in inline buffers).
769 DCHECK_EQ(thisDestinationBegin, otherSourceBegin);
770 DCHECK_EQ(otherDestinationBegin, thisSourceBegin);
771 TypeOperations::swap(thisSourceBegin + sectionBegin,
772 thisSourceBegin + sectionEnd,
773 otherSourceBegin + sectionBegin);
774 } else if (thisOccupied) {
775 // Move from ours to theirs.
776 TypeOperations::move(thisSourceBegin + sectionBegin,
777 thisSourceBegin + sectionEnd,
778 thisDestinationBegin + sectionBegin);
779 Base::clearUnusedSlots(thisSourceBegin + sectionBegin,
780 thisSourceBegin + sectionEnd);
781 } else if (otherOccupied) {
782 // Move from theirs to ours.
783 TypeOperations::move(otherSourceBegin + sectionBegin,
784 otherSourceBegin + sectionEnd,
785 otherDestinationBegin + sectionBegin);
786 Base::clearUnusedSlots(otherSourceBegin + sectionBegin,
787 otherSourceBegin + sectionEnd);
788 } else {
789 // Both empty; nothing to do.
790 }
791
792 sectionBegin = sectionEnd;
793 }
794
795 Allocator::leaveGCForbiddenScope();
796 }
797
798 using Base::buffer;
799 using Base::capacity;
800
801 bool hasOutOfLineBuffer() const {
802 return buffer() && buffer() != inlineBuffer();
803 }
804
805 T** bufferSlot() { return &m_buffer; }
806
807 protected:
808 using Base::m_size;
809
810 private:
811 using Base::m_buffer;
812 using Base::m_capacity;
813
814 static const size_t m_inlineBufferSize = inlineCapacity * sizeof(T);
815 T* inlineBuffer() { return reinterpret_cast_ptr<T*>(m_inlineBuffer.buffer); }
816 const T* inlineBuffer() const {
817 return reinterpret_cast_ptr<const T*>(m_inlineBuffer.buffer);
818 }
819
820 AlignedBuffer<m_inlineBufferSize, WTF_ALIGN_OF(T)> m_inlineBuffer;
821 template <typename U, size_t inlineBuffer, typename V>
822 friend class Deque;
823 };
824
825 //
826 // Vector
827 //
828
829 // Vector is a container that works just like std::vector. WTF's Vector has
830 // several extra functionalities: inline buffer, behavior customization via
831 // traits, and Oilpan support. Those are explained in the sections below.
832 //
833 // Vector is the most basic container, which stores its element in a contiguous
834 // buffer. The buffer is expanded automatically when necessary. The elements
835 // are automatically moved to the new buffer. This event is called a
836 // reallocation. A reallocation takes O(N)-time (N = number of elements), but
837 // its occurrences are rare, so its time cost should not be significant,
838 // compared to the time cost of other operations to the vector.
839 //
840 // Time complexity of key operations is as follows:
841 //
842 // * Indexed access -- O(1)
843 // * Insertion or removal of an element at the end -- amortized O(1)
844 // * Other insertion or removal -- O(N)
845 // * Swapping with another vector -- O(1)
846 //
847 // 1. Iterator invalidation semantics
848 //
849 // Vector provides STL-compatible iterators and reverse iterators. Iterators
850 // are _invalidated_ on certain occasions. Reading an invalidated iterator
851 // causes undefined behavior.
852 //
853 // Iterators are invalidated on the following situations:
854 //
855 // * When a reallocation happens on a vector, all the iterators for that
856 // vector will be invalidated.
857 // * Some member functions invalidate part of the existing iterators for
858 // the vector; see comments on the individual functions.
859 // * [Oilpan only] Heap compaction invalidates all the iterators for any
860 // HeapVectors. This means you can only store an iterator on stack, as
861 // a local variable.
862 //
863 // In this context, pointers or references to an element of a Vector are
864 // essentially equivalent to iterators, in that they also become invalid
865 // whenever corresponding iterators are invalidated.
866 //
867 // 2. Inline buffer
868 //
869 // Vectors may have an _inline buffer_. An inline buffer is a storage area
870 // that is contained in the vector itself, along with other metadata like
871 // m_size. It is used as a storage space when the vector's elements fit in
872 // that space. If the inline buffer becomes full and further space is
873 // necessary, an out-of-line buffer is allocated in the heap, and it will
874 // take over the role of the inline buffer.
875 //
876 // The existence of an inline buffer is indicated by non-zero |inlineCapacity|
877 // template argument. The value represents the number of elements that can be
878 // stored in the inline buffer. Zero |inlineCapacity| means the vector has no
879 // inline buffer.
880 //
881 // An inline buffer increases the size of the Vector instances, and, in trade
882 // for that, it gives you several performance benefits, as long as the number
883 // of elements do not exceed |inlineCapacity|:
884 //
885 // * No heap allocation will be made.
886 // * Memory locality will improve.
887 //
888 // Generally, having an inline buffer is useful for vectors that (1) are
889 // frequently accessed or modified, and (2) contain only a few elements at
890 // most.
891 //
892 // 3. Behavior customization
893 //
894 // You usually do not need to customize Vector's behavior, since the default
895 // behavior is appropriate for normal usage. The behavior is controlled by
896 // VectorTypeOperations traits template above. Read VectorTypeOperations
897 // and VectorTraits if you want to change the behavior for your types (i.e.
898 // if you really want faster vector operations).
899 //
900 // The default traits basically do the following:
901 //
902 // * Skip constructor call and fill zeros with memset for simple types;
903 // * Skip destructor call for simple types;
904 // * Copy or move by memcpy for simple types; and
905 // * Customize the comparisons for smart pointer types, so you can look
906 // up a std::unique_ptr<T> element with a raw pointer, for instance.
907 //
908 // 4. Oilpan
909 //
910 // If you want to store garbage collected objects in Vector, (1) use HeapVector
911 // (defined in HeapAllocator.h) instead of Vector, and (2) make sure your
912 // garbage-collected type is wrapped with Member, like:
913 //
914 // HeapVector<Member<Node>> nodes;
915 //
916 // Unlike normal garbage-collected objects, a HeapVector object itself is
917 // NOT a garbage-collected object, but its backing buffer is allocated in
918 // Oilpan heap, and it may still carry garbage-collected objects.
919 //
920 // Even though a HeapVector object is not garbage-collected, you still need
921 // to trace it, if you stored it in your class. Also, you can allocate it
922 // as a local variable. This is useful when you want to build a vector locally
923 // and put it in an on-heap vector with swap().
924 //
925 // Also, heap compaction, which may happen at any time when Blink code is not
926 // running (i.e. Blink code does not appear in the call stack), may invalidate
927 // existing iterators for any HeapVectors. So, essentially, you should always
928 // allocate an iterator on stack (as a local variable), and you should not
929 // store iterators in another heap object.
930
931 template <typename T,
932 size_t inlineCapacity = 0,
933 typename Allocator = PartitionAllocator>
934 class Vector
935 : private VectorBuffer<T, INLINE_CAPACITY, Allocator>,
936 // Heap-allocated vectors with no inlineCapacity never need a destructor.
937 public ConditionalDestructor<Vector<T, INLINE_CAPACITY, Allocator>,
938 (INLINE_CAPACITY == 0) &&
939 Allocator::isGarbageCollected> {
940 USE_ALLOCATOR(Vector, Allocator);
941 using Base = VectorBuffer<T, INLINE_CAPACITY, Allocator>;
942 using TypeOperations = VectorTypeOperations<T>;
943 using OffsetRange = typename Base::OffsetRange;
944
945 public:
946 using ValueType = T;
947 using value_type = T;
948
949 using iterator = T*;
950 using const_iterator = const T*;
951 using reverse_iterator = std::reverse_iterator<iterator>;
952 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
953
954 // Create an empty vector.
955 inline Vector();
956 // Create a vector containing the specified number of default-initialized
957 // elements.
958 inline explicit Vector(size_t);
959 // Create a vector containing the specified number of elements, each of which
960 // is copy initialized from the specified value.
961 inline Vector(size_t, const T&);
962
963 // Copying.
964 Vector(const Vector&);
965 template <size_t otherCapacity>
966 explicit Vector(const Vector<T, otherCapacity, Allocator>&);
967
968 Vector& operator=(const Vector&);
969 template <size_t otherCapacity>
970 Vector& operator=(const Vector<T, otherCapacity, Allocator>&);
971
972 // Moving.
973 Vector(Vector&&);
974 Vector& operator=(Vector&&);
975
976 // Construct with an initializer list. You can do e.g.
977 // Vector<int> v({1, 2, 3});
978 // or
979 // v = {4, 5, 6};
980 Vector(std::initializer_list<T> elements);
981 Vector& operator=(std::initializer_list<T> elements);
982
983 // Basic inquiry about the vector's state.
984 //
985 // capacity() is the maximum number of elements that the Vector can hold
986 // without a reallocation. It can be zero.
987 size_t size() const { return m_size; }
988 size_t capacity() const { return Base::capacity(); }
989 bool isEmpty() const { return !size(); }
990
991 // at() and operator[]: Obtain the reference of the element that is located
992 // at the given index. The reference may be invalidated on a reallocation.
993 //
994 // at() can be used in cases like:
995 // pointerToVector->at(1);
996 // instead of:
997 // (*pointerToVector)[1];
998 T& at(size_t i) {
999 RELEASE_ASSERT(i < size());
1000 return Base::buffer()[i];
1001 }
1002 const T& at(size_t i) const {
1003 RELEASE_ASSERT(i < size());
1004 return Base::buffer()[i];
1005 }
1006
1007 T& operator[](size_t i) { return at(i); }
1008 const T& operator[](size_t i) const { return at(i); }
1009
1010 // Return a pointer to the front of the backing buffer. Those pointers get
1011 // invalidated on a reallocation.
1012 T* data() { return Base::buffer(); }
1013 const T* data() const { return Base::buffer(); }
1014
1015 // Iterators and reverse iterators. They are invalidated on a reallocation.
1016 iterator begin() { return data(); }
1017 iterator end() { return begin() + m_size; }
1018 const_iterator begin() const { return data(); }
1019 const_iterator end() const { return begin() + m_size; }
1020
1021 reverse_iterator rbegin() { return reverse_iterator(end()); }
1022 reverse_iterator rend() { return reverse_iterator(begin()); }
1023 const_reverse_iterator rbegin() const {
1024 return const_reverse_iterator(end());
1025 }
1026 const_reverse_iterator rend() const {
1027 return const_reverse_iterator(begin());
1028 }
1029
1030 // Quick access to the first and the last element. It is invalid to call
1031 // these functions when the vector is empty.
1032 T& front() { return at(0); }
1033 const T& front() const { return at(0); }
1034 T& back() { return at(size() - 1); }
1035 const T& back() const { return at(size() - 1); }
1036
1037 // Searching.
1038 //
1039 // Comparisons are done in terms of compareElement(), which is usually
1040 // operator==(). find() and reverseFind() returns an index of the element
1041 // that is found first. If no match is found, kNotFound will be returned.
1042 template <typename U>
1043 bool contains(const U&) const;
1044 template <typename U>
1045 size_t find(const U&) const;
1046 template <typename U>
1047 size_t reverseFind(const U&) const;
1048
1049 // Resize the vector to the specified size.
1050 //
1051 // These three functions are essentially similar. They differ in that
1052 // (1) shrink() has a DCHECK to make sure the specified size is not more than
1053 // size(), and (2) grow() has a DCHECK to make sure the specified size is
1054 // not less than size().
1055 //
1056 // When a vector shrinks, the extra elements in the back will be destructed.
1057 // All the iterators pointing to a to-be-destructed element will be
1058 // invalidated.
1059 //
1060 // When a vector grows, new elements will be added in the back, and they
1061 // will be default-initialized. A reallocation may happen in this case.
1062 void shrink(size_t);
1063 void grow(size_t);
1064 void resize(size_t);
1065
1066 // Increase the capacity of the vector to at least |newCapacity|. The
1067 // elements in the vector are not affected. This function does not shrink
1068 // the size of the backing buffer, even if |newCapacity| is small. This
1069 // function may cause a reallocation.
1070 void reserveCapacity(size_t newCapacity);
1071
1072 // This is similar to reserveCapacity() but must be called immediately after
1073 // the vector is default-constructed.
1074 void reserveInitialCapacity(size_t initialCapacity);
1075
1076 // Shrink the backing buffer so it can contain exactly |size()| elements.
1077 // This function may cause a reallocation.
1078 void shrinkToFit() { shrinkCapacity(size()); }
1079
1080 // Shrink the backing buffer if at least 50% of the vector's capacity is
1081 // unused. If it shrinks, the new buffer contains roughly 25% of unused
1082 // space. This function may cause a reallocation.
1083 void shrinkToReasonableCapacity() {
1084 if (size() * 2 < capacity())
1085 shrinkCapacity(size() + size() / 4 + 1);
1086 }
1087
1088 // Remove all the elements. This function actually releases the backing
1089 // buffer, thus any iterators will get invalidated (including begin()).
1090 void clear() { shrinkCapacity(0); }
1091
1092 // Insertion to the back. All of these functions except uncheckedAppend() may
1093 // cause a reallocation.
1094 //
1095 // push_back(value)
1096 // Insert a single element to the back.
1097 // emplace_back(args...)
1098 // Insert a single element constructed as T(args...) to the back. The
1099 // element is constructed directly on the backing buffer with placement
1100 // new.
1101 // append(buffer, size)
1102 // appendVector(vector)
1103 // appendRange(begin, end)
1104 // Insert multiple elements represented by (1) |buffer| and |size|
1105 // (for append), (2) |vector| (for appendVector), or (3) a pair of
1106 // iterators (for appendRange) to the back. The elements will be copied.
1107 // uncheckedAppend(value)
1108 // Insert a single element like push_back(), but this function assumes
1109 // the vector has enough capacity such that it can store the new element
1110 // without a reallocation. Using this function could improve the
1111 // performance when you append many elements repeatedly.
1112 template <typename U>
1113 void push_back(U&&);
1114 template <typename... Args>
1115 T& emplace_back(Args&&...);
1116 ALWAYS_INLINE T& emplace_back() {
1117 grow(m_size + 1);
1118 return back();
1119 }
1120 template <typename U>
1121 void append(const U*, size_t);
1122 template <typename U, size_t otherCapacity, typename V>
1123 void appendVector(const Vector<U, otherCapacity, V>&);
1124 template <typename Iterator>
1125 void appendRange(Iterator begin, Iterator end);
1126 template <typename U>
1127 void uncheckedAppend(U&&);
1128
1129 // Insertion to an arbitrary position. All of these functions will take
1130 // O(size())-time. All of the elements after |position| will be moved to
1131 // the new locations. |position| must be no more than size(). All of these
1132 // functions may cause a reallocation. In any case, all the iterators
1133 // pointing to an element after |position| will be invalidated.
1134 //
1135 // insert(position, value)
1136 // Insert a single element at |position|.
1137 // insert(position, buffer, size)
1138 // insert(position, vector)
1139 // Insert multiple elements represented by either |buffer| and |size|
1140 // or |vector| at |position|. The elements will be copied.
1141 //
1142 // TODO(yutak): Why not insertVector()?
1143 template <typename U>
1144 void insert(size_t position, U&&);
1145 template <typename U>
1146 void insert(size_t position, const U*, size_t);
1147 template <typename U, size_t otherCapacity, typename OtherAllocator>
1148 void insert(size_t position, const Vector<U, otherCapacity, OtherAllocator>&);
1149
1150 // Insertion to the front. All of these functions will take O(size())-time.
1151 // All of the elements in the vector will be moved to the new locations.
1152 // All of these functions may cause a reallocation. In any case, all the
1153 // iterators pointing to any element in the vector will be invalidated.
1154 //
1155 // push_front(value)
1156 // Insert a single element to the front.
1157 // push_front(buffer, size)
1158 // prependVector(vector)
1159 // Insert multiple elements represented by either |buffer| and |size| or
1160 // |vector| to the front. The elements will be copied.
1161 template <typename U>
1162 void push_front(U&&);
1163 template <typename U>
1164 void push_front(const U*, size_t);
1165 template <typename U, size_t otherCapacity, typename OtherAllocator>
1166 void prependVector(const Vector<U, otherCapacity, OtherAllocator>&);
1167
1168 // Remove an element or elements at the specified position. These functions
1169 // take O(size())-time. All of the elements after the removed ones will be
1170 // moved to the new locations. All the iterators pointing to any element
1171 // after |position| will be invalidated.
1172 void remove(size_t position);
1173 void remove(size_t position, size_t length);
1174
1175 // Remove the last element. Unlike remove(), (1) this function is fast, and
1176 // (2) only iterators pointing to the last element will be invalidated. Other
1177 // references will remain valid.
1178 void pop_back() {
1179 DCHECK(!isEmpty());
1180 shrink(size() - 1);
1181 }
1182
1183 // Filling the vector with the same value. If the vector has shrinked or
1184 // growed as a result of this call, those events may invalidate some
1185 // iterators. See comments for shrink() and grow().
1186 //
1187 // fill(value, size) will resize the Vector to |size|, and then copy-assign
1188 // or copy-initialize all the elements.
1189 //
1190 // fill(value) is a synonym for fill(value, size()).
1191 void fill(const T&, size_t);
1192 void fill(const T& val) { fill(val, size()); }
1193
1194 // Swap two vectors quickly.
1195 void swap(Vector& other) {
1196 Base::swapVectorBuffer(other, OffsetRange(), OffsetRange());
1197 }
1198
1199 // Reverse the contents.
1200 void reverse();
1201
1202 // Maximum element count supported; allocating a vector
1203 // buffer with a larger count will fail.
1204 static size_t maxCapacity() {
1205 return Allocator::template maxElementCountInBackingStore<T>();
1206 }
1207
1208 // Off-GC-heap vectors: Destructor should be called.
1209 // On-GC-heap vectors: Destructor should be called for inline buffers (if
1210 // any) but destructor shouldn't be called for vector backing since it is
1211 // managed by the traced GC heap.
1212 void finalize() {
1213 if (!INLINE_CAPACITY) {
1214 if (LIKELY(!Base::buffer()))
1215 return;
1216 }
1217 ANNOTATE_DELETE_BUFFER(begin(), capacity(), m_size);
1218 if (LIKELY(m_size) &&
1219 !(Allocator::isGarbageCollected && this->hasOutOfLineBuffer())) {
1220 TypeOperations::destruct(begin(), end());
1221 m_size = 0; // Partial protection against use-after-free.
1222 }
1223
1224 Base::destruct();
1225 }
1226
1227 void finalizeGarbageCollectedObject() { finalize(); }
1228
1229 template <typename VisitorDispatcher>
1230 void trace(VisitorDispatcher);
1231
1232 class GCForbiddenScope {
1233 STACK_ALLOCATED();
1234
1235 public:
1236 GCForbiddenScope() { Allocator::enterGCForbiddenScope(); }
1237 ~GCForbiddenScope() { Allocator::leaveGCForbiddenScope(); }
1238 };
1239
1240 protected:
1241 using Base::checkUnusedSlots;
1242 using Base::clearUnusedSlots;
1243
1244 private:
1245 void expandCapacity(size_t newMinCapacity);
1246 T* expandCapacity(size_t newMinCapacity, T*);
1247 T* expandCapacity(size_t newMinCapacity, const T* data) {
1248 return expandCapacity(newMinCapacity, const_cast<T*>(data));
1249 }
1250
1251 template <typename U>
1252 U* expandCapacity(size_t newMinCapacity, U*);
1253 void shrinkCapacity(size_t newCapacity);
1254 template <typename U>
1255 void appendSlowCase(U&&);
1256
1257 using Base::m_size;
1258 using Base::buffer;
1259 using Base::swapVectorBuffer;
1260 using Base::allocateBuffer;
1261 using Base::allocationSize;
1262 };
1263
1264 //
1265 // Vector out-of-line implementation
1266 //
1267
1268 template <typename T, size_t inlineCapacity, typename Allocator>
1269 inline Vector<T, inlineCapacity, Allocator>::Vector() {
1270 static_assert(!std::is_polymorphic<T>::value ||
1271 !VectorTraits<T>::canInitializeWithMemset,
1272 "Cannot initialize with memset if there is a vtable");
1273 static_assert(Allocator::isGarbageCollected ||
1274 !AllowsOnlyPlacementNew<T>::value || !IsTraceable<T>::value,
1275 "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that "
1276 "have trace methods into an off-heap Vector");
1277 static_assert(Allocator::isGarbageCollected ||
1278 !IsPointerToGarbageCollectedType<T>::value,
1279 "Cannot put raw pointers to garbage-collected classes into "
1280 "an off-heap Vector. Use HeapVector<Member<T>> instead.");
1281
1282 ANNOTATE_NEW_BUFFER(begin(), capacity(), 0);
1283 m_size = 0;
1284 }
1285
1286 template <typename T, size_t inlineCapacity, typename Allocator>
1287 inline Vector<T, inlineCapacity, Allocator>::Vector(size_t size) : Base(size) {
1288 static_assert(!std::is_polymorphic<T>::value ||
1289 !VectorTraits<T>::canInitializeWithMemset,
1290 "Cannot initialize with memset if there is a vtable");
1291 static_assert(Allocator::isGarbageCollected ||
1292 !AllowsOnlyPlacementNew<T>::value || !IsTraceable<T>::value,
1293 "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that "
1294 "have trace methods into an off-heap Vector");
1295 static_assert(Allocator::isGarbageCollected ||
1296 !IsPointerToGarbageCollectedType<T>::value,
1297 "Cannot put raw pointers to garbage-collected classes into "
1298 "an off-heap Vector. Use HeapVector<Member<T>> instead.");
1299
1300 ANNOTATE_NEW_BUFFER(begin(), capacity(), size);
1301 m_size = size;
1302 TypeOperations::initialize(begin(), end());
1303 }
1304
1305 template <typename T, size_t inlineCapacity, typename Allocator>
1306 inline Vector<T, inlineCapacity, Allocator>::Vector(size_t size, const T& val)
1307 : Base(size) {
1308 // TODO(yutak): Introduce these assertions. Some use sites call this function
1309 // in the context where T is an incomplete type.
1310 //
1311 // static_assert(!std::is_polymorphic<T>::value ||
1312 // !VectorTraits<T>::canInitializeWithMemset,
1313 // "Cannot initialize with memset if there is a vtable");
1314 // static_assert(Allocator::isGarbageCollected ||
1315 // !AllowsOnlyPlacementNew<T>::value ||
1316 // !IsTraceable<T>::value,
1317 // "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that "
1318 // "have trace methods into an off-heap Vector");
1319 // static_assert(Allocator::isGarbageCollected ||
1320 // !IsPointerToGarbageCollectedType<T>::value,
1321 // "Cannot put raw pointers to garbage-collected classes into "
1322 // "an off-heap Vector. Use HeapVector<Member<T>> instead.");
1323
1324 ANNOTATE_NEW_BUFFER(begin(), capacity(), size);
1325 m_size = size;
1326 TypeOperations::uninitializedFill(begin(), end(), val);
1327 }
1328
1329 template <typename T, size_t inlineCapacity, typename Allocator>
1330 Vector<T, inlineCapacity, Allocator>::Vector(const Vector& other)
1331 : Base(other.capacity()) {
1332 ANNOTATE_NEW_BUFFER(begin(), capacity(), other.size());
1333 m_size = other.size();
1334 TypeOperations::uninitializedCopy(other.begin(), other.end(), begin());
1335 }
1336
1337 template <typename T, size_t inlineCapacity, typename Allocator>
1338 template <size_t otherCapacity>
1339 Vector<T, inlineCapacity, Allocator>::Vector(
1340 const Vector<T, otherCapacity, Allocator>& other)
1341 : Base(other.capacity()) {
1342 ANNOTATE_NEW_BUFFER(begin(), capacity(), other.size());
1343 m_size = other.size();
1344 TypeOperations::uninitializedCopy(other.begin(), other.end(), begin());
1345 }
1346
1347 template <typename T, size_t inlineCapacity, typename Allocator>
1348 Vector<T, inlineCapacity, Allocator>& Vector<T, inlineCapacity, Allocator>::
1349 operator=(const Vector<T, inlineCapacity, Allocator>& other) {
1350 if (UNLIKELY(&other == this))
1351 return *this;
1352
1353 if (size() > other.size()) {
1354 shrink(other.size());
1355 } else if (other.size() > capacity()) {
1356 clear();
1357 reserveCapacity(other.size());
1358 DCHECK(begin());
1359 }
1360
1361 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, other.size());
1362 std::copy(other.begin(), other.begin() + size(), begin());
1363 TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end());
1364 m_size = other.size();
1365
1366 return *this;
1367 }
1368
1369 inline bool typelessPointersAreEqual(const void* a, const void* b) {
1370 return a == b;
1371 }
1372
1373 template <typename T, size_t inlineCapacity, typename Allocator>
1374 template <size_t otherCapacity>
1375 Vector<T, inlineCapacity, Allocator>& Vector<T, inlineCapacity, Allocator>::
1376 operator=(const Vector<T, otherCapacity, Allocator>& other) {
1377 // If the inline capacities match, we should call the more specific
1378 // template. If the inline capacities don't match, the two objects
1379 // shouldn't be allocated the same address.
1380 DCHECK(!typelessPointersAreEqual(&other, this));
1381
1382 if (size() > other.size()) {
1383 shrink(other.size());
1384 } else if (other.size() > capacity()) {
1385 clear();
1386 reserveCapacity(other.size());
1387 DCHECK(begin());
1388 }
1389
1390 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, other.size());
1391 std::copy(other.begin(), other.begin() + size(), begin());
1392 TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end());
1393 m_size = other.size();
1394
1395 return *this;
1396 }
1397
1398 template <typename T, size_t inlineCapacity, typename Allocator>
1399 Vector<T, inlineCapacity, Allocator>::Vector(
1400 Vector<T, inlineCapacity, Allocator>&& other) {
1401 m_size = 0;
1402 // It's a little weird to implement a move constructor using swap but this
1403 // way we don't have to add a move constructor to VectorBuffer.
1404 swap(other);
1405 }
1406
1407 template <typename T, size_t inlineCapacity, typename Allocator>
1408 Vector<T, inlineCapacity, Allocator>& Vector<T, inlineCapacity, Allocator>::
1409 operator=(Vector<T, inlineCapacity, Allocator>&& other) {
1410 swap(other);
1411 return *this;
1412 }
1413
1414 template <typename T, size_t inlineCapacity, typename Allocator>
1415 Vector<T, inlineCapacity, Allocator>::Vector(std::initializer_list<T> elements)
1416 : Base(elements.size()) {
1417 ANNOTATE_NEW_BUFFER(begin(), capacity(), elements.size());
1418 m_size = elements.size();
1419 TypeOperations::uninitializedCopy(elements.begin(), elements.end(), begin());
1420 }
1421
1422 template <typename T, size_t inlineCapacity, typename Allocator>
1423 Vector<T, inlineCapacity, Allocator>& Vector<T, inlineCapacity, Allocator>::
1424 operator=(std::initializer_list<T> elements) {
1425 if (size() > elements.size()) {
1426 shrink(elements.size());
1427 } else if (elements.size() > capacity()) {
1428 clear();
1429 reserveCapacity(elements.size());
1430 DCHECK(begin());
1431 }
1432
1433 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, elements.size());
1434 std::copy(elements.begin(), elements.begin() + m_size, begin());
1435 TypeOperations::uninitializedCopy(elements.begin() + m_size, elements.end(),
1436 end());
1437 m_size = elements.size();
1438
1439 return *this;
1440 }
1441
1442 template <typename T, size_t inlineCapacity, typename Allocator>
1443 template <typename U>
1444 bool Vector<T, inlineCapacity, Allocator>::contains(const U& value) const {
1445 return find(value) != kNotFound;
1446 }
1447
1448 template <typename T, size_t inlineCapacity, typename Allocator>
1449 template <typename U>
1450 size_t Vector<T, inlineCapacity, Allocator>::find(const U& value) const {
1451 const T* b = begin();
1452 const T* e = end();
1453 for (const T* iter = b; iter < e; ++iter) {
1454 if (TypeOperations::compareElement(*iter, value))
1455 return iter - b;
1456 }
1457 return kNotFound;
1458 }
1459
1460 template <typename T, size_t inlineCapacity, typename Allocator>
1461 template <typename U>
1462 size_t Vector<T, inlineCapacity, Allocator>::reverseFind(const U& value) const {
1463 const T* b = begin();
1464 const T* iter = end();
1465 while (iter > b) {
1466 --iter;
1467 if (TypeOperations::compareElement(*iter, value))
1468 return iter - b;
1469 }
1470 return kNotFound;
1471 }
1472
1473 template <typename T, size_t inlineCapacity, typename Allocator>
1474 void Vector<T, inlineCapacity, Allocator>::fill(const T& val, size_t newSize) {
1475 if (size() > newSize) {
1476 shrink(newSize);
1477 } else if (newSize > capacity()) {
1478 clear();
1479 reserveCapacity(newSize);
1480 DCHECK(begin());
1481 }
1482
1483 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, newSize);
1484 std::fill(begin(), end(), val);
1485 TypeOperations::uninitializedFill(end(), begin() + newSize, val);
1486 m_size = newSize;
1487 }
1488
1489 template <typename T, size_t inlineCapacity, typename Allocator>
1490 void Vector<T, inlineCapacity, Allocator>::expandCapacity(
1491 size_t newMinCapacity) {
1492 size_t oldCapacity = capacity();
1493 size_t expandedCapacity = oldCapacity;
1494 // We use a more aggressive expansion strategy for Vectors with inline
1495 // storage. This is because they are more likely to be on the stack, so the
1496 // risk of heap bloat is minimized. Furthermore, exceeding the inline
1497 // capacity limit is not supposed to happen in the common case and may
1498 // indicate a pathological condition or microbenchmark.
1499 if (INLINE_CAPACITY) {
1500 expandedCapacity *= 2;
1501 // Check for integer overflow, which could happen in the 32-bit build.
1502 RELEASE_ASSERT(expandedCapacity > oldCapacity);
1503 } else {
1504 // This cannot integer overflow.
1505 // On 64-bit, the "expanded" integer is 32-bit, and any encroachment
1506 // above 2^32 will fail allocation in allocateBuffer(). On 32-bit,
1507 // there's not enough address space to hold the old and new buffers. In
1508 // addition, our underlying allocator is supposed to always fail on >
1509 // (2^31 - 1) allocations.
1510 expandedCapacity += (expandedCapacity / 4) + 1;
1511 }
1512 reserveCapacity(std::max(
1513 newMinCapacity,
1514 std::max(static_cast<size_t>(kInitialVectorSize), expandedCapacity)));
1515 }
1516
1517 template <typename T, size_t inlineCapacity, typename Allocator>
1518 T* Vector<T, inlineCapacity, Allocator>::expandCapacity(size_t newMinCapacity,
1519 T* ptr) {
1520 if (ptr < begin() || ptr >= end()) {
1521 expandCapacity(newMinCapacity);
1522 return ptr;
1523 }
1524 size_t index = ptr - begin();
1525 expandCapacity(newMinCapacity);
1526 return begin() + index;
1527 }
1528
1529 template <typename T, size_t inlineCapacity, typename Allocator>
1530 template <typename U>
1531 inline U* Vector<T, inlineCapacity, Allocator>::expandCapacity(
1532 size_t newMinCapacity,
1533 U* ptr) {
1534 expandCapacity(newMinCapacity);
1535 return ptr;
1536 }
1537
1538 template <typename T, size_t inlineCapacity, typename Allocator>
1539 inline void Vector<T, inlineCapacity, Allocator>::resize(size_t size) {
1540 if (size <= m_size) {
1541 TypeOperations::destruct(begin() + size, end());
1542 clearUnusedSlots(begin() + size, end());
1543 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, size);
1544 } else {
1545 if (size > capacity())
1546 expandCapacity(size);
1547 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, size);
1548 TypeOperations::initialize(end(), begin() + size);
1549 }
1550
1551 m_size = size;
1552 }
1553
1554 template <typename T, size_t inlineCapacity, typename Allocator>
1555 void Vector<T, inlineCapacity, Allocator>::shrink(size_t size) {
1556 DCHECK_LE(size, m_size);
1557 TypeOperations::destruct(begin() + size, end());
1558 clearUnusedSlots(begin() + size, end());
1559 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, size);
1560 m_size = size;
1561 }
1562
1563 template <typename T, size_t inlineCapacity, typename Allocator>
1564 void Vector<T, inlineCapacity, Allocator>::grow(size_t size) {
1565 DCHECK_GE(size, m_size);
1566 if (size > capacity())
1567 expandCapacity(size);
1568 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, size);
1569 TypeOperations::initialize(end(), begin() + size);
1570 m_size = size;
1571 }
1572
1573 template <typename T, size_t inlineCapacity, typename Allocator>
1574 void Vector<T, inlineCapacity, Allocator>::reserveCapacity(size_t newCapacity) {
1575 if (UNLIKELY(newCapacity <= capacity()))
1576 return;
1577 T* oldBuffer = begin();
1578 if (!oldBuffer) {
1579 Base::allocateBuffer(newCapacity);
1580 return;
1581 }
1582 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER
1583 size_t oldCapacity = capacity();
1584 #endif
1585 // The Allocator::isGarbageCollected check is not needed. The check is just
1586 // a static hint for a compiler to indicate that Base::expandBuffer returns
1587 // false if Allocator is a PartitionAllocator.
1588 if (Allocator::isGarbageCollected && Base::expandBuffer(newCapacity)) {
1589 ANNOTATE_CHANGE_CAPACITY(begin(), oldCapacity, m_size, capacity());
1590 return;
1591 }
1592 T* oldEnd = end();
1593 Base::allocateExpandedBuffer(newCapacity);
1594 ANNOTATE_NEW_BUFFER(begin(), capacity(), m_size);
1595 TypeOperations::move(oldBuffer, oldEnd, begin());
1596 clearUnusedSlots(oldBuffer, oldEnd);
1597 ANNOTATE_DELETE_BUFFER(oldBuffer, oldCapacity, m_size);
1598 Base::deallocateBuffer(oldBuffer);
1599 }
1600
1601 template <typename T, size_t inlineCapacity, typename Allocator>
1602 inline void Vector<T, inlineCapacity, Allocator>::reserveInitialCapacity(
1603 size_t initialCapacity) {
1604 DCHECK(!m_size);
1605 DCHECK(capacity() == INLINE_CAPACITY);
1606 if (initialCapacity > INLINE_CAPACITY) {
1607 ANNOTATE_DELETE_BUFFER(begin(), capacity(), m_size);
1608 Base::allocateBuffer(initialCapacity);
1609 ANNOTATE_NEW_BUFFER(begin(), capacity(), m_size);
1610 }
1611 }
1612
1613 template <typename T, size_t inlineCapacity, typename Allocator>
1614 void Vector<T, inlineCapacity, Allocator>::shrinkCapacity(size_t newCapacity) {
1615 if (newCapacity >= capacity())
1616 return;
1617
1618 if (newCapacity < size())
1619 shrink(newCapacity);
1620
1621 T* oldBuffer = begin();
1622 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER
1623 size_t oldCapacity = capacity();
1624 #endif
1625 if (newCapacity > 0) {
1626 if (Base::shrinkBuffer(newCapacity)) {
1627 ANNOTATE_CHANGE_CAPACITY(begin(), oldCapacity, m_size, capacity());
1628 return;
1629 }
1630
1631 T* oldEnd = end();
1632 Base::allocateBuffer(newCapacity);
1633 if (begin() != oldBuffer) {
1634 ANNOTATE_NEW_BUFFER(begin(), capacity(), m_size);
1635 TypeOperations::move(oldBuffer, oldEnd, begin());
1636 clearUnusedSlots(oldBuffer, oldEnd);
1637 ANNOTATE_DELETE_BUFFER(oldBuffer, oldCapacity, m_size);
1638 }
1639 } else {
1640 Base::resetBufferPointer();
1641 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER
1642 if (oldBuffer != begin()) {
1643 ANNOTATE_NEW_BUFFER(begin(), capacity(), m_size);
1644 ANNOTATE_DELETE_BUFFER(oldBuffer, oldCapacity, m_size);
1645 }
1646 #endif
1647 }
1648
1649 Base::deallocateBuffer(oldBuffer);
1650 }
1651
1652 // Templatizing these is better than just letting the conversion happen
1653 // implicitly, because for instance it allows a PassRefPtr to be appended to a
1654 // RefPtr vector without refcount thrash.
1655
1656 template <typename T, size_t inlineCapacity, typename Allocator>
1657 template <typename U>
1658 ALWAYS_INLINE void Vector<T, inlineCapacity, Allocator>::push_back(U&& val) {
1659 DCHECK(Allocator::isAllocationAllowed());
1660 if (LIKELY(size() != capacity())) {
1661 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, m_size + 1);
1662 new (NotNull, end()) T(std::forward<U>(val));
1663 ++m_size;
1664 return;
1665 }
1666
1667 appendSlowCase(std::forward<U>(val));
1668 }
1669
1670 template <typename T, size_t inlineCapacity, typename Allocator>
1671 template <typename... Args>
1672 ALWAYS_INLINE T& Vector<T, inlineCapacity, Allocator>::emplace_back(
1673 Args&&... args) {
1674 DCHECK(Allocator::isAllocationAllowed());
1675 if (UNLIKELY(size() == capacity()))
1676 expandCapacity(size() + 1);
1677
1678 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, m_size + 1);
1679 T* t = new (NotNull, end()) T(std::forward<Args>(args)...);
1680 ++m_size;
1681 return *t;
1682 }
1683
1684 template <typename T, size_t inlineCapacity, typename Allocator>
1685 template <typename U>
1686 void Vector<T, inlineCapacity, Allocator>::append(const U* data,
1687 size_t dataSize) {
1688 DCHECK(Allocator::isAllocationAllowed());
1689 size_t newSize = m_size + dataSize;
1690 if (newSize > capacity()) {
1691 data = expandCapacity(newSize, data);
1692 DCHECK(begin());
1693 }
1694 RELEASE_ASSERT(newSize >= m_size);
1695 T* dest = end();
1696 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, newSize);
1697 VectorCopier<VectorTraits<T>::canCopyWithMemcpy, T>::uninitializedCopy(
1698 data, &data[dataSize], dest);
1699 m_size = newSize;
1700 }
1701
1702 template <typename T, size_t inlineCapacity, typename Allocator>
1703 template <typename U>
1704 NEVER_INLINE void Vector<T, inlineCapacity, Allocator>::appendSlowCase(
1705 U&& val) {
1706 DCHECK_EQ(size(), capacity());
1707
1708 typename std::remove_reference<U>::type* ptr = &val;
1709 ptr = expandCapacity(size() + 1, ptr);
1710 DCHECK(begin());
1711
1712 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, m_size + 1);
1713 new (NotNull, end()) T(std::forward<U>(*ptr));
1714 ++m_size;
1715 }
1716
1717 template <typename T, size_t inlineCapacity, typename Allocator>
1718 template <typename U, size_t otherCapacity, typename OtherAllocator>
1719 inline void Vector<T, inlineCapacity, Allocator>::appendVector(
1720 const Vector<U, otherCapacity, OtherAllocator>& val) {
1721 append(val.begin(), val.size());
1722 }
1723
1724 template <typename T, size_t inlineCapacity, typename Allocator>
1725 template <typename Iterator>
1726 void Vector<T, inlineCapacity, Allocator>::appendRange(Iterator begin,
1727 Iterator end) {
1728 for (Iterator it = begin; it != end; ++it)
1729 push_back(*it);
1730 }
1731
1732 // This version of append saves a branch in the case where you know that the
1733 // vector's capacity is large enough for the append to succeed.
1734 template <typename T, size_t inlineCapacity, typename Allocator>
1735 template <typename U>
1736 ALWAYS_INLINE void Vector<T, inlineCapacity, Allocator>::uncheckedAppend(
1737 U&& val) {
1738 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER
1739 // Vectors in ASAN builds don't have inlineCapacity.
1740 push_back(std::forward<U>(val));
1741 #else
1742 DCHECK_LT(size(), capacity());
1743 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, m_size + 1);
1744 new (NotNull, end()) T(std::forward<U>(val));
1745 ++m_size;
1746 #endif
1747 }
1748
1749 template <typename T, size_t inlineCapacity, typename Allocator>
1750 template <typename U>
1751 inline void Vector<T, inlineCapacity, Allocator>::insert(size_t position,
1752 U&& val) {
1753 DCHECK(Allocator::isAllocationAllowed());
1754 RELEASE_ASSERT(position <= size());
1755 typename std::remove_reference<U>::type* data = &val;
1756 if (size() == capacity()) {
1757 data = expandCapacity(size() + 1, data);
1758 DCHECK(begin());
1759 }
1760 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, m_size + 1);
1761 T* spot = begin() + position;
1762 TypeOperations::moveOverlapping(spot, end(), spot + 1);
1763 new (NotNull, spot) T(std::forward<U>(*data));
1764 ++m_size;
1765 }
1766
1767 template <typename T, size_t inlineCapacity, typename Allocator>
1768 template <typename U>
1769 void Vector<T, inlineCapacity, Allocator>::insert(size_t position,
1770 const U* data,
1771 size_t dataSize) {
1772 DCHECK(Allocator::isAllocationAllowed());
1773 RELEASE_ASSERT(position <= size());
1774 size_t newSize = m_size + dataSize;
1775 if (newSize > capacity()) {
1776 data = expandCapacity(newSize, data);
1777 DCHECK(begin());
1778 }
1779 RELEASE_ASSERT(newSize >= m_size);
1780 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, newSize);
1781 T* spot = begin() + position;
1782 TypeOperations::moveOverlapping(spot, end(), spot + dataSize);
1783 VectorCopier<VectorTraits<T>::canCopyWithMemcpy, T>::uninitializedCopy(
1784 data, &data[dataSize], spot);
1785 m_size = newSize;
1786 }
1787
1788 template <typename T, size_t inlineCapacity, typename Allocator>
1789 template <typename U, size_t otherCapacity, typename OtherAllocator>
1790 inline void Vector<T, inlineCapacity, Allocator>::insert(
1791 size_t position,
1792 const Vector<U, otherCapacity, OtherAllocator>& val) {
1793 insert(position, val.begin(), val.size());
1794 }
1795
1796 template <typename T, size_t inlineCapacity, typename Allocator>
1797 template <typename U>
1798 inline void Vector<T, inlineCapacity, Allocator>::push_front(U&& val) {
1799 insert(0, std::forward<U>(val));
1800 }
1801
1802 template <typename T, size_t inlineCapacity, typename Allocator>
1803 template <typename U>
1804 void Vector<T, inlineCapacity, Allocator>::push_front(const U* data,
1805 size_t dataSize) {
1806 insert(0, data, dataSize);
1807 }
1808
1809 template <typename T, size_t inlineCapacity, typename Allocator>
1810 template <typename U, size_t otherCapacity, typename OtherAllocator>
1811 inline void Vector<T, inlineCapacity, Allocator>::prependVector(
1812 const Vector<U, otherCapacity, OtherAllocator>& val) {
1813 insert(0, val.begin(), val.size());
1814 }
1815
1816 template <typename T, size_t inlineCapacity, typename Allocator>
1817 inline void Vector<T, inlineCapacity, Allocator>::remove(size_t position) {
1818 RELEASE_ASSERT(position < size());
1819 T* spot = begin() + position;
1820 spot->~T();
1821 TypeOperations::moveOverlapping(spot + 1, end(), spot);
1822 clearUnusedSlots(end() - 1, end());
1823 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, m_size - 1);
1824 --m_size;
1825 }
1826
1827 template <typename T, size_t inlineCapacity, typename Allocator>
1828 inline void Vector<T, inlineCapacity, Allocator>::remove(size_t position,
1829 size_t length) {
1830 SECURITY_DCHECK(position <= size());
1831 if (!length)
1832 return;
1833 RELEASE_ASSERT(position + length <= size());
1834 T* beginSpot = begin() + position;
1835 T* endSpot = beginSpot + length;
1836 TypeOperations::destruct(beginSpot, endSpot);
1837 TypeOperations::moveOverlapping(endSpot, end(), beginSpot);
1838 clearUnusedSlots(end() - length, end());
1839 ANNOTATE_CHANGE_SIZE(begin(), capacity(), m_size, m_size - length);
1840 m_size -= length;
1841 }
1842
1843 template <typename T, size_t inlineCapacity, typename Allocator>
1844 inline void Vector<T, inlineCapacity, Allocator>::reverse() {
1845 for (size_t i = 0; i < m_size / 2; ++i)
1846 std::swap(at(i), at(m_size - 1 - i));
1847 }
1848
1849 template <typename T, size_t inlineCapacity, typename Allocator>
1850 inline void swap(Vector<T, inlineCapacity, Allocator>& a,
1851 Vector<T, inlineCapacity, Allocator>& b) {
1852 a.swap(b);
1853 }
1854
1855 template <typename T,
1856 size_t inlineCapacityA,
1857 size_t inlineCapacityB,
1858 typename Allocator>
1859 bool operator==(const Vector<T, inlineCapacityA, Allocator>& a,
1860 const Vector<T, inlineCapacityB, Allocator>& b) {
1861 if (a.size() != b.size())
1862 return false;
1863 if (a.isEmpty())
1864 return true;
1865 return VectorTypeOperations<T>::compare(a.data(), b.data(), a.size());
1866 }
1867
1868 template <typename T,
1869 size_t inlineCapacityA,
1870 size_t inlineCapacityB,
1871 typename Allocator>
1872 inline bool operator!=(const Vector<T, inlineCapacityA, Allocator>& a,
1873 const Vector<T, inlineCapacityB, Allocator>& b) {
1874 return !(a == b);
1875 }
1876
1877 // This is only called if the allocator is a HeapAllocator. It is used when
1878 // visiting during a tracing GC.
1879 template <typename T, size_t inlineCapacity, typename Allocator>
1880 template <typename VisitorDispatcher>
1881 void Vector<T, inlineCapacity, Allocator>::trace(VisitorDispatcher visitor) {
1882 DCHECK(Allocator::isGarbageCollected) << "Garbage collector must be enabled.";
1883 if (!buffer())
1884 return;
1885 if (this->hasOutOfLineBuffer()) {
1886 // This is a performance optimization for a case where the buffer has
1887 // been already traced by somewhere. This can happen if the conservative
1888 // scanning traced an on-stack (false-positive or real) pointer to the
1889 // HeapVector, and then visitor->trace() traces the HeapVector.
1890 if (Allocator::isHeapObjectAlive(buffer()))
1891 return;
1892 Allocator::markNoTracing(visitor, buffer());
1893 Allocator::registerBackingStoreReference(visitor, Base::bufferSlot());
1894 }
1895 const T* bufferBegin = buffer();
1896 const T* bufferEnd = buffer() + size();
1897 if (IsTraceableInCollectionTrait<VectorTraits<T>>::value) {
1898 for (const T* bufferEntry = bufferBegin; bufferEntry != bufferEnd;
1899 bufferEntry++)
1900 Allocator::template trace<VisitorDispatcher, T, VectorTraits<T>>(
1901 visitor, *const_cast<T*>(bufferEntry));
1902 checkUnusedSlots(buffer() + size(), buffer() + capacity());
1903 }
1904 }
1905
1906 } // namespace WTF
1907
1908 using WTF::Vector;
1909
1910 #endif // WTF_Vector_h
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/wtf/PrintStream.h ('k') | third_party/WebKit/Source/wtf/VectorTraits.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698