diff --git a/Libraries/LibJS/Runtime/IndexedProperties.cpp b/Libraries/LibJS/Runtime/IndexedProperties.cpp index 12538bf075..83a79b9be8 100644 --- a/Libraries/LibJS/Runtime/IndexedProperties.cpp +++ b/Libraries/LibJS/Runtime/IndexedProperties.cpp @@ -24,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include @@ -229,22 +230,16 @@ IndexedPropertyIterator::IndexedPropertyIterator(const IndexedProperties& indexe , m_index(staring_index) , m_skip_empty(skip_empty) { - while (m_skip_empty && m_index < m_indexed_properties.array_like_size()) { - if (m_indexed_properties.has_index(m_index)) - break; - m_index++; - } + if (m_skip_empty) + skip_empty_indices(); } IndexedPropertyIterator& IndexedPropertyIterator::operator++() { m_index++; - while (m_skip_empty && m_index < m_indexed_properties.array_like_size()) { - if (m_indexed_properties.has_index(m_index)) - break; - m_index++; - }; + if (m_skip_empty) + skip_empty_indices(); return *this; } @@ -266,6 +261,21 @@ ValueAndAttributes IndexedPropertyIterator::value_and_attributes(Object* this_ob return {}; } +void IndexedPropertyIterator::skip_empty_indices() +{ + auto indices = m_indexed_properties.indices(); + if (indices.is_empty()) { + m_index = m_indexed_properties.array_like_size(); + return; + } + for (auto i : indices) { + if (i < m_index) + continue; + m_index = i; + break; + } +} + Optional IndexedProperties::get(Object* this_object, u32 index, bool evaluate_accessors) const { auto result = m_storage->get(index); @@ -354,6 +364,32 @@ void IndexedProperties::set_array_like_size(size_t new_size) m_storage->set_array_like_size(new_size); } +Vector IndexedProperties::indices() const +{ + Vector indices; + if (m_storage->is_simple_storage()) { + const auto& storage = static_cast(*m_storage); + const auto& elements = storage.elements(); + indices.ensure_capacity(storage.array_like_size()); + for (size_t i = 0; i < elements.size(); ++i) { + if (!elements.at(i).is_empty()) + indices.unchecked_append(i); + } + } else { + const auto& storage = static_cast(*m_storage); + const auto packed_elements = storage.packed_elements(); + indices.ensure_capacity(storage.array_like_size()); + for (size_t i = 0; i < packed_elements.size(); ++i) { + if (!packed_elements.at(i).value.is_empty()) + indices.unchecked_append(i); + } + auto sparse_elements_keys = storage.sparse_elements().keys(); + quick_sort(sparse_elements_keys); + indices.append(move(sparse_elements_keys)); + } + return indices; +} + Vector IndexedProperties::values_unordered() const { if (m_storage->is_simple_storage()) { diff --git a/Libraries/LibJS/Runtime/IndexedProperties.h b/Libraries/LibJS/Runtime/IndexedProperties.h index a6d89b77c3..c0ce391c0e 100644 --- a/Libraries/LibJS/Runtime/IndexedProperties.h +++ b/Libraries/LibJS/Runtime/IndexedProperties.h @@ -130,6 +130,8 @@ public: ValueAndAttributes value_and_attributes(Object* this_object, bool evaluate_accessors = true); private: + void skip_empty_indices(); + const IndexedProperties& m_indexed_properties; u32 m_index; bool m_skip_empty; @@ -164,6 +166,8 @@ public: size_t array_like_size() const { return m_storage->array_like_size(); } void set_array_like_size(size_t); + Vector indices() const; + Vector values_unordered() const; private: