View Javadoc
1   /*
2    * Copyright (C) 2007 The Guava 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 com.google.common.base;
18  
19  import com.google.common.annotations.Beta;
20  import com.google.common.annotations.GwtCompatible;
21  import com.google.common.annotations.VisibleForTesting;
22  
23  import java.io.Serializable;
24  import java.util.concurrent.TimeUnit;
25  
26  import javax.annotation.Nullable;
27  
28  /**
29   * Useful suppliers.
30   *
31   * <p>All methods return serializable suppliers as long as they're given
32   * serializable parameters.
33   *
34   * @author Laurence Gonsalves
35   * @author Harry Heymann
36   * @since 2.0 (imported from Google Collections Library)
37   */
38  @GwtCompatible
39  public final class Suppliers {
40    private Suppliers() {}
41  
42    /**
43     * Returns a new supplier which is the composition of the provided function
44     * and supplier. In other words, the new supplier's value will be computed by
45     * retrieving the value from {@code supplier}, and then applying
46     * {@code function} to that value. Note that the resulting supplier will not
47     * call {@code supplier} or invoke {@code function} until it is called.
48     */
49    public static <F, T> Supplier<T> compose(
50        Function<? super F, T> function, Supplier<F> supplier) {
51      Preconditions.checkNotNull(function);
52      Preconditions.checkNotNull(supplier);
53      return new SupplierComposition<F, T>(function, supplier);
54    }
55  
56    private static class SupplierComposition<F, T>
57        implements Supplier<T>, Serializable {
58      final Function<? super F, T> function;
59      final Supplier<F> supplier;
60  
61      SupplierComposition(Function<? super F, T> function, Supplier<F> supplier) {
62        this.function = function;
63        this.supplier = supplier;
64      }
65  
66      @Override public T get() {
67        return function.apply(supplier.get());
68      }
69  
70      @Override public boolean equals(@Nullable Object obj) {
71        if (obj instanceof SupplierComposition) {
72          SupplierComposition<?, ?> that = (SupplierComposition<?, ?>) obj;
73          return function.equals(that.function) && supplier.equals(that.supplier);
74        }
75        return false;
76      }
77  
78      @Override public int hashCode() {
79        return Objects.hashCode(function, supplier);
80      }
81  
82      @Override public String toString() {
83        return "Suppliers.compose(" + function + ", " + supplier + ")";
84      }
85  
86      private static final long serialVersionUID = 0;
87    }
88  
89    /**
90     * Returns a supplier which caches the instance retrieved during the first
91     * call to {@code get()} and returns that value on subsequent calls to
92     * {@code get()}. See:
93     * <a href="http://en.wikipedia.org/wiki/Memoization">memoization</a>
94     *
95     * <p>The returned supplier is thread-safe. The supplier's serialized form
96     * does not contain the cached value, which will be recalculated when {@code
97     * get()} is called on the reserialized instance.
98     *
99     * <p>If {@code delegate} is an instance created by an earlier call to {@code
100    * memoize}, it is returned directly.
101    */
102   public static <T> Supplier<T> memoize(Supplier<T> delegate) {
103     return (delegate instanceof MemoizingSupplier)
104         ? delegate
105         : new MemoizingSupplier<T>(Preconditions.checkNotNull(delegate));
106   }
107 
108   @VisibleForTesting
109   static class MemoizingSupplier<T> implements Supplier<T>, Serializable {
110     final Supplier<T> delegate;
111     transient volatile boolean initialized;
112     // "value" does not need to be volatile; visibility piggy-backs
113     // on volatile read of "initialized".
114     transient T value;
115 
116     MemoizingSupplier(Supplier<T> delegate) {
117       this.delegate = delegate;
118     }
119 
120     @Override public T get() {
121       // A 2-field variant of Double Checked Locking.
122       if (!initialized) {
123         synchronized (this) {
124           if (!initialized) {
125             T t = delegate.get();
126             value = t;
127             initialized = true;
128             return t;
129           }
130         }
131       }
132       return value;
133     }
134 
135     @Override public String toString() {
136       return "Suppliers.memoize(" + delegate + ")";
137     }
138 
139     private static final long serialVersionUID = 0;
140   }
141 
142   /**
143    * Returns a supplier that caches the instance supplied by the delegate and
144    * removes the cached value after the specified time has passed. Subsequent
145    * calls to {@code get()} return the cached value if the expiration time has
146    * not passed. After the expiration time, a new value is retrieved, cached,
147    * and returned. See:
148    * <a href="http://en.wikipedia.org/wiki/Memoization">memoization</a>
149    *
150    * <p>The returned supplier is thread-safe. The supplier's serialized form
151    * does not contain the cached value, which will be recalculated when {@code
152    * get()} is called on the reserialized instance.
153    *
154    * @param duration the length of time after a value is created that it
155    *     should stop being returned by subsequent {@code get()} calls
156    * @param unit the unit that {@code duration} is expressed in
157    * @throws IllegalArgumentException if {@code duration} is not positive
158    * @since 2.0
159    */
160   public static <T> Supplier<T> memoizeWithExpiration(
161       Supplier<T> delegate, long duration, TimeUnit unit) {
162     return new ExpiringMemoizingSupplier<T>(delegate, duration, unit);
163   }
164 
165   @VisibleForTesting static class ExpiringMemoizingSupplier<T>
166       implements Supplier<T>, Serializable {
167     final Supplier<T> delegate;
168     final long durationNanos;
169     transient volatile T value;
170     // The special value 0 means "not yet initialized".
171     transient volatile long expirationNanos;
172 
173     ExpiringMemoizingSupplier(
174         Supplier<T> delegate, long duration, TimeUnit unit) {
175       this.delegate = Preconditions.checkNotNull(delegate);
176       this.durationNanos = unit.toNanos(duration);
177       Preconditions.checkArgument(duration > 0);
178     }
179 
180     @Override public T get() {
181       // Another variant of Double Checked Locking.
182       //
183       // We use two volatile reads.  We could reduce this to one by
184       // putting our fields into a holder class, but (at least on x86)
185       // the extra memory consumption and indirection are more
186       // expensive than the extra volatile reads.
187       long nanos = expirationNanos;
188       long now = Platform.systemNanoTime();
189       if (nanos == 0 || now - nanos >= 0) {
190         synchronized (this) {
191           if (nanos == expirationNanos) {  // recheck for lost race
192             T t = delegate.get();
193             value = t;
194             nanos = now + durationNanos;
195             // In the very unlikely event that nanos is 0, set it to 1;
196             // no one will notice 1 ns of tardiness.
197             expirationNanos = (nanos == 0) ? 1 : nanos;
198             return t;
199           }
200         }
201       }
202       return value;
203     }
204 
205     @Override public String toString() {
206       // This is a little strange if the unit the user provided was not NANOS,
207       // but we don't want to store the unit just for toString
208       return "Suppliers.memoizeWithExpiration(" + delegate + ", " +
209           durationNanos + ", NANOS)";
210     }
211 
212     private static final long serialVersionUID = 0;
213   }
214 
215   /**
216    * Returns a supplier that always supplies {@code instance}.
217    */
218   public static <T> Supplier<T> ofInstance(@Nullable T instance) {
219     return new SupplierOfInstance<T>(instance);
220   }
221 
222   private static class SupplierOfInstance<T>
223       implements Supplier<T>, Serializable {
224     final T instance;
225 
226     SupplierOfInstance(@Nullable T instance) {
227       this.instance = instance;
228     }
229 
230     @Override public T get() {
231       return instance;
232     }
233 
234     @Override public boolean equals(@Nullable Object obj) {
235       if (obj instanceof SupplierOfInstance) {
236         SupplierOfInstance<?> that = (SupplierOfInstance<?>) obj;
237         return Objects.equal(instance, that.instance);
238       }
239       return false;
240     }
241 
242     @Override public int hashCode() {
243       return Objects.hashCode(instance);
244     }
245 
246     @Override public String toString() {
247       return "Suppliers.ofInstance(" + instance + ")";
248     }
249 
250     private static final long serialVersionUID = 0;
251   }
252 
253   /**
254    * Returns a supplier whose {@code get()} method synchronizes on
255    * {@code delegate} before calling it, making it thread-safe.
256    */
257   public static <T> Supplier<T> synchronizedSupplier(Supplier<T> delegate) {
258     return new ThreadSafeSupplier<T>(Preconditions.checkNotNull(delegate));
259   }
260 
261   private static class ThreadSafeSupplier<T>
262       implements Supplier<T>, Serializable {
263     final Supplier<T> delegate;
264 
265     ThreadSafeSupplier(Supplier<T> delegate) {
266       this.delegate = delegate;
267     }
268 
269     @Override public T get() {
270       synchronized (delegate) {
271         return delegate.get();
272       }
273     }
274 
275     @Override public String toString() {
276       return "Suppliers.synchronizedSupplier(" + delegate + ")";
277     }
278 
279     private static final long serialVersionUID = 0;
280   }
281 
282   /**
283    * Returns a function that accepts a supplier and returns the result of
284    * invoking {@link Supplier#get} on that supplier.
285    *
286    * @since 8.0
287    */
288   @Beta
289   public static <T> Function<Supplier<T>, T> supplierFunction() {
290     @SuppressWarnings("unchecked") // implementation is "fully variant"
291     SupplierFunction<T> sf = (SupplierFunction<T>) SupplierFunctionImpl.INSTANCE;
292     return sf;
293   }
294 
295   private interface SupplierFunction<T> extends Function<Supplier<T>, T> {}
296 
297   private enum SupplierFunctionImpl implements SupplierFunction<Object> {
298     INSTANCE;
299 
300     // Note: This makes T a "pass-through type"
301     @Override public Object apply(Supplier<Object> input) {
302       return input.get();
303     }
304 
305     @Override public String toString() {
306       return "Suppliers.supplierFunction()";
307     }
308   }
309 }