This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch danielsun/tweak-ManagedIdentityConcurrentMap
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 9923bced18b32b66954c63667cab1f309a5f5991
Author: Daniel Sun <sun...@apache.org>
AuthorDate: Fri Jul 31 07:41:24 2020 +0800

    Tweak `ConcurrentIdentityHashMap`
---
 .../groovy/util/ConcurrentReferenceHashMap.java    | 107 ++++++++-------
 .../groovy/util/ManagedIdentityConcurrentMap.java  |  48 +++++++
 .../java/org/codehaus/groovy/ast/ClassHelper.java  |   5 +-
 .../org/codehaus/groovy/reflection/ClassInfo.java  |   4 +-
 .../groovy/reflection/MixinInMetaClass.java        |   5 +-
 .../metaclass/ThreadManagedMetaBeanProperty.java   |   4 +-
 .../groovy/util/ManagedIdentityConcurrentMap.java  | 149 ---------------------
 .../util/ManagedIdentityConcurrentMapTest.groovy   |  16 +--
 8 files changed, 120 insertions(+), 218 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/util/ConcurrentReferenceHashMap.java 
b/src/main/java/org/apache/groovy/util/ConcurrentReferenceHashMap.java
similarity index 95%
rename from 
src/main/java/org/codehaus/groovy/util/ConcurrentReferenceHashMap.java
rename to src/main/java/org/apache/groovy/util/ConcurrentReferenceHashMap.java
index 171e4f1..9c4395a 100644
--- a/src/main/java/org/codehaus/groovy/util/ConcurrentReferenceHashMap.java
+++ b/src/main/java/org/apache/groovy/util/ConcurrentReferenceHashMap.java
@@ -1,4 +1,22 @@
 /*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+/*
  * Copyright (c) 2008-2020, Hazelcast, Inc. All Rights Reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +32,7 @@
  * limitations under the License.
  */
 
-package org.codehaus.groovy.util;
+package org.apache.groovy.util;
 
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
@@ -22,7 +40,6 @@ package org.codehaus.groovy.util;
  * http://creativecommons.org/licenses/publicdomain
  */
 
-import com.hazelcast.internal.serialization.SerializableByConvention;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 import java.io.IOException;
@@ -44,13 +61,12 @@ import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 
-import static com.hazelcast.internal.util.Preconditions.checkNotNull;
-
 /**
  * An advanced hash table supporting configurable garbage collection semantics
  * of keys and values, optional referential-equality, full concurrency of
@@ -149,10 +165,7 @@ import static 
com.hazelcast.internal.util.Preconditions.checkNotNull;
  * @author Jason T. Greene
  */
 @SuppressWarnings("all")
