Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * This library is free software; you can redistribute it and/or | 4 * This library is free software; you can redistribute it and/or |
| 5 * modify it under the terms of the GNU Library General Public | 5 * modify it under the terms of the GNU Library General Public |
| 6 * License as published by the Free Software Foundation; either | 6 * License as published by the Free Software Foundation; either |
| 7 * version 2 of the License, or (at your option) any later version. | 7 * version 2 of the License, or (at your option) any later version. |
| 8 * | 8 * |
| 9 * This library is distributed in the hope that it will be useful, | 9 * This library is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 #include "wtf/NotFound.h" | 28 #include "wtf/NotFound.h" |
| 29 #include "wtf/StdLibExtras.h" | 29 #include "wtf/StdLibExtras.h" |
| 30 #include "wtf/VectorTraits.h" | 30 #include "wtf/VectorTraits.h" |
| 31 #include "wtf/allocator/PartitionAllocator.h" | 31 #include "wtf/allocator/PartitionAllocator.h" |
| 32 #include <algorithm> | 32 #include <algorithm> |
| 33 #include <initializer_list> | 33 #include <initializer_list> |
| 34 #include <iterator> | 34 #include <iterator> |
| 35 #include <string.h> | 35 #include <string.h> |
| 36 #include <utility> | 36 #include <utility> |
| 37 | 37 |
| 38 // For ASAN builds, disable inline buffers completely as they cause various issu es. | 38 // For ASAN builds, disable inline buffers completely as they cause various |
| 39 // issues. | |
| 39 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER | 40 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER |
| 40 #define INLINE_CAPACITY 0 | 41 #define INLINE_CAPACITY 0 |
| 41 #else | 42 #else |
| 42 #define INLINE_CAPACITY inlineCapacity | 43 #define INLINE_CAPACITY inlineCapacity |
| 43 #endif | 44 #endif |
| 44 | 45 |
| 45 namespace WTF { | 46 namespace WTF { |
| 46 | 47 |
| 47 #if defined(MEMORY_SANITIZER_INITIAL_SIZE) | 48 #if defined(MEMORY_SANITIZER_INITIAL_SIZE) |
| 48 static const size_t kInitialVectorSize = 1; | 49 static const size_t kInitialVectorSize = 1; |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 456 return true; | 457 return true; |
| 457 } | 458 } |
| 458 return false; | 459 return false; |
| 459 } | 460 } |
| 460 | 461 |
| 461 void resetBufferPointer() { | 462 void resetBufferPointer() { |
| 462 m_buffer = nullptr; | 463 m_buffer = nullptr; |
| 463 m_capacity = 0; | 464 m_capacity = 0; |
| 464 } | 465 } |
| 465 | 466 |
| 466 // See the other specialization for the meaning of |thisHole| and |otherHole|. They are irrelevant in this case. | 467 // See the other specialization for the meaning of |thisHole| and |otherHole|. |
| 468 // They are irrelevant in this case. | |
| 467 void swapVectorBuffer(VectorBuffer<T, 0, Allocator>& other, | 469 void swapVectorBuffer(VectorBuffer<T, 0, Allocator>& other, |
| 468 OffsetRange thisHole, | 470 OffsetRange thisHole, |
| 469 OffsetRange otherHole) { | 471 OffsetRange otherHole) { |
| 470 std::swap(m_buffer, other.m_buffer); | 472 std::swap(m_buffer, other.m_buffer); |
| 471 std::swap(m_capacity, other.m_capacity); | 473 std::swap(m_capacity, other.m_capacity); |
| 472 std::swap(m_size, other.m_size); | 474 std::swap(m_size, other.m_size); |
| 473 } | 475 } |
| 474 | 476 |
| 475 using Base::allocateBuffer; | 477 using Base::allocateBuffer; |
| 476 using Base::allocationSize; | 478 using Base::allocationSize; |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 575 else | 577 else |
| 576 resetBufferPointer(); | 578 resetBufferPointer(); |
| 577 } | 579 } |
| 578 | 580 |
| 579 size_t allocationSize(size_t capacity) const { | 581 size_t allocationSize(size_t capacity) const { |
| 580 if (capacity <= inlineCapacity) | 582 if (capacity <= inlineCapacity) |
| 581 return m_inlineBufferSize; | 583 return m_inlineBufferSize; |
| 582 return Base::allocationSize(capacity); | 584 return Base::allocationSize(capacity); |
| 583 } | 585 } |
| 584 | 586 |
| 585 // Swap two vector buffers, both of which have the same non-zero inline capaci ty. | 587 // Swap two vector buffers, both of which have the same non-zero inline |
| 588 // capacity. | |
| 586 // | 589 // |
| 587 // If the data is in an out-of-line buffer, we can just pass the pointers acro ss the two buffers. | 590 // If the data is in an out-of-line buffer, we can just pass the pointers |
| 588 // If the data is in an inline buffer, we need to either swap or move each ele ment, depending on whether each | 591 // across the two buffers. If the data is in an inline buffer, we need to |
| 589 // slot is occupied or not. | 592 // either swap or move each element, depending on whether each slot is |
| 593 // occupied or not. | |
| 590 // | 594 // |
| 591 // Further complication comes from the fact that VectorBuffer is also used as the backing store of a Deque. | 595 // Further complication comes from the fact that VectorBuffer is also used as |
| 592 // Deque allocates the objects like a ring buffer, so there may be a "hole" (u nallocated region) in the middle | 596 // the backing store of a Deque. Deque allocates the objects like a ring |
| 593 // of the buffer. This function assumes elements in a range [m_buffer, m_buffe r + m_size) are all allocated | 597 // buffer, so there may be a "hole" (unallocated region) in the middle of the |
| 594 // except for elements within |thisHole|. The same applies for |other.m_buffer | and |otherHole|. | 598 // buffer. This function assumes elements in a range [m_buffer, m_buffer + |
| 599 // m_size) are all allocated except for elements within |thisHole|. The same | |
| 600 // applies for |other.m_buffer| and |otherHole|. | |
| 595 void swapVectorBuffer(VectorBuffer<T, inlineCapacity, Allocator>& other, | 601 void swapVectorBuffer(VectorBuffer<T, inlineCapacity, Allocator>& other, |
| 596 OffsetRange thisHole, | 602 OffsetRange thisHole, |
| 597 OffsetRange otherHole) { | 603 OffsetRange otherHole) { |
| 598 using TypeOperations = VectorTypeOperations<T>; | 604 using TypeOperations = VectorTypeOperations<T>; |
| 599 | 605 |
| 600 if (buffer() != inlineBuffer() && other.buffer() != other.inlineBuffer()) { | 606 if (buffer() != inlineBuffer() && other.buffer() != other.inlineBuffer()) { |
| 601 // The easiest case: both buffers are non-inline. We just need to swap the pointers. | 607 // The easiest case: both buffers are non-inline. We just need to swap the |
| 608 // pointers. | |
| 602 std::swap(m_buffer, other.m_buffer); | 609 std::swap(m_buffer, other.m_buffer); |
| 603 std::swap(m_capacity, other.m_capacity); | 610 std::swap(m_capacity, other.m_capacity); |
| 604 std::swap(m_size, other.m_size); | 611 std::swap(m_size, other.m_size); |
| 605 return; | 612 return; |
| 606 } | 613 } |
| 607 | 614 |
| 608 Allocator::enterGCForbiddenScope(); | 615 Allocator::enterGCForbiddenScope(); |
| 609 | 616 |
| 610 // Otherwise, we at least need to move some elements from one inline buffer to another. | 617 // Otherwise, we at least need to move some elements from one inline buffer |
| 618 // to another. | |
| 611 // | 619 // |
| 612 // Terminology: "source" is a place from which elements are copied, and "des tination" is a place to which | 620 // Terminology: "source" is a place from which elements are copied, and |
| 613 // elements are copied. thisSource or otherSource can be empty (represented by nullptr) when this range or | 621 // "destination" is a place to which elements are copied. thisSource or |
| 622 // otherSource can be empty (represented by nullptr) when this range or | |
| 614 // other range is in an out-of-line buffer. | 623 // other range is in an out-of-line buffer. |
| 615 // | 624 // |
| 616 // We first record which range needs to get moved and where elements in such a range will go. Elements in | 625 // We first record which range needs to get moved and where elements in such |
| 617 // an inline buffer will go to the other buffer's inline buffer. Elements in an out-of-line buffer won't move, | 626 // a range will go. Elements in an inline buffer will go to the other |
| 627 // buffer's inline buffer. Elements in an out-of-line buffer won't move, | |
| 618 // because we can just swap pointers of out-of-line buffers. | 628 // because we can just swap pointers of out-of-line buffers. |
| 619 T* thisSourceBegin = nullptr; | 629 T* thisSourceBegin = nullptr; |
| 620 size_t thisSourceSize = 0; | 630 size_t thisSourceSize = 0; |
| 621 T* thisDestinationBegin = nullptr; | 631 T* thisDestinationBegin = nullptr; |
| 622 if (buffer() == inlineBuffer()) { | 632 if (buffer() == inlineBuffer()) { |
| 623 thisSourceBegin = buffer(); | 633 thisSourceBegin = buffer(); |
| 624 thisSourceSize = m_size; | 634 thisSourceSize = m_size; |
| 625 thisDestinationBegin = other.inlineBuffer(); | 635 thisDestinationBegin = other.inlineBuffer(); |
| 626 if (!thisHole.empty()) { // Sanity check. | 636 if (!thisHole.empty()) { // Sanity check. |
| 627 ASSERT(thisHole.begin < thisHole.end); | 637 ASSERT(thisHole.begin < thisHole.end); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 639 otherSourceSize = other.m_size; | 649 otherSourceSize = other.m_size; |
| 640 otherDestinationBegin = inlineBuffer(); | 650 otherDestinationBegin = inlineBuffer(); |
| 641 if (!otherHole.empty()) { | 651 if (!otherHole.empty()) { |
| 642 ASSERT(otherHole.begin < otherHole.end); | 652 ASSERT(otherHole.begin < otherHole.end); |
| 643 ASSERT(otherHole.end <= otherSourceSize); | 653 ASSERT(otherHole.end <= otherSourceSize); |
| 644 } | 654 } |
| 645 } else { | 655 } else { |
| 646 otherHole.begin = otherHole.end = 0; | 656 otherHole.begin = otherHole.end = 0; |
| 647 } | 657 } |
| 648 | 658 |
| 649 // Next, we mutate members and do other bookkeeping. We do pointer swapping (for out-of-line buffers) here if | 659 // Next, we mutate members and do other bookkeeping. We do pointer swapping |
| 650 // we can. From now on, don't assume buffer() or capacity() maintains their original values. | 660 // (for out-of-line buffers) here if |
|
dcheng
2016/10/01 19:58:17
Nit: merge next lines.
Nico
2016/10/02 00:49:28
Done.
| |
| 661 // we can. From now on, don't assume buffer() or capacity() maintains their | |
| 662 // original values. | |
| 651 std::swap(m_capacity, other.m_capacity); | 663 std::swap(m_capacity, other.m_capacity); |
| 652 if (thisSourceBegin && | 664 if (thisSourceBegin && |
| 653 !otherSourceBegin) { // Our buffer is inline, theirs is not. | 665 !otherSourceBegin) { // Our buffer is inline, theirs is not. |
| 654 ASSERT(buffer() == inlineBuffer()); | 666 ASSERT(buffer() == inlineBuffer()); |
| 655 ASSERT(other.buffer() != other.inlineBuffer()); | 667 ASSERT(other.buffer() != other.inlineBuffer()); |
| 656 ANNOTATE_DELETE_BUFFER(m_buffer, inlineCapacity, m_size); | 668 ANNOTATE_DELETE_BUFFER(m_buffer, inlineCapacity, m_size); |
| 657 m_buffer = other.buffer(); | 669 m_buffer = other.buffer(); |
| 658 other.m_buffer = other.inlineBuffer(); | 670 other.m_buffer = other.inlineBuffer(); |
| 659 std::swap(m_size, other.m_size); | 671 std::swap(m_size, other.m_size); |
| 660 ANNOTATE_NEW_BUFFER(other.m_buffer, inlineCapacity, other.m_size); | 672 ANNOTATE_NEW_BUFFER(other.m_buffer, inlineCapacity, other.m_size); |
| 661 } else if (!thisSourceBegin && | 673 } else if (!thisSourceBegin && |
| 662 otherSourceBegin) { // Their buffer is inline, ours is not. | 674 otherSourceBegin) { // Their buffer is inline, ours is not. |
| 663 ASSERT(buffer() != inlineBuffer()); | 675 ASSERT(buffer() != inlineBuffer()); |
| 664 ASSERT(other.buffer() == other.inlineBuffer()); | 676 ASSERT(other.buffer() == other.inlineBuffer()); |
| 665 ANNOTATE_DELETE_BUFFER(other.m_buffer, inlineCapacity, other.m_size); | 677 ANNOTATE_DELETE_BUFFER(other.m_buffer, inlineCapacity, other.m_size); |
| 666 other.m_buffer = buffer(); | 678 other.m_buffer = buffer(); |
| 667 m_buffer = inlineBuffer(); | 679 m_buffer = inlineBuffer(); |
| 668 std::swap(m_size, other.m_size); | 680 std::swap(m_size, other.m_size); |
| 669 ANNOTATE_NEW_BUFFER(m_buffer, inlineCapacity, m_size); | 681 ANNOTATE_NEW_BUFFER(m_buffer, inlineCapacity, m_size); |
| 670 } else { // Both buffers are inline. | 682 } else { // Both buffers are inline. |
| 671 ASSERT(thisSourceBegin && otherSourceBegin); | 683 ASSERT(thisSourceBegin && otherSourceBegin); |
| 672 ASSERT(buffer() == inlineBuffer()); | 684 ASSERT(buffer() == inlineBuffer()); |
| 673 ASSERT(other.buffer() == other.inlineBuffer()); | 685 ASSERT(other.buffer() == other.inlineBuffer()); |
| 674 ANNOTATE_CHANGE_SIZE(m_buffer, inlineCapacity, m_size, other.m_size); | 686 ANNOTATE_CHANGE_SIZE(m_buffer, inlineCapacity, m_size, other.m_size); |
| 675 ANNOTATE_CHANGE_SIZE(other.m_buffer, inlineCapacity, other.m_size, | 687 ANNOTATE_CHANGE_SIZE(other.m_buffer, inlineCapacity, other.m_size, |
| 676 m_size); | 688 m_size); |
| 677 std::swap(m_size, other.m_size); | 689 std::swap(m_size, other.m_size); |
| 678 } | 690 } |
| 679 | 691 |
| 680 // We are ready to move elements. We determine an action for each "section", which is a contiguous range such | 692 // We are ready to move elements. We determine an action for each "section", |
| 693 // which is a contiguous range such | |
|
dcheng
2016/10/01 19:58:17
Nit: merge next lines
Nico
2016/10/02 00:49:28
Done.
| |
| 681 // that all elements in the range are treated similarly. | 694 // that all elements in the range are treated similarly. |
| 682 size_t sectionBegin = 0; | 695 size_t sectionBegin = 0; |
| 683 while (sectionBegin < inlineCapacity) { | 696 while (sectionBegin < inlineCapacity) { |
| 684 // To determine the end of this section, we list up all the boundaries whe re the "occupiedness" may change. | 697 // To determine the end of this section, we list up all the boundaries |
| 698 // where the "occupiedness" may change. | |
| 685 size_t sectionEnd = inlineCapacity; | 699 size_t sectionEnd = inlineCapacity; |
| 686 if (thisSourceBegin && sectionBegin < thisSourceSize) | 700 if (thisSourceBegin && sectionBegin < thisSourceSize) |
| 687 sectionEnd = std::min(sectionEnd, thisSourceSize); | 701 sectionEnd = std::min(sectionEnd, thisSourceSize); |
| 688 if (!thisHole.empty() && sectionBegin < thisHole.begin) | 702 if (!thisHole.empty() && sectionBegin < thisHole.begin) |
| 689 sectionEnd = std::min(sectionEnd, thisHole.begin); | 703 sectionEnd = std::min(sectionEnd, thisHole.begin); |
| 690 if (!thisHole.empty() && sectionBegin < thisHole.end) | 704 if (!thisHole.empty() && sectionBegin < thisHole.end) |
| 691 sectionEnd = std::min(sectionEnd, thisHole.end); | 705 sectionEnd = std::min(sectionEnd, thisHole.end); |
| 692 if (otherSourceBegin && sectionBegin < otherSourceSize) | 706 if (otherSourceBegin && sectionBegin < otherSourceSize) |
| 693 sectionEnd = std::min(sectionEnd, otherSourceSize); | 707 sectionEnd = std::min(sectionEnd, otherSourceSize); |
| 694 if (!otherHole.empty() && sectionBegin < otherHole.begin) | 708 if (!otherHole.empty() && sectionBegin < otherHole.begin) |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 707 thisOccupied = true; | 721 thisOccupied = true; |
| 708 } | 722 } |
| 709 bool otherOccupied = false; | 723 bool otherOccupied = false; |
| 710 if (otherSourceBegin && sectionBegin < otherSourceSize) { | 724 if (otherSourceBegin && sectionBegin < otherSourceSize) { |
| 711 if (otherHole.empty() || sectionBegin < otherHole.begin || | 725 if (otherHole.empty() || sectionBegin < otherHole.begin || |
| 712 sectionBegin >= otherHole.end) | 726 sectionBegin >= otherHole.end) |
| 713 otherOccupied = true; | 727 otherOccupied = true; |
| 714 } | 728 } |
| 715 | 729 |
| 716 if (thisOccupied && otherOccupied) { | 730 if (thisOccupied && otherOccupied) { |
| 717 // Both occupied; swap them. In this case, one's destination must be the other's source (i.e. both | 731 // Both occupied; swap them. In this case, one's destination must be the |
| 718 // ranges are in inline buffers). | 732 // other's source (i.e. both ranges are in inline buffers). |
| 719 ASSERT(thisDestinationBegin == otherSourceBegin); | 733 ASSERT(thisDestinationBegin == otherSourceBegin); |
| 720 ASSERT(otherDestinationBegin == thisSourceBegin); | 734 ASSERT(otherDestinationBegin == thisSourceBegin); |
| 721 TypeOperations::swap(thisSourceBegin + sectionBegin, | 735 TypeOperations::swap(thisSourceBegin + sectionBegin, |
| 722 thisSourceBegin + sectionEnd, | 736 thisSourceBegin + sectionEnd, |
| 723 otherSourceBegin + sectionBegin); | 737 otherSourceBegin + sectionBegin); |
| 724 } else if (thisOccupied) { | 738 } else if (thisOccupied) { |
| 725 // Move from ours to theirs. | 739 // Move from ours to theirs. |
| 726 TypeOperations::move(thisSourceBegin + sectionBegin, | 740 TypeOperations::move(thisSourceBegin + sectionBegin, |
| 727 thisSourceBegin + sectionEnd, | 741 thisSourceBegin + sectionEnd, |
| 728 thisDestinationBegin + sectionBegin); | 742 thisDestinationBegin + sectionBegin); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 762 static const size_t m_inlineBufferSize = inlineCapacity * sizeof(T); | 776 static const size_t m_inlineBufferSize = inlineCapacity * sizeof(T); |
| 763 T* inlineBuffer() { return reinterpret_cast_ptr<T*>(m_inlineBuffer.buffer); } | 777 T* inlineBuffer() { return reinterpret_cast_ptr<T*>(m_inlineBuffer.buffer); } |
| 764 const T* inlineBuffer() const { | 778 const T* inlineBuffer() const { |
| 765 return reinterpret_cast_ptr<const T*>(m_inlineBuffer.buffer); | 779 return reinterpret_cast_ptr<const T*>(m_inlineBuffer.buffer); |
| 766 } | 780 } |
| 767 | 781 |
| 768 AlignedBuffer<m_inlineBufferSize, WTF_ALIGN_OF(T)> m_inlineBuffer; | 782 AlignedBuffer<m_inlineBufferSize, WTF_ALIGN_OF(T)> m_inlineBuffer; |
| 769 template <typename U, size_t inlineBuffer, typename V> | 783 template <typename U, size_t inlineBuffer, typename V> |
| 770 friend class Deque; | 784 friend class Deque; |
| 771 }; | 785 }; |
| 772 | 786 // Heap-allocated vectors with no inlineCapacity never need a destructor. |
| 773 template < | 787 template <typename T, |
| 774 typename T, | 788 size_t inlineCapacity = 0, |
| 775 size_t inlineCapacity = 0, | 789 typename Allocator = PartitionAllocator> |
| 776 typename Allocator = | |
| 777 PartitionAllocator> // Heap-allocated vectors with no inlineCapacity ne ver need a destructor. | |
| 778 class Vector | 790 class Vector |
| 779 : private VectorBuffer<T, INLINE_CAPACITY, Allocator>, | 791 : private VectorBuffer<T, INLINE_CAPACITY, Allocator>, |
| 780 public ConditionalDestructor<Vector<T, INLINE_CAPACITY, Allocator>, | 792 public ConditionalDestructor<Vector<T, INLINE_CAPACITY, Allocator>, |
| 781 (INLINE_CAPACITY == 0) && | 793 (INLINE_CAPACITY == 0) && |
| 782 Allocator::isGarbageCollected> { | 794 Allocator::isGarbageCollected> { |
| 783 WTF_USE_ALLOCATOR(Vector, Allocator); | 795 WTF_USE_ALLOCATOR(Vector, Allocator); |
| 784 using Base = VectorBuffer<T, INLINE_CAPACITY, Allocator>; | 796 using Base = VectorBuffer<T, INLINE_CAPACITY, Allocator>; |
| 785 using TypeOperations = VectorTypeOperations<T>; | 797 using TypeOperations = VectorTypeOperations<T>; |
| 786 using OffsetRange = typename Base::OffsetRange; | 798 using OffsetRange = typename Base::OffsetRange; |
| 787 | 799 |
| (...skipping 799 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1587 visitor, *const_cast<T*>(bufferEntry)); | 1599 visitor, *const_cast<T*>(bufferEntry)); |
| 1588 checkUnusedSlots(buffer() + size(), buffer() + capacity()); | 1600 checkUnusedSlots(buffer() + size(), buffer() + capacity()); |
| 1589 } | 1601 } |
| 1590 } | 1602 } |
| 1591 | 1603 |
| 1592 } // namespace WTF | 1604 } // namespace WTF |
| 1593 | 1605 |
| 1594 using WTF::Vector; | 1606 using WTF::Vector; |
| 1595 | 1607 |
| 1596 #endif // WTF_Vector_h | 1608 #endif // WTF_Vector_h |
| OLD | NEW |