Home | History | Annotate | Download | only in injector
      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