• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 Google Inc. All rights reserved.
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 #ifndef FRUIT_COMPONENT_STORAGE_ENTRY_H
18 #define FRUIT_COMPONENT_STORAGE_ENTRY_H
19 
20 #include <fruit/impl/component_storage/binding_deps.h>
21 #include <fruit/impl/data_structures/arena_allocator.h>
22 #include <fruit/impl/data_structures/semistatic_graph.h>
23 #include <fruit/impl/fruit_internal_forward_decls.h>
24 
25 namespace fruit {
26 namespace impl {
27 
28 /**
29  * This represents a generic entry in ComponentStorage.
30  * We use a single POD (this struct) to represent any binding so that ComponentStorage can hold a single vector, instead
31  * of having to hold multiple vectors (each of which potentially requiring allocation/deallocation when a
32  * ComponentStorage is constructed/destroyed).
33  * This way each ComponentStorage can hold a single vector and do a single allocation.
34  */
35 struct ComponentStorageEntry {
36   enum class Kind {
37 #if FRUIT_EXTRA_DEBUG
38     INVALID,
39 #endif
40     BINDING_FOR_CONSTRUCTED_OBJECT,
41     BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION,
42     BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION,
43     BINDING_FOR_OBJECT_TO_CONSTRUCT_WITH_UNKNOWN_ALLOCATION,
44     COMPRESSED_BINDING,
45     MULTIBINDING_FOR_CONSTRUCTED_OBJECT,
46     MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION,
47     MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION,
48     // This is not an actual binding, it's an "addendum" to multibinding bindings that specifies how the multibinding
49     // vector can be created. Unlike real multibinding entries, this *can* be deduped.
50     MULTIBINDING_VECTOR_CREATOR,
51 
52     LAZY_COMPONENT_WITH_NO_ARGS,
53     LAZY_COMPONENT_WITH_ARGS,
54 
55     // Component replacements are stored as a REPLACEMENT_LAZY_COMPONENT_* entry followed by a REPLACED_LAZY_COMPONENT_*
56     // entry. Note that the args are independent: e.g. a component with args can be replaced by a component with no
57     // args. This also means that the type_id of the two entries can be different (since it's the type_id of the
58     // function signature rather than just of the Component<...>).
59     REPLACED_LAZY_COMPONENT_WITH_NO_ARGS,
60     REPLACED_LAZY_COMPONENT_WITH_ARGS,
61     REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS,
62     REPLACEMENT_LAZY_COMPONENT_WITH_ARGS,
63 
64     // These markers are used in expandLazyComponents(), see the comments there for details.
65     COMPONENT_WITH_ARGS_END_MARKER,
66     COMPONENT_WITHOUT_ARGS_END_MARKER,
67   };
68 
69 #if FRUIT_EXTRA_DEBUG
70   mutable
71 #endif
72       Kind kind;
73 
74   // This is usually the TypeId for the bound type, except:
75   // * when kind==COMPRESSED_BINDING, this is the interface's TypeId
76   // * when kind==*LAZY_COMPONENT_*, this is the TypeId of the
77   //       Component<...>-returning function.
78   TypeId type_id;
79 
80   /**
81    * This represents an entry in ComponentStorage for a binding (not a multibinding) that holds an already-constructed
82    * object.
83    */
84   struct BindingForConstructedObject {
85     using object_ptr_t = const void*;
86 
87     // The already-constructed object. We do *not* own this, this object must outlive the injector.
88     // This is a const pointer because in some cases it might be a const binding.
89     // We can cast this to a non-const pointer when we're sure that the original binding was for a non-const reference.
90     object_ptr_t object_ptr;
91 
92 #if FRUIT_EXTRA_DEBUG
93     bool is_nonconst;
94 #endif
95   };
96 
97   /**
98    * This represents an entry in ComponentStorage for a binding (not a multibinding) that holds an object that needs to
99    * be constructed (potentially after injecting any dependencies).
100    */
101   struct BindingForObjectToConstruct {
102     // This is a const pointer because this might be a const binding. If not, we'll cast this back to a non-const
103     // pointer when we need to.
104     using object_t = const void*;
105     using create_t = object_t (*)(InjectorStorage&, SemistaticGraph<TypeId, NormalizedBinding>::node_iterator);
106 
107     // The return value of this function is a pointer to the constructed object (guaranteed to be !=nullptr).
108     // Once the object is constructed (at injection time), the injector owns that object.
109     create_t create;
110 
111     // The type IDs that this type depends on.
112     const BindingDeps* deps;
113 
114 #if FRUIT_EXTRA_DEBUG
115     bool is_nonconst;
116 #endif
117   };
118 
119   /**
120    * This represents an entry in ComponentStorage for a multibinding that holds an already-constructed
121    * object.
122    */
123   struct MultibindingForConstructedObject {
124     using object_ptr_t = void*;
125 
126     // The already-constructed object. We do *not* own this, this object must outlive the injector.
127     object_ptr_t object_ptr;
128   };
129 
130   /**
131    * This represents an entry in ComponentStorage for a multibinding that holds an object that needs to
132    * be constructed (potentially after injecting any dependencies).
133    */
134   struct MultibindingForObjectToConstruct {
135 
136     using object_t = void*;
137     using create_t = object_t (*)(InjectorStorage&);
138 
139     // The return value of this function is a pointer to the constructed object (guaranteed to be !=nullptr).
140     // Once the object is constructed (at injection time), the injector owns that object.
141     create_t create;
142 
143     // The type IDs that this type depends on.
144     const BindingDeps* deps;
145   };
146 
147   /**
148    * This is not an actual binding, it's an "addendum" to multibinding bindings that specifies how the multibinding
149    * vector can be created. Unlike real multibinding entries, this *can* be deduped.
150    */
151   struct MultibindingVectorCreator {
152 
153     using get_multibindings_vector_t = std::shared_ptr<char> (*)(InjectorStorage&);
154 
155     // Returns the std::vector<T*> of instances, or nullptr if none.
156     // Caches the result in the `v' member of NormalizedMultibindingData.
157     get_multibindings_vector_t get_multibindings_vector;
158   };
159 
160   // A CompressedBinding with interface_id==getTypeId<I>() and class_id==getTypeId<C>() means that if:
161   // * C is not exposed by the component
162   // * I is the only node that depends on C
163   // * There are no multibindings that directly depend on C
164   // The BindingData for C is BindingForObjectToConstruct(
165   // Then, taken create1, needs_reallocation such that the ComponentStorageEntry for c_type_id is
166   // BindingForObjectToConstruct(createC, deps, needs_allocation), we can remove the binding for I and C and replace
167   // them
168   // with just a binding for I, with BindingForObjectToConstruct(create, deps, needs_allocation).
169   struct CompressedBinding {
170 
171     using create_t = BindingForObjectToConstruct::create_t;
172 
173     // TypeId for the implementation.
174     TypeId c_type_id;
175 
176     // The return value of this function is a pointer to the constructed object (guaranteed to be !=nullptr).
177     // Once the object is constructed (at injection time), the injector owns that object.
178     create_t create;
179   };
180 
181   /**
182    * This represents an entry in ComponentStorage for a lazy component with no arguments.
183    */
184   struct LazyComponentWithNoArgs {
185     // An arbitrary function type, used as type for the field `erased_fun`.
186     // Note that we can't use void* here, since data pointers might not have the same size as function pointers.
187     using erased_fun_t = void (*)();
188 
189     // The function that will be invoked to create the Component.
190     // Here we don't know the type, it's only known at construction time.
191     erased_fun_t erased_fun;
192 
193     using entry_vector_t = std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>;
194 
195     // The function that allows to add this component's bindings to the given ComponentStorage.
196     using add_bindings_fun_t = void (*)(erased_fun_t, entry_vector_t&);
197     add_bindings_fun_t add_bindings_fun;
198 
199     template <typename Component>
200     static void addBindings(erased_fun_t erased_fun, entry_vector_t& entries);
201 
202     template <typename Component>
203     static ComponentStorageEntry create(Component (*fun)());
204 
205     template <typename Component>
206     static ComponentStorageEntry create(fruit::ComponentFunction<Component> component_function);
207 
208     template <typename Component>
209     static ComponentStorageEntry createReplacedComponentEntry(Component (*fun)());
210 
211     template <typename Component>
212     static ComponentStorageEntry createReplacementComponentEntry(Component (*fun)());
213 
214     bool operator==(const LazyComponentWithNoArgs&) const;
215 
216     void addBindings(entry_vector_t& entries) const;
217 
218     std::size_t hashCode() const;
219 
220     bool isValid() const;
221   };
222 
223   /**
224    * This represents an entry in ComponentStorage for a lazy component with arguments.
225    */
226   struct LazyComponentWithArgs {
227     class ComponentInterface {
228     public:
229       // An arbitrary function type, used as type for the field `erased_fun`.
230       // Note that we can't use void* here, since data pointers might not have the same size as function pointers.
231       using erased_fun_t = void (*)();
232 
233       // The function that will be invoked to create the Component.
234       // Here we don't know the type, it's only known to the LazyComponent implementation.
235       // We store this here instead of in the LazyComponent implementation so that we can do a quick comparison on the
236       // pointer without virtual calls (and we can then do the rest of the comparison via virtual call if needed).
237       erased_fun_t erased_fun;
238 
239       using entry_vector_t = std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>;
240 
241       ComponentInterface(erased_fun_t erased_fun);
242 
243       virtual ~ComponentInterface() = default;
244 
245       // Checks if *this and other are equal, assuming that this->fun and other.fun are equal.
246       virtual bool areParamsEqual(const ComponentInterface& other) const = 0;
247 
248       bool operator==(const ComponentInterface& other) const;
249 
250       virtual void addBindings(entry_vector_t& component_storage_entries) const = 0;
251       virtual std::size_t hashCode() const = 0;
252       virtual ComponentInterface* copy() const = 0;
253 
254       /**
255        * Returns the type ID of the real `fun` object stored by the implementation.
256        * We use this instead of the `typeid` operator so that we don't require RTTI.
257        */
258       virtual TypeId getFunTypeId() const = 0;
259     };
260 
261     template <typename Component, typename... Args>
262     static ComponentStorageEntry create(Component (*fun)(Args...), std::tuple<Args...> args_tuple);
263 
264     template <typename Component, typename Arg, typename... Args>
265     static ComponentStorageEntry create(fruit::ComponentFunction<Component, Arg, Args...> component_function);
266 
267     template <typename Component, typename... Args>
268     static ComponentStorageEntry createReplacedComponentEntry(Component (*fun)(Args...),
269                                                               std::tuple<Args...> args_tuple);
270 
271     template <typename Component, typename... Args>
272     static ComponentStorageEntry createReplacementComponentEntry(Component (*fun)(Args...),
273                                                                  std::tuple<Args...> args_tuple);
274 
275     LazyComponentWithArgs(LazyComponentWithArgs&&) = default;
276     LazyComponentWithArgs& operator=(LazyComponentWithArgs&&) = default;
277 
278     // Note: we must allow these (and use the default implementations) since this class is used in a union so it must be
279     // a POD. However when we need a real object we must call the other constructor above, and when we need a copy we
280     // must
281     // call copy() explicitly.
282     LazyComponentWithArgs() = default; // LCOV_EXCL_LINE
283     LazyComponentWithArgs(const LazyComponentWithArgs&) = default;
284     LazyComponentWithArgs& operator=(const LazyComponentWithArgs&) = default;
285 
286     LazyComponentWithArgs copy() const;
287     void destroy() const;
288 
289     ComponentInterface* component;
290   };
291 
292   union {
293     // Valid iff kind is BINDING_FOR_CONSTRUCTED_OBJECT.
294     BindingForConstructedObject binding_for_constructed_object;
295 
296     // Valid iff kind is BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_[NO_]ALLOCATION
297     // or BINDING_FOR_OBJECT_TO_CONSTRUCT_WITH_UNKNOWN_ALLOCATION.
298     BindingForObjectToConstruct binding_for_object_to_construct;
299 
300     // Valid iff kind is MULTIBINDING_FOR_CONSTRUCTED_OBJECT.
301     MultibindingForConstructedObject multibinding_for_constructed_object;
302 
303     // Valid iff kind is MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_[NO_]ALLOCATION.
304     MultibindingForObjectToConstruct multibinding_for_object_to_construct;
305 
306     // Valid iff kind is MULTIBINDING_VECTOR_CREATOR.
307     MultibindingVectorCreator multibinding_vector_creator;
308 
309     // Valid iff kind is COMPRESSED_BINDING.
310     CompressedBinding compressed_binding;
311 
312     // Valid iff kind is LAZY_COMPONENT_WITH_NO_ARGS, REPLACED_LAZY_COMPONENT_WITH_NO_ARGS or
313     // REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS.
314     LazyComponentWithNoArgs lazy_component_with_no_args;
315 
316     // Valid iff kind is LAZY_COMPONENT_WITH_ARGS, REPLACED_LAZY_COMPONENT_WITH_ARGS or
317     // REPLACEMENT_LAZY_COMPONENT_WITH_ARGS.
318     LazyComponentWithArgs lazy_component_with_args;
319   };
320 
321   // We use a custom method instead of a real copy constructor so that all copies are explicit (since copying is a
322   // fairly expensive operation).
323   ComponentStorageEntry copy() const;
324 
325   // We use a custom method instead of a real destructor, so that we can hold these in a std::vector but still destroy
326   // them when desired.
327   void destroy() const;
328 };
329 
330 // We can't have this assert in debug mode because we add debug-only fields that increase the size.
331 #if !FRUIT_EXTRA_DEBUG
332 // This is not required for correctness, but 4 64-bit words should be enough to hold this object, if not we'd end up
333 // using more memory/CPU than expected.
334 static_assert(sizeof(ComponentStorageEntry) <= 4 * sizeof(std::uint64_t),
335               "Error: a ComponentStorageEntry doesn't fit in 32 bytes as we expected");
336 #endif
337 
338 } // namespace impl
339 } // namespace fruit
340 
341 #include <fruit/impl/component_storage/component_storage_entry.defn.h>
342 
343 #endif // FRUIT_COMPONENT_STORAGE_ENTRY_H
344