mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
extract NotNullizer allowing to hide its own null-object inside
This commit is contained in:
@@ -2,8 +2,6 @@
|
||||
package com.intellij.util
|
||||
|
||||
import com.intellij.openapi.util.RecursionManager
|
||||
import com.intellij.util.ObjectUtils.notNullize
|
||||
import com.intellij.util.ObjectUtils.nullize
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
/**
|
||||
@@ -12,7 +10,7 @@ import java.util.concurrent.atomic.AtomicReference
|
||||
class RecursionPreventingSafePublicationLazy<T>(recursionKey: Any?, initializer: () -> T) : Lazy<T?> {
|
||||
|
||||
@Volatile
|
||||
private var initializer: (() -> T)? = { notNullize(initializer()) }
|
||||
private var initializer: (() -> T)? = { ourNotNullizer.notNullize(initializer()) }
|
||||
private val valueRef: AtomicReference<T> = AtomicReference()
|
||||
private val recursionKey: Any = recursionKey ?: this
|
||||
|
||||
@@ -20,13 +18,13 @@ class RecursionPreventingSafePublicationLazy<T>(recursionKey: Any?, initializer:
|
||||
get() {
|
||||
val computedValue = valueRef.get()
|
||||
if (computedValue !== null) {
|
||||
return nullize(computedValue)
|
||||
return ourNotNullizer.nullize(computedValue)
|
||||
}
|
||||
|
||||
val initializerValue = initializer
|
||||
if (initializerValue === null) {
|
||||
// Some thread managed to clear the initializer => it managed to set the value.
|
||||
return nullize(valueRef.get())
|
||||
return ourNotNullizer.nullize(valueRef.get())
|
||||
}
|
||||
|
||||
val stamp = ourRecursionGuard.markStack()
|
||||
@@ -38,16 +36,16 @@ class RecursionPreventingSafePublicationLazy<T>(recursionKey: Any?, initializer:
|
||||
}
|
||||
if (!stamp.mayCacheNow()) {
|
||||
// Recursion occurred somewhere deep.
|
||||
return nullize(newValue)
|
||||
return ourNotNullizer.nullize(newValue)
|
||||
}
|
||||
|
||||
if (!valueRef.compareAndSet(null, newValue)) {
|
||||
// Some thread managed to set the value.
|
||||
return nullize(valueRef.get())
|
||||
return ourNotNullizer.nullize(valueRef.get())
|
||||
}
|
||||
|
||||
initializer = null
|
||||
return nullize(newValue)
|
||||
return ourNotNullizer.nullize(newValue)
|
||||
}
|
||||
|
||||
override fun isInitialized(): Boolean = valueRef.get() !== null
|
||||
@@ -56,5 +54,6 @@ class RecursionPreventingSafePublicationLazy<T>(recursionKey: Any?, initializer:
|
||||
|
||||
companion object {
|
||||
private val ourRecursionGuard = RecursionManager.createGuard("RecursionPreventingSafePublicationLazy")
|
||||
private val ourNotNullizer = NotNullizer("RecursionPreventingSafePublicationLazy")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.util;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Has its own {@code null}-object instance, which is hidden from outside world, preventing accidental "unwrapping".
|
||||
*/
|
||||
public final class NotNullizer {
|
||||
|
||||
private final Object myNull;
|
||||
|
||||
@Contract(pure = true)
|
||||
public NotNullizer(@NotNull String name) {
|
||||
myNull = ObjectUtils.sentinel(name);
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@NotNull
|
||||
private <T> T fakeNull() {
|
||||
//noinspection unchecked
|
||||
return (T)myNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Wraps" {@code null} with {@code null}-object.
|
||||
* <p/>
|
||||
* Useful when some generic data structure A does not allow {@code null}s,
|
||||
* but there is a need to implement another structure B on top of A which should support {@code null}s.
|
||||
* <br/>
|
||||
* Returned value should never be presented to clients of structure B,
|
||||
* and it must be "unwrapped" back with {@link #nullize(Object)}.
|
||||
* <br/>
|
||||
* Casting the value to anything but {@link Object} will result in {@link ClassCastException},
|
||||
* this means the value cannot be used anywhere where {@link T} is a specific type different from {@link Object}.
|
||||
*
|
||||
* @return {@code null} wrapper if value is {@code null}, otherwise original value
|
||||
* @see #nullize(Object)
|
||||
*/
|
||||
@Contract(value = "!null -> param1", pure = true)
|
||||
@NotNull
|
||||
public <T> T notNullize(@Nullable T value) {
|
||||
if (value == null) {
|
||||
return fakeNull();
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "Unwraps" {@code null} from the value returned by {@link #notNullize(Object)}.
|
||||
*
|
||||
* @return {@code null} if value is the {@code null} wrapper, otherwise original value
|
||||
* @see #notNullize(Object)
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
@Nullable
|
||||
public <T> T nullize(@NotNull T value) {
|
||||
return value == myNull ? null : value;
|
||||
}
|
||||
}
|
||||
@@ -19,53 +19,11 @@ public class ObjectUtils {
|
||||
private ObjectUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see NotNullizer
|
||||
*/
|
||||
public static final Object NULL = sentinel("ObjectUtils.NULL");
|
||||
|
||||
@Contract(pure = true)
|
||||
@NotNull
|
||||
private static <T> T fakeNull() {
|
||||
//noinspection unchecked
|
||||
return (T)NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Wraps" {@code null} with {@code null}-object.
|
||||
* <p/>
|
||||
* Useful when some generic data structure A does not allow {@code null}s,
|
||||
* but there is a need to implement another structure B on top of A which should support {@code null}s.
|
||||
* <br/>
|
||||
* Returned value should never be presented to clients of structure B,
|
||||
* and it must be "unwrapped" back with {@link #nullize(Object)}.
|
||||
* <br/>
|
||||
* Casting the value to anything but {@link Object} will result in {@link ClassCastException},
|
||||
* this means the value cannot be used anywhere where {@link T} is a specific type different from {@link Object}.
|
||||
*
|
||||
* @return {@code null} wrapper if value is {@code null}, otherwise original value
|
||||
* @see #nullize(Object)
|
||||
*/
|
||||
@Contract(value = "!null -> param1", pure = true)
|
||||
@NotNull
|
||||
public static <T> T notNullize(@Nullable T value) {
|
||||
if (value == null) {
|
||||
return fakeNull();
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "Unwraps" {@code null} from the value returned by {@link #notNullize(Object)}.
|
||||
*
|
||||
* @return {@code null} if value is the {@code null} wrapper, otherwise original value
|
||||
* @see #notNullize(Object)
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
@Nullable
|
||||
public static <T> T nullize(@NotNull T value) {
|
||||
return value == NULL ? null : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object which could be used as sentinel value (special value to distinguish from any other object). It does not equal
|
||||
* to any other object. Usually should be assigned to the static final field.
|
||||
|
||||
Reference in New Issue
Block a user