/* * Copyright (C) 2014-2019 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include #include #include #include namespace JSC { DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(GCSegmentedArray); template class GCArraySegment : public DoublyLinkedListNode> { friend class WTF::DoublyLinkedListNode>; public: GCArraySegment() : DoublyLinkedListNode>() #if ASSERT_ENABLED , m_top(0) #endif { } static GCArraySegment* create(); static void destroy(GCArraySegment*); T* data() { return bitwise_cast(this + 1); } static constexpr size_t blockSize = 4 * KB; GCArraySegment* m_prev; GCArraySegment* m_next; #if ASSERT_ENABLED size_t m_top; #endif }; template class GCSegmentedArrayIterator; template class GCSegmentedArray { WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(GCSegmentedArray); friend class GCSegmentedArrayIterator; friend class GCSegmentedArrayIterator; public: GCSegmentedArray(); ~GCSegmentedArray(); void append(T); bool canRemoveLast(); const T removeLast(); bool refill(); size_t size(); bool isEmpty(); void fillVector(Vector&); void clear(); typedef GCSegmentedArrayIterator iterator; iterator begin() const { return GCSegmentedArrayIterator(m_segments.head(), m_top); } iterator end() const { return GCSegmentedArrayIterator(); } protected: template struct CapacityFromSize { static constexpr size_t value = (size - sizeof(GCArraySegment)) / sizeof(T); }; void expand(); size_t postIncTop(); size_t preDecTop(); void setTopForFullSegment(); void setTopForEmptySegment(); size_t top(); void validatePrevious(); DoublyLinkedList> m_segments; JS_EXPORT_PRIVATE static const size_t s_segmentCapacity = CapacityFromSize::blockSize>::value; size_t m_top; size_t m_numberOfSegments; }; template class GCSegmentedArrayIterator { friend class GCSegmentedArray; public: GCSegmentedArrayIterator() : m_currentSegment(nullptr) , m_currentOffset(0) { } T& get() { return m_currentSegment->data()[m_currentOffset]; } T& operator*() { return get(); } T& operator->() { return get(); } bool operator==(const GCSegmentedArrayIterator& other) { return m_currentSegment == other.m_currentSegment && m_currentOffset == other.m_currentOffset; } bool operator!=(const GCSegmentedArrayIterator& other) { return !(*this == other); } GCSegmentedArrayIterator& operator++() { ASSERT(m_currentSegment); m_currentOffset++; if (m_currentOffset >= m_offsetLimit) { m_currentSegment = m_currentSegment->next(); m_currentOffset = 0; m_offsetLimit = GCSegmentedArray::s_segmentCapacity; } return *this; } private: GCSegmentedArrayIterator(GCArraySegment* start, size_t top) : m_currentSegment(start) , m_currentOffset(0) , m_offsetLimit(top) { if (!m_offsetLimit) m_currentSegment = nullptr; } GCArraySegment* m_currentSegment; size_t m_currentOffset; size_t m_offsetLimit; }; } // namespace JSC