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