/* * Copyright (C) 2013, 2016 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. ``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 * 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 "IterationKind.h" #include "JSInternalFieldObjectImpl.h" #include "JSMap.h" namespace JSC { class JSMapIterator final : public JSInternalFieldObjectImpl<3> { public: using HashMapBucketType = HashMapBucket; using Base = JSInternalFieldObjectImpl<3>; DECLARE_EXPORT_INFO; enum class Field : uint8_t { MapBucket = 0, IteratedObject, Kind, }; static_assert(numberOfInternalFields == 3); static std::array initialValues() { return { { jsNull(), jsNull(), jsNumber(0), } }; } const WriteBarrier& internalField(Field field) const { return Base::internalField(static_cast(field)); } WriteBarrier& internalField(Field field) { return Base::internalField(static_cast(field)); } template static IsoSubspace* subspaceFor(VM& vm) { return vm.mapIteratorSpace(); } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(vm, globalObject, prototype, TypeInfo(JSMapIteratorType, StructureFlags), info()); } static JSMapIterator* create(VM& vm, Structure* structure, JSMap* iteratedObject, IterationKind kind) { JSMapIterator* instance = new (NotNull, allocateCell(vm.heap)) JSMapIterator(vm, structure); instance->finishCreation(vm, iteratedObject, kind); return instance; } static JSMapIterator* createWithInitialValues(VM&, Structure*); ALWAYS_INLINE HashMapBucketType* advanceIter(VM& vm) { HashMapBucketType* prev = iterator(); HashMapBucketType* sentinel = jsCast(vm.sentinelMapBucket()); if (prev == sentinel) return nullptr; HashMapBucketType* bucket = prev->next(); while (bucket && bucket->deleted()) bucket = bucket->next(); if (!bucket) { setIterator(vm, sentinel); return nullptr; } setIterator(vm, bucket); // We keep iterator on the last value since the first thing we do in this function is call next(). return bucket; } bool next(JSGlobalObject* globalObject, JSValue& value) { HashMapBucketType* bucket = advanceIter(getVM(globalObject)); if (!bucket) return false; switch (kind()) { case IterationKind::Values: value = bucket->value(); break; case IterationKind::Keys: value = bucket->key(); break; case IterationKind::Entries: value = createPair(globalObject, bucket->key(), bucket->value()); break; } return true; } bool nextKeyValue(JSGlobalObject* globalObject, JSValue& key, JSValue& value) { HashMapBucketType* bucket = advanceIter(getVM(globalObject)); if (!bucket) return false; key = bucket->key(); value = bucket->value(); return true; } IterationKind kind() const { return static_cast(internalField(Field::Kind).get().asUInt32AsAnyInt()); } JSObject* iteratedObject() const { return jsCast(internalField(Field::IteratedObject).get()); } HashMapBucketType* iterator() const { return jsCast(internalField(Field::MapBucket).get()); } private: JSMapIterator(VM& vm, Structure* structure) : Base(vm, structure) { } void setIterator(VM& vm, HashMapBucketType* bucket) { internalField(Field::MapBucket).set(vm, this, bucket); } JS_EXPORT_PRIVATE void finishCreation(VM&, JSMap*, IterationKind); void finishCreation(VM&); JSValue createPair(JSGlobalObject*, JSValue, JSValue); static void visitChildren(JSCell*, SlotVisitor&); }; STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSMapIterator); } // namespace JSC