-@SerializableByConvention
-public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V>
-        implements com.hazelcast.internal.util.IConcurrentMap<K, V>, 
Serializable {
-
+public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> 
implements Serializable {
     /*
      * The basic strategy is to subdivide the table among Segments,
      * each of which itself is a concurrently readable hash table.
@@ -194,28 +207,28 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
 
     /* ---------------- Constants -------------- */
 
-    static final ReferenceType DEFAULT_KEY_TYPE = ReferenceType.WEAK;
+    private static final ReferenceType DEFAULT_KEY_TYPE = ReferenceType.WEAK;
 
-    static final ReferenceType DEFAULT_VALUE_TYPE = ReferenceType.STRONG;
+    private static final ReferenceType DEFAULT_VALUE_TYPE = 
ReferenceType.STRONG;
 
 
     /**
      * The default initial capacity for this table,
      * used when not otherwise specified in a constructor.
      */
-    static final int DEFAULT_INITIAL_CAPACITY = 16;
+    private static final int DEFAULT_INITIAL_CAPACITY = 16;
 
     /**
      * The default load factor for this table, used when not
      * otherwise specified in a constructor.
      */
-    static final float DEFAULT_LOAD_FACTOR = 0.75f;
+    private static final float DEFAULT_LOAD_FACTOR = 0.75f;
 
     /**
      * The default concurrency level for this table, used when not
      * otherwise specified in a constructor.
      */
-    static final int DEFAULT_CONCURRENCY_LEVEL = 16;
+    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
 
     /**
      * The maximum capacity, used if a higher value is implicitly
@@ -223,13 +236,13 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
      * be a power of two &lt;= 1&lt;&lt;30 to ensure that entries are indexable
      * using ints.
      */
-    static final int MAXIMUM_CAPACITY = 1 << 30;
+    private static final int MAXIMUM_CAPACITY = 1 << 30;
 
     /**
      * The maximum number of segments to allow; used to bound
      * constructor arguments.
      */
-    static final int MAX_SEGMENTS = 1 << 16;
+    private static final int MAX_SEGMENTS = 1 << 16;
 
     /**
      * Number of unsynchronized retries in size and containsValue
@@ -237,7 +250,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
      * unbounded retries if tables undergo continuous modification
      * which would make it impossible to obtain an accurate result.
      */
-    static final int RETRIES_BEFORE_LOCK = 2;
+    private static final int RETRIES_BEFORE_LOCK = 2;
 
     private static final long serialVersionUID = 7249069246763182397L;
 
@@ -247,23 +260,23 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
      * Mask value for indexing into segments. The upper bits of a
      * key's hash code are used to choose the segment.
      */
-    final int segmentMask;
+    private final int segmentMask;
 
     /**
      * Shift value for indexing within segments.
      */
-    final int segmentShift;
+    private final int segmentShift;
 
     /**
      * The segments, each of which is a specialized hash table
      */
-    final Segment<K, V>[] segments;
+    private final Segment<K, V>[] segments;
 
-    boolean identityComparisons;
+    private boolean identityComparisons;
 
-    transient Set<K> keySet;
-    transient Set<Entry<K, V>> entrySet;
-    transient Collection<V> values;
+    private transient Set<K> keySet;
+    private transient Set<Entry<K, V>> entrySet;
+    private transient Collection<V> values;
 
     /* ---------------- Small Utilities -------------- */
 
@@ -291,7 +304,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
      * @param hash the hash code for the key
      * @return the segment
      */
-    final Segment<K, V> segmentFor(int hash) {
+    private final Segment<K, V> segmentFor(int hash) {
         return segments[(hash >>> segmentShift) & segmentMask];
     }
 
@@ -301,7 +314,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
 
     /* ---------------- Inner Classes -------------- */
 
-    interface KeyReference {
+    private interface KeyReference {
         int keyHash();
 
         Object keyRef();
@@ -310,7 +323,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
     /**
      * A weak-key reference which stores the key hash needed for reclamation.
      */
-    static final class WeakKeyReference<K> extends WeakReference<K> implements 
KeyReference {
+    private static final class WeakKeyReference<K> extends WeakReference<K> 
implements KeyReference {
         final int hash;
 
         WeakKeyReference(K key, int hash, ReferenceQueue<Object> refQueue) {
@@ -330,7 +343,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
     /**
      * A soft-key reference which stores the key hash needed for reclamation.
      */
-    static final class SoftKeyReference<K> extends SoftReference<K> implements 
KeyReference {
+    private static final class SoftKeyReference<K> extends SoftReference<K> 
implements KeyReference {
         final int hash;
 
         SoftKeyReference(K key, int hash, ReferenceQueue<Object> refQueue) {
@@ -347,7 +360,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
         }
     }
 
-    static final class WeakValueReference<V> extends WeakReference<V> 
implements KeyReference {
+    private static final class WeakValueReference<V> extends WeakReference<V> 
implements KeyReference {
         final Object keyRef;
         final int hash;
 
@@ -366,7 +379,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
         }
     }
 
-    static final class SoftValueReference<V> extends SoftReference<V> 
implements KeyReference {
+    private static final class SoftValueReference<V> extends SoftReference<V> 
implements KeyReference {
         final Object keyRef;
         final int hash;
 
@@ -397,7 +410,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
      * backup in case a null (pre-initialized) value is ever seen in
      * an unsynchronized access method.
      */
-    static final class HashEntry<K, V> {
+    private static final class HashEntry<K, V> {
         final Object keyRef;
         final int hash;
         volatile Object valueRef;
@@ -471,8 +484,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
      * subclasses from ReentrantLock opportunistically, just to
      * simplify some locking and avoid separate construction.
      */
-    @SerializableByConvention
-    static final class Segment<K, V> extends ReentrantLock implements 
Serializable {
+    private static final class Segment<K, V> extends ReentrantLock implements 
Serializable {
         /*
          * Segments maintain a table of entry lists that are ALWAYS
          * kept in a consistent state, so they can be read without locking.
@@ -1447,10 +1459,9 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
      * absent. Implementations which support null values <strong>must</strong>
      * override this default implementation.
      */
-    @Override
     public V applyIfAbsent(K key, Function<? super K, ? extends V> 
mappingFunction) {
-        checkNotNull(key);
-        checkNotNull(mappingFunction);
+        Objects.requireNonNull(key);
+        Objects.requireNonNull(mappingFunction);
 
         int hash = hashOf(key);
         Segment<K, V> segment = segmentFor(hash);
@@ -1458,10 +1469,9 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
         return v == null ? segment.put(key, hash, null, mappingFunction, true) 
: v;
     }
 
-    @Override
     public V applyIfPresent(K key, BiFunction<? super K, ? super V, ? extends 
V> remappingFunction) {
-        checkNotNull(key);
-        checkNotNull(remappingFunction);
+        Objects.requireNonNull(key);
+        Objects.requireNonNull(remappingFunction);
 
         int hash = hashOf(key);
         Segment<K, V> segment = segmentFor(hash);
@@ -1473,10 +1483,9 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
         return segmentFor(hash).applyIfPresent(key, hash, remappingFunction);
     }
 
-    @Override
     public V apply(K key, BiFunction<? super K, ? super V, ? extends V> 
remappingFunction) {
-        checkNotNull(key);
-        checkNotNull(remappingFunction);
+        Objects.requireNonNull(key);
+        Objects.requireNonNull(remappingFunction);
 
         int hash = hashOf(key);
         Segment<K, V> segment = segmentFor(hash);
@@ -1741,7 +1750,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
         }
     }
 
-    final class KeyIterator extends HashIterator implements Iterator<K>, 
Enumeration<K> {
+    private final class KeyIterator extends HashIterator implements 
Iterator<K>, Enumeration<K> {
         public K next() {
             return super.nextEntry().key();
         }
@@ -1751,7 +1760,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
         }
     }
 
-    final class ValueIterator extends HashIterator implements Iterator<V>, 
Enumeration<V> {
+    private final class ValueIterator extends HashIterator implements 
Iterator<V>, Enumeration<V> {
         public V next() {
             return super.nextEntry().value();
         }
@@ -1764,7 +1773,6 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
     /*
      * This class is needed for JDK5 compatibility.
      */
-    @SerializableByConvention
     protected static class SimpleEntry<K, V> implements Entry<K, V>, 
Serializable {
         private static final long serialVersionUID = -8499721149061103585L;
 
@@ -1822,7 +1830,6 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
      * Custom Entry class used by EntryIterator.next(), that relays setValue
      * changes to the underlying map.
      */
-    @SerializableByConvention
     protected class WriteThroughEntry extends SimpleEntry<K, V> {
         private static final long serialVersionUID = -7900634345345313646L;
 
@@ -1849,14 +1856,14 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
         }
     }
 
-    final class EntryIterator extends HashIterator implements 
Iterator<Entry<K, V>> {
+    private final class EntryIterator extends HashIterator implements 
Iterator<Entry<K, V>> {
         public Entry<K, V> next() {
             HashEntry<K, V> e = super.nextEntry();
             return new WriteThroughEntry(e.key(), e.value());
         }
     }
 
-    final class CachedEntryIterator extends HashIterator implements 
Iterator<Entry<K, V>> {
+    private final class CachedEntryIterator extends HashIterator implements 
Iterator<Entry<K, V>> {
         private InitializableEntry entry = new InitializableEntry();
 
         public Entry<K, V> next() {
@@ -1891,7 +1898,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
         }
     }
 
-    final class KeySet extends AbstractSet<K> {
+    private final class KeySet extends AbstractSet<K> {
         public Iterator<K> iterator() {
             return new KeyIterator();
         }
@@ -1917,7 +1924,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
         }
     }
 
-    final class Values extends AbstractCollection<V> {
+    private final class Values extends AbstractCollection<V> {
         public Iterator<V> iterator() {
             return new ValueIterator();
         }
@@ -1939,7 +1946,7 @@ public class ConcurrentReferenceHashMap<K, V> extends 
AbstractMap<K, V>
         }
     }
 
-    final class EntrySet extends AbstractSet<Entry<K, V>> {
+    private final class EntrySet extends AbstractSet<Entry<K, V>> {
         private final boolean cached;
 
         public EntrySet(boolean cached) {
diff --git 
a/src/main/java/org/apache/groovy/util/ManagedIdentityConcurrentMap.java 
b/src/main/java/org/apache/groovy/util/ManagedIdentityConcurrentMap.java
new file mode 100644
index 0000000..0615290
--- /dev/null
+++ b/src/main/java/org/apache/groovy/util/ManagedIdentityConcurrentMap.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.util;
+
+import java.util.EnumSet;
+
+/**
+ * This is a basic implementation of a map able to forget its keys. This
+ * map uses internally a ConcurrentHashMap, thus should be safe for 
concurrency.
+ * hashcode and equals are used to find the entries and should thus be 
implemented
+ * properly for the keys. This map does not support null keys.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @since 4.0.0
+ */
+public class ManagedIdentityConcurrentMap<K, V> extends 
ConcurrentReferenceHashMap<K, V> {
+    public ManagedIdentityConcurrentMap(ReferenceType keyType) {
+        super(keyType, ReferenceType.STRONG, 
EnumSet.of(Option.IDENTITY_COMPARISONS));
+    }
+
+    /**
+     * Get the key specified value, or put the default value and return it if 
the key is absent
+     *
+     * @param key the key to look up
+     * @param value the default value if the key is absent
+     * @return the value
+     */
+    public V getOrPut(K key, V value) {
+        return this.applyIfAbsent(key, k -> value);
+    }
+}
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java 
b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
index 54b320f..50ab79a 100644
--- a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
+++ b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
@@ -46,14 +46,13 @@ import groovy.lang.Tuple6;
 import groovy.lang.Tuple7;
 import groovy.lang.Tuple8;
 import groovy.lang.Tuple9;
+import org.apache.groovy.util.ManagedIdentityConcurrentMap;
 import org.apache.groovy.util.Maps;
 import org.codehaus.groovy.classgen.asm.util.TypeUtil;
 import org.codehaus.groovy.runtime.GeneratedClosure;
 import org.codehaus.groovy.runtime.GeneratedLambda;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
 import org.codehaus.groovy.transform.trait.Traits;
-import org.codehaus.groovy.util.ManagedIdentityConcurrentMap;
-import org.codehaus.groovy.util.ReferenceBundle;
 import org.codehaus.groovy.vmplugin.VMPluginFactory;
 import org.objectweb.asm.Opcodes;
 
@@ -408,7 +407,7 @@ public class ClassHelper {
     }
 
     static class ClassHelperCache {
-        static ManagedIdentityConcurrentMap<Class, SoftReference<ClassNode>> 
classCache = new ManagedIdentityConcurrentMap<Class, 
SoftReference<ClassNode>>(ReferenceBundle.getWeakBundle());
+        static ManagedIdentityConcurrentMap<Class, SoftReference<ClassNode>> 
classCache = new 
ManagedIdentityConcurrentMap<>(ManagedIdentityConcurrentMap.ReferenceType.WEAK);
     }
 
     public static boolean isSAMType(final ClassNode type) {
diff --git a/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java 
b/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java
index b0c00e1..42cc3e4 100644
--- a/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java
+++ b/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java
@@ -25,6 +25,7 @@ import groovy.lang.GroovySystem;
 import groovy.lang.MetaClass;
 import groovy.lang.MetaClassRegistry;
 import groovy.lang.MetaMethod;
+import org.apache.groovy.util.ManagedIdentityConcurrentMap;
 import org.codehaus.groovy.reflection.GroovyClassValue.ComputeValue;
 import org.codehaus.groovy.reflection.stdclasses.ArrayCachedClass;
 import org.codehaus.groovy.reflection.stdclasses.BigDecimalCachedClass;
@@ -46,7 +47,6 @@ import org.codehaus.groovy.util.Finalizable;
 import org.codehaus.groovy.util.LazyReference;
 import org.codehaus.groovy.util.LockableObject;
 import org.codehaus.groovy.util.ManagedConcurrentLinkedQueue;
-import org.codehaus.groovy.util.ManagedIdentityConcurrentMap;
 import org.codehaus.groovy.util.ManagedReference;
 import org.codehaus.groovy.util.ReferenceBundle;
 import org.codehaus.groovy.vmplugin.VMPluginFactory;
@@ -409,7 +409,7 @@ public class ClassInfo implements Finalizable {
 
         if (metaClass != null) {
             if (perInstanceMetaClassMap == null)
-              perInstanceMetaClassMap = new 
ManagedIdentityConcurrentMap<Object, 
MetaClass>(ReferenceBundle.getWeakBundle());
+              perInstanceMetaClassMap = new 
ManagedIdentityConcurrentMap<>(ManagedIdentityConcurrentMap.ReferenceType.WEAK);
 
             perInstanceMetaClassMap.put(obj, metaClass);
         }
diff --git a/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java 
b/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java
index f9763e1..77477c1 100644
--- a/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java
+++ b/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java
@@ -26,14 +26,13 @@ import groovy.lang.MetaClass;
 import groovy.lang.MetaMethod;
 import groovy.lang.MetaProperty;
 import groovy.transform.Internal;
+import org.apache.groovy.util.ManagedIdentityConcurrentMap;
 import org.codehaus.groovy.runtime.HandleMetaClass;
 import org.codehaus.groovy.runtime.MetaClassHelper;
 import org.codehaus.groovy.runtime.metaclass.MixedInMetaClass;
 import org.codehaus.groovy.runtime.metaclass.MixinInstanceMetaMethod;
 import org.codehaus.groovy.runtime.metaclass.MixinInstanceMetaProperty;
 import org.codehaus.groovy.runtime.metaclass.NewInstanceMetaMethod;
-import org.codehaus.groovy.util.ManagedIdentityConcurrentMap;
-import org.codehaus.groovy.util.ReferenceBundle;
 
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -45,7 +44,7 @@ public class MixinInMetaClass {
     final CachedClass mixinClass;
     final CachedConstructor constructor;
     private final ManagedIdentityConcurrentMap managedIdentityConcurrentMap =
-            new ManagedIdentityConcurrentMap(ReferenceBundle.getSoftBundle());
+            new 
ManagedIdentityConcurrentMap(ManagedIdentityConcurrentMap.ReferenceType.SOFT);
 
     public MixinInMetaClass(ExpandoMetaClass emc, CachedClass mixinClass) {
         this.emc = emc;
diff --git 
a/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
 
b/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
index 8cae32f..d75d934 100644
--- 
a/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
+++ 
b/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
@@ -21,9 +21,9 @@ package org.codehaus.groovy.runtime.metaclass;
 import groovy.lang.Closure;
 import groovy.lang.MetaBeanProperty;
 import groovy.lang.MetaMethod;
+import org.apache.groovy.util.ManagedIdentityConcurrentMap;
 import org.codehaus.groovy.reflection.CachedClass;
 import org.codehaus.groovy.reflection.ReflectionCache;
-import org.codehaus.groovy.util.ManagedIdentityConcurrentMap;
 import org.codehaus.groovy.util.ReferenceBundle;
 
 import java.lang.reflect.Modifier;
@@ -120,7 +120,7 @@ public class ThreadManagedMetaBeanProperty extends 
MetaBeanProperty {
     private static ManagedIdentityConcurrentMap getInstance2PropName(String 
name) {
         ManagedIdentityConcurrentMap res = PROPNAME_TO_MAP.get(name);
         if (res == null) {
-            res = new ManagedIdentityConcurrentMap(SOFT_BUNDLE);
+            res = new 
ManagedIdentityConcurrentMap(ManagedIdentityConcurrentMap.ReferenceType.SOFT);
             ManagedIdentityConcurrentMap ores = 
PROPNAME_TO_MAP.putIfAbsent(name, res);
             if (ores != null)
               return ores;
diff --git 
a/src/main/java/org/codehaus/groovy/util/ManagedIdentityConcurrentMap.java 
b/src/main/java/org/codehaus/groovy/util/ManagedIdentityConcurrentMap.java
deleted file mode 100644
index 2736244..0000000
--- a/src/main/java/org/codehaus/groovy/util/ManagedIdentityConcurrentMap.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.codehaus.groovy.util;
-
-import java.util.Collection;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * This is a basic implementation of a map able to forget its keys. This
- * map uses internally a ConcurrentHashMap, thus should be safe for 
concurrency.
- * hashcode and equals are used to find the entries and should thus be 
implemented
- * properly for the keys. This map does not support null keys.
- *
- * @param <K> the key type
- * @param <V> the value type
- * @since 4.0.0
- */
-public class ManagedIdentityConcurrentMap<K, V> {
-    private final ConcurrentHashMap<ManagedReference<K>, V> internalMap;
-    private final ReferenceBundle bundle;
-
-    public ManagedIdentityConcurrentMap(ReferenceBundle bundle) {
-        this.internalMap = new ConcurrentHashMap<>();
-        this.bundle = bundle;
-    }
-
-    /**
-     * Returns the value stored for the given key at the point of call.
-     *
-     * @param key a non null key
-     * @return the value stored in the map for the given key
-     */
-    public V get(K key) {
-        return internalMap.get(new ManagedIdentityKey<K>(key));
-    }
-
-    /**
-     * Sets a new value for a given key. an older value is overwritten.
-     *
-     * @param key   a non null key
-     * @param value the new value
-     */
-    public V put(final K key, V value) {
-        return internalMap.put(new ManagedIdentityKey<K>(key), value);
-    }
-
-    /**
-     * Returns the values of the map
-     */
-    public Collection<V> values() {
-        return internalMap.values();
-    }
-
-    /**
-     * Remove the key specified entry
-     *
-     * @param key the key to look up
-     * @return the removed value
-     */
-    public V remove(K key) {
-        return internalMap.remove(new ManagedIdentityKey<K>(key));
-    }
-
-    /**
-     * Get the key specified value, or put the default value and return it if 
the key is absent
-     *
-     * @param key the key to look up
-     * @param value the default value if the key is absent
-     * @return the value
-     */
-    public V getOrPut(K key, V value) {
-        return internalMap.computeIfAbsent(new ManagedIdentityKey<K>(key), k 
-> value);
-    }
-
-    /**
-     * Returns the map size
-     */
-    public Object size() {
-        return internalMap.size();
-    }
-
-    /**
-     * Check if the map is empty or not
-     *
-     * @return {@code true} when the map is empty, otherwise {@code false}
-     */
-    public boolean isEmpty() {
-        return internalMap.isEmpty();
-    }
-
-    /**
-     * Represents identity key of {@link ManagedIdentityConcurrentMap}
-     *
-     * @param <K> the key type
-     */
-    private class ManagedIdentityKey<K> extends ManagedReference<K> {
-        private final int hashCode;
-
-        private ManagedIdentityKey(K key) {
-            super(bundle, key);
-            this.hashCode = hash(key);
-        }
-
-        @Override
-        public void finalizeReference() {
-            internalMap.remove(this);
-            super.finalizeReference();
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (!(o instanceof ManagedIdentityKey)) return false;
-            return get() == ((ManagedIdentityKey<?>) o).get();
-        }
-
-        @Override
-        public int hashCode() {
-            return this.hashCode;
-        }
-
-        private int hash(K key) {
-            int h = (null == key) ? 0 : System.identityHashCode(key);
-            h += (h << 15) ^ 0xffffcd7d;
-            h ^= (h >>> 10);
-            h += (h << 3);
-            h ^= (h >>> 6);
-            h += (h << 2) + (h << 14);
-            h ^= (h >>> 16);
-            return h;
-        }
-    }
-}
diff --git 
a/src/test/org/codehaus/groovy/util/ManagedIdentityConcurrentMapTest.groovy 
b/src/test/org/apache/groovy/util/ManagedIdentityConcurrentMapTest.groovy
similarity index 84%
rename from 
src/test/org/codehaus/groovy/util/ManagedIdentityConcurrentMapTest.groovy
rename to 
src/test/org/apache/groovy/util/ManagedIdentityConcurrentMapTest.groovy
index d454b3f..3c76b1c 100644
--- a/src/test/org/codehaus/groovy/util/ManagedIdentityConcurrentMapTest.groovy
+++ b/src/test/org/apache/groovy/util/ManagedIdentityConcurrentMapTest.groovy
@@ -16,15 +16,14 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.codehaus.groovy.util
-
+package org.apache.groovy.util
 
 import org.junit.Test
 
 class ManagedIdentityConcurrentMapTest {
     @Test
     void testRemovingEntriesFromMapAfterGC() {
-        def m = new ManagedIdentityConcurrentMap<Object, 
String>(ReferenceBundle.getWeakBundle())
+        def m = new ManagedIdentityConcurrentMap<Object, 
String>(ManagedIdentityConcurrentMap.ReferenceType.WEAK)
         def k1 = new Object()
         m.put(k1, "a")
         def k2 = new Object()
@@ -50,11 +49,10 @@ class ManagedIdentityConcurrentMapTest {
             Thread.sleep(100)
         }
 
-        // finalize manually
-        if (!m.isEmpty()) {
-            m.internalMap.keySet().stream().forEach(e -> e.finalizeReference())
-        }
-
-        assert m.isEmpty()
+        def k4 = new Object()
+        assert "d" == m.getOrPut(k4, "d")
+        assert "d" == m.getOrPut(k4, "e")
+        assert [k4] == (m.keySet() as List)
+        assert ["d"] == (m.values() as List)
     }
 }

Reply via email to