xref: /aosp_15_r20/external/dagger2/java/dagger/internal/SetFactory.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
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.DaggerCollections.hasDuplicates;
20 import static dagger.internal.DaggerCollections.newHashSetWithExpectedSize;
21 import static dagger.internal.DaggerCollections.presizedList;
22 import static dagger.internal.Preconditions.checkNotNull;
23 import static dagger.internal.Providers.asDaggerProvider;
24 import static java.util.Collections.emptySet;
25 import static java.util.Collections.unmodifiableSet;
26 
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.List;
30 import java.util.Set;
31 
32 /**
33  * A {@link Factory} implementation used to implement {@link Set} bindings. This factory always
34  * returns a new {@link Set} instance for each call to {@link #get} (as required by {@link Factory})
35  * whose elements are populated by subsequent calls to their {@link Provider#get} methods.
36  */
37 public final class SetFactory<T> implements Factory<Set<T>> {
38   private static final Factory<Set<Object>> EMPTY_FACTORY = InstanceFactory.create(emptySet());
39 
40   @SuppressWarnings({"unchecked", "rawtypes"}) // safe covariant cast
empty()41   public static <T> Factory<Set<T>> empty() {
42     return (Factory) EMPTY_FACTORY;
43   }
44 
45   /**
46    * Constructs a new {@link Builder} for a {@link SetFactory} with {@code individualProviderSize}
47    * individual {@code Provider<T>} and {@code collectionProviderSize} {@code
48    * Provider<Collection<T>>} instances.
49    */
builder(int individualProviderSize, int collectionProviderSize)50   public static <T> Builder<T> builder(int individualProviderSize, int collectionProviderSize) {
51     return new Builder<T>(individualProviderSize, collectionProviderSize);
52   }
53 
54   /**
55    * A builder to accumulate {@code Provider<T>} and {@code Provider<Collection<T>>} instances.
56    * These are only intended to be single-use and from within generated code. Do <em>NOT</em> add
57    * providers after calling {@link #build()}.
58    */
59   public static final class Builder<T> {
60     private final List<Provider<T>> individualProviders;
61     private final List<Provider<Collection<T>>> collectionProviders;
62 
Builder(int individualProviderSize, int collectionProviderSize)63     private Builder(int individualProviderSize, int collectionProviderSize) {
64       individualProviders = presizedList(individualProviderSize);
65       collectionProviders = presizedList(collectionProviderSize);
66     }
67 
68     @SuppressWarnings("unchecked")
addProvider(Provider<? extends T> individualProvider)69     public Builder<T> addProvider(Provider<? extends T> individualProvider) {
70       assert individualProvider != null : "Codegen error? Null provider";
71       // TODO(ronshapiro): Store a List<? extends Provider<T>> and avoid the cast to Provider<T>
72       individualProviders.add((Provider<T>) individualProvider);
73       return this;
74     }
75 
76     /**
77      * Legacy javax version of the method to support libraries compiled with an older version of
78      * Dagger. Do not use directly.
79      */
80     @Deprecated
addProvider(javax.inject.Provider<? extends T> individualProvider)81     public Builder<T> addProvider(javax.inject.Provider<? extends T> individualProvider) {
82       return addProvider(asDaggerProvider(individualProvider));
83     }
84 
85     @SuppressWarnings("unchecked")
addCollectionProvider( Provider<? extends Collection<? extends T>> collectionProvider)86     public Builder<T> addCollectionProvider(
87         Provider<? extends Collection<? extends T>> collectionProvider) {
88       assert collectionProvider != null : "Codegen error? Null provider";
89       collectionProviders.add((Provider<Collection<T>>) collectionProvider);
90       return this;
91     }
92 
93     /**
94      * Legacy javax version of the method to support libraries compiled with an older version of
95      * Dagger. Do not use directly.
96      */
97     @Deprecated
addCollectionProvider( javax.inject.Provider<? extends Collection<? extends T>> collectionProvider)98     public Builder<T> addCollectionProvider(
99         javax.inject.Provider<? extends Collection<? extends T>> collectionProvider) {
100       return addCollectionProvider(asDaggerProvider(collectionProvider));
101     }
102 
build()103     public SetFactory<T> build() {
104       assert !hasDuplicates(individualProviders)
105           : "Codegen error?  Duplicates in the provider list";
106       assert !hasDuplicates(collectionProviders)
107           : "Codegen error?  Duplicates in the provider list";
108 
109       return new SetFactory<T>(individualProviders, collectionProviders);
110     }
111   }
112 
113   private final List<Provider<T>> individualProviders;
114   private final List<Provider<Collection<T>>> collectionProviders;
115 
SetFactory( List<Provider<T>> individualProviders, List<Provider<Collection<T>>> collectionProviders)116   private SetFactory(
117       List<Provider<T>> individualProviders, List<Provider<Collection<T>>> collectionProviders) {
118     this.individualProviders = individualProviders;
119     this.collectionProviders = collectionProviders;
120   }
121 
122   /**
123    * Returns a {@link Set} that contains the elements given by each of the providers.
124    *
125    * @throws NullPointerException if any of the delegate {@link Set} instances or elements therein
126    *     are {@code null}
127    */
128   @Override
get()129   public Set<T> get() {
130     int size = individualProviders.size();
131     // Profiling revealed that this method was a CPU-consuming hotspot in some applications, so
132     // these loops were changed to use c-style for.  Versus enhanced for-each loops, C-style for is
133     // faster for ArrayLists, at least through Java 8.
134 
135     List<Collection<T>> providedCollections =
136         new ArrayList<Collection<T>>(collectionProviders.size());
137     for (int i = 0, c = collectionProviders.size(); i < c; i++) {
138       Collection<T> providedCollection = collectionProviders.get(i).get();
139       size += providedCollection.size();
140       providedCollections.add(providedCollection);
141     }
142 
143     Set<T> providedValues = newHashSetWithExpectedSize(size);
144     for (int i = 0, c = individualProviders.size(); i < c; i++) {
145       providedValues.add(checkNotNull(individualProviders.get(i).get()));
146     }
147     for (int i = 0, c = providedCollections.size(); i < c; i++) {
148       for (T element : providedCollections.get(i)) {
149         providedValues.add(checkNotNull(element));
150       }
151     }
152 
153     return unmodifiableSet(providedValues);
154   }
155 }
156