blob: 9df4e10fdb7edb9102b140c8c471ec6ddc42f5b5 [file] [log] [blame]
/*
* Copyright 2000-2011 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 com.intellij.openapi.util;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* A helper object for {@link RecursionManager}. Is obtained from {@link RecursionManager#createGuard(String)}.
*
* @author peter
*/
public abstract class RecursionGuard {
/**
* See {@link #doPreventingRecursion(Object, boolean, Computable)} with memoization disabled
*/
@SuppressWarnings("JavaDoc")
@Deprecated
@Nullable
public <T> T doPreventingRecursion(@NotNull Object key, @NotNull Computable<T> computation) {
return doPreventingRecursion(key, false, computation);
}
/**
* @param key an id of the computation. Is stored internally to ensure that a recursive calls with the same key won't lead to endless recursion.
* @param memoize whether the result of the computation may me cached thread-locally until the last currently active doPreventingRecursion call
* completes. May be used to speedup things when recursion re-entrance happens: otherwise nothing would be cached at all and
* in some cases exponential performance may be observed.
* @param computation a piece of code to compute.
* @return the result of the computation or null if we're entering a computation with this key on this thread recursively,
*/
@Nullable
public abstract <T> T doPreventingRecursion(@NotNull Object key, boolean memoize, @NotNull Computable<T> computation);
/**
* Used in pair with {@link com.intellij.openapi.util.RecursionGuard.StackStamp#mayCacheNow()} to ensure that cached are only the reliable values,
* not depending on anything incomplete due to recursive prevention policies.
* A typical usage is this:
* <code>
* RecursionGuard.StackStamp stamp = RecursionManager.createGuard("id").markStack();
*
* Result result = doComputation();
*
* if (stamp.mayCacheNow()) {
* cache(result);
* }
* return result;
* </code>
* @return an object representing the current stack state, managed by {@link RecursionManager}
*/
@NotNull
public abstract StackStamp markStack();
/**
* @return the current thread-local stack of keys passed to {@link #doPreventingRecursion(Object, Computable)}
*/
@NotNull
public abstract List<Object> currentStack();
/**
* Makes {@link com.intellij.openapi.util.RecursionGuard.StackStamp#mayCacheNow()} return false for all stamps created since a computation with
* key <code>since</code> began.
*
* Used to prevent caching of results that are non-reliable NOT due to recursion prevention: for example, too deep recursion
* ({@link #currentStack()} may help in determining the recursion depth)
*
* Also disables thread-local memoization (see the second parameter of {@link #doPreventingRecursion(Object, boolean, Computable)}.
*
* @param since the id of a computation whose result is safe to cache whilst for more nested ones it's not.
*/
public abstract void prohibitResultCaching(Object since);
public interface StackStamp {
/**
* @return whether a computation that started at the moment of this {@link StackStamp} instance creation does not depend on any re-entrant recursive
* results. When such non-reliable results exist in the thread's call stack, returns false, otherwise true.
* If you use this with {@link RecursionGuard#doPreventingRecursion(Object, Computable)}, then the
* {@link com.intellij.openapi.util.RecursionGuard#markStack()}+{@link #mayCacheNow()} should be outside of recursion prevention call. Otherwise
* even the outer recursive computation result won't be cached.
*
*/
boolean mayCacheNow();
}
}