diff options
Diffstat (limited to 'JavaScriptCore/wtf/Vector.h')
| -rw-r--r-- | JavaScriptCore/wtf/Vector.h | 124 |
1 files changed, 118 insertions, 6 deletions
diff --git a/JavaScriptCore/wtf/Vector.h b/JavaScriptCore/wtf/Vector.h index 81ea321..f73793f 100644 --- a/JavaScriptCore/wtf/Vector.h +++ b/JavaScriptCore/wtf/Vector.h @@ -24,6 +24,7 @@ #include "FastAllocBase.h" #include "Noncopyable.h" #include "NotFound.h" +#include "StdLibExtras.h" #include "ValueCheck.h" #include "VectorTraits.h" #include <limits> @@ -49,7 +50,7 @@ namespace WTF { #error WTF_ALIGN macros need alignment control. #endif - #if COMPILER(GCC) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 303) + #if COMPILER(GCC) && !COMPILER(INTEL) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 303) typedef char __attribute__((__may_alias__)) AlignedBufferChar; #else typedef char AlignedBufferChar; @@ -286,6 +287,20 @@ namespace WTF { m_buffer = static_cast<T*>(fastMalloc(newCapacity * sizeof(T))); } + bool tryAllocateBuffer(size_t newCapacity) + { + if (newCapacity > std::numeric_limits<size_t>::max() / sizeof(T)) + return false; + + T* newBuffer; + if (tryFastMalloc(newCapacity * sizeof(T)).getValue(newBuffer)) { + m_capacity = newCapacity; + m_buffer = newBuffer; + return true; + } + return false; + } + void deallocateBuffer(T* bufferToDeallocate) { if (m_buffer == bufferToDeallocate) { @@ -361,6 +376,7 @@ namespace WTF { void restoreInlineBufferIfNeeded() { } using Base::allocateBuffer; + using Base::tryAllocateBuffer; using Base::deallocateBuffer; using Base::buffer; @@ -405,6 +421,15 @@ namespace WTF { } } + bool tryAllocateBuffer(size_t newCapacity) + { + if (newCapacity > inlineCapacity) + return Base::tryAllocateBuffer(newCapacity); + m_buffer = inlineBuffer(); + m_capacity = inlineCapacity; + return true; + } + void deallocateBuffer(T* bufferToDeallocate) { if (bufferToDeallocate == inlineBuffer()) @@ -457,7 +482,7 @@ namespace WTF { using Base::m_capacity; static const size_t m_inlineBufferSize = inlineCapacity * sizeof(T); - T* inlineBuffer() { return reinterpret_cast<T*>(m_inlineBuffer.buffer); } + T* inlineBuffer() { return reinterpret_cast_ptr<T*>(m_inlineBuffer.buffer); } AlignedBuffer<m_inlineBufferSize, WTF_ALIGN_OF(T)> m_inlineBuffer; }; @@ -533,11 +558,13 @@ namespace WTF { const T& last() const { return at(size() - 1); } template<typename U> size_t find(const U&) const; + template<typename U> size_t reverseFind(const U&) const; void shrink(size_t size); void grow(size_t size); void resize(size_t size); void reserveCapacity(size_t newCapacity); + bool tryReserveCapacity(size_t newCapacity); void reserveInitialCapacity(size_t initialCapacity); void shrinkCapacity(size_t newCapacity); void shrinkToFit() { shrinkCapacity(size()); } @@ -548,6 +575,7 @@ namespace WTF { template<typename U> void append(const U&); template<typename U> void uncheckedAppend(const U& val); template<size_t otherCapacity> void append(const Vector<T, otherCapacity>&); + template<typename U> bool tryAppend(const U*, size_t); template<typename U> void insert(size_t position, const U*, size_t); template<typename U> void insert(size_t position, const U&); @@ -592,6 +620,8 @@ namespace WTF { private: void expandCapacity(size_t newMinCapacity); const T* expandCapacity(size_t newMinCapacity, const T*); + bool tryExpandCapacity(size_t newMinCapacity); + const T* tryExpandCapacity(size_t newMinCapacity, const T*); template<typename U> U* expandCapacity(size_t newMinCapacity, U*); size_t m_size; @@ -658,6 +688,12 @@ namespace WTF { return *this; } +// Works around an assert in VS2010. See https://connect.microsoft.com/VisualStudio/feedback/details/558044/std-copy-should-not-check-dest-when-first-last +#if COMPILER(MSVC) && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL + if (!begin()) + return *this; +#endif + std::copy(other.begin(), other.begin() + size(), begin()); TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end()); m_size = other.size(); @@ -665,13 +701,17 @@ namespace WTF { return *this; } + inline bool typelessPointersAreEqual(const void* a, const void* b) { return a == b; } + template<typename T, size_t inlineCapacity> template<size_t otherCapacity> Vector<T, inlineCapacity>& Vector<T, inlineCapacity>::operator=(const Vector<T, otherCapacity>& other) { - if (&other == this) - return *this; - + // If the inline capacities match, we should call the more specific + // template. If the inline capacities don't match, the two objects + // shouldn't be allocated the same address. + ASSERT(!typelessPointersAreEqual(&other, this)); + if (size() > other.size()) shrink(other.size()); else if (other.size() > capacity()) { @@ -681,6 +721,12 @@ namespace WTF { return *this; } +// Works around an assert in VS2010. See https://connect.microsoft.com/VisualStudio/feedback/details/558044/std-copy-should-not-check-dest-when-first-last +#if COMPILER(MSVC) && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL + if (!begin()) + return *this; +#endif + std::copy(other.begin(), other.begin() + size(), begin()); TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end()); m_size = other.size(); @@ -700,6 +746,18 @@ namespace WTF { } template<typename T, size_t inlineCapacity> + template<typename U> + size_t Vector<T, inlineCapacity>::reverseFind(const U& value) const + { + for (size_t i = 1; i <= size(); ++i) { + const size_t index = size() - i; + if (at(index) == value) + return index; + } + return notFound; + } + + template<typename T, size_t inlineCapacity> void Vector<T, inlineCapacity>::fill(const T& val, size_t newSize) { if (size() > newSize) @@ -742,6 +800,26 @@ namespace WTF { return begin() + index; } + template<typename T, size_t inlineCapacity> + bool Vector<T, inlineCapacity>::tryExpandCapacity(size_t newMinCapacity) + { + return tryReserveCapacity(max(newMinCapacity, max(static_cast<size_t>(16), capacity() + capacity() / 4 + 1))); + } + + template<typename T, size_t inlineCapacity> + const T* Vector<T, inlineCapacity>::tryExpandCapacity(size_t newMinCapacity, const T* ptr) + { + if (ptr < begin() || ptr >= end()) { + if (!tryExpandCapacity(newMinCapacity)) + return 0; + return ptr; + } + size_t index = ptr - begin(); + if (!tryExpandCapacity(newMinCapacity)) + return 0; + return begin() + index; + } + template<typename T, size_t inlineCapacity> template<typename U> inline U* Vector<T, inlineCapacity>::expandCapacity(size_t newMinCapacity, U* ptr) { @@ -797,6 +875,21 @@ namespace WTF { } template<typename T, size_t inlineCapacity> + bool Vector<T, inlineCapacity>::tryReserveCapacity(size_t newCapacity) + { + if (newCapacity <= capacity()) + return true; + T* oldBuffer = begin(); + T* oldEnd = end(); + if (!m_buffer.tryAllocateBuffer(newCapacity)) + return false; + ASSERT(begin()); + TypeOperations::move(oldBuffer, oldEnd, begin()); + m_buffer.deallocateBuffer(oldBuffer); + return true; + } + + template<typename T, size_t inlineCapacity> inline void Vector<T, inlineCapacity>::reserveInitialCapacity(size_t initialCapacity) { ASSERT(!m_size); @@ -848,6 +941,25 @@ namespace WTF { } template<typename T, size_t inlineCapacity> template<typename U> + bool Vector<T, inlineCapacity>::tryAppend(const U* data, size_t dataSize) + { + size_t newSize = m_size + dataSize; + if (newSize > capacity()) { + data = tryExpandCapacity(newSize, data); + if (!data) + return false; + ASSERT(begin()); + } + if (newSize < m_size) + return false; + T* dest = end(); + for (size_t i = 0; i < dataSize; ++i) + new (&dest[i]) T(data[i]); + m_size = newSize; + return true; + } + + template<typename T, size_t inlineCapacity> template<typename U> ALWAYS_INLINE void Vector<T, inlineCapacity>::append(const U& val) { const U* ptr = &val; @@ -857,7 +969,7 @@ namespace WTF { return; } -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) // FIXME: MSVC7 generates compilation errors when trying to assign // a pointer to a Vector of its base class (i.e. can't downcast). So far // I've been unable to determine any logical reason for this, so I can |
