• 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_INJECTOR_STORAGE_DEFN_H
18 #define FRUIT_INJECTOR_STORAGE_DEFN_H
19 
20 #include <fruit/impl/component_storage/component_storage_entry.h>
21 #include <fruit/impl/fruit_assert.h>
22 #include <fruit/impl/meta/component.h>
23 #include <fruit/impl/meta/vector.h>
24 #include <fruit/impl/util/demangle_type_name.h>
25 #include <fruit/impl/util/lambda_invoker.h>
26 #include <fruit/impl/util/type_info.h>
27 
28 #include <cassert>
29 
30 // Redundant, but makes KDevelop happy.
31 #include <fruit/impl/injector/injector_storage.h>
32 
33 namespace fruit {
34 namespace impl {
35 
36 inline InjectorStorage::BindingDataNodeIter* InjectorStorage::BindingDataNodeIter::operator->() {
37   return this;
38 }
39 
40 inline void InjectorStorage::BindingDataNodeIter::operator++() {
41   ++itr;
42 }
43 
44 inline bool InjectorStorage::BindingDataNodeIter::operator==(const BindingDataNodeIter& other) const {
45   return itr == other.itr;
46 }
47 
48 inline bool InjectorStorage::BindingDataNodeIter::operator!=(const BindingDataNodeIter& other) const {
49   return itr != other.itr;
50 }
51 
52 inline std::ptrdiff_t InjectorStorage::BindingDataNodeIter::operator-(BindingDataNodeIter other) const {
53   return itr - other.itr;
54 }
55 
getId()56 inline TypeId InjectorStorage::BindingDataNodeIter::getId() {
57   // For these kinds the type_id has a different meaning, but we never need to call this method for those.
58   FruitAssert(itr->kind != ComponentStorageEntry::Kind::COMPRESSED_BINDING);
59   FruitAssert(itr->kind != ComponentStorageEntry::Kind::LAZY_COMPONENT_WITH_NO_ARGS);
60   FruitAssert(itr->kind != ComponentStorageEntry::Kind::REPLACED_LAZY_COMPONENT_WITH_NO_ARGS);
61   FruitAssert(itr->kind != ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS);
62   FruitAssert(itr->kind != ComponentStorageEntry::Kind::LAZY_COMPONENT_WITH_ARGS);
63   FruitAssert(itr->kind != ComponentStorageEntry::Kind::REPLACED_LAZY_COMPONENT_WITH_ARGS);
64   FruitAssert(itr->kind != ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_ARGS);
65   return itr->type_id;
66 }
67 
getValue()68 inline NormalizedBinding InjectorStorage::BindingDataNodeIter::getValue() {
69   return NormalizedBinding(*itr);
70 }
71 
isTerminal()72 inline bool InjectorStorage::BindingDataNodeIter::isTerminal() {
73 #if FRUIT_EXTRA_DEBUG
74   if (itr->kind != ComponentStorageEntry::Kind::BINDING_FOR_CONSTRUCTED_OBJECT &&
75       itr->kind != ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION &&
76       itr->kind != ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION &&
77       itr->kind != ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_WITH_UNKNOWN_ALLOCATION) {
78     std::cerr << "Unexpected binding kind: " << (std::size_t)itr->kind << std::endl;
79     FruitAssert(false);
80   }
81 #endif
82   return itr->kind == ComponentStorageEntry::Kind::BINDING_FOR_CONSTRUCTED_OBJECT;
83 }
84 
getEdgesBegin()85 inline const TypeId* InjectorStorage::BindingDataNodeIter::getEdgesBegin() {
86   FruitAssert(itr->kind == ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION ||
87               itr->kind == ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION ||
88               itr->kind == ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_WITH_UNKNOWN_ALLOCATION);
89   return itr->binding_for_object_to_construct.deps->deps;
90 }
91 
getEdgesEnd()92 inline const TypeId* InjectorStorage::BindingDataNodeIter::getEdgesEnd() {
93   FruitAssert(itr->kind == ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION ||
94               itr->kind == ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION ||
95               itr->kind == ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_WITH_UNKNOWN_ALLOCATION);
96   return itr->binding_for_object_to_construct.deps->deps + itr->binding_for_object_to_construct.deps->num_deps;
97 }
98 
99 template <typename AnnotatedT>
100 struct GetFirstStage;
101 
102 // General case, value.
103 template <typename C>
104 struct GetFirstStage {
operatorGetFirstStage105   const C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
106     return injector.getPtr<C>(node_itr);
107   }
108 };
109 
110 template <typename C>
111 struct GetFirstStage<const C> {
112   const C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
113     return injector.getPtr<C>(node_itr);
114   }
115 };
116 
117 template <typename C>
118 struct GetFirstStage<std::shared_ptr<C>> {
119   // This method is covered by tests, even though lcov doesn't detect that.
120   C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
121     FruitAssert(node_itr.getNode().is_nonconst);
122     return const_cast<C*>(injector.getPtr<C>(node_itr));
123   }
124 };
125 
126 template <typename C>
127 struct GetFirstStage<C*> {
128   C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
129     FruitAssert(node_itr.getNode().is_nonconst);
130     return const_cast<C*>(injector.getPtr<C>(node_itr));
131   }
132 };
133 
134 template <typename C>
135 struct GetFirstStage<const C*> {
136   const C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
137     return injector.getPtr<C>(node_itr);
138   }
139 };
140 
141 template <typename C>
142 struct GetFirstStage<C&> {
143   C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
144     FruitAssert(node_itr.getNode().is_nonconst);
145     return const_cast<C*>(injector.getPtr<C>(node_itr));
146   }
147 };
148 
149 template <typename C>
150 struct GetFirstStage<const C&> {
151   // This method is covered by tests, even though lcov doesn't detect that.
152   const C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
153     return injector.getPtr<C>(node_itr);
154   }
155 };
156 
157 template <typename C>
158 struct GetFirstStage<Provider<C>> {
159   Provider<C> operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
160     return Provider<C>(&injector, node_itr);
161   }
162 };
163 
164 template <typename Annotation, typename T>
165 struct GetFirstStage<fruit::Annotated<Annotation, T>> : public GetFirstStage<T> {};
166 
167 template <typename AnnotatedT>
168 struct GetSecondStage;
169 
170 // General case, value.
171 template <typename C>
172 struct GetSecondStage {
173   C operator()(const C* p) {
174     return *p;
175   }
176 };
177 
178 template <typename C>
179 struct GetSecondStage<const C> {
180   const C operator()(const C* p) {
181     return *p;
182   }
183 };
184 
185 template <typename C>
186 struct GetSecondStage<std::shared_ptr<C>> {
187   // This method is covered by tests, even though lcov doesn't detect that.
188   std::shared_ptr<C> operator()(C* p) {
189     return std::shared_ptr<C>(std::shared_ptr<char>(), p);
190   }
191 };
192 
193 template <typename C>
194 struct GetSecondStage<C*> {
195   C* operator()(C* p) {
196     return p;
197   }
198 };
199 
200 template <typename C>
201 struct GetSecondStage<const C*> {
202   // This method is covered by tests, even though lcov doesn't detect that.
203   const C* operator()(const C* p) {
204     return p;
205   }
206 };
207 
208 template <typename C>
209 struct GetSecondStage<C&> {
210   C& operator()(C* p) {
211     return *p;
212   }
213 };
214 
215 template <typename C>
216 struct GetSecondStage<const C&> {
217   const C& operator()(const C* p) {
218     return *p;
219   }
220 };
221 
222 template <typename C>
223 struct GetSecondStage<Provider<C>> {
224   Provider<C> operator()(Provider<C> p) {
225     return p;
226   }
227 };
228 
229 template <typename Annotation, typename T>
230 struct GetSecondStage<fruit::Annotated<Annotation, T>> : public GetSecondStage<T> {};
231 
232 template <typename AnnotatedT>
233 inline InjectorStorage::RemoveAnnotations<AnnotatedT> InjectorStorage::get() {
234   std::lock_guard<std::recursive_mutex> lock(mutex);
235   return GetSecondStage<AnnotatedT>()(GetFirstStage<AnnotatedT>()(*this, lazyGetPtr<NormalizeType<AnnotatedT>>()));
236 }
237 
238 template <typename T>
239 inline T InjectorStorage::get(InjectorStorage::Graph::node_iterator node_iterator) {
240   FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<T>,
241                                               fruit::impl::meta::RemoveAnnotations(fruit::impl::meta::Type<T>)));
242   std::lock_guard<std::recursive_mutex> lock(mutex);
243   return GetSecondStage<T>()(GetFirstStage<T>()(*this, node_iterator));
244 }
245 
246 template <typename AnnotatedC>
247 inline InjectorStorage::Graph::node_iterator InjectorStorage::lazyGetPtr() {
248   return lazyGetPtr(getTypeId<AnnotatedC>());
249 }
250 
251 template <typename AnnotatedC>
252 inline InjectorStorage::Graph::node_iterator
253 InjectorStorage::lazyGetPtr(Graph::edge_iterator deps, std::size_t dep_index, Graph::node_iterator bindings_begin)
254     const {
255   // Here we (intentionally) do not lock `mutex', since this is a read-only method that only accesses immutable data.
256   Graph::node_iterator itr = deps.getNodeIterator(dep_index, bindings_begin);
257   FruitAssert(bindings.find(getTypeId<AnnotatedC>()) == Graph::const_node_iterator(itr));
258   FruitAssert(!(bindings.end() == Graph::const_node_iterator(itr)));
259   return itr;
260 }
261 
262 template <typename C>
263 inline const C* InjectorStorage::getPtr(Graph::node_iterator itr) {
264   FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<C>,
265                                               fruit::impl::meta::NormalizeType(fruit::impl::meta::Type<C>)));
266   const void* p = getPtrInternal(itr);
267   return reinterpret_cast<const C*>(p);
268 }
269 
270 template <typename AnnotatedC>
271 inline const InjectorStorage::RemoveAnnotations<AnnotatedC>* InjectorStorage::unsafeGet() {
272   std::lock_guard<std::recursive_mutex> lock(mutex);
273   using C = RemoveAnnotations<AnnotatedC>;
274   const void* p = unsafeGetPtr(getTypeId<AnnotatedC>());
275   return reinterpret_cast<const C*>(p);
276 }
277 
278 inline InjectorStorage::Graph::node_iterator InjectorStorage::lazyGetPtr(TypeId type) {
279   return bindings.at(type);
280 }
281 
282 inline const void* InjectorStorage::unsafeGetPtr(TypeId type) {
283   Graph::node_iterator itr = bindings.find(type);
284   if (itr == bindings.end()) {
285     return nullptr;
286   }
287   return getPtrInternal(itr);
288 }
289 
290 template <typename AnnotatedC>
291 inline const std::vector<InjectorStorage::RemoveAnnotations<AnnotatedC>*>& InjectorStorage::getMultibindings() {
292   std::lock_guard<std::recursive_mutex> lock(mutex);
293   using C = RemoveAnnotations<AnnotatedC>;
294   void* p = getMultibindings(getTypeId<AnnotatedC>());
295   if (p == nullptr) {
296     static std::vector<C*> empty_vector;
297     return empty_vector;
298   } else {
299     return *reinterpret_cast<std::vector<C*>*>(p);
300   }
301 }
302 
303 inline const void* InjectorStorage::getPtrInternal(Graph::node_iterator node_itr) {
304   NormalizedBinding& normalized_binding = node_itr.getNode();
305   if (!node_itr.isTerminal()) {
306     normalized_binding.object = normalized_binding.create(*this, node_itr);
307     FruitAssert(node_itr.isTerminal());
308   }
309   return normalized_binding.object;
310 }
311 
312 inline NormalizedMultibindingSet* InjectorStorage::getNormalizedMultibindingSet(TypeId type) {
313   auto itr = multibindings.find(type);
314   if (itr != multibindings.end())
315     return &(itr->second);
316   else
317     return nullptr;
318 }
319 
320 template <typename AnnotatedC>
321 inline std::shared_ptr<char> InjectorStorage::createMultibindingVector(InjectorStorage& storage) {
322   using C = RemoveAnnotations<AnnotatedC>;
323   TypeId type = getTypeId<AnnotatedC>();
324   NormalizedMultibindingSet* multibinding_set = storage.getNormalizedMultibindingSet(type);
325 
326   // This method is only called if there was at least 1 multibinding (otherwise the would-be caller would have returned
327   // nullptr
328   // instead of calling this).
329   FruitAssert(multibinding_set != nullptr);
330 
331   if (multibinding_set->v.get() != nullptr) {
332     // Result cached, return early.
333     return multibinding_set->v;
334   }
335 
336   storage.ensureConstructedMultibinding(*multibinding_set);
337 
338   std::vector<C*> s;
339   s.reserve(multibinding_set->elems.size());
340   for (const NormalizedMultibinding& multibinding : multibinding_set->elems) {
341     FruitAssert(multibinding.is_constructed);
342     s.push_back(reinterpret_cast<C*>(multibinding.object));
343   }
344 
345   std::shared_ptr<std::vector<C*>> vector_ptr = std::make_shared<std::vector<C*>>(std::move(s));
346   std::shared_ptr<char> result(vector_ptr, reinterpret_cast<char*>(vector_ptr.get()));
347 
348   multibinding_set->v = result;
349 
350   return result;
351 }
352 
353 template <typename I, typename C, typename AnnotatedC>
354 InjectorStorage::const_object_ptr_t
355 InjectorStorage::createInjectedObjectForBind(InjectorStorage& injector,
356                                              InjectorStorage::Graph::node_iterator node_itr) {
357 
358   InjectorStorage::Graph::node_iterator bindings_begin = injector.bindings.begin();
359   const C* cPtr = injector.get<const C*>(injector.lazyGetPtr<AnnotatedC>(node_itr.neighborsBegin(), 0, bindings_begin));
360   node_itr.setTerminal();
361   // This step is needed when the cast C->I changes the pointer
362   // (e.g. for multiple inheritance).
363   const I* iPtr = static_cast<const I*>(cPtr);
364   return reinterpret_cast<const_object_ptr_t>(iPtr);
365 }
366 
367 // I, C must not be pointers.
368 template <typename AnnotatedI, typename AnnotatedC>
369 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForBind() {
370   using I = RemoveAnnotations<AnnotatedI>;
371   using C = RemoveAnnotations<AnnotatedC>;
372   FruitStaticAssert(fruit::impl::meta::Not(fruit::impl::meta::IsPointer(fruit::impl::meta::Type<I>)));
373   FruitStaticAssert(fruit::impl::meta::Not(fruit::impl::meta::IsPointer(fruit::impl::meta::Type<C>)));
374   ComponentStorageEntry result;
375   result.kind = ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION;
376   result.type_id = getTypeId<AnnotatedI>();
377   ComponentStorageEntry::BindingForObjectToConstruct& binding = result.binding_for_object_to_construct;
378   binding.create = createInjectedObjectForBind<I, C, AnnotatedC>;
379   binding.deps = getBindingDeps<fruit::impl::meta::Vector<fruit::impl::meta::Type<AnnotatedC>>>();
380 #if FRUIT_EXTRA_DEBUG
381   binding.is_nonconst = true;
382 #endif
383   return result;
384 }
385 
386 // I, C must not be pointers.
387 template <typename AnnotatedI, typename AnnotatedC>
388 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForConstBind() {
389   using I = RemoveAnnotations<AnnotatedI>;
390   using C = RemoveAnnotations<AnnotatedC>;
391   FruitStaticAssert(fruit::impl::meta::Not(fruit::impl::meta::IsPointer(fruit::impl::meta::Type<I>)));
392   FruitStaticAssert(fruit::impl::meta::Not(fruit::impl::meta::IsPointer(fruit::impl::meta::Type<C>)));
393   ComponentStorageEntry result;
394   result.kind = ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION;
395   result.type_id = getTypeId<AnnotatedI>();
396   ComponentStorageEntry::BindingForObjectToConstruct& binding = result.binding_for_object_to_construct;
397   binding.create = createInjectedObjectForBind<I, C, AnnotatedC>;
398   binding.deps = getBindingDeps<fruit::impl::meta::Vector<fruit::impl::meta::Type<AnnotatedC>>>();
399 #if FRUIT_EXTRA_DEBUG
400   binding.is_nonconst = false;
401 #endif
402   return result;
403 }
404 
405 template <typename AnnotatedC, typename C>
406 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForBindInstance(C& instance) {
407   ComponentStorageEntry result;
408   result.kind = ComponentStorageEntry::Kind::BINDING_FOR_CONSTRUCTED_OBJECT;
409   result.type_id = getTypeId<AnnotatedC>();
410   ComponentStorageEntry::BindingForConstructedObject& binding = result.binding_for_constructed_object;
411   binding.object_ptr = &instance;
412 #if FRUIT_EXTRA_DEBUG
413   binding.is_nonconst = true;
414 #endif
415   return result;
416 }
417 
418 template <typename AnnotatedC, typename C>
419 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForBindConstInstance(const C& instance) {
420   ComponentStorageEntry result;
421   result.kind = ComponentStorageEntry::Kind::BINDING_FOR_CONSTRUCTED_OBJECT;
422   result.type_id = getTypeId<AnnotatedC>();
423   ComponentStorageEntry::BindingForConstructedObject& binding = result.binding_for_constructed_object;
424   binding.object_ptr = &instance;
425 #if FRUIT_EXTRA_DEBUG
426   binding.is_nonconst = false;
427 #endif
428   return result;
429 }
430 
431 // The inner operator() takes an InjectorStorage& and a Graph::edge_iterator (the type's deps) and
432 // returns the injected object as a C*.
433 // This takes care of move-constructing a C into the injector's own allocator if needed.
434 template <typename AnnotatedSignature, typename Lambda, bool lambda_returns_pointer,
435           typename AnnotatedT = InjectorStorage::SignatureType<AnnotatedSignature>,
436           typename AnnotatedArgVector =
437               fruit::impl::meta::Eval<fruit::impl::meta::SignatureArgs(fruit::impl::meta::Type<AnnotatedSignature>)>,
438           typename Indexes =
439               fruit::impl::meta::Eval<fruit::impl::meta::GenerateIntSequence(fruit::impl::meta::VectorSize(
440                   fruit::impl::meta::SignatureArgs(fruit::impl::meta::Type<AnnotatedSignature>)))>>
441 struct InvokeLambdaWithInjectedArgVector;
442 
443 // AnnotatedT is of the form C* or Annotated<Annotation, C*>
444 template <typename AnnotatedSignature, typename Lambda, typename AnnotatedT, typename... AnnotatedArgs,
445           typename... Indexes>
446 struct InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, true /* lambda_returns_pointer */, AnnotatedT,
447                                          fruit::impl::meta::Vector<AnnotatedArgs...>,
448                                          fruit::impl::meta::Vector<Indexes...>> {
449   using CPtr = InjectorStorage::RemoveAnnotations<AnnotatedT>;
450   using AnnotatedC = InjectorStorage::NormalizeType<AnnotatedT>;
451 
452   FRUIT_ALWAYS_INLINE
453   CPtr operator()(InjectorStorage& injector, FixedSizeAllocator& allocator) {
454     // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
455     (void)injector;
456     CPtr cPtr =
457         LambdaInvoker::invoke<Lambda, typename InjectorStorage::AnnotationRemover<
458                                           typename fruit::impl::meta::TypeUnwrapper<AnnotatedArgs>::type>::type...>(
459             injector.get<fruit::impl::meta::UnwrapType<AnnotatedArgs>>()...);
460 
461     allocator.registerExternallyAllocatedObject(cPtr);
462 
463     // This can happen if the user-supplied provider returns nullptr.
464     if (cPtr == nullptr) {
465       InjectorStorage::fatal("attempting to get an instance for the type " + std::string(getTypeId<AnnotatedC>()) +
466                              " but the provider returned nullptr");
467       FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
468     }
469 
470     return cPtr;
471   }
472 
473   // This is not inlined in outerConstructHelper so that when get<> needs to construct an object more complex than a
474   // pointer
475   // (e.g. a shared_ptr), that happens as late as possible so that it's easier for the optimizer to optimize out some
476   // operations (e.g. the increment/decrement/check of shared_ptr's reference count).
477   template <typename... GetFirstStageResults>
478   FRUIT_ALWAYS_INLINE CPtr innerConstructHelper(InjectorStorage& injector,
479                                                 GetFirstStageResults... getFirstStageResults) {
480     // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
481     (void)injector;
482     return LambdaInvoker::invoke<Lambda, typename InjectorStorage::AnnotationRemover<
483                                              typename fruit::impl::meta::TypeUnwrapper<AnnotatedArgs>::type>::type...>(
484         GetSecondStage<InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>()(
485             getFirstStageResults)...);
486   }
487 
488   // This is not inlined in operator() so that all the lazyGetPtr() calls happen first (instead of being interleaved
489   // with the get() calls). The lazyGetPtr() calls don't branch, while the get() calls branch on the result of the
490   // lazyGetPtr()s, so it's faster to execute them in this order.
491   template <typename... NodeItrs>
492   FRUIT_ALWAYS_INLINE CPtr outerConstructHelper(InjectorStorage& injector, NodeItrs... nodeItrs) {
493     // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
494     (void)injector;
495     return innerConstructHelper(
496         injector, GetFirstStage<InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>()(
497                       injector, nodeItrs)...);
498   }
499 
500   FRUIT_ALWAYS_INLINE
501   CPtr operator()(InjectorStorage& injector, SemistaticGraph<TypeId, NormalizedBinding>& bindings,
502                   FixedSizeAllocator& allocator, InjectorStorage::Graph::edge_iterator deps) {
503     // `deps' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
504     (void)deps;
505 
506     InjectorStorage::Graph::node_iterator bindings_begin = bindings.begin();
507     // `bindings_begin' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
508     (void)bindings_begin;
509     CPtr cPtr = outerConstructHelper(
510         injector,
511         injector.lazyGetPtr<InjectorStorage::NormalizeType<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>(
512             deps, fruit::impl::meta::getIntValue<Indexes>(), bindings_begin)...);
513     allocator.registerExternallyAllocatedObject(cPtr);
514 
515     // This can happen if the user-supplied provider returns nullptr.
516     if (cPtr == nullptr) {
517       InjectorStorage::fatal("attempting to get an instance for the type " + std::string(getTypeId<AnnotatedC>()) +
518                              " but the provider returned nullptr");
519       FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
520     }
521 
522     return cPtr;
523   }
524 };
525 
526 template <typename AnnotatedSignature, typename Lambda, typename AnnotatedC, typename... AnnotatedArgs,
527           typename... Indexes>
528 struct InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, false /* lambda_returns_pointer */, AnnotatedC,
529                                          fruit::impl::meta::Vector<AnnotatedArgs...>,
530                                          fruit::impl::meta::Vector<Indexes...>> {
531   using C = InjectorStorage::RemoveAnnotations<AnnotatedC>;
532 
533   FRUIT_ALWAYS_INLINE
534   C* operator()(InjectorStorage& injector, FixedSizeAllocator& allocator) {
535     // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
536     (void)injector;
537     return allocator.constructObject<AnnotatedC, C&&>(
538         LambdaInvoker::invoke<Lambda, typename InjectorStorage::AnnotationRemover<
539                                           typename fruit::impl::meta::TypeUnwrapper<AnnotatedArgs>::type>::type&&...>(
540             injector.get<typename fruit::impl::meta::TypeUnwrapper<AnnotatedArgs>::type>()...));
541   }
542 
543   // This is not inlined in outerConstructHelper so that when get<> needs to construct an object more complex than a
544   // pointer
545   // (e.g. a shared_ptr), that happens as late as possible so that it's easier for the optimizer to optimize out some
546   // operations (e.g. the increment/decrement/check of shared_ptr's reference count).
547   template <typename... GetFirstStageResults>
548   FRUIT_ALWAYS_INLINE C* innerConstructHelper(InjectorStorage& injector, FixedSizeAllocator& allocator,
549                                               GetFirstStageResults... getFirstStageResults) {
550     // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
551     (void)injector;
552     return allocator.constructObject<AnnotatedC, C&&>(
553         LambdaInvoker::invoke<Lambda, typename InjectorStorage::AnnotationRemover<
554                                           typename fruit::impl::meta::TypeUnwrapper<AnnotatedArgs>::type>::type...>(
555             GetSecondStage<typename InjectorStorage::AnnotationRemover<
556                 typename fruit::impl::meta::TypeUnwrapper<AnnotatedArgs>::type>::type>()(getFirstStageResults)...));
557   }
558 
559   // This is not inlined in operator() so that all the lazyGetPtr() calls happen first (instead of being interleaved
560   // with the get() calls). The lazyGetPtr() calls don't branch, while the get() calls branch on the result of the
561   // lazyGetPtr()s, so it's faster to execute them in this order.
562   template <typename... NodeItrs>
563   FRUIT_ALWAYS_INLINE C* outerConstructHelper(InjectorStorage& injector, FixedSizeAllocator& allocator,
564                                               NodeItrs... nodeItrs) {
565     // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
566     (void)injector;
567     return innerConstructHelper(
568         injector, allocator,
569         GetFirstStage<InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>()(injector,
570                                                                                                           nodeItrs)...);
571   }
572 
573   C* operator()(InjectorStorage& injector, SemistaticGraph<TypeId, NormalizedBinding>& bindings,
574                 FixedSizeAllocator& allocator, InjectorStorage::Graph::edge_iterator deps) {
575     InjectorStorage::Graph::node_iterator bindings_begin = bindings.begin();
576     // `bindings_begin' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
577     (void)bindings_begin;
578 
579     // `deps' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
580     (void)deps;
581 
582     // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
583     (void)injector;
584     C* p = outerConstructHelper(
585         injector, allocator,
586         injector.lazyGetPtr<InjectorStorage::NormalizeType<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>(
587             deps, fruit::impl::meta::getIntValue<Indexes>(), bindings_begin)...);
588     return p;
589   }
590 };
591 
592 template <typename C, typename T, typename AnnotatedSignature, typename Lambda>
593 InjectorStorage::const_object_ptr_t InjectorStorage::createInjectedObjectForProvider(InjectorStorage& injector,
594                                                                                      Graph::node_iterator node_itr) {
595   C* cPtr = InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, std::is_pointer<T>::value>()(
596       injector, injector.bindings, injector.allocator, node_itr.neighborsBegin());
597   node_itr.setTerminal();
598   return reinterpret_cast<const_object_ptr_t>(cPtr);
599 }
600 
601 template <typename AnnotatedSignature, typename Lambda>
602 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForProvider() {
603 #if FRUIT_EXTRA_DEBUG
604   using Signature =
605       fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<fruit::impl::meta::RemoveAnnotationsFromSignature(
606           fruit::impl::meta::Type<AnnotatedSignature>)>>;
607   FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<Signature>,
608                                               fruit::impl::meta::FunctionSignature(fruit::impl::meta::Type<Lambda>)));
609 #endif
610   using AnnotatedT = SignatureType<AnnotatedSignature>;
611   using AnnotatedC = NormalizeType<AnnotatedT>;
612   // T is either C or C*.
613   using T = RemoveAnnotations<AnnotatedT>;
614   using C = NormalizeType<T>;
615   ComponentStorageEntry result;
616   constexpr bool needs_allocation = !std::is_pointer<T>::value;
617   result.kind = needs_allocation
618                     ? ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION
619                     : ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION;
620   result.type_id = getTypeId<AnnotatedC>();
621   ComponentStorageEntry::BindingForObjectToConstruct& binding = result.binding_for_object_to_construct;
622   binding.create = createInjectedObjectForProvider<C, T, AnnotatedSignature, Lambda>;
623   binding.deps = getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>();
624 #if FRUIT_EXTRA_DEBUG
625   binding.is_nonconst = true;
626 #endif
627   return result;
628 }
629 
630 template <typename I, typename C, typename T, typename AnnotatedSignature, typename Lambda>
631 InjectorStorage::const_object_ptr_t
632 InjectorStorage::createInjectedObjectForCompressedProvider(InjectorStorage& injector, Graph::node_iterator node_itr) {
633   C* cPtr = InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, std::is_pointer<T>::value>()(
634       injector, injector.bindings, injector.allocator, node_itr.neighborsBegin());
635   node_itr.setTerminal();
636   I* iPtr = static_cast<I*>(cPtr);
637   return reinterpret_cast<object_ptr_t>(iPtr);
638 }
639 
640 template <typename AnnotatedSignature, typename Lambda, typename AnnotatedI>
641 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForCompressedProvider() {
642 #if FRUIT_EXTRA_DEBUG
643   using Signature =
644       fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<fruit::impl::meta::RemoveAnnotationsFromSignature(
645           fruit::impl::meta::Type<AnnotatedSignature>)>>;
646   FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<Signature>,
647                                               fruit::impl::meta::FunctionSignature(fruit::impl::meta::Type<Lambda>)));
648 #endif
649   using AnnotatedT = SignatureType<AnnotatedSignature>;
650   using AnnotatedC = NormalizeType<AnnotatedT>;
651   // T is either C or C*.
652   using T = RemoveAnnotations<AnnotatedT>;
653   using C = NormalizeType<T>;
654   using I = RemoveAnnotations<AnnotatedI>;
655   ComponentStorageEntry result;
656   result.kind = ComponentStorageEntry::Kind::COMPRESSED_BINDING;
657   result.type_id = getTypeId<AnnotatedI>();
658   ComponentStorageEntry::CompressedBinding& binding = result.compressed_binding;
659   binding.c_type_id = getTypeId<AnnotatedC>();
660   binding.create = createInjectedObjectForCompressedProvider<I, C, T, AnnotatedSignature, Lambda>;
661   return result;
662 }
663 
664 // The inner operator() takes an InjectorStorage& and a Graph::edge_iterator (the type's deps) and
665 // returns the injected object as a C*.
666 // This takes care of allocating the required space into the injector's allocator.
667 template <typename AnnotatedSignature,
668           typename Indexes =
669               fruit::impl::meta::Eval<fruit::impl::meta::GenerateIntSequence(fruit::impl::meta::VectorSize(
670                   fruit::impl::meta::SignatureArgs(fruit::impl::meta::Type<AnnotatedSignature>)))>>
671 struct InvokeConstructorWithInjectedArgVector;
672 
673 template <typename AnnotatedC, typename... AnnotatedArgs, typename... Indexes>
674 struct InvokeConstructorWithInjectedArgVector<AnnotatedC(AnnotatedArgs...), fruit::impl::meta::Vector<Indexes...>> {
675   using C = InjectorStorage::RemoveAnnotations<AnnotatedC>;
676 
677   // This is not inlined in outerConstructHelper so that when get<> needs to construct an object more complex than a
678   // pointer
679   // (e.g. a shared_ptr), that happens as late as possible so that it's easier for the optimizer to optimize out some
680   // operations (e.g. the increment/decrement/check of shared_ptr's reference count).
681   template <typename... GetFirstStageResults>
682   FRUIT_ALWAYS_INLINE C* innerConstructHelper(InjectorStorage& injector, FixedSizeAllocator& allocator,
683                                               GetFirstStageResults... getFirstStageResults) {
684     // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
685     (void)injector;
686     return allocator.constructObject<AnnotatedC, typename InjectorStorage::AnnotationRemover<AnnotatedArgs>::type&&...>(
687         GetSecondStage<InjectorStorage::RemoveAnnotations<AnnotatedArgs>>()(getFirstStageResults)...);
688   }
689 
690   // This is not inlined in operator() so that all the lazyGetPtr() calls happen first (instead of being interleaved
691   // with the get() calls). The lazyGetPtr() calls don't branch, while the get() calls branch on the result of the
692   // lazyGetPtr()s, so it's faster to execute them in this order.
693   template <typename... NodeItrs>
694   FRUIT_ALWAYS_INLINE C* outerConstructHelper(InjectorStorage& injector, FixedSizeAllocator& allocator,
695                                               NodeItrs... nodeItrs) {
696     // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
697     (void)injector;
698     return innerConstructHelper(
699         injector, allocator, GetFirstStage<InjectorStorage::RemoveAnnotations<AnnotatedArgs>>()(injector, nodeItrs)...);
700   }
701 
702   FRUIT_ALWAYS_INLINE
703   C* operator()(InjectorStorage& injector, SemistaticGraph<TypeId, NormalizedBinding>& bindings,
704                 FixedSizeAllocator& allocator, InjectorStorage::Graph::edge_iterator deps) {
705 
706     // `deps' *is* used below, but when there are no Args some compilers report it as unused.
707     (void)deps;
708 
709     InjectorStorage::Graph::node_iterator bindings_begin = bindings.begin();
710     // `bindings_begin' *is* used below, but when there are no Args some compilers report it as unused.
711     (void)bindings_begin;
712     C* p = outerConstructHelper(injector, allocator,
713                                 injector.lazyGetPtr<typename InjectorStorage::TypeNormalizer<AnnotatedArgs>::type>(
714                                     deps, fruit::impl::meta::getIntValue<Indexes>(), bindings_begin)...);
715     return p;
716   }
717 };
718 
719 template <typename C, typename AnnotatedSignature>
720 InjectorStorage::const_object_ptr_t InjectorStorage::createInjectedObjectForConstructor(InjectorStorage& injector,
721                                                                                         Graph::node_iterator node_itr) {
722   C* cPtr = InvokeConstructorWithInjectedArgVector<AnnotatedSignature>()(injector, injector.bindings,
723                                                                          injector.allocator, node_itr.neighborsBegin());
724   node_itr.setTerminal();
725   return reinterpret_cast<InjectorStorage::object_ptr_t>(cPtr);
726 }
727 
728 template <typename AnnotatedSignature>
729 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForConstructor() {
730   using AnnotatedC = SignatureType<AnnotatedSignature>;
731   using C = RemoveAnnotations<AnnotatedC>;
732   ComponentStorageEntry result;
733   result.kind = ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION;
734   result.type_id = getTypeId<AnnotatedC>();
735   ComponentStorageEntry::BindingForObjectToConstruct& binding = result.binding_for_object_to_construct;
736   binding.create = createInjectedObjectForConstructor<C, AnnotatedSignature>;
737   binding.deps = getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>();
738 #if FRUIT_EXTRA_DEBUG
739   binding.is_nonconst = true;
740 #endif
741   return result;
742 }
743 
744 template <typename I, typename C, typename AnnotatedSignature>
745 InjectorStorage::const_object_ptr_t
746 InjectorStorage::createInjectedObjectForCompressedConstructor(InjectorStorage& injector,
747                                                               Graph::node_iterator node_itr) {
748   C* cPtr = InvokeConstructorWithInjectedArgVector<AnnotatedSignature>()(injector, injector.bindings,
749                                                                          injector.allocator, node_itr.neighborsBegin());
750   node_itr.setTerminal();
751   I* iPtr = static_cast<I*>(cPtr);
752   return reinterpret_cast<object_ptr_t>(iPtr);
753 }
754 
755 template <typename AnnotatedSignature, typename AnnotatedI>
756 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForCompressedConstructor() {
757   using AnnotatedC = SignatureType<AnnotatedSignature>;
758   using C = RemoveAnnotations<AnnotatedC>;
759   using I = RemoveAnnotations<AnnotatedI>;
760   ComponentStorageEntry result;
761   result.kind = ComponentStorageEntry::Kind::COMPRESSED_BINDING;
762   result.type_id = getTypeId<AnnotatedI>();
763   ComponentStorageEntry::CompressedBinding& binding = result.compressed_binding;
764   binding.c_type_id = getTypeId<AnnotatedC>();
765   binding.create = createInjectedObjectForCompressedConstructor<I, C, AnnotatedSignature>;
766   return result;
767 }
768 
769 template <typename AnnotatedT>
770 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForMultibindingVectorCreator() {
771   ComponentStorageEntry result;
772   result.kind = ComponentStorageEntry::Kind::MULTIBINDING_VECTOR_CREATOR;
773   result.type_id = getTypeId<AnnotatedT>();
774   ComponentStorageEntry::MultibindingVectorCreator& binding = result.multibinding_vector_creator;
775   binding.get_multibindings_vector = createMultibindingVector<AnnotatedT>;
776   return result;
777 }
778 
779 template <typename I, typename C, typename AnnotatedCPtr>
780 InjectorStorage::object_ptr_t InjectorStorage::createInjectedObjectForMultibinding(InjectorStorage& m) {
781   C* cPtr = m.get<AnnotatedCPtr>();
782   // This step is needed when the cast C->I changes the pointer
783   // (e.g. for multiple inheritance).
784   I* iPtr = static_cast<I*>(cPtr);
785   return reinterpret_cast<InjectorStorage::object_ptr_t>(iPtr);
786 }
787 
788 template <typename AnnotatedI, typename AnnotatedC>
789 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForMultibinding() {
790   using AnnotatedCPtr = fruit::impl::meta::UnwrapType<
791       fruit::impl::meta::Eval<fruit::impl::meta::AddPointerInAnnotatedType(fruit::impl::meta::Type<AnnotatedC>)>>;
792   using I = RemoveAnnotations<AnnotatedI>;
793   using C = RemoveAnnotations<AnnotatedC>;
794   ComponentStorageEntry result;
795   result.kind = ComponentStorageEntry::Kind::MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION;
796   result.type_id = getTypeId<AnnotatedI>();
797   ComponentStorageEntry::MultibindingForObjectToConstruct& binding = result.multibinding_for_object_to_construct;
798   binding.create = createInjectedObjectForMultibinding<I, C, AnnotatedCPtr>;
799   binding.deps = getBindingDeps<fruit::impl::meta::Vector<fruit::impl::meta::Type<AnnotatedC>>>();
800   return result;
801 }
802 
803 template <typename AnnotatedC, typename C>
804 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForInstanceMultibinding(C& instance) {
805   ComponentStorageEntry result;
806   result.kind = ComponentStorageEntry::Kind::MULTIBINDING_FOR_CONSTRUCTED_OBJECT;
807   result.type_id = getTypeId<AnnotatedC>();
808   ComponentStorageEntry::MultibindingForConstructedObject& binding = result.multibinding_for_constructed_object;
809   binding.object_ptr = &instance;
810   return result;
811 }
812 
813 template <typename C, typename T, typename AnnotatedSignature, typename Lambda>
814 InjectorStorage::object_ptr_t InjectorStorage::createInjectedObjectForMultibindingProvider(InjectorStorage& injector) {
815   C* cPtr = InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, std::is_pointer<T>::value>()(
816       injector, injector.allocator);
817   return reinterpret_cast<object_ptr_t>(cPtr);
818 }
819 
820 template <typename AnnotatedSignature, typename Lambda>
821 inline ComponentStorageEntry InjectorStorage::createComponentStorageEntryForMultibindingProvider() {
822 #if FRUIT_EXTRA_DEBUG
823   using Signature =
824       fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<fruit::impl::meta::RemoveAnnotationsFromSignature(
825           fruit::impl::meta::Type<AnnotatedSignature>)>>;
826   FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<Signature>,
827                                               fruit::impl::meta::FunctionSignature(fruit::impl::meta::Type<Lambda>)));
828 #endif
829 
830   using AnnotatedT = SignatureType<AnnotatedSignature>;
831   using AnnotatedC = NormalizeType<AnnotatedT>;
832   using T = RemoveAnnotations<AnnotatedT>;
833   using C = NormalizeType<T>;
834   ComponentStorageEntry result;
835   bool needs_allocation = !std::is_pointer<T>::value;
836   if (needs_allocation)
837     result.kind = ComponentStorageEntry::Kind::MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION;
838   else
839     result.kind = ComponentStorageEntry::Kind::MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION;
840   result.type_id = getTypeId<AnnotatedC>();
841   ComponentStorageEntry::MultibindingForObjectToConstruct& binding = result.multibinding_for_object_to_construct;
842   binding.create = createInjectedObjectForMultibindingProvider<C, T, AnnotatedSignature, Lambda>;
843   binding.deps = getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>();
844   return result;
845 }
846 
847 } // namespace fruit
848 } // namespace impl
849 
850 #endif // FRUIT_INJECTOR_STORAGE_DEFN_H
851