|
@@ -0,0 +1,137 @@
|
|
|
|
|
+/*
|
|
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
|
|
+ * @copyright Ranides Atterwim
|
|
|
|
|
+ * @license WTFPL
|
|
|
|
|
+ * @url http://ranides.net/projects/everything
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+package net.ranides.assira.generic;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.concurrent.Callable;
|
|
|
|
|
+import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
|
+import net.ranides.assira.reflection.MethodPointer;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * @author Mariusz Sieron <m.sieron@samsung.com>
|
|
|
|
|
+ * @param <T>
|
|
|
|
|
+ */
|
|
|
|
|
+public abstract class LazyRef<T> {
|
|
|
|
|
+
|
|
|
|
|
+ protected final Callable<T> generator;
|
|
|
|
|
+
|
|
|
|
|
+ protected LazyRef(Callable<T> generator) {
|
|
|
|
|
+ this.generator = generator;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public abstract T get();
|
|
|
|
|
+
|
|
|
|
|
+ public static <T> LazyRef<T> nonlocking(Callable<T> generator) {
|
|
|
|
|
+ return new NonLocking<T>(generator);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static <T> LazyRef<T> nonlocking(MethodPointer<T> method) {
|
|
|
|
|
+ return nonlocking(LazyRef.wrap(method));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static <T> LazyRef<T> locking(Callable<T> generator) {
|
|
|
|
|
+ return new Locking<T>(generator);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static <T> LazyRef<T> locking(MethodPointer<T> method) {
|
|
|
|
|
+ return locking(LazyRef.wrap(method));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static <T> LazyRef<T> lockfree(Callable<T> generator) {
|
|
|
|
|
+ return new LockFree<T>(generator);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static <T> LazyRef<T> lockfree(MethodPointer<T> method) {
|
|
|
|
|
+ return lockfree(LazyRef.wrap(method));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static <T> Callable<T> wrap(final MethodPointer<T> method) {
|
|
|
|
|
+ return new Callable<T>() {
|
|
|
|
|
+ public T call() throws Exception {
|
|
|
|
|
+ return method.call();
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static class NonLocking<T> extends LazyRef<T> {
|
|
|
|
|
+
|
|
|
|
|
+ private T ret;
|
|
|
|
|
+
|
|
|
|
|
+ public NonLocking(Callable<T> generator) {
|
|
|
|
|
+ super(generator);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public T get() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if( ret == null) {
|
|
|
|
|
+ ret = generator.call();
|
|
|
|
|
+ }
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ } catch(Exception cause) {
|
|
|
|
|
+ throw new RuntimeException(cause);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static class Locking<T> extends LazyRef<T> {
|
|
|
|
|
+
|
|
|
|
|
+ private volatile T ref = null;
|
|
|
|
|
+
|
|
|
|
|
+ public Locking(Callable<T> generator) {
|
|
|
|
|
+ super(generator);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public T get() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ T temp = ref;
|
|
|
|
|
+ if(null == temp) {
|
|
|
|
|
+ synchronized(this) {
|
|
|
|
|
+ if(null == ref) {
|
|
|
|
|
+ ref = temp = generator.call();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return temp;
|
|
|
|
|
+ } catch(Exception cause) {
|
|
|
|
|
+ throw new RuntimeException(cause);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static class LockFree<T> extends LazyRef<T> {
|
|
|
|
|
+
|
|
|
|
|
+ private static enum State { UNDEFINED_1, UNDEFINED_2 }
|
|
|
|
|
+
|
|
|
|
|
+ private final AtomicReference<Object> ref = new AtomicReference<Object>(State.UNDEFINED_1);
|
|
|
|
|
+
|
|
|
|
|
+ public LockFree(Callable<T> generator) {
|
|
|
|
|
+ super(generator);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public T get() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if( ref.compareAndSet(State.UNDEFINED_1, State.UNDEFINED_2) ) {
|
|
|
|
|
+ ref.set( generator.call() );
|
|
|
|
|
+ return (T)ref.get();
|
|
|
|
|
+ }
|
|
|
|
|
+ if( ref.compareAndSet(State.UNDEFINED_2, State.UNDEFINED_1) ) {
|
|
|
|
|
+ ref.set( generator.call() );
|
|
|
|
|
+ return (T)ref.get();
|
|
|
|
|
+ }
|
|
|
|
|
+ return (T)ref.get();
|
|
|
|
|
+ } catch(Exception cause) {
|
|
|
|
|
+ throw new RuntimeException(cause);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|