1// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28"use strict";
29
30var $Set = global.Set;
31var $Map = global.Map;
32var $WeakMap = global.WeakMap;
33
34//-------------------------------------------------------------------
35
36// Global sentinel to be used instead of undefined keys, which are not
37// supported internally but required for Harmony sets and maps.
38var undefined_sentinel = {};
39
40
41function SetConstructor() {
42  if (%_IsConstructCall()) {
43    %SetInitialize(this);
44  } else {
45    return new $Set();
46  }
47}
48
49
50function SetAdd(key) {
51  if (!IS_SET(this)) {
52    throw MakeTypeError('incompatible_method_receiver',
53                        ['Set.prototype.add', this]);
54  }
55  if (IS_UNDEFINED(key)) {
56    key = undefined_sentinel;
57  }
58  return %SetAdd(this, key);
59}
60
61
62function SetHas(key) {
63  if (!IS_SET(this)) {
64    throw MakeTypeError('incompatible_method_receiver',
65                        ['Set.prototype.has', this]);
66  }
67  if (IS_UNDEFINED(key)) {
68    key = undefined_sentinel;
69  }
70  return %SetHas(this, key);
71}
72
73
74function SetDelete(key) {
75  if (!IS_SET(this)) {
76    throw MakeTypeError('incompatible_method_receiver',
77                        ['Set.prototype.delete', this]);
78  }
79  if (IS_UNDEFINED(key)) {
80    key = undefined_sentinel;
81  }
82  return %SetDelete(this, key);
83}
84
85
86function MapConstructor() {
87  if (%_IsConstructCall()) {
88    %MapInitialize(this);
89  } else {
90    return new $Map();
91  }
92}
93
94
95function MapGet(key) {
96  if (!IS_MAP(this)) {
97    throw MakeTypeError('incompatible_method_receiver',
98                        ['Map.prototype.get', this]);
99  }
100  if (IS_UNDEFINED(key)) {
101    key = undefined_sentinel;
102  }
103  return %MapGet(this, key);
104}
105
106
107function MapSet(key, value) {
108  if (!IS_MAP(this)) {
109    throw MakeTypeError('incompatible_method_receiver',
110                        ['Map.prototype.set', this]);
111  }
112  if (IS_UNDEFINED(key)) {
113    key = undefined_sentinel;
114  }
115  return %MapSet(this, key, value);
116}
117
118
119function MapHas(key) {
120  if (!IS_MAP(this)) {
121    throw MakeTypeError('incompatible_method_receiver',
122                        ['Map.prototype.has', this]);
123  }
124  if (IS_UNDEFINED(key)) {
125    key = undefined_sentinel;
126  }
127  return !IS_UNDEFINED(%MapGet(this, key));
128}
129
130
131function MapDelete(key) {
132  if (!IS_MAP(this)) {
133    throw MakeTypeError('incompatible_method_receiver',
134                        ['Map.prototype.delete', this]);
135  }
136  if (IS_UNDEFINED(key)) {
137    key = undefined_sentinel;
138  }
139  if (!IS_UNDEFINED(%MapGet(this, key))) {
140    %MapSet(this, key, void 0);
141    return true;
142  } else {
143    return false;
144  }
145}
146
147
148function WeakMapConstructor() {
149  if (%_IsConstructCall()) {
150    %WeakMapInitialize(this);
151  } else {
152    return new $WeakMap();
153  }
154}
155
156
157function WeakMapGet(key) {
158  if (!IS_WEAKMAP(this)) {
159    throw MakeTypeError('incompatible_method_receiver',
160                        ['WeakMap.prototype.get', this]);
161  }
162  if (!IS_SPEC_OBJECT(key)) {
163    throw %MakeTypeError('invalid_weakmap_key', [this, key]);
164  }
165  return %WeakMapGet(this, key);
166}
167
168
169function WeakMapSet(key, value) {
170  if (!IS_WEAKMAP(this)) {
171    throw MakeTypeError('incompatible_method_receiver',
172                        ['WeakMap.prototype.set', this]);
173  }
174  if (!IS_SPEC_OBJECT(key)) {
175    throw %MakeTypeError('invalid_weakmap_key', [this, key]);
176  }
177  return %WeakMapSet(this, key, value);
178}
179
180
181function WeakMapHas(key) {
182  if (!IS_WEAKMAP(this)) {
183    throw MakeTypeError('incompatible_method_receiver',
184                        ['WeakMap.prototype.has', this]);
185  }
186  if (!IS_SPEC_OBJECT(key)) {
187    throw %MakeTypeError('invalid_weakmap_key', [this, key]);
188  }
189  return !IS_UNDEFINED(%WeakMapGet(this, key));
190}
191
192
193function WeakMapDelete(key) {
194  if (!IS_WEAKMAP(this)) {
195    throw MakeTypeError('incompatible_method_receiver',
196                        ['WeakMap.prototype.delete', this]);
197  }
198  if (!IS_SPEC_OBJECT(key)) {
199    throw %MakeTypeError('invalid_weakmap_key', [this, key]);
200  }
201  if (!IS_UNDEFINED(%WeakMapGet(this, key))) {
202    %WeakMapSet(this, key, void 0);
203    return true;
204  } else {
205    return false;
206  }
207}
208
209// -------------------------------------------------------------------
210
211(function () {
212  %CheckIsBootstrapping();
213
214  // Set up the Set and Map constructor function.
215  %SetCode($Set, SetConstructor);
216  %SetCode($Map, MapConstructor);
217
218  // Set up the constructor property on the Set and Map prototype object.
219  %SetProperty($Set.prototype, "constructor", $Set, DONT_ENUM);
220  %SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM);
221
222  // Set up the non-enumerable functions on the Set prototype object.
223  InstallFunctions($Set.prototype, DONT_ENUM, $Array(
224    "add", SetAdd,
225    "has", SetHas,
226    "delete", SetDelete
227  ));
228
229  // Set up the non-enumerable functions on the Map prototype object.
230  InstallFunctions($Map.prototype, DONT_ENUM, $Array(
231    "get", MapGet,
232    "set", MapSet,
233    "has", MapHas,
234    "delete", MapDelete
235  ));
236
237  // Set up the WeakMap constructor function.
238  %SetCode($WeakMap, WeakMapConstructor);
239
240  // Set up the constructor property on the WeakMap prototype object.
241  %SetProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM);
242
243  // Set up the non-enumerable functions on the WeakMap prototype object.
244  InstallFunctions($WeakMap.prototype, DONT_ENUM, $Array(
245    "get", WeakMapGet,
246    "set", WeakMapSet,
247    "has", WeakMapHas,
248    "delete", WeakMapDelete
249  ));
250})();
251