1/*
2 * Copyright (C) 2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY CANON INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CANON INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "JSDOMBinding.h"
29#include "JSDOMConvert.h"
30#include "JSDOMGuardedObject.h"
31#include <JavaScriptCore/BuiltinNames.h>
32#include <JavaScriptCore/CommonIdentifiers.h>
33#include <JavaScriptCore/JSMap.h>
34
35namespace WebCore {
36
37JSC::JSMap& createBackingMap(JSC::ExecState&, JSC::JSGlobalObject&, JSC::JSObject&);
38void initializeBackingMap(JSC::VM&, JSC::JSObject&, JSC::JSMap&);
39JSC::JSValue forwardAttributeGetterToBackingMap(JSC::ExecState&, JSC::JSObject&, const JSC::Identifier&);
40JSC::JSValue forwardFunctionCallToBackingMap(JSC::ExecState&, JSC::JSObject&, const JSC::Identifier&);
41JSC::JSValue forwardForEachCallToBackingMap(JSC::ExecState&, JSDOMGlobalObject&, JSC::JSObject&);
42
43template<typename WrapperClass> void synchronizeBackingMap(JSC::ExecState&, JSDOMGlobalObject&, WrapperClass&);
44template<typename WrapperClass> JSC::JSValue forwardSizeToMapLike(JSC::ExecState&, WrapperClass&);
45template<typename WrapperClass> JSC::JSValue forwardEntriesToMapLike(JSC::ExecState&, WrapperClass&);
46template<typename WrapperClass> JSC::JSValue forwardKeysToMapLike(JSC::ExecState&, WrapperClass&);
47template<typename WrapperClass> JSC::JSValue forwardValuesToMapLike(JSC::ExecState&, WrapperClass&);
48template<typename WrapperClass> JSC::JSValue forwardClearToMapLike(JSC::ExecState&, WrapperClass&);
49template<typename WrapperClass, typename Callback> JSC::JSValue forwardForEachToMapLike(JSC::ExecState&, WrapperClass&, Callback&&);
50template<typename WrapperClass, typename ItemType> JSC::JSValue forwardGetToMapLike(JSC::ExecState&, WrapperClass&, ItemType&&);
51template<typename WrapperClass, typename ItemType> JSC::JSValue forwardHasToMapLike(JSC::ExecState&, WrapperClass&, ItemType&&);
52template<typename WrapperClass, typename ItemType> JSC::JSValue forwardAddToMapLike(JSC::ExecState&, WrapperClass&, ItemType&&);
53template<typename WrapperClass, typename ItemType> JSC::JSValue forwardDeleteToMapLike(JSC::ExecState&, WrapperClass&, ItemType&&);
54
55class DOMMapLike final : public DOMGuarded<JSC::JSMap> {
56public:
57 static Ref<DOMMapLike> create(JSDOMGlobalObject& globalObject, JSC::JSMap& map) { return adoptRef(*new DOMMapLike(globalObject, map)); }
58
59 template<typename Key, typename Value> void set(typename Key::ParameterType&&, typename Value::ParameterType&&);
60
61 JSC::JSMap* backingMap() { return guarded(); }
62
63protected:
64 DOMMapLike(JSDOMGlobalObject& globalObject, JSC::JSMap& map) : DOMGuarded<JSC::JSMap>(globalObject, map) { }
65};
66
67template<typename Key, typename Value> inline void DOMMapLike::set(typename Key::ParameterType&& key, typename Value::ParameterType&& value)
68{
69 if (isEmpty())
70 return;
71 auto* state = globalObject()->globalExec();
72 JSC::JSLockHolder locker(state);
73 backingMap()->set(state,
74 toJS<Key>(*state, *globalObject(), std::forward<typename Key::ParameterType>(key)),
75 toJS<Value>(*state, *globalObject(), std::forward<typename Value::ParameterType>(value)));
76}
77
78template<typename WrapperClass> inline void synchronizeBackingMap(JSC::ExecState& state, JSDOMGlobalObject& globalObject, WrapperClass& mapLike)
79{
80 auto backingMap = mapLike.wrapped().backingMap();
81 if (backingMap) {
82 ASSERT(backingMap->backingMap());
83 initializeBackingMap(state.vm(), mapLike, *backingMap->backingMap());
84 return;
85 }
86 auto& map = createBackingMap(state, globalObject, mapLike);
87 mapLike.wrapped().synchronizeBackingMap(DOMMapLike::create(globalObject, map));
88}
89
90template<typename WrapperClass> inline JSC::JSValue forwardSizeToMapLike(JSC::ExecState& state, WrapperClass& mapLike)
91{
92 JSC::VM& vm = state.vm();
93 return forwardAttributeGetterToBackingMap(state, mapLike, vm.propertyNames->size);
94}
95
96template<typename WrapperClass> inline JSC::JSValue forwardEntriesToMapLike(JSC::ExecState& state, WrapperClass& mapLike)
97{
98 JSC::VM& vm = state.vm();
99 return forwardFunctionCallToBackingMap(state, mapLike, vm.propertyNames->builtinNames().entriesPublicName());
100}
101
102template<typename WrapperClass> inline JSC::JSValue forwardKeysToMapLike(JSC::ExecState& state, WrapperClass& mapLike)
103{
104 JSC::VM& vm = state.vm();
105 return forwardFunctionCallToBackingMap(state, mapLike, vm.propertyNames->builtinNames().keysPublicName());
106}
107
108template<typename WrapperClass> inline JSC::JSValue forwardValuesToMapLike(JSC::ExecState& state, WrapperClass& mapLike)
109{
110 JSC::VM& vm = state.vm();
111 return forwardFunctionCallToBackingMap(state, mapLike, vm.propertyNames->builtinNames().valuesPublicName());
112}
113
114template<typename WrapperClass> inline JSC::JSValue forwardClearToMapLike(JSC::ExecState& state, WrapperClass& mapLike)
115{
116 mapLike.wrapped().clear();
117 return forwardFunctionCallToBackingMap(state, mapLike, state.vm().propertyNames->clear);
118}
119
120template<typename WrapperClass, typename Callback> inline JSC::JSValue forwardForEachToMapLike(JSC::ExecState& state, WrapperClass& mapLike, Callback&&)
121{
122 return forwardForEachCallToBackingMap(state, *mapLike.globalObject(), mapLike);
123}
124
125template<typename WrapperClass, typename ItemType> inline JSC::JSValue forwardGetToMapLike(JSC::ExecState& state, WrapperClass& mapLike, ItemType&&)
126{
127 JSC::VM& vm = state.vm();
128 return forwardFunctionCallToBackingMap(state, mapLike, vm.propertyNames->builtinNames().getPublicName());
129}
130
131template<typename WrapperClass, typename ItemType> inline JSC::JSValue forwardHasToMapLike(JSC::ExecState& state, WrapperClass& mapLike, ItemType&&)
132{
133 JSC::VM& vm = state.vm();
134 return forwardFunctionCallToBackingMap(state, mapLike, vm.propertyNames->builtinNames().hasPublicName());
135}
136
137template<typename WrapperClass, typename ItemType> inline JSC::JSValue forwardAddToMapLike(JSC::ExecState& state, WrapperClass& mapLike, ItemType&& item)
138{
139 if (mapLike.wrapped().addFromMapLike(std::forward<ItemType>(item)))
140 forwardFunctionCallToBackingMap(state, mapLike, state.vm().propertyNames->add);
141 return &mapLike;
142}
143
144template<typename WrapperClass, typename ItemType> inline JSC::JSValue forwardDeleteToMapLike(JSC::ExecState& state, WrapperClass& mapLike, ItemType&& item)
145{
146 auto isDeleted = mapLike.wrapped().remove(std::forward<ItemType>(item));
147 UNUSED_PARAM(isDeleted);
148 auto result = forwardFunctionCallToBackingMap(state, mapLike, state.vm().propertyNames->deleteKeyword);
149 ASSERT_UNUSED(result, result.asBoolean() == isDeleted);
150 return result;
151}
152
153}
154