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