All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kotlin.reflect.jvm.internal.ReflectProperties Maven / Gradle / Ivy

/*
 * 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.jvm.functions.Function0;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

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() {};

        @SuppressWarnings({"UnusedParameters", "unused"})
        public final T getValue(Object instance, Object metadata) {
            return invoke();
        }

        public abstract T invoke();

        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 invoke() {
            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(@Nullable T initialValue, @NotNull Function0 initializer) {
            this.initializer = initializer;
            if (initialValue != null) {
                this.value = new SoftReference(escape(initialValue));
            }
        }

        @Override
        public T invoke() {
            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 invoke() {
            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(@Nullable T initialValue, @NotNull Function0 initializer) {
        return new LazySoftVal(initialValue, initializer);
    }

    @NotNull
    public static  LazySoftVal lazySoft(@NotNull Function0 initializer) {
        return lazySoft(null, initializer);
    }

    @NotNull
    public static  LazyWeakVal lazyWeak(@NotNull Function0 initializer) {
        return new LazyWeakVal(initializer);
    }
}