blob: e3cdb7bb6fad9125c9287c3a9f355bc06f3ec731 [file] [log] [blame]
Marco Polettifdbfcbe2014-08-31 08:57:47 +01001/*
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
Marco Poletti7f35b652014-11-01 10:11:37 +000017#ifndef FRUIT_INJECTOR_STORAGE_DEFN_H
18#define FRUIT_INJECTOR_STORAGE_DEFN_H
Marco Polettifdbfcbe2014-08-31 08:57:47 +010019
Marco Polettif2895102016-01-30 13:38:37 +000020#include <fruit/impl/util/demangle_type_name.h>
21#include <fruit/impl/util/type_info.h>
22#include <fruit/impl/util/lambda_invoker.h>
23#include <fruit/impl/fruit_assert.h>
24#include <fruit/impl/meta/vector.h>
25#include <fruit/impl/meta/component.h>
Marco Polettifdbfcbe2014-08-31 08:57:47 +010026
Marco Poletti633a3892014-10-19 17:33:11 -070027#include <cassert>
28
Marco Polettifdbfcbe2014-08-31 08:57:47 +010029// Redundant, but makes KDevelop happy.
Marco Polettif2895102016-01-30 13:38:37 +000030#include <fruit/impl/storage/injector_storage.h>
Marco Polettifdbfcbe2014-08-31 08:57:47 +010031
32namespace fruit {
33namespace impl {
34
Marco Poletti0bfbe052014-11-24 17:11:27 +000035inline InjectorStorage::BindingDataNodeIter* InjectorStorage::BindingDataNodeIter::operator->() {
36 return this;
37}
38
39inline void InjectorStorage::BindingDataNodeIter::operator++() {
40 ++itr;
41}
42
43inline bool InjectorStorage::BindingDataNodeIter::operator==(const BindingDataNodeIter& other) const {
44 return itr == other.itr;
45}
46
47inline bool InjectorStorage::BindingDataNodeIter::operator!=(const BindingDataNodeIter& other) const {
48 return itr != other.itr;
49}
50
Marco Polettie99fdb72016-05-22 12:26:08 +010051inline std::ptrdiff_t InjectorStorage::BindingDataNodeIter::operator-(BindingDataNodeIter other) const {
52 return itr - other.itr;
53}
54
Marco Poletti0bfbe052014-11-24 17:11:27 +000055inline TypeId InjectorStorage::BindingDataNodeIter::getId() {
56 return itr->first;
57}
58
59inline NormalizedBindingData InjectorStorage::BindingDataNodeIter::getValue() {
60 return NormalizedBindingData(itr->second);
61}
62
63inline bool InjectorStorage::BindingDataNodeIter::isTerminal() {
64 return itr->second.isCreated();
65}
66
67inline const TypeId* InjectorStorage::BindingDataNodeIter::getEdgesBegin() {
68 const BindingDeps* deps = itr->second.getDeps();
69 return deps->deps;
70}
71
72inline const TypeId* InjectorStorage::BindingDataNodeIter::getEdgesEnd() {
73 const BindingDeps* deps = itr->second.getDeps();
74 return deps->deps + deps->num_deps;
75}
76
Marco Poletticc97a162015-05-10 12:10:12 +010077template <typename AnnotatedT>
Marco Polettifdc79902017-05-21 13:27:57 +010078struct GetFirstStage;
Marco Poletticc97a162015-05-10 12:10:12 +010079
80// General case, value.
Marco Polettifdbfcbe2014-08-31 08:57:47 +010081template <typename C>
Marco Polettifdc79902017-05-21 13:27:57 +010082struct GetFirstStage {
Marco Poletti9491d652014-11-24 15:47:14 +000083 C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
84 return injector.getPtr<C>(node_itr);
Marco Polettib1d265c2014-10-19 21:24:11 -070085 }
Marco Polettifdbfcbe2014-08-31 08:57:47 +010086};
87
88template <typename C>
Marco Polettifdc79902017-05-21 13:27:57 +010089struct GetFirstStage<const C> {
90 C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
Marco Poletti9491d652014-11-24 15:47:14 +000091 return injector.getPtr<C>(node_itr);
Marco Polettib1d265c2014-10-19 21:24:11 -070092 }
Marco Polettifdbfcbe2014-08-31 08:57:47 +010093};
94
95template <typename C>
Marco Polettifdc79902017-05-21 13:27:57 +010096struct GetFirstStage<std::shared_ptr<C>> {
Marco Poletti3d3b7172015-02-15 12:13:51 +000097 // This method is covered by tests, even though lcov doesn't detect that.
Marco Polettifdc79902017-05-21 13:27:57 +010098 C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
99 return injector.getPtr<C>(node_itr);
Marco Polettib1d265c2014-10-19 21:24:11 -0700100 }
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100101};
102
Marco Poletti9250dea2014-11-09 09:10:53 +0000103template <typename C>
Marco Polettifdc79902017-05-21 13:27:57 +0100104struct GetFirstStage<C*> {
105 C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
106 return injector.getPtr<C>(node_itr);
107 }
108};
109
110template <typename C>
111struct GetFirstStage<const C*> {
112 C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
113 return injector.getPtr<C>(node_itr);
114 }
115};
116
117template <typename C>
118struct GetFirstStage<C&> {
119 C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
120 return injector.getPtr<C>(node_itr);
121 }
122};
123
124template <typename C>
125struct GetFirstStage<const C&> {
126 // This method is covered by tests, even though lcov doesn't detect that.
127 C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
128 return injector.getPtr<C>(node_itr);
129 }
130};
131
132template <typename C>
133struct GetFirstStage<Provider<C>> {
Marco Poletti9491d652014-11-24 15:47:14 +0000134 Provider<C> operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
135 return Provider<C>(&injector, node_itr);
Marco Polettib1d265c2014-10-19 21:24:11 -0700136 }
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100137};
138
Marco Poletti4fe2e722015-05-31 15:47:33 +0100139template <typename Annotation, typename T>
Marco Polettifdc79902017-05-21 13:27:57 +0100140struct GetFirstStage<fruit::Annotated<Annotation, T>> : public GetFirstStage<T> {
141};
142
143template <typename AnnotatedT>
144struct GetSecondStage;
145
146// General case, value.
147template <typename C>
148struct GetSecondStage {
149 C operator()(C* p) {
150 return *p;
151 }
152};
153
154template <typename C>
155struct GetSecondStage<const C> {
156 const C operator()(C* p) {
157 return *p;
158 }
159};
160
161template <typename C>
162struct GetSecondStage<std::shared_ptr<C>> {
163 // This method is covered by tests, even though lcov doesn't detect that.
164 std::shared_ptr<C> operator()(C* p) {
165 return std::shared_ptr<C>(std::shared_ptr<char>(), p);
166 }
167};
168
169template <typename C>
170struct GetSecondStage<C*> {
171 C* operator()(C* p) {
172 return p;
173 }
174};
175
176template <typename C>
177struct GetSecondStage<const C*> {
178 // This method is covered by tests, even though lcov doesn't detect that.
179 const C* operator()(C* p) {
180 return p;
181 }
182};
183
184template <typename C>
185struct GetSecondStage<C&> {
186 C& operator()(C* p) {
187 return *p;
188 }
189};
190
191template <typename C>
192struct GetSecondStage<const C&> {
193 const C& operator()(C* p) {
194 return *p;
195 }
196};
197
198template <typename C>
199struct GetSecondStage<Provider<C>> {
200 Provider<C> operator()(Provider<C> p) {
201 return p;
202 }
203};
204
205template <typename Annotation, typename T>
206struct GetSecondStage<fruit::Annotated<Annotation, T>> : public GetSecondStage<T> {
Marco Poletticc97a162015-05-10 12:10:12 +0100207};
208
209template <typename AnnotatedT>
Marco Poletti3b95a512015-07-11 13:43:39 +0100210inline InjectorStorage::RemoveAnnotations<AnnotatedT> InjectorStorage::get() {
Marco Polettifdc79902017-05-21 13:27:57 +0100211 return GetSecondStage<AnnotatedT>()(GetFirstStage<AnnotatedT>()(*this, lazyGetPtr<NormalizeType<AnnotatedT>>()));
Marco Poletti207597b2014-11-24 14:46:35 +0000212}
213
Marco Poletti31f638a2015-05-10 21:21:25 +0100214template <typename T>
215inline T InjectorStorage::get(InjectorStorage::Graph::node_iterator node_iterator) {
Marco Poletti010daa62015-07-06 01:15:12 +0100216 FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<T>, fruit::impl::meta::RemoveAnnotations(fruit::impl::meta::Type<T>)));
Marco Polettifdc79902017-05-21 13:27:57 +0100217 return GetSecondStage<T>()(GetFirstStage<T>()(*this, node_iterator));
Marco Poletti207597b2014-11-24 14:46:35 +0000218}
219
Marco Poletticc97a162015-05-10 12:10:12 +0100220template <typename AnnotatedC>
Marco Poletti934689f2014-11-16 14:28:16 +0000221inline InjectorStorage::Graph::node_iterator InjectorStorage::lazyGetPtr() {
Marco Poletticc97a162015-05-10 12:10:12 +0100222 return lazyGetPtr(getTypeId<AnnotatedC>());
Marco Poletti934689f2014-11-16 14:28:16 +0000223}
224
Marco Poletticc97a162015-05-10 12:10:12 +0100225template <typename AnnotatedC>
Marco Poletti80c7bb42015-02-28 16:42:43 +0000226inline InjectorStorage::Graph::node_iterator InjectorStorage::lazyGetPtr(Graph::edge_iterator deps, std::size_t dep_index, Graph::node_iterator bindings_begin) {
227 Graph::node_iterator itr = deps.getNodeIterator(dep_index, bindings_begin);
Marco Poletti31335f82016-05-22 18:36:23 +0100228 FruitAssert(bindings.find(getTypeId<AnnotatedC>()) == itr);
229 FruitAssert(!(bindings.end() == itr));
Marco Poletti934689f2014-11-16 14:28:16 +0000230 return itr;
231}
232
Marco Polettie4647132015-05-31 14:35:27 +0100233template <typename C>
234inline C* InjectorStorage::getPtr(Graph::node_iterator itr) {
Marco Poletti010daa62015-07-06 01:15:12 +0100235 FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<C>, fruit::impl::meta::NormalizeType(fruit::impl::meta::Type<C>)));
Marco Polettibfcb7ed2015-02-28 18:55:16 +0000236 void* p = getPtrInternal(itr);
Marco Polettib1d265c2014-10-19 21:24:11 -0700237 return reinterpret_cast<C*>(p);
238}
239
Marco Poletticc97a162015-05-10 12:10:12 +0100240template <typename AnnotatedC>
Marco Poletti3b95a512015-07-11 13:43:39 +0100241inline InjectorStorage::RemoveAnnotations<AnnotatedC>* InjectorStorage::unsafeGet() {
Marco Poletti3b95a512015-07-11 13:43:39 +0100242 using C = RemoveAnnotations<AnnotatedC>;
Marco Poletticc97a162015-05-10 12:10:12 +0100243 void* p = unsafeGetPtr(getTypeId<AnnotatedC>());
Marco Poletti1576a732014-10-18 12:35:17 -0700244 return reinterpret_cast<C*>(p);
245}
246
Marco Poletti9491d652014-11-24 15:47:14 +0000247inline InjectorStorage::Graph::node_iterator InjectorStorage::lazyGetPtr(TypeId type) {
248 return bindings.at(type);
Marco Poletti934689f2014-11-16 14:28:16 +0000249}
250
Marco Poletti9491d652014-11-24 15:47:14 +0000251inline void* InjectorStorage::unsafeGetPtr(TypeId type) {
252 Graph::node_iterator itr = bindings.find(type);
Marco Poletti85aea002014-11-24 13:15:27 +0000253 if (itr == bindings.end()) {
Marco Poletti1576a732014-10-18 12:35:17 -0700254 return nullptr;
255 }
Marco Polettibfcb7ed2015-02-28 18:55:16 +0000256 return getPtrInternal(itr);
Marco Poletti1576a732014-10-18 12:35:17 -0700257}
258
Marco Poletticc97a162015-05-10 12:10:12 +0100259template <typename AnnotatedC>
Marco Poletti3b95a512015-07-11 13:43:39 +0100260inline const std::vector<InjectorStorage::RemoveAnnotations<AnnotatedC>*>& InjectorStorage::getMultibindings() {
Marco Poletti3b95a512015-07-11 13:43:39 +0100261 using C = RemoveAnnotations<AnnotatedC>;
Marco Poletticc97a162015-05-10 12:10:12 +0100262 void* p = getMultibindings(getTypeId<AnnotatedC>());
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100263 if (p == nullptr) {
Marco Poletti1fd26492014-09-28 12:31:13 +0100264 static std::vector<C*> empty_vector;
265 return empty_vector;
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100266 } else {
Marco Poletti1fd26492014-09-28 12:31:13 +0100267 return *reinterpret_cast<std::vector<C*>*>(p);
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100268 }
269}
270
Marco Polettibfcb7ed2015-02-28 18:55:16 +0000271inline void* InjectorStorage::getPtrInternal(Graph::node_iterator node_itr) {
Marco Poletti9491d652014-11-24 15:47:14 +0000272 NormalizedBindingData& bindingData = node_itr.getNode();
273 if (!node_itr.isTerminal()) {
Marco Poletti0fbf7742015-02-28 17:48:54 +0000274 bindingData.create(*this, node_itr);
Marco Poletti31335f82016-05-22 18:36:23 +0100275 FruitAssert(node_itr.isTerminal());
Marco Poletti21802c62014-10-12 15:55:59 +0100276 }
Marco Polettic4fbcb12015-02-28 17:57:04 +0000277 return bindingData.getObject();
Marco Poletti21802c62014-10-12 15:55:59 +0100278}
Marco Polettic4fbcb12015-02-28 17:57:04 +0000279
Marco Poletti9491d652014-11-24 15:47:14 +0000280inline NormalizedMultibindingData* InjectorStorage::getNormalizedMultibindingData(TypeId type) {
281 auto itr = multibindings.find(type);
Marco Poletti85aea002014-11-24 13:15:27 +0000282 if (itr != multibindings.end())
Marco Poletti71c36de2014-11-01 10:51:07 +0000283 return &(itr->second);
284 else
285 return nullptr;
286}
287
Marco Poletticc97a162015-05-10 12:10:12 +0100288template <typename AnnotatedC>
Marco Poletti6c130032014-11-24 15:09:05 +0000289inline std::shared_ptr<char> InjectorStorage::createMultibindingVector(InjectorStorage& storage) {
Marco Poletti3b95a512015-07-11 13:43:39 +0100290 using C = RemoveAnnotations<AnnotatedC>;
Marco Poletticc97a162015-05-10 12:10:12 +0100291 TypeId type = getTypeId<AnnotatedC>();
Marco Poletti9491d652014-11-24 15:47:14 +0000292 NormalizedMultibindingData* multibinding = storage.getNormalizedMultibindingData(type);
Marco Poletti224bd9c2014-11-24 12:34:51 +0000293
294 // This method is only called if there was at least 1 multibinding (otherwise the would-be caller would have returned nullptr
295 // instead of calling this).
Marco Poletti31335f82016-05-22 18:36:23 +0100296 FruitAssert(multibinding != nullptr);
Marco Poletti224bd9c2014-11-24 12:34:51 +0000297
Marco Poletti9491d652014-11-24 15:47:14 +0000298 if (multibinding->v.get() != nullptr) {
Marco Poletti224bd9c2014-11-24 12:34:51 +0000299 // Result cached, return early.
Marco Poletti9491d652014-11-24 15:47:14 +0000300 return multibinding->v;
Marco Poletti224bd9c2014-11-24 12:34:51 +0000301 }
302
Marco Poletti9491d652014-11-24 15:47:14 +0000303 storage.ensureConstructedMultibinding(*multibinding);
Marco Poletti224bd9c2014-11-24 12:34:51 +0000304
305 std::vector<C*> s;
Marco Poletti9491d652014-11-24 15:47:14 +0000306 s.reserve(multibinding->elems.size());
307 for (const NormalizedMultibindingData::Elem& elem : multibinding->elems) {
Marco Poletti224bd9c2014-11-24 12:34:51 +0000308 s.push_back(reinterpret_cast<C*>(elem.object));
309 }
310
Marco Poletti9491d652014-11-24 15:47:14 +0000311 std::shared_ptr<std::vector<C*>> vector_ptr = std::make_shared<std::vector<C*>>(std::move(s));
312 std::shared_ptr<char> result(vector_ptr, reinterpret_cast<char*>(vector_ptr.get()));
Marco Poletti224bd9c2014-11-24 12:34:51 +0000313
Marco Poletti9491d652014-11-24 15:47:14 +0000314 multibinding->v = result;
Marco Poletti224bd9c2014-11-24 12:34:51 +0000315
316 return result;
317}
318
Marco Polettid1b46ee2017-05-20 13:06:21 +0100319template <typename I, typename C, typename AnnotatedC>
320BindingData::object_t InjectorStorage::createInjectedObjectForBind(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) {
321 InjectorStorage::Graph::node_iterator bindings_begin = injector.bindings.begin();
322 C* cPtr = injector.get<C*>(injector.lazyGetPtr<AnnotatedC>(node_itr.neighborsBegin(), 0, bindings_begin));
323 node_itr.setTerminal();
324 // This step is needed when the cast C->I changes the pointer
325 // (e.g. for multiple inheritance).
326 I* iPtr = static_cast<I*>(cPtr);
327 return reinterpret_cast<BindingData::object_t>(iPtr);
328}
329
Marco Poletti224bd9c2014-11-24 12:34:51 +0000330// I, C must not be pointers.
Marco Poletticc97a162015-05-10 12:10:12 +0100331template <typename AnnotatedI, typename AnnotatedC>
Marco Poletti224bd9c2014-11-24 12:34:51 +0000332inline std::tuple<TypeId, BindingData> InjectorStorage::createBindingDataForBind() {
Marco Poletti3b95a512015-07-11 13:43:39 +0100333 using I = RemoveAnnotations<AnnotatedI>;
334 using C = RemoveAnnotations<AnnotatedC>;
Marco Poletti79b01d62016-03-25 12:25:30 +0000335 FruitStaticAssert(fruit::impl::meta::Not(fruit::impl::meta::IsPointer(fruit::impl::meta::Type<I>)));
336 FruitStaticAssert(fruit::impl::meta::Not(fruit::impl::meta::IsPointer(fruit::impl::meta::Type<C>)));
Marco Polettid1b46ee2017-05-20 13:06:21 +0100337 return std::make_tuple(getTypeId<AnnotatedI>(),
338 BindingData(createInjectedObjectForBind<I, C, AnnotatedC>,
339 getBindingDeps<fruit::impl::meta::Vector<fruit::impl::meta::Type<AnnotatedC>>>(),
340 false /* needs_allocation */));
Marco Poletti224bd9c2014-11-24 12:34:51 +0000341}
342
Marco Poletticc97a162015-05-10 12:10:12 +0100343template <typename AnnotatedC, typename C>
Marco Poletti224bd9c2014-11-24 12:34:51 +0000344inline std::tuple<TypeId, BindingData> InjectorStorage::createBindingDataForBindInstance(C& instance) {
Marco Poletticc97a162015-05-10 12:10:12 +0100345 return std::make_tuple(getTypeId<AnnotatedC>(), BindingData(&instance));
Marco Poletti224bd9c2014-11-24 12:34:51 +0000346}
347
Marco Poletticc97a162015-05-10 12:10:12 +0100348// The inner operator() takes an InjectorStorage& and a Graph::edge_iterator (the type's deps) and
349// returns the injected object as a C*.
350// This takes care of move-constructing a C into the injector's own allocator if needed.
351template <typename AnnotatedSignature,
352 typename Lambda,
353 bool lambda_returns_pointer,
Marco Poletti79b01d62016-03-25 12:25:30 +0000354 typename AnnotatedT = InjectorStorage::SignatureType<AnnotatedSignature>,
Marco Poletti3b95a512015-07-11 13:43:39 +0100355 typename AnnotatedArgVector = fruit::impl::meta::Eval<fruit::impl::meta::SignatureArgs(fruit::impl::meta::Type<AnnotatedSignature>)>,
Marco Poletti36253c92015-07-19 17:12:47 +0100356 typename Indexes = fruit::impl::meta::Eval<
357 fruit::impl::meta::GenerateIntSequence(fruit::impl::meta::VectorSize(
358 fruit::impl::meta::SignatureArgs(fruit::impl::meta::Type<AnnotatedSignature>)))
359 >>
Marco Poletticc97a162015-05-10 12:10:12 +0100360struct InvokeLambdaWithInjectedArgVector;
361
362// AnnotatedT is of the form C* or Annotated<Annotation, C*>
Marco Poletti905dc092017-03-12 15:54:31 +0000363template <typename AnnotatedSignature, typename Lambda, typename AnnotatedT, typename... AnnotatedArgs, typename... Indexes>
364struct InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, true /* lambda_returns_pointer */, AnnotatedT, fruit::impl::meta::Vector<AnnotatedArgs...>, fruit::impl::meta::Vector<Indexes...>> {
Marco Poletti3b95a512015-07-11 13:43:39 +0100365 using CPtr = InjectorStorage::RemoveAnnotations<AnnotatedT>;
Marco Poletti79b01d62016-03-25 12:25:30 +0000366 using AnnotatedC = InjectorStorage::NormalizeType<AnnotatedT>;
Marco Poletticc97a162015-05-10 12:10:12 +0100367
Marco Polettidfcdced2017-05-20 15:24:14 +0100368 FRUIT_ALWAYS_INLINE
Marco Poletticc97a162015-05-10 12:10:12 +0100369 CPtr operator()(InjectorStorage& injector, FixedSizeAllocator& allocator) {
Marco Poletti905dc092017-03-12 15:54:31 +0000370 // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
371 (void)injector;
372 CPtr cPtr = LambdaInvoker::invoke<Lambda, InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>...>(
Marco Poletti79b01d62016-03-25 12:25:30 +0000373 injector.get<fruit::impl::meta::UnwrapType<AnnotatedArgs>>()...);
Marco Poletticc97a162015-05-10 12:10:12 +0100374 allocator.registerExternallyAllocatedObject(cPtr);
375
376 // This can happen if the user-supplied provider returns nullptr.
377 if (cPtr == nullptr) {
378 InjectorStorage::fatal("attempting to get an instance for the type " + std::string(getTypeId<AnnotatedC>()) + " but the provider returned nullptr");
379 }
380
381 return cPtr;
382 }
Marco Polettifdc79902017-05-21 13:27:57 +0100383
384 // This is not inlined in outerConstructHelper so that when get<> needs to construct an object more complex than a pointer
385 // (e.g. a shared_ptr), that happens as late as possible so that it's easier for the optimizer to optimize out some
386 // operations (e.g. the increment/decrement/check of shared_ptr's reference count).
387 template <typename... GetFirstStageResults>
388 FRUIT_ALWAYS_INLINE
389 CPtr innerConstructHelper(InjectorStorage& injector, GetFirstStageResults... getFirstStageResults) {
390 // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
391 (void)injector;
392 return LambdaInvoker::invoke<Lambda, InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>...>(
393 GetSecondStage<InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>()(getFirstStageResults)
394 ...);
395 }
396
Marco Poletti8223fe52016-08-29 19:44:52 +0100397 // This is not inlined in operator() so that all the lazyGetPtr() calls happen first (instead of being interleaved
398 // with the get() calls). The lazyGetPtr() calls don't branch, while the get() calls branch on the result of the
399 // lazyGetPtr()s, so it's faster to execute them in this order.
400 template <typename... NodeItrs>
Marco Polettidfcdced2017-05-20 15:24:14 +0100401 FRUIT_ALWAYS_INLINE
Marco Polettifdc79902017-05-21 13:27:57 +0100402 CPtr outerConstructHelper(InjectorStorage& injector, NodeItrs... nodeItrs) {
Marco Poletti905dc092017-03-12 15:54:31 +0000403 // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
404 (void)injector;
Marco Polettifdc79902017-05-21 13:27:57 +0100405 return innerConstructHelper(injector,
406 GetFirstStage<InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>()(injector, nodeItrs)
Marco Poletti8223fe52016-08-29 19:44:52 +0100407 ...);
408 }
409
Marco Polettidfcdced2017-05-20 15:24:14 +0100410 FRUIT_ALWAYS_INLINE
Marco Poletti21972972015-05-31 15:56:20 +0100411 CPtr operator()(InjectorStorage& injector, SemistaticGraph<TypeId, NormalizedBindingData>& bindings,
412 FixedSizeAllocator& allocator, InjectorStorage::Graph::edge_iterator deps) {
Marco Poletticc97a162015-05-10 12:10:12 +0100413 // `deps' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
414 (void)deps;
415
Marco Poletti21972972015-05-31 15:56:20 +0100416 InjectorStorage::Graph::node_iterator bindings_begin = bindings.begin();
Marco Poletticc97a162015-05-10 12:10:12 +0100417 // `bindings_begin' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
418 (void) bindings_begin;
Marco Polettifdc79902017-05-21 13:27:57 +0100419 CPtr cPtr = outerConstructHelper(injector,
Marco Poletti905dc092017-03-12 15:54:31 +0000420 injector.lazyGetPtr<InjectorStorage::NormalizeType<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>(deps, Indexes::value, bindings_begin)
Marco Poletti31f638a2015-05-10 21:21:25 +0100421 ...);
Marco Poletticc97a162015-05-10 12:10:12 +0100422 allocator.registerExternallyAllocatedObject(cPtr);
423
424 // This can happen if the user-supplied provider returns nullptr.
425 if (cPtr == nullptr) {
426 InjectorStorage::fatal("attempting to get an instance for the type " + std::string(getTypeId<AnnotatedC>()) + " but the provider returned nullptr");
427 }
428
429 return cPtr;
430 }
431};
432
Marco Poletti905dc092017-03-12 15:54:31 +0000433template <typename AnnotatedSignature, typename Lambda, typename AnnotatedC, typename... AnnotatedArgs, typename... Indexes>
434struct InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, false /* lambda_returns_pointer */, AnnotatedC, fruit::impl::meta::Vector<AnnotatedArgs...>, fruit::impl::meta::Vector<Indexes...>> {
Marco Poletti3b95a512015-07-11 13:43:39 +0100435 using C = InjectorStorage::RemoveAnnotations<AnnotatedC>;
Marco Poletticc97a162015-05-10 12:10:12 +0100436
Marco Polettidfcdced2017-05-20 15:24:14 +0100437 FRUIT_ALWAYS_INLINE
Marco Poletticc97a162015-05-10 12:10:12 +0100438 C* operator()(InjectorStorage& injector, FixedSizeAllocator& allocator) {
Marco Poletti905dc092017-03-12 15:54:31 +0000439 // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
440 (void)injector;
441 return allocator.constructObject<AnnotatedC, C&&>(
Marco Poletti9198ba02017-05-20 11:58:34 +0100442 LambdaInvoker::invoke<Lambda, InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>&&...>(
Marco Poletti79b01d62016-03-25 12:25:30 +0000443 injector.get<fruit::impl::meta::UnwrapType<AnnotatedArgs>>()...));
Marco Poletticc97a162015-05-10 12:10:12 +0100444 }
Marco Polettifdc79902017-05-21 13:27:57 +0100445
446 // This is not inlined in outerConstructHelper so that when get<> needs to construct an object more complex than a pointer
447 // (e.g. a shared_ptr), that happens as late as possible so that it's easier for the optimizer to optimize out some
448 // operations (e.g. the increment/decrement/check of shared_ptr's reference count).
449 template <typename... GetFirstStageResults>
450 FRUIT_ALWAYS_INLINE
451 C* innerConstructHelper(InjectorStorage& injector, FixedSizeAllocator& allocator, GetFirstStageResults... getFirstStageResults) {
452 // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
453 (void)injector;
454 return allocator.constructObject<AnnotatedC, C&&>(LambdaInvoker::invoke<Lambda, InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>...>(
455 GetSecondStage<InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>()(getFirstStageResults)
456 ...));
457 }
458
Marco Poletti8223fe52016-08-29 19:44:52 +0100459 // This is not inlined in operator() so that all the lazyGetPtr() calls happen first (instead of being interleaved
460 // with the get() calls). The lazyGetPtr() calls don't branch, while the get() calls branch on the result of the
461 // lazyGetPtr()s, so it's faster to execute them in this order.
462 template <typename... NodeItrs>
Marco Polettidfcdced2017-05-20 15:24:14 +0100463 FRUIT_ALWAYS_INLINE
Marco Polettifdc79902017-05-21 13:27:57 +0100464 C* outerConstructHelper(InjectorStorage& injector, FixedSizeAllocator& allocator, NodeItrs... nodeItrs) {
Marco Poletti905dc092017-03-12 15:54:31 +0000465 // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
466 (void)injector;
Marco Polettifdc79902017-05-21 13:27:57 +0100467 return innerConstructHelper(injector, allocator,
468 GetFirstStage<InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>()(injector, nodeItrs)
469 ...);
Marco Poletti8223fe52016-08-29 19:44:52 +0100470 }
471
Marco Poletti21972972015-05-31 15:56:20 +0100472 C* operator()(InjectorStorage& injector, SemistaticGraph<TypeId, NormalizedBindingData>& bindings,
473 FixedSizeAllocator& allocator, InjectorStorage::Graph::edge_iterator deps) {
Marco Poletti21972972015-05-31 15:56:20 +0100474 InjectorStorage::Graph::node_iterator bindings_begin = bindings.begin();
Marco Poletticc97a162015-05-10 12:10:12 +0100475 // `bindings_begin' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
476 (void) bindings_begin;
477
478 // `deps' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
479 (void)deps;
480
Marco Poletti905dc092017-03-12 15:54:31 +0000481 // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
482 (void)injector;
Marco Polettifdc79902017-05-21 13:27:57 +0100483 C* p = outerConstructHelper(injector, allocator,
Marco Poletti905dc092017-03-12 15:54:31 +0000484 injector.lazyGetPtr<InjectorStorage::NormalizeType<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>(deps, Indexes::value, bindings_begin)
Marco Poletti8223fe52016-08-29 19:44:52 +0100485 ...);
Marco Poletticc97a162015-05-10 12:10:12 +0100486 return p;
487 }
488};
489
Marco Polettid1b46ee2017-05-20 13:06:21 +0100490
491template <typename C, typename T, typename AnnotatedSignature, typename Lambda>
492BindingData::object_t InjectorStorage::createInjectedObjectForProvider(InjectorStorage& injector, Graph::node_iterator node_itr) {
493 C* cPtr = InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, std::is_pointer<T>::value>()(
494 injector, injector.bindings, injector.allocator, node_itr.neighborsBegin());
495 node_itr.setTerminal();
496 return reinterpret_cast<BindingData::object_t>(cPtr);
497}
498
Marco Poletticc97a162015-05-10 12:10:12 +0100499template <typename AnnotatedSignature, typename Lambda>
Marco Poletti224bd9c2014-11-24 12:34:51 +0000500inline std::tuple<TypeId, BindingData> InjectorStorage::createBindingDataForProvider() {
Marco Poletti16810cb2015-05-31 15:33:39 +0100501#ifdef FRUIT_EXTRA_DEBUG
Marco Poletti79b01d62016-03-25 12:25:30 +0000502 using Signature = fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<fruit::impl::meta::RemoveAnnotationsFromSignature(fruit::impl::meta::Type<AnnotatedSignature>)>>;
503 FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<Signature>, fruit::impl::meta::FunctionSignature(fruit::impl::meta::Type<Lambda>)));
Marco Poletti16810cb2015-05-31 15:33:39 +0100504#endif
Marco Poletti79b01d62016-03-25 12:25:30 +0000505 using AnnotatedT = SignatureType<AnnotatedSignature>;
506 using AnnotatedC = NormalizeType<AnnotatedT>;
Marco Poletticc97a162015-05-10 12:10:12 +0100507 // T is either C or C*.
Marco Poletti3b95a512015-07-11 13:43:39 +0100508 using T = RemoveAnnotations<AnnotatedT>;
Marco Poletti79b01d62016-03-25 12:25:30 +0000509 using C = NormalizeType<T>;
Marco Poletti79b01d62016-03-25 12:25:30 +0000510 const BindingDeps* deps = getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>();
Marco Poletticc97a162015-05-10 12:10:12 +0100511 bool needs_allocation = !std::is_pointer<T>::value;
Marco Polettid1b46ee2017-05-20 13:06:21 +0100512 return std::make_tuple(getTypeId<AnnotatedC>(),
513 BindingData(createInjectedObjectForProvider<C, T, AnnotatedSignature, Lambda>,
514 deps,
515 needs_allocation));
516}
517
518template <typename I, typename C, typename T, typename AnnotatedSignature, typename Lambda>
519BindingData::object_t InjectorStorage::createInjectedObjectForCompressedProvider(InjectorStorage& injector, Graph::node_iterator node_itr) {
520 C* cPtr = InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, std::is_pointer<T>::value>()(
521 injector, injector.bindings, injector.allocator, node_itr.neighborsBegin());
522 node_itr.setTerminal();
523 I* iPtr = static_cast<I*>(cPtr);
524 return reinterpret_cast<BindingData::object_t>(iPtr);
Marco Poletti224bd9c2014-11-24 12:34:51 +0000525}
526
Marco Poletticc97a162015-05-10 12:10:12 +0100527template <typename AnnotatedSignature, typename Lambda, typename AnnotatedI>
Marco Poletti224bd9c2014-11-24 12:34:51 +0000528inline std::tuple<TypeId, TypeId, BindingData> InjectorStorage::createBindingDataForCompressedProvider() {
Marco Poletti16810cb2015-05-31 15:33:39 +0100529#ifdef FRUIT_EXTRA_DEBUG
Marco Poletti79b01d62016-03-25 12:25:30 +0000530 using Signature = fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<fruit::impl::meta::RemoveAnnotationsFromSignature(fruit::impl::meta::Type<AnnotatedSignature>)>>;
531 FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<Signature>, fruit::impl::meta::FunctionSignature(fruit::impl::meta::Type<Lambda>)));
Marco Poletti16810cb2015-05-31 15:33:39 +0100532#endif
Marco Poletti79b01d62016-03-25 12:25:30 +0000533 using AnnotatedT = SignatureType<AnnotatedSignature>;
534 using AnnotatedC = NormalizeType<AnnotatedT>;
Marco Poletticc97a162015-05-10 12:10:12 +0100535 // T is either C or C*.
Marco Poletti3b95a512015-07-11 13:43:39 +0100536 using T = RemoveAnnotations<AnnotatedT>;
Marco Poletti79b01d62016-03-25 12:25:30 +0000537 using C = NormalizeType<T>;
Marco Poletti3b95a512015-07-11 13:43:39 +0100538 using I = RemoveAnnotations<AnnotatedI>;
Marco Poletti79b01d62016-03-25 12:25:30 +0000539 const BindingDeps* deps = getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>();
Marco Poletticc97a162015-05-10 12:10:12 +0100540 bool needs_allocation = !std::is_pointer<T>::value;
Marco Polettid1b46ee2017-05-20 13:06:21 +0100541 return std::make_tuple(getTypeId<AnnotatedI>(),
542 getTypeId<AnnotatedC>(),
543 BindingData(createInjectedObjectForCompressedProvider<I, C, T, AnnotatedSignature, Lambda>,
544 deps,
545 needs_allocation));
Marco Poletti224bd9c2014-11-24 12:34:51 +0000546}
547
Marco Poletticc97a162015-05-10 12:10:12 +0100548// The inner operator() takes an InjectorStorage& and a Graph::edge_iterator (the type's deps) and
549// returns the injected object as a C*.
550// This takes care of allocating the required space into the injector's allocator.
551template <typename AnnotatedSignature,
Marco Poletti36253c92015-07-19 17:12:47 +0100552 typename Indexes = fruit::impl::meta::Eval<
553 fruit::impl::meta::GenerateIntSequence(fruit::impl::meta::VectorSize(
554 fruit::impl::meta::SignatureArgs(fruit::impl::meta::Type<AnnotatedSignature>)))
555 >>
Marco Poletticc97a162015-05-10 12:10:12 +0100556struct InvokeConstructorWithInjectedArgVector;
557
Marco Poletti905dc092017-03-12 15:54:31 +0000558template <typename AnnotatedC, typename... AnnotatedArgs, typename... Indexes>
559struct InvokeConstructorWithInjectedArgVector<AnnotatedC(AnnotatedArgs...), fruit::impl::meta::Vector<Indexes...>> {
Marco Poletti3b95a512015-07-11 13:43:39 +0100560 using C = InjectorStorage::RemoveAnnotations<AnnotatedC>;
Marco Poletti8223fe52016-08-29 19:44:52 +0100561
Marco Polettifdc79902017-05-21 13:27:57 +0100562 // This is not inlined in outerConstructHelper so that when get<> needs to construct an object more complex than a pointer
563 // (e.g. a shared_ptr), that happens as late as possible so that it's easier for the optimizer to optimize out some
564 // operations (e.g. the increment/decrement/check of shared_ptr's reference count).
565 template <typename... GetFirstStageResults>
566 FRUIT_ALWAYS_INLINE
567 C* innerConstructHelper(InjectorStorage& injector, FixedSizeAllocator& allocator, GetFirstStageResults... getFirstStageResults) {
568 // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
569 (void)injector;
570 return allocator.constructObject<AnnotatedC, InjectorStorage::RemoveAnnotations<AnnotatedArgs>&&...>(
571 GetSecondStage<InjectorStorage::RemoveAnnotations<AnnotatedArgs>>()(getFirstStageResults)
572 ...);
573 }
574
Marco Poletti8223fe52016-08-29 19:44:52 +0100575 // This is not inlined in operator() so that all the lazyGetPtr() calls happen first (instead of being interleaved
576 // with the get() calls). The lazyGetPtr() calls don't branch, while the get() calls branch on the result of the
577 // lazyGetPtr()s, so it's faster to execute them in this order.
578 template <typename... NodeItrs>
Marco Polettidfcdced2017-05-20 15:24:14 +0100579 FRUIT_ALWAYS_INLINE
Marco Polettifdc79902017-05-21 13:27:57 +0100580 C* outerConstructHelper(InjectorStorage& injector, FixedSizeAllocator& allocator, NodeItrs... nodeItrs) {
Marco Poletti905dc092017-03-12 15:54:31 +0000581 // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused.
582 (void)injector;
Marco Polettifdc79902017-05-21 13:27:57 +0100583 return innerConstructHelper(injector, allocator,
584 GetFirstStage<InjectorStorage::RemoveAnnotations<AnnotatedArgs>>()(injector, nodeItrs)
Marco Poletti8223fe52016-08-29 19:44:52 +0100585 ...);
586 }
587
Marco Polettidfcdced2017-05-20 15:24:14 +0100588 FRUIT_ALWAYS_INLINE
Marco Poletti21972972015-05-31 15:56:20 +0100589 C* operator()(InjectorStorage& injector, SemistaticGraph<TypeId, NormalizedBindingData>& bindings,
590 FixedSizeAllocator& allocator, InjectorStorage::Graph::edge_iterator deps) {
Marco Polettifdc79902017-05-21 13:27:57 +0100591
Marco Poletticc97a162015-05-10 12:10:12 +0100592 // `deps' *is* used below, but when there are no Args some compilers report it as unused.
593 (void)deps;
Marco Polettifdc79902017-05-21 13:27:57 +0100594
Marco Poletti21972972015-05-31 15:56:20 +0100595 InjectorStorage::Graph::node_iterator bindings_begin = bindings.begin();
Marco Poletticc97a162015-05-10 12:10:12 +0100596 // `bindings_begin' *is* used below, but when there are no Args some compilers report it as unused.
597 (void) bindings_begin;
Marco Polettifdc79902017-05-21 13:27:57 +0100598 C* p = outerConstructHelper(injector, allocator,
Marco Poletti905dc092017-03-12 15:54:31 +0000599 injector.lazyGetPtr<InjectorStorage::NormalizeType<AnnotatedArgs>>(deps, Indexes::value, bindings_begin)
Marco Poletti31f638a2015-05-10 21:21:25 +0100600 ...);
Marco Poletticc97a162015-05-10 12:10:12 +0100601 return p;
602 }
603};
604
Marco Polettid1b46ee2017-05-20 13:06:21 +0100605template <typename C, typename AnnotatedSignature>
606BindingData::object_t InjectorStorage::createInjectedObjectForConstructor(InjectorStorage& injector, Graph::node_iterator node_itr) {
607 C* cPtr = InvokeConstructorWithInjectedArgVector<AnnotatedSignature>()(injector,
608 injector.bindings, injector.allocator, node_itr.neighborsBegin());
609 node_itr.setTerminal();
610 return reinterpret_cast<BindingData::object_t>(cPtr);
611}
612
Marco Poletticc97a162015-05-10 12:10:12 +0100613template <typename AnnotatedSignature>
Marco Poletti224bd9c2014-11-24 12:34:51 +0000614inline std::tuple<TypeId, BindingData> InjectorStorage::createBindingDataForConstructor() {
Marco Poletti79b01d62016-03-25 12:25:30 +0000615 using AnnotatedC = SignatureType<AnnotatedSignature>;
616 using C = RemoveAnnotations<AnnotatedC>;
Marco Poletti79b01d62016-03-25 12:25:30 +0000617 const BindingDeps* deps = getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>();
Marco Polettid1b46ee2017-05-20 13:06:21 +0100618 return std::make_tuple(getTypeId<AnnotatedC>(),
619 BindingData(createInjectedObjectForConstructor<C, AnnotatedSignature>,
620 deps,
621 true /* needs_allocation */));
622}
623
624template <typename I, typename C, typename AnnotatedSignature>
625BindingData::object_t InjectorStorage::createInjectedObjectForCompressedConstructor(InjectorStorage& injector, Graph::node_iterator node_itr) {
626 C* cPtr = InvokeConstructorWithInjectedArgVector<AnnotatedSignature>()(injector,
627 injector.bindings, injector.allocator, node_itr.neighborsBegin());
628 node_itr.setTerminal();
629 I* iPtr = static_cast<I*>(cPtr);
630 return reinterpret_cast<BindingData::object_t>(iPtr);
Marco Poletti224bd9c2014-11-24 12:34:51 +0000631}
632
Marco Poletticc97a162015-05-10 12:10:12 +0100633template <typename AnnotatedSignature, typename AnnotatedI>
Marco Poletti224bd9c2014-11-24 12:34:51 +0000634inline std::tuple<TypeId, TypeId, BindingData> InjectorStorage::createBindingDataForCompressedConstructor() {
Marco Poletti79b01d62016-03-25 12:25:30 +0000635 using AnnotatedC = SignatureType<AnnotatedSignature>;
Marco Poletti3b95a512015-07-11 13:43:39 +0100636 using C = RemoveAnnotations<AnnotatedC>;
637 using I = RemoveAnnotations<AnnotatedI>;
Marco Poletti79b01d62016-03-25 12:25:30 +0000638 const BindingDeps* deps = getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>();
Marco Polettid1b46ee2017-05-20 13:06:21 +0100639 return std::make_tuple(getTypeId<AnnotatedI>(),
640 getTypeId<AnnotatedC>(),
641 BindingData(createInjectedObjectForCompressedConstructor<I, C, AnnotatedSignature>,
642 deps,
643 true /* needs_allocation */));
644}
645
646template <typename I, typename C, typename AnnotatedCPtr>
647MultibindingData::object_t InjectorStorage::createInjectedObjectForMultibinding(InjectorStorage& m) {
648 C* cPtr = m.get<AnnotatedCPtr>();
649 // This step is needed when the cast C->I changes the pointer
650 // (e.g. for multiple inheritance).
651 I* iPtr = static_cast<I*>(cPtr);
652 return reinterpret_cast<MultibindingData::object_t>(iPtr);
Marco Poletti224bd9c2014-11-24 12:34:51 +0000653}
654
Marco Poletticc97a162015-05-10 12:10:12 +0100655template <typename AnnotatedI, typename AnnotatedC>
Marco Poletti224bd9c2014-11-24 12:34:51 +0000656inline std::tuple<TypeId, MultibindingData> InjectorStorage::createMultibindingDataForBinding() {
Marco Poletti79b01d62016-03-25 12:25:30 +0000657 using AnnotatedCPtr = fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<fruit::impl::meta::AddPointerInAnnotatedType(fruit::impl::meta::Type<AnnotatedC>)>>;
Marco Poletti3b95a512015-07-11 13:43:39 +0100658 using I = RemoveAnnotations<AnnotatedI>;
659 using C = RemoveAnnotations<AnnotatedC>;
Marco Polettid1b46ee2017-05-20 13:06:21 +0100660 return std::make_tuple(getTypeId<AnnotatedI>(),
661 MultibindingData(createInjectedObjectForMultibinding<I, C, AnnotatedCPtr>,
662 getBindingDeps<fruit::impl::meta::Vector<fruit::impl::meta::Type<AnnotatedC>>>(), createMultibindingVector<AnnotatedI>,
663 false /* needs_allocation */));
Marco Poletti224bd9c2014-11-24 12:34:51 +0000664}
665
Marco Poletticc97a162015-05-10 12:10:12 +0100666template <typename AnnotatedC, typename C>
Marco Poletti224bd9c2014-11-24 12:34:51 +0000667inline std::tuple<TypeId, MultibindingData> InjectorStorage::createMultibindingDataForInstance(C& instance) {
Marco Poletticc97a162015-05-10 12:10:12 +0100668 return std::make_tuple(getTypeId<AnnotatedC>(), MultibindingData(&instance, createMultibindingVector<AnnotatedC>));
Marco Poletti224bd9c2014-11-24 12:34:51 +0000669}
670
Marco Polettid1b46ee2017-05-20 13:06:21 +0100671template <typename C, typename T, typename AnnotatedSignature, typename Lambda>
672BindingData::object_t InjectorStorage::createInjectedObjectForMultibindingProvider(InjectorStorage& injector) {
673 C* cPtr = InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, std::is_pointer<T>::value>()(
674 injector, injector.allocator);
675 return reinterpret_cast<BindingData::object_t>(cPtr);
676}
677
Marco Poletticc97a162015-05-10 12:10:12 +0100678template <typename AnnotatedSignature, typename Lambda>
Marco Poletti224bd9c2014-11-24 12:34:51 +0000679inline std::tuple<TypeId, MultibindingData> InjectorStorage::createMultibindingDataForProvider() {
Marco Poletti16810cb2015-05-31 15:33:39 +0100680#ifdef FRUIT_EXTRA_DEBUG
Marco Poletti79b01d62016-03-25 12:25:30 +0000681 using Signature = fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<fruit::impl::meta::RemoveAnnotationsFromSignature(fruit::impl::meta::Type<AnnotatedSignature>)>>;
682 FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<Signature>, fruit::impl::meta::FunctionSignature(fruit::impl::meta::Type<Lambda>)));
Marco Poletti16810cb2015-05-31 15:33:39 +0100683#endif
684
Marco Poletti79b01d62016-03-25 12:25:30 +0000685 using AnnotatedT = SignatureType<AnnotatedSignature>;
686 using AnnotatedC = NormalizeType<AnnotatedT>;
Marco Poletti3b95a512015-07-11 13:43:39 +0100687 using T = RemoveAnnotations<AnnotatedT>;
Marco Poletti79b01d62016-03-25 12:25:30 +0000688 using C = NormalizeType<T>;
Marco Poletticc97a162015-05-10 12:10:12 +0100689 bool needs_allocation = !std::is_pointer<T>::value;
690 return std::make_tuple(getTypeId<AnnotatedC>(),
Marco Polettid1b46ee2017-05-20 13:06:21 +0100691 MultibindingData(createInjectedObjectForMultibindingProvider<C, T, AnnotatedSignature, Lambda>,
692 getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>(),
693 InjectorStorage::createMultibindingVector<AnnotatedC>,
Marco Polettia85fc032014-12-26 20:00:38 +0100694 needs_allocation));
Marco Poletti224bd9c2014-11-24 12:34:51 +0000695}
696
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100697} // namespace fruit
698} // namespace impl
699
700
Marco Poletti7f35b652014-11-01 10:11:37 +0000701#endif // FRUIT_INJECTOR_STORAGE_DEFN_H