• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.internal;
18 
19 import static dagger.internal.Preconditions.checkNotNull;
20 
21 import javax.inject.Provider;
22 
23 /**
24  * A {@link Provider} implementation that memoizes the result of another {@link Provider} using
25  * simple lazy initialization, not the double-checked lock pattern.
26  */
27 public final class SingleCheck<T> implements Provider<T> {
28   private static final Object UNINITIALIZED = new Object();
29 
30   private volatile Provider<T> provider;
31   private volatile Object instance = UNINITIALIZED;
32 
SingleCheck(Provider<T> provider)33   private SingleCheck(Provider<T> provider) {
34     assert provider != null;
35     this.provider = provider;
36   }
37 
38   @SuppressWarnings("unchecked") // cast only happens when result comes from the delegate provider
39   @Override
get()40   public T get() {
41     Object local = instance;
42     if (local == UNINITIALIZED) {
43       // provider is volatile and might become null after the check, so retrieve the provider first
44       Provider<T> providerReference = provider;
45       if (providerReference == null) {
46         // The provider was null, so the instance must already be set
47         local = instance;
48       } else {
49         local = providerReference.get();
50         instance = local;
51 
52         // Null out the reference to the provider. We are never going to need it again, so we can
53         // make it eligible for GC.
54         provider = null;
55       }
56     }
57     return (T) local;
58   }
59 
60   /** Returns a {@link Provider} that caches the value from the given delegate provider. */
61   // This method is declared this way instead of "<T> Provider<T> provider(Provider<T> provider)"
62   // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949.
provider(P provider)63   public static <P extends Provider<T>, T> Provider<T> provider(P provider) {
64     // If a scoped @Binds delegates to a scoped binding, don't cache the value again.
65     if (provider instanceof SingleCheck || provider instanceof DoubleCheck) {
66       return provider;
67     }
68     return new SingleCheck<T>(checkNotNull(provider));
69   }
70 }
71