• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base.supplier;
6 
7 import androidx.annotation.NonNull;
8 
9 import org.chromium.base.Callback;
10 import org.chromium.base.ThreadUtils;
11 
12 /** Utilities for interactions with Suppliers. */
13 public class SupplierUtils {
SupplierUtils()14     private SupplierUtils() {}
15 
16     private static class Barrier {
17         private final ThreadUtils.ThreadChecker mThreadChecker = new ThreadUtils.ThreadChecker();
18         private int mWaitingCount;
19         private Runnable mCallback;
20 
waitForAll(Runnable callback, Supplier... suppliers)21         void waitForAll(Runnable callback, Supplier... suppliers) {
22             mThreadChecker.assertOnValidThread();
23             assert mCallback == null;
24             mCallback = callback;
25             int waitingSupplierCount = 0;
26             Callback<?> supplierCallback = (unused) -> onSupplierAvailable();
27             for (Supplier<?> supplier : suppliers) {
28                 if (supplier.hasValue()) continue;
29 
30                 waitingSupplierCount++;
31                 if (supplier instanceof ObservableSupplier) {
32                     ObservableSupplier<?> observableSupplier = ((ObservableSupplier) supplier);
33                     new OneShotCallback(observableSupplier, supplierCallback);
34                 } else if (supplier instanceof OneshotSupplier) {
35                     ((OneshotSupplier) supplier).onAvailable(supplierCallback);
36                 } else if (supplier instanceof SyncOneshotSupplier) {
37                     ((SyncOneshotSupplier) supplier).onAvailable(supplierCallback);
38                 } else {
39                     assert false
40                             : "Unexpected Supplier type that does not already have a value: "
41                                     + supplier;
42                 }
43             }
44             mWaitingCount = waitingSupplierCount;
45             notifyCallbackIfAppropriate();
46         }
47 
onSupplierAvailable()48         private void onSupplierAvailable() {
49             mThreadChecker.assertOnValidThread();
50             mWaitingCount--;
51             assert mWaitingCount >= 0;
52             notifyCallbackIfAppropriate();
53         }
54 
notifyCallbackIfAppropriate()55         private void notifyCallbackIfAppropriate() {
56             if (mWaitingCount != 0) return;
57             if (mCallback == null) return;
58             mCallback.run();
59             mCallback = null;
60         }
61     }
62 
63     /**
64      * Waits for all suppliers to have assigned values, and when that happens, notifies the
65      * specified callback.
66      *
67      * <p>If all suppliers already have values, then the callback will be notified synchronously.
68      *
69      * <p>To prevent leaking objects, it is recommended to use {@link
70      * org.chromium.base.CallbackController} for the {@link Runnable} callback.
71      *
72      * <p>Not thread safe. All passed in suppliers must be notified on the same thread this method
73      * is called.
74      *
75      * @param callback The callback to be notified when all suppliers have values set.
76      * @param suppliers The list of suppliers to check for values.
77      */
waitForAll(@onNull Runnable callback, Supplier... suppliers)78     public static void waitForAll(@NonNull Runnable callback, Supplier... suppliers) {
79         assert callback != null;
80         new Barrier().waitForAll(callback, suppliers);
81     }
82 }
83