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 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 68 inline NormalizedBinding InjectorStorage::BindingDataNodeIter::getValue() { 69 return NormalizedBinding(*itr); 70 } 71 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 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 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 { 105 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