1 /*
   2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.objects;
  27 
  28 import java.util.Map;
  29 import java.util.WeakHashMap;
  30 import jdk.nashorn.internal.objects.annotations.Attribute;
  31 import jdk.nashorn.internal.objects.annotations.Constructor;
  32 import jdk.nashorn.internal.objects.annotations.Function;
  33 import jdk.nashorn.internal.objects.annotations.ScriptClass;
  34 import jdk.nashorn.internal.runtime.PropertyMap;
  35 import jdk.nashorn.internal.runtime.ScriptObject;
  36 import jdk.nashorn.internal.runtime.ScriptRuntime;
  37 import jdk.nashorn.internal.runtime.Undefined;
  38 
  39 import static jdk.nashorn.internal.objects.NativeWeakMap.checkKey;
  40 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
  41 import static jdk.nashorn.internal.runtime.JSType.isPrimitive;
  42 
  43 /**
  44  * This implements the ECMA6 WeakSet object.
  45  */
  46 @ScriptClass("WeakSet")
  47 public class NativeWeakSet extends ScriptObject {
  48 
  49     private final Map<Object, Boolean> map = new WeakHashMap<>();
  50 
  51     // initialized by nasgen
  52     private static PropertyMap $nasgenmap$;
  53 
  54     private NativeWeakSet(final ScriptObject proto, final PropertyMap map) {
  55         super(proto, map);
  56     }
  57 
  58     /**
  59      * ECMA6 23.3.1 The WeakSet Constructor
  60      *
  61      * @param isNew  whether the new operator used
  62      * @param self self reference
  63      * @param arg optional iterable argument
  64      * @return a new WeakSet object
  65      */
  66     @Constructor(arity = 0)
  67     public static Object construct(final boolean isNew, final Object self, final Object arg) {
  68         if (!isNew) {
  69             throw typeError("constructor.requires.new", "WeakSet");
  70         }
  71         final Global global = Global.instance();
  72         final NativeWeakSet weakSet = new NativeWeakSet(global.getWeakSetPrototype(), $nasgenmap$);
  73         populateWeakSet(weakSet.map, arg, global);
  74         return weakSet;
  75     }
  76 
  77     /**
  78      * ECMA6 23.4.3.1 WeakSet.prototype.add ( value )
  79      *
  80      * @param self the self reference
  81      * @param value the value to add
  82      * @return this Set object
  83      */
  84     @Function(attributes = Attribute.NOT_ENUMERABLE)
  85     public static Object add(final Object self, final Object value) {
  86         final NativeWeakSet set = getSet(self);
  87         set.map.put(checkKey(value), Boolean.TRUE);
  88         return self;
  89     }
  90 
  91     /**
  92      * ECMA6 23.4.3.4 WeakSet.prototype.has ( value )
  93      *
  94      * @param self the self reference
  95      * @param value the value
  96      * @return true if value is contained
  97      */
  98     @Function(attributes = Attribute.NOT_ENUMERABLE)
  99     public static boolean has(final Object self, final Object value) {
 100         final NativeWeakSet set = getSet(self);
 101         return !isPrimitive(value) && set.map.containsKey(value);
 102     }
 103 
 104     /**
 105      * ECMA6 23.4.3.3 WeakSet.prototype.delete ( value )
 106      *
 107      * @param self the self reference
 108      * @param value the value
 109      * @return true if value was deleted
 110      */
 111     @Function(attributes = Attribute.NOT_ENUMERABLE)
 112     public static boolean delete(final Object self, final Object value) {
 113         final Map<Object, Boolean> map = getSet(self).map;
 114         if (isPrimitive(value)) {
 115             return false;
 116         }
 117         final boolean returnValue = map.containsKey(value);
 118         map.remove(value);
 119         return returnValue;
 120     }
 121 
 122     @Override
 123     public String getClassName() {
 124         return "WeakSet";
 125     }
 126 
 127     static void populateWeakSet(final Map<Object, Boolean> set, final Object arg, final Global global) {
 128         if (arg != null && arg != Undefined.getUndefined()) {
 129             AbstractIterator.iterate(arg, global, value -> {
 130                     set.put(checkKey(value), Boolean.TRUE);
 131             });
 132         }
 133     }
 134 
 135     private static NativeWeakSet getSet(final Object self) {
 136         if (self instanceof NativeWeakSet) {
 137             return (NativeWeakSet) self;
 138         } else {
 139             throw typeError("not.a.weak.set", ScriptRuntime.safeToString(self));
 140         }
 141     }
 142 }