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