diff src/fschmidt/util/java/Interner.java @ 68:00520880ad02

add fschmidt source
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 05 Oct 2025 17:24:15 -0600
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fschmidt/util/java/Interner.java	Sun Oct 05 17:24:15 2025 -0600
@@ -0,0 +1,65 @@
+package fschmidt.util.java;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+public final class Interner<T>  {
+
+	private static final class MyReference<T> extends WeakReference<T> {
+		private final int hash;
+
+		MyReference(T t,ReferenceQueue<T> q) {
+			super(t,q);
+			hash = t.hashCode();
+		}
+
+		public boolean equals(Object obj) {
+			if( this==obj )
+				return true;
+			if( !(obj instanceof MyReference) )
+				return false;
+			MyReference ref = (MyReference)obj;
+			T t = this.get();
+			if( t==null )
+				return false;
+			return t.equals(ref.get());
+		}
+
+		public int hashCode() {
+			return hash;
+		}
+	}
+
+	private final ConcurrentMap<MyReference<T>,MyReference<T>> map = new ConcurrentHashMap<MyReference<T>,MyReference<T>>();
+	private ReferenceQueue<T> queue = new ReferenceQueue<T>();
+
+	private void sweep() {
+		while(true) {
+			Reference<? extends T> ref = queue.poll();
+			if( ref == null )
+				return;
+			map.remove(ref);
+		}
+	}
+
+	public T intern(T t) {
+		MyReference<T> ref = new MyReference<T>(t,queue);
+		while(true) {
+			MyReference<T> ref2 = map.putIfAbsent(ref,ref);
+			if( ref2 == null ) {
+				sweep();
+				return t;
+			}
+			T t2 = ref2.get();
+			if( t2 != null ) {
+				ref.clear();
+				return t2;
+			}
+		}
+	}
+
+}