From ecde41d9ab88a394df6c5c0a7887b7ed7fe27a43 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 5 Mar 2015 19:41:09 +0300 Subject: [PATCH] Introduce ReflectProperties for lazy weak/soft property delegates This class needs to be written in Java because no Kotlin classes can be used in KClassImpl constructor (otherwise since each Kotlin class creates a KClassImpl in its static initializer, this would result in infinite recursion) --- .../jvm/internal/ReflectProperties.java | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java new file mode 100644 index 00000000000..25d6cf86f75 --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java @@ -0,0 +1,132 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed 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 kotlin.reflect.jvm.internal; + +import kotlin.Function0; +import org.jetbrains.annotations.NotNull; + +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; + +/* package */ class ReflectProperties { + public static abstract class Val { + private static final Object NULL_VALUE = new Object() {}; + + public abstract T get(Object instance, Object metadata); + + protected Object escape(T value) { + return value == null ? NULL_VALUE : value; + } + + @SuppressWarnings("unchecked") + protected T unescape(Object value) { + return value == NULL_VALUE ? null : (T) value; + } + } + + // A delegate for a lazy property, whose initializer may be invoked multiple times including simultaneously from different threads + public static class LazyVal extends Val { + private final Function0 initializer; + private Object value = null; + + public LazyVal(@NotNull Function0 initializer) { + this.initializer = initializer; + } + + @Override + public T get(Object instance, Object metadata) { + Object cached = value; + if (cached != null) { + return unescape(cached); + } + + T result = initializer.invoke(); + value = escape(result); + + return result; + } + } + + // A delegate for a lazy property on a soft reference, whose initializer may be invoked multiple times + // including simultaneously from different threads + public static class LazySoftVal extends Val { + private final Function0 initializer; + private SoftReference value = null; + + public LazySoftVal(@NotNull Function0 initializer) { + this.initializer = initializer; + } + + @Override + public T get(Object instance, Object metadata) { + SoftReference cached = value; + if (cached != null) { + Object result = cached.get(); + if (result != null) { + return unescape(result); + } + } + + T result = initializer.invoke(); + value = new SoftReference(escape(result)); + + return result; + } + } + + // A delegate for a lazy property on a weak reference, whose initializer may be invoked multiple times + // including simultaneously from different threads + public static class LazyWeakVal extends Val { + private final Function0 initializer; + private WeakReference value = null; + + public LazyWeakVal(@NotNull Function0 initializer) { + this.initializer = initializer; + } + + @Override + public T get(Object instance, Object metadata) { + WeakReference cached = value; + if (cached != null) { + Object result = cached.get(); + if (result != null) { + return unescape(result); + } + } + + T result = initializer.invoke(); + value = new WeakReference(escape(result)); + + return result; + } + } + + @NotNull + public static LazyVal lazy(@NotNull Function0 initializer) { + return new LazyVal(initializer); + } + + @NotNull + public static LazySoftVal lazySoft(@NotNull Function0 initializer) { + return new LazySoftVal(initializer); + } + + @NotNull + public static LazyWeakVal lazyWeak(@NotNull Function0 initializer) { + return new LazyWeakVal(initializer); + } +}