NativeSet.java revision 1626:d99fa86747ee
11541Srgrimes/* 21541Srgrimes * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41541Srgrimes * 51541Srgrimes * This code is free software; you can redistribute it and/or modify it 61541Srgrimes * under the terms of the GNU General Public License version 2 only, as 71541Srgrimes * published by the Free Software Foundation. Oracle designates this 81541Srgrimes * particular file as subject to the "Classpath" exception as provided 91541Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101541Srgrimes * 111541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151541Srgrimes * accompanied this code). 161541Srgrimes * 171541Srgrimes * You should have received a copy of the GNU General Public License version 181541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201541Srgrimes * 211541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221541Srgrimes * or visit www.oracle.com if you need additional information or have any 231541Srgrimes * questions. 241541Srgrimes */ 251541Srgrimes 261541Srgrimespackage jdk.nashorn.internal.objects; 271541Srgrimes 281541Srgrimesimport java.lang.invoke.MethodHandle; 291541Srgrimesimport jdk.nashorn.internal.objects.annotations.Attribute; 301541Srgrimesimport jdk.nashorn.internal.objects.annotations.Constructor; 311541Srgrimesimport jdk.nashorn.internal.objects.annotations.Function; 321541Srgrimesimport jdk.nashorn.internal.objects.annotations.Getter; 331541Srgrimesimport jdk.nashorn.internal.objects.annotations.ScriptClass; 341541Srgrimesimport jdk.nashorn.internal.objects.annotations.Where; 351541Srgrimesimport jdk.nashorn.internal.runtime.PropertyMap; 361541Srgrimesimport jdk.nashorn.internal.runtime.ScriptObject; 3722521Sdysonimport jdk.nashorn.internal.runtime.ScriptRuntime; 381541Srgrimesimport jdk.nashorn.internal.runtime.Undefined; 3922521Sdysonimport jdk.nashorn.internal.runtime.linker.Bootstrap; 4050477Speter 411541Srgrimesimport static jdk.nashorn.internal.objects.NativeMap.convertKey; 421541Srgrimesimport static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 431541Srgrimes 441541Srgrimes/** 451541Srgrimes * This implements the ECMA6 Set object. 461541Srgrimes */ 477090Sbde@ScriptClass("Set") 487090Sbdepublic class NativeSet extends ScriptObject { 4922521Sdyson 507090Sbde // our set/map implementation 5122579Smpp private final LinkedMap map = new LinkedMap(); 5222579Smpp 5322579Smpp // Invoker for the forEach callback 5422521Sdyson private final static Object FOREACH_INVOKER_KEY = new Object(); 5522521Sdyson 5622521Sdyson // initialized by nasgen 577090Sbde private static PropertyMap $nasgenmap$; 581541Srgrimes 591541Srgrimes private NativeSet(final ScriptObject proto, final PropertyMap map) { 601541Srgrimes super(proto, map); 611541Srgrimes } 621541Srgrimes 631541Srgrimes /** 641541Srgrimes * ECMA6 23.1 Set constructor 651541Srgrimes * 661541Srgrimes * @param isNew whether the new operator used 671541Srgrimes * @param self self reference 681541Srgrimes * @param arg optional iterable argument 691541Srgrimes * @return a new Set object 701541Srgrimes */ 711541Srgrimes @Constructor(arity = 0) 721541Srgrimes public static Object construct(final boolean isNew, final Object self, final Object arg){ 731541Srgrimes if (!isNew) { 741541Srgrimes throw typeError("constructor.requires.new", "Set"); 751541Srgrimes } 761541Srgrimes final Global global = Global.instance(); 771541Srgrimes final NativeSet set = new NativeSet(global.getSetPrototype(), $nasgenmap$); 781541Srgrimes populateSet(set.getJavaMap(), arg, global); 791541Srgrimes return set; 801541Srgrimes } 811541Srgrimes 821541Srgrimes /** 831541Srgrimes * ECMA6 23.2.3.1 Set.prototype.add ( value ) 841541Srgrimes * 851541Srgrimes * @param self the self reference 861541Srgrimes * @param value the value to add 871541Srgrimes * @return this Set object 881541Srgrimes */ 891541Srgrimes @Function(attributes = Attribute.NOT_ENUMERABLE) 901541Srgrimes public static Object add(final Object self, final Object value) { 911541Srgrimes getNativeSet(self).map.set(convertKey(value), null); 921541Srgrimes return self; 931541Srgrimes } 941541Srgrimes 951541Srgrimes /** 961541Srgrimes * ECMA6 23.2.3.7 Set.prototype.has ( value ) 971541Srgrimes * 981541Srgrimes * @param self the self reference 991541Srgrimes * @param value the value 1001541Srgrimes * @return true if value is contained 1011541Srgrimes */ 1021541Srgrimes @Function(attributes = Attribute.NOT_ENUMERABLE) 1031541Srgrimes public static boolean has(final Object self, final Object value) { 10412595Sbde return getNativeSet(self).map.has(convertKey(value)); 10512595Sbde } 1061541Srgrimes 1071541Srgrimes /** 1081541Srgrimes * ECMA6 23.2.3.2 Set.prototype.clear ( ) 1091541Srgrimes * 1101541Srgrimes * @param self the self reference 1111541Srgrimes */ 1121541Srgrimes @Function(attributes = Attribute.NOT_ENUMERABLE) 1131541Srgrimes public static void clear(final Object self) { 1141541Srgrimes getNativeSet(self).map.clear(); 1151541Srgrimes } 1161541Srgrimes 1171541Srgrimes /** 1181541Srgrimes * ECMA6 23.2.3.4 Set.prototype.delete ( value ) 1191541Srgrimes * 1201541Srgrimes * @param self the self reference 1211541Srgrimes * @param value the value 1221541Srgrimes * @return true if value was deleted 1231541Srgrimes */ 1241541Srgrimes @Function(attributes = Attribute.NOT_ENUMERABLE) 1251541Srgrimes public static boolean delete(final Object self, final Object value) { 1261541Srgrimes return getNativeSet(self).map.delete(convertKey(value)); 12725200Salex } 12825200Salex 12925200Salex /** 13025200Salex * ECMA6 23.2.3.9 get Set.prototype.size 1311541Srgrimes * 1321541Srgrimes * @param self the self reference 1331541Srgrimes * @return the number of contained values 1341541Srgrimes */ 1351541Srgrimes @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.IS_ACCESSOR, where = Where.PROTOTYPE) 1361541Srgrimes public static int size(final Object self) { 1371541Srgrimes return getNativeSet(self).map.size(); 1381541Srgrimes } 1391541Srgrimes 1406569Sdg /** 1411541Srgrimes * ECMA6 23.2.3.5 Set.prototype.entries ( ) 1421541Srgrimes * 1431541Srgrimes * @param self the self reference 1441541Srgrimes * @return an iterator over the Set object's entries 1451541Srgrimes */ 1461541Srgrimes @Function(attributes = Attribute.NOT_ENUMERABLE) 1471541Srgrimes public static Object entries(final Object self) { 1481541Srgrimes return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.KEY_VALUE, Global.instance()); 1491541Srgrimes } 1501541Srgrimes 1511541Srgrimes /** 1521541Srgrimes * ECMA6 23.2.3.8 Set.prototype.keys ( ) 1531541Srgrimes * 1541541Srgrimes * @param self the self reference 1551541Srgrimes * @return an iterator over the Set object's values 1561541Srgrimes */ 1571541Srgrimes @Function(attributes = Attribute.NOT_ENUMERABLE) 1581541Srgrimes public static Object keys(final Object self) { 1591541Srgrimes return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.KEY, Global.instance()); 1601541Srgrimes } 1611541Srgrimes 1621541Srgrimes /** 1631541Srgrimes * ECMA6 23.2.3.10 Set.prototype.values ( ) 1641541Srgrimes * 1651541Srgrimes * @param self the self reference 16613608Speter * @return an iterator over the Set object's values 16713608Speter */ 1681541Srgrimes @Function(attributes = Attribute.NOT_ENUMERABLE) 1691541Srgrimes public static Object values(final Object self) { 1701541Srgrimes return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.VALUE, Global.instance()); 1711541Srgrimes } 17213608Speter 1731541Srgrimes /** 1741541Srgrimes * ECMA6 23.2.3.11 Set.prototype [ @@iterator ] ( ) 1751541Srgrimes * 1761541Srgrimes * @param self the self reference 1771541Srgrimes * @return an iterator over the Set object's values 1781541Srgrimes */ 1791541Srgrimes @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator") 1801541Srgrimes public static Object getIterator(final Object self) { 1811541Srgrimes return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.VALUE, Global.instance()); 1821541Srgrimes } 1831541Srgrimes 1841541Srgrimes /** 1851541Srgrimes * ECMA6 23.2.3.6 Set.prototype.forEach ( callbackfn [ , thisArg ] ) 1861541Srgrimes * 1871541Srgrimes * @param self the self reference 1881541Srgrimes * @param callbackFn the callback function 1891541Srgrimes * @param thisArg optional this object 1901541Srgrimes */ 1911541Srgrimes @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1921541Srgrimes public static void forEach(final Object self, final Object callbackFn, final Object thisArg) { 1931541Srgrimes final NativeSet set = getNativeSet(self); 1945312Sache if (!Bootstrap.isCallable(callbackFn)) { 1955312Sache throw typeError("not.a.function", ScriptRuntime.safeToString(callbackFn)); 1965312Sache } 1971541Srgrimes final MethodHandle invoker = Global.instance().getDynamicInvoker(FOREACH_INVOKER_KEY, 1981541Srgrimes () -> Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class, Object.class, Object.class, Object.class)); 1991541Srgrimes 2001541Srgrimes final LinkedMap.LinkedMapIterator iterator = set.getJavaMap().getIterator(); 2011541Srgrimes for (;;) { 2021541Srgrimes final LinkedMap.Node node = iterator.next(); 2031541Srgrimes if (node == null) { 2041541Srgrimes break; 2051541Srgrimes } 2061541Srgrimes 2071541Srgrimes try { 2081541Srgrimes final Object result = invoker.invokeExact(callbackFn, thisArg, node.getKey(), node.getKey(), self); 2091541Srgrimes } catch (final RuntimeException | Error e) { 2101541Srgrimes throw e; 2111541Srgrimes } catch (final Throwable t) { 2121541Srgrimes throw new RuntimeException(t); 2131541Srgrimes } 2141541Srgrimes } 2151541Srgrimes } 21613608Speter 21722521Sdyson @Override 21813608Speter public String getClassName() { 21922521Sdyson return "Set"; 22022521Sdyson } 2211541Srgrimes 2221541Srgrimes static void populateSet(final LinkedMap map, final Object arg, final Global global) { 2231541Srgrimes if (arg != null && arg != Undefined.getUndefined()) { 2241541Srgrimes AbstractIterator.iterate(arg, global, value -> map.set(convertKey(value), null)); 2251541Srgrimes } 2261541Srgrimes } 2271541Srgrimes 2281541Srgrimes LinkedMap getJavaMap() { 2291541Srgrimes return map; 2301541Srgrimes } 2311541Srgrimes 2321541Srgrimes private static NativeSet getNativeSet(final Object self) { 2331541Srgrimes if (self instanceof NativeSet) { 2341541Srgrimes return (NativeSet) self; 2351541Srgrimes } else { 2361541Srgrimes throw typeError("not.a.set", ScriptRuntime.safeToString(self)); 2371541Srgrimes } 2381541Srgrimes } 2391541Srgrimes} 2401541Srgrimes