Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 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 | |
Marco Poletti | 7f35b65 | 2014-11-01 10:11:37 +0000 | [diff] [blame] | 17 | #ifndef FRUIT_INJECTOR_STORAGE_DEFN_H |
| 18 | #define FRUIT_INJECTOR_STORAGE_DEFN_H |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 19 | |
Marco Poletti | f289510 | 2016-01-30 13:38:37 +0000 | [diff] [blame] | 20 | #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 Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 26 | |
Marco Poletti | 633a389 | 2014-10-19 17:33:11 -0700 | [diff] [blame] | 27 | #include <cassert> |
| 28 | |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 29 | // Redundant, but makes KDevelop happy. |
Marco Poletti | f289510 | 2016-01-30 13:38:37 +0000 | [diff] [blame] | 30 | #include <fruit/impl/storage/injector_storage.h> |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 31 | |
| 32 | namespace fruit { |
| 33 | namespace impl { |
| 34 | |
Marco Poletti | 0bfbe05 | 2014-11-24 17:11:27 +0000 | [diff] [blame] | 35 | inline InjectorStorage::BindingDataNodeIter* InjectorStorage::BindingDataNodeIter::operator->() { |
| 36 | return this; |
| 37 | } |
| 38 | |
| 39 | inline void InjectorStorage::BindingDataNodeIter::operator++() { |
| 40 | ++itr; |
| 41 | } |
| 42 | |
| 43 | inline bool InjectorStorage::BindingDataNodeIter::operator==(const BindingDataNodeIter& other) const { |
| 44 | return itr == other.itr; |
| 45 | } |
| 46 | |
| 47 | inline bool InjectorStorage::BindingDataNodeIter::operator!=(const BindingDataNodeIter& other) const { |
| 48 | return itr != other.itr; |
| 49 | } |
| 50 | |
Marco Poletti | e99fdb7 | 2016-05-22 12:26:08 +0100 | [diff] [blame] | 51 | inline std::ptrdiff_t InjectorStorage::BindingDataNodeIter::operator-(BindingDataNodeIter other) const { |
| 52 | return itr - other.itr; |
| 53 | } |
| 54 | |
Marco Poletti | 0bfbe05 | 2014-11-24 17:11:27 +0000 | [diff] [blame] | 55 | inline TypeId InjectorStorage::BindingDataNodeIter::getId() { |
| 56 | return itr->first; |
| 57 | } |
| 58 | |
| 59 | inline NormalizedBindingData InjectorStorage::BindingDataNodeIter::getValue() { |
| 60 | return NormalizedBindingData(itr->second); |
| 61 | } |
| 62 | |
| 63 | inline bool InjectorStorage::BindingDataNodeIter::isTerminal() { |
| 64 | return itr->second.isCreated(); |
| 65 | } |
| 66 | |
| 67 | inline const TypeId* InjectorStorage::BindingDataNodeIter::getEdgesBegin() { |
| 68 | const BindingDeps* deps = itr->second.getDeps(); |
| 69 | return deps->deps; |
| 70 | } |
| 71 | |
| 72 | inline const TypeId* InjectorStorage::BindingDataNodeIter::getEdgesEnd() { |
| 73 | const BindingDeps* deps = itr->second.getDeps(); |
| 74 | return deps->deps + deps->num_deps; |
| 75 | } |
| 76 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 77 | template <typename AnnotatedT> |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 78 | struct GetFirstStage; |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 79 | |
| 80 | // General case, value. |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 81 | template <typename C> |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 82 | struct GetFirstStage { |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 83 | C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) { |
| 84 | return injector.getPtr<C>(node_itr); |
Marco Poletti | b1d265c | 2014-10-19 21:24:11 -0700 | [diff] [blame] | 85 | } |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 86 | }; |
| 87 | |
| 88 | template <typename C> |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 89 | struct GetFirstStage<const C> { |
| 90 | C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) { |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 91 | return injector.getPtr<C>(node_itr); |
Marco Poletti | b1d265c | 2014-10-19 21:24:11 -0700 | [diff] [blame] | 92 | } |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 93 | }; |
| 94 | |
| 95 | template <typename C> |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 96 | struct GetFirstStage<std::shared_ptr<C>> { |
Marco Poletti | 3d3b717 | 2015-02-15 12:13:51 +0000 | [diff] [blame] | 97 | // This method is covered by tests, even though lcov doesn't detect that. |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 98 | C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) { |
| 99 | return injector.getPtr<C>(node_itr); |
Marco Poletti | b1d265c | 2014-10-19 21:24:11 -0700 | [diff] [blame] | 100 | } |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 101 | }; |
| 102 | |
Marco Poletti | 9250dea | 2014-11-09 09:10:53 +0000 | [diff] [blame] | 103 | template <typename C> |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 104 | struct GetFirstStage<C*> { |
| 105 | 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 | 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<C&> { |
| 119 | C* operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) { |
| 120 | return injector.getPtr<C>(node_itr); |
| 121 | } |
| 122 | }; |
| 123 | |
| 124 | template <typename C> |
| 125 | struct 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 | |
| 132 | template <typename C> |
| 133 | struct GetFirstStage<Provider<C>> { |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 134 | Provider<C> operator()(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr) { |
| 135 | return Provider<C>(&injector, node_itr); |
Marco Poletti | b1d265c | 2014-10-19 21:24:11 -0700 | [diff] [blame] | 136 | } |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 137 | }; |
| 138 | |
Marco Poletti | 4fe2e72 | 2015-05-31 15:47:33 +0100 | [diff] [blame] | 139 | template <typename Annotation, typename T> |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 140 | struct GetFirstStage<fruit::Annotated<Annotation, T>> : public GetFirstStage<T> { |
| 141 | }; |
| 142 | |
| 143 | template <typename AnnotatedT> |
| 144 | struct GetSecondStage; |
| 145 | |
| 146 | // General case, value. |
| 147 | template <typename C> |
| 148 | struct GetSecondStage { |
| 149 | C operator()(C* p) { |
| 150 | return *p; |
| 151 | } |
| 152 | }; |
| 153 | |
| 154 | template <typename C> |
| 155 | struct GetSecondStage<const C> { |
| 156 | const C operator()(C* p) { |
| 157 | return *p; |
| 158 | } |
| 159 | }; |
| 160 | |
| 161 | template <typename C> |
| 162 | struct 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 | |
| 169 | template <typename C> |
| 170 | struct GetSecondStage<C*> { |
| 171 | C* operator()(C* p) { |
| 172 | return p; |
| 173 | } |
| 174 | }; |
| 175 | |
| 176 | template <typename C> |
| 177 | struct 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 | |
| 184 | template <typename C> |
| 185 | struct GetSecondStage<C&> { |
| 186 | C& operator()(C* p) { |
| 187 | return *p; |
| 188 | } |
| 189 | }; |
| 190 | |
| 191 | template <typename C> |
| 192 | struct GetSecondStage<const C&> { |
| 193 | const C& operator()(C* p) { |
| 194 | return *p; |
| 195 | } |
| 196 | }; |
| 197 | |
| 198 | template <typename C> |
| 199 | struct GetSecondStage<Provider<C>> { |
| 200 | Provider<C> operator()(Provider<C> p) { |
| 201 | return p; |
| 202 | } |
| 203 | }; |
| 204 | |
| 205 | template <typename Annotation, typename T> |
| 206 | struct GetSecondStage<fruit::Annotated<Annotation, T>> : public GetSecondStage<T> { |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 207 | }; |
| 208 | |
| 209 | template <typename AnnotatedT> |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 210 | inline InjectorStorage::RemoveAnnotations<AnnotatedT> InjectorStorage::get() { |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 211 | return GetSecondStage<AnnotatedT>()(GetFirstStage<AnnotatedT>()(*this, lazyGetPtr<NormalizeType<AnnotatedT>>())); |
Marco Poletti | 207597b | 2014-11-24 14:46:35 +0000 | [diff] [blame] | 212 | } |
| 213 | |
Marco Poletti | 31f638a | 2015-05-10 21:21:25 +0100 | [diff] [blame] | 214 | template <typename T> |
| 215 | inline T InjectorStorage::get(InjectorStorage::Graph::node_iterator node_iterator) { |
Marco Poletti | 010daa6 | 2015-07-06 01:15:12 +0100 | [diff] [blame] | 216 | FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<T>, fruit::impl::meta::RemoveAnnotations(fruit::impl::meta::Type<T>))); |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 217 | return GetSecondStage<T>()(GetFirstStage<T>()(*this, node_iterator)); |
Marco Poletti | 207597b | 2014-11-24 14:46:35 +0000 | [diff] [blame] | 218 | } |
| 219 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 220 | template <typename AnnotatedC> |
Marco Poletti | 934689f | 2014-11-16 14:28:16 +0000 | [diff] [blame] | 221 | inline InjectorStorage::Graph::node_iterator InjectorStorage::lazyGetPtr() { |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 222 | return lazyGetPtr(getTypeId<AnnotatedC>()); |
Marco Poletti | 934689f | 2014-11-16 14:28:16 +0000 | [diff] [blame] | 223 | } |
| 224 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 225 | template <typename AnnotatedC> |
Marco Poletti | 80c7bb4 | 2015-02-28 16:42:43 +0000 | [diff] [blame] | 226 | inline 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 Poletti | 31335f8 | 2016-05-22 18:36:23 +0100 | [diff] [blame] | 228 | FruitAssert(bindings.find(getTypeId<AnnotatedC>()) == itr); |
| 229 | FruitAssert(!(bindings.end() == itr)); |
Marco Poletti | 934689f | 2014-11-16 14:28:16 +0000 | [diff] [blame] | 230 | return itr; |
| 231 | } |
| 232 | |
Marco Poletti | e464713 | 2015-05-31 14:35:27 +0100 | [diff] [blame] | 233 | template <typename C> |
| 234 | inline C* InjectorStorage::getPtr(Graph::node_iterator itr) { |
Marco Poletti | 010daa6 | 2015-07-06 01:15:12 +0100 | [diff] [blame] | 235 | FruitStaticAssert(fruit::impl::meta::IsSame(fruit::impl::meta::Type<C>, fruit::impl::meta::NormalizeType(fruit::impl::meta::Type<C>))); |
Marco Poletti | bfcb7ed | 2015-02-28 18:55:16 +0000 | [diff] [blame] | 236 | void* p = getPtrInternal(itr); |
Marco Poletti | b1d265c | 2014-10-19 21:24:11 -0700 | [diff] [blame] | 237 | return reinterpret_cast<C*>(p); |
| 238 | } |
| 239 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 240 | template <typename AnnotatedC> |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 241 | inline InjectorStorage::RemoveAnnotations<AnnotatedC>* InjectorStorage::unsafeGet() { |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 242 | using C = RemoveAnnotations<AnnotatedC>; |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 243 | void* p = unsafeGetPtr(getTypeId<AnnotatedC>()); |
Marco Poletti | 1576a73 | 2014-10-18 12:35:17 -0700 | [diff] [blame] | 244 | return reinterpret_cast<C*>(p); |
| 245 | } |
| 246 | |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 247 | inline InjectorStorage::Graph::node_iterator InjectorStorage::lazyGetPtr(TypeId type) { |
| 248 | return bindings.at(type); |
Marco Poletti | 934689f | 2014-11-16 14:28:16 +0000 | [diff] [blame] | 249 | } |
| 250 | |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 251 | inline void* InjectorStorage::unsafeGetPtr(TypeId type) { |
| 252 | Graph::node_iterator itr = bindings.find(type); |
Marco Poletti | 85aea00 | 2014-11-24 13:15:27 +0000 | [diff] [blame] | 253 | if (itr == bindings.end()) { |
Marco Poletti | 1576a73 | 2014-10-18 12:35:17 -0700 | [diff] [blame] | 254 | return nullptr; |
| 255 | } |
Marco Poletti | bfcb7ed | 2015-02-28 18:55:16 +0000 | [diff] [blame] | 256 | return getPtrInternal(itr); |
Marco Poletti | 1576a73 | 2014-10-18 12:35:17 -0700 | [diff] [blame] | 257 | } |
| 258 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 259 | template <typename AnnotatedC> |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 260 | inline const std::vector<InjectorStorage::RemoveAnnotations<AnnotatedC>*>& InjectorStorage::getMultibindings() { |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 261 | using C = RemoveAnnotations<AnnotatedC>; |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 262 | void* p = getMultibindings(getTypeId<AnnotatedC>()); |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 263 | if (p == nullptr) { |
Marco Poletti | 1fd2649 | 2014-09-28 12:31:13 +0100 | [diff] [blame] | 264 | static std::vector<C*> empty_vector; |
| 265 | return empty_vector; |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 266 | } else { |
Marco Poletti | 1fd2649 | 2014-09-28 12:31:13 +0100 | [diff] [blame] | 267 | return *reinterpret_cast<std::vector<C*>*>(p); |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 268 | } |
| 269 | } |
| 270 | |
Marco Poletti | bfcb7ed | 2015-02-28 18:55:16 +0000 | [diff] [blame] | 271 | inline void* InjectorStorage::getPtrInternal(Graph::node_iterator node_itr) { |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 272 | NormalizedBindingData& bindingData = node_itr.getNode(); |
| 273 | if (!node_itr.isTerminal()) { |
Marco Poletti | 0fbf774 | 2015-02-28 17:48:54 +0000 | [diff] [blame] | 274 | bindingData.create(*this, node_itr); |
Marco Poletti | 31335f8 | 2016-05-22 18:36:23 +0100 | [diff] [blame] | 275 | FruitAssert(node_itr.isTerminal()); |
Marco Poletti | 21802c6 | 2014-10-12 15:55:59 +0100 | [diff] [blame] | 276 | } |
Marco Poletti | c4fbcb1 | 2015-02-28 17:57:04 +0000 | [diff] [blame] | 277 | return bindingData.getObject(); |
Marco Poletti | 21802c6 | 2014-10-12 15:55:59 +0100 | [diff] [blame] | 278 | } |
Marco Poletti | c4fbcb1 | 2015-02-28 17:57:04 +0000 | [diff] [blame] | 279 | |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 280 | inline NormalizedMultibindingData* InjectorStorage::getNormalizedMultibindingData(TypeId type) { |
| 281 | auto itr = multibindings.find(type); |
Marco Poletti | 85aea00 | 2014-11-24 13:15:27 +0000 | [diff] [blame] | 282 | if (itr != multibindings.end()) |
Marco Poletti | 71c36de | 2014-11-01 10:51:07 +0000 | [diff] [blame] | 283 | return &(itr->second); |
| 284 | else |
| 285 | return nullptr; |
| 286 | } |
| 287 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 288 | template <typename AnnotatedC> |
Marco Poletti | 6c13003 | 2014-11-24 15:09:05 +0000 | [diff] [blame] | 289 | inline std::shared_ptr<char> InjectorStorage::createMultibindingVector(InjectorStorage& storage) { |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 290 | using C = RemoveAnnotations<AnnotatedC>; |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 291 | TypeId type = getTypeId<AnnotatedC>(); |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 292 | NormalizedMultibindingData* multibinding = storage.getNormalizedMultibindingData(type); |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 293 | |
| 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 Poletti | 31335f8 | 2016-05-22 18:36:23 +0100 | [diff] [blame] | 296 | FruitAssert(multibinding != nullptr); |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 297 | |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 298 | if (multibinding->v.get() != nullptr) { |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 299 | // Result cached, return early. |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 300 | return multibinding->v; |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 301 | } |
| 302 | |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 303 | storage.ensureConstructedMultibinding(*multibinding); |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 304 | |
| 305 | std::vector<C*> s; |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 306 | s.reserve(multibinding->elems.size()); |
| 307 | for (const NormalizedMultibindingData::Elem& elem : multibinding->elems) { |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 308 | s.push_back(reinterpret_cast<C*>(elem.object)); |
| 309 | } |
| 310 | |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 311 | 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 Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 313 | |
Marco Poletti | 9491d65 | 2014-11-24 15:47:14 +0000 | [diff] [blame] | 314 | multibinding->v = result; |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 315 | |
| 316 | return result; |
| 317 | } |
| 318 | |
Marco Poletti | d1b46ee | 2017-05-20 13:06:21 +0100 | [diff] [blame] | 319 | template <typename I, typename C, typename AnnotatedC> |
| 320 | BindingData::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 Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 330 | // I, C must not be pointers. |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 331 | template <typename AnnotatedI, typename AnnotatedC> |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 332 | inline std::tuple<TypeId, BindingData> InjectorStorage::createBindingDataForBind() { |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 333 | using I = RemoveAnnotations<AnnotatedI>; |
| 334 | using C = RemoveAnnotations<AnnotatedC>; |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 335 | 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 Poletti | d1b46ee | 2017-05-20 13:06:21 +0100 | [diff] [blame] | 337 | 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 Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 341 | } |
| 342 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 343 | template <typename AnnotatedC, typename C> |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 344 | inline std::tuple<TypeId, BindingData> InjectorStorage::createBindingDataForBindInstance(C& instance) { |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 345 | return std::make_tuple(getTypeId<AnnotatedC>(), BindingData(&instance)); |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 346 | } |
| 347 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 348 | // 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. |
| 351 | template <typename AnnotatedSignature, |
| 352 | typename Lambda, |
| 353 | bool lambda_returns_pointer, |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 354 | typename AnnotatedT = InjectorStorage::SignatureType<AnnotatedSignature>, |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 355 | typename AnnotatedArgVector = fruit::impl::meta::Eval<fruit::impl::meta::SignatureArgs(fruit::impl::meta::Type<AnnotatedSignature>)>, |
Marco Poletti | 36253c9 | 2015-07-19 17:12:47 +0100 | [diff] [blame] | 356 | 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 Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 360 | struct InvokeLambdaWithInjectedArgVector; |
| 361 | |
| 362 | // AnnotatedT is of the form C* or Annotated<Annotation, C*> |
Marco Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 363 | template <typename AnnotatedSignature, typename Lambda, typename AnnotatedT, typename... AnnotatedArgs, typename... Indexes> |
| 364 | struct InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, true /* lambda_returns_pointer */, AnnotatedT, fruit::impl::meta::Vector<AnnotatedArgs...>, fruit::impl::meta::Vector<Indexes...>> { |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 365 | using CPtr = InjectorStorage::RemoveAnnotations<AnnotatedT>; |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 366 | using AnnotatedC = InjectorStorage::NormalizeType<AnnotatedT>; |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 367 | |
Marco Poletti | dfcdced | 2017-05-20 15:24:14 +0100 | [diff] [blame] | 368 | FRUIT_ALWAYS_INLINE |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 369 | CPtr operator()(InjectorStorage& injector, FixedSizeAllocator& allocator) { |
Marco Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 370 | // `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 Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 373 | injector.get<fruit::impl::meta::UnwrapType<AnnotatedArgs>>()...); |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 374 | 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 Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 383 | |
| 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 Poletti | 8223fe5 | 2016-08-29 19:44:52 +0100 | [diff] [blame] | 397 | // 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 Poletti | dfcdced | 2017-05-20 15:24:14 +0100 | [diff] [blame] | 401 | FRUIT_ALWAYS_INLINE |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 402 | CPtr outerConstructHelper(InjectorStorage& injector, NodeItrs... nodeItrs) { |
Marco Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 403 | // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused. |
| 404 | (void)injector; |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 405 | return innerConstructHelper(injector, |
| 406 | GetFirstStage<InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>()(injector, nodeItrs) |
Marco Poletti | 8223fe5 | 2016-08-29 19:44:52 +0100 | [diff] [blame] | 407 | ...); |
| 408 | } |
| 409 | |
Marco Poletti | dfcdced | 2017-05-20 15:24:14 +0100 | [diff] [blame] | 410 | FRUIT_ALWAYS_INLINE |
Marco Poletti | 2197297 | 2015-05-31 15:56:20 +0100 | [diff] [blame] | 411 | CPtr operator()(InjectorStorage& injector, SemistaticGraph<TypeId, NormalizedBindingData>& bindings, |
| 412 | FixedSizeAllocator& allocator, InjectorStorage::Graph::edge_iterator deps) { |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 413 | // `deps' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused. |
| 414 | (void)deps; |
| 415 | |
Marco Poletti | 2197297 | 2015-05-31 15:56:20 +0100 | [diff] [blame] | 416 | InjectorStorage::Graph::node_iterator bindings_begin = bindings.begin(); |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 417 | // `bindings_begin' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused. |
| 418 | (void) bindings_begin; |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 419 | CPtr cPtr = outerConstructHelper(injector, |
Marco Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 420 | injector.lazyGetPtr<InjectorStorage::NormalizeType<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>(deps, Indexes::value, bindings_begin) |
Marco Poletti | 31f638a | 2015-05-10 21:21:25 +0100 | [diff] [blame] | 421 | ...); |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 422 | 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 Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 433 | template <typename AnnotatedSignature, typename Lambda, typename AnnotatedC, typename... AnnotatedArgs, typename... Indexes> |
| 434 | struct InvokeLambdaWithInjectedArgVector<AnnotatedSignature, Lambda, false /* lambda_returns_pointer */, AnnotatedC, fruit::impl::meta::Vector<AnnotatedArgs...>, fruit::impl::meta::Vector<Indexes...>> { |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 435 | using C = InjectorStorage::RemoveAnnotations<AnnotatedC>; |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 436 | |
Marco Poletti | dfcdced | 2017-05-20 15:24:14 +0100 | [diff] [blame] | 437 | FRUIT_ALWAYS_INLINE |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 438 | C* operator()(InjectorStorage& injector, FixedSizeAllocator& allocator) { |
Marco Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 439 | // `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 Poletti | 9198ba0 | 2017-05-20 11:58:34 +0100 | [diff] [blame] | 442 | LambdaInvoker::invoke<Lambda, InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>&&...>( |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 443 | injector.get<fruit::impl::meta::UnwrapType<AnnotatedArgs>>()...)); |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 444 | } |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 445 | |
| 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 Poletti | 8223fe5 | 2016-08-29 19:44:52 +0100 | [diff] [blame] | 459 | // 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 Poletti | dfcdced | 2017-05-20 15:24:14 +0100 | [diff] [blame] | 463 | FRUIT_ALWAYS_INLINE |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 464 | C* outerConstructHelper(InjectorStorage& injector, FixedSizeAllocator& allocator, NodeItrs... nodeItrs) { |
Marco Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 465 | // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused. |
| 466 | (void)injector; |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 467 | return innerConstructHelper(injector, allocator, |
| 468 | GetFirstStage<InjectorStorage::RemoveAnnotations<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>()(injector, nodeItrs) |
| 469 | ...); |
Marco Poletti | 8223fe5 | 2016-08-29 19:44:52 +0100 | [diff] [blame] | 470 | } |
| 471 | |
Marco Poletti | 2197297 | 2015-05-31 15:56:20 +0100 | [diff] [blame] | 472 | C* operator()(InjectorStorage& injector, SemistaticGraph<TypeId, NormalizedBindingData>& bindings, |
| 473 | FixedSizeAllocator& allocator, InjectorStorage::Graph::edge_iterator deps) { |
Marco Poletti | 2197297 | 2015-05-31 15:56:20 +0100 | [diff] [blame] | 474 | InjectorStorage::Graph::node_iterator bindings_begin = bindings.begin(); |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 475 | // `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 Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 481 | // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused. |
| 482 | (void)injector; |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 483 | C* p = outerConstructHelper(injector, allocator, |
Marco Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 484 | injector.lazyGetPtr<InjectorStorage::NormalizeType<fruit::impl::meta::UnwrapType<AnnotatedArgs>>>(deps, Indexes::value, bindings_begin) |
Marco Poletti | 8223fe5 | 2016-08-29 19:44:52 +0100 | [diff] [blame] | 485 | ...); |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 486 | return p; |
| 487 | } |
| 488 | }; |
| 489 | |
Marco Poletti | d1b46ee | 2017-05-20 13:06:21 +0100 | [diff] [blame] | 490 | |
| 491 | template <typename C, typename T, typename AnnotatedSignature, typename Lambda> |
| 492 | BindingData::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 Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 499 | template <typename AnnotatedSignature, typename Lambda> |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 500 | inline std::tuple<TypeId, BindingData> InjectorStorage::createBindingDataForProvider() { |
Marco Poletti | 16810cb | 2015-05-31 15:33:39 +0100 | [diff] [blame] | 501 | #ifdef FRUIT_EXTRA_DEBUG |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 502 | 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 Poletti | 16810cb | 2015-05-31 15:33:39 +0100 | [diff] [blame] | 504 | #endif |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 505 | using AnnotatedT = SignatureType<AnnotatedSignature>; |
| 506 | using AnnotatedC = NormalizeType<AnnotatedT>; |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 507 | // T is either C or C*. |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 508 | using T = RemoveAnnotations<AnnotatedT>; |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 509 | using C = NormalizeType<T>; |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 510 | const BindingDeps* deps = getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>(); |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 511 | bool needs_allocation = !std::is_pointer<T>::value; |
Marco Poletti | d1b46ee | 2017-05-20 13:06:21 +0100 | [diff] [blame] | 512 | return std::make_tuple(getTypeId<AnnotatedC>(), |
| 513 | BindingData(createInjectedObjectForProvider<C, T, AnnotatedSignature, Lambda>, |
| 514 | deps, |
| 515 | needs_allocation)); |
| 516 | } |
| 517 | |
| 518 | template <typename I, typename C, typename T, typename AnnotatedSignature, typename Lambda> |
| 519 | BindingData::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 Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 525 | } |
| 526 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 527 | template <typename AnnotatedSignature, typename Lambda, typename AnnotatedI> |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 528 | inline std::tuple<TypeId, TypeId, BindingData> InjectorStorage::createBindingDataForCompressedProvider() { |
Marco Poletti | 16810cb | 2015-05-31 15:33:39 +0100 | [diff] [blame] | 529 | #ifdef FRUIT_EXTRA_DEBUG |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 530 | 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 Poletti | 16810cb | 2015-05-31 15:33:39 +0100 | [diff] [blame] | 532 | #endif |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 533 | using AnnotatedT = SignatureType<AnnotatedSignature>; |
| 534 | using AnnotatedC = NormalizeType<AnnotatedT>; |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 535 | // T is either C or C*. |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 536 | using T = RemoveAnnotations<AnnotatedT>; |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 537 | using C = NormalizeType<T>; |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 538 | using I = RemoveAnnotations<AnnotatedI>; |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 539 | const BindingDeps* deps = getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>(); |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 540 | bool needs_allocation = !std::is_pointer<T>::value; |
Marco Poletti | d1b46ee | 2017-05-20 13:06:21 +0100 | [diff] [blame] | 541 | return std::make_tuple(getTypeId<AnnotatedI>(), |
| 542 | getTypeId<AnnotatedC>(), |
| 543 | BindingData(createInjectedObjectForCompressedProvider<I, C, T, AnnotatedSignature, Lambda>, |
| 544 | deps, |
| 545 | needs_allocation)); |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 546 | } |
| 547 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 548 | // 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. |
| 551 | template <typename AnnotatedSignature, |
Marco Poletti | 36253c9 | 2015-07-19 17:12:47 +0100 | [diff] [blame] | 552 | 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 Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 556 | struct InvokeConstructorWithInjectedArgVector; |
| 557 | |
Marco Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 558 | template <typename AnnotatedC, typename... AnnotatedArgs, typename... Indexes> |
| 559 | struct InvokeConstructorWithInjectedArgVector<AnnotatedC(AnnotatedArgs...), fruit::impl::meta::Vector<Indexes...>> { |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 560 | using C = InjectorStorage::RemoveAnnotations<AnnotatedC>; |
Marco Poletti | 8223fe5 | 2016-08-29 19:44:52 +0100 | [diff] [blame] | 561 | |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 562 | // 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 Poletti | 8223fe5 | 2016-08-29 19:44:52 +0100 | [diff] [blame] | 575 | // 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 Poletti | dfcdced | 2017-05-20 15:24:14 +0100 | [diff] [blame] | 579 | FRUIT_ALWAYS_INLINE |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 580 | C* outerConstructHelper(InjectorStorage& injector, FixedSizeAllocator& allocator, NodeItrs... nodeItrs) { |
Marco Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 581 | // `injector' *is* used below, but when there are no AnnotatedArgs some compilers report it as unused. |
| 582 | (void)injector; |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 583 | return innerConstructHelper(injector, allocator, |
| 584 | GetFirstStage<InjectorStorage::RemoveAnnotations<AnnotatedArgs>>()(injector, nodeItrs) |
Marco Poletti | 8223fe5 | 2016-08-29 19:44:52 +0100 | [diff] [blame] | 585 | ...); |
| 586 | } |
| 587 | |
Marco Poletti | dfcdced | 2017-05-20 15:24:14 +0100 | [diff] [blame] | 588 | FRUIT_ALWAYS_INLINE |
Marco Poletti | 2197297 | 2015-05-31 15:56:20 +0100 | [diff] [blame] | 589 | C* operator()(InjectorStorage& injector, SemistaticGraph<TypeId, NormalizedBindingData>& bindings, |
| 590 | FixedSizeAllocator& allocator, InjectorStorage::Graph::edge_iterator deps) { |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 591 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 592 | // `deps' *is* used below, but when there are no Args some compilers report it as unused. |
| 593 | (void)deps; |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 594 | |
Marco Poletti | 2197297 | 2015-05-31 15:56:20 +0100 | [diff] [blame] | 595 | InjectorStorage::Graph::node_iterator bindings_begin = bindings.begin(); |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 596 | // `bindings_begin' *is* used below, but when there are no Args some compilers report it as unused. |
| 597 | (void) bindings_begin; |
Marco Poletti | fdc7990 | 2017-05-21 13:27:57 +0100 | [diff] [blame^] | 598 | C* p = outerConstructHelper(injector, allocator, |
Marco Poletti | 905dc09 | 2017-03-12 15:54:31 +0000 | [diff] [blame] | 599 | injector.lazyGetPtr<InjectorStorage::NormalizeType<AnnotatedArgs>>(deps, Indexes::value, bindings_begin) |
Marco Poletti | 31f638a | 2015-05-10 21:21:25 +0100 | [diff] [blame] | 600 | ...); |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 601 | return p; |
| 602 | } |
| 603 | }; |
| 604 | |
Marco Poletti | d1b46ee | 2017-05-20 13:06:21 +0100 | [diff] [blame] | 605 | template <typename C, typename AnnotatedSignature> |
| 606 | BindingData::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 Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 613 | template <typename AnnotatedSignature> |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 614 | inline std::tuple<TypeId, BindingData> InjectorStorage::createBindingDataForConstructor() { |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 615 | using AnnotatedC = SignatureType<AnnotatedSignature>; |
| 616 | using C = RemoveAnnotations<AnnotatedC>; |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 617 | const BindingDeps* deps = getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>(); |
Marco Poletti | d1b46ee | 2017-05-20 13:06:21 +0100 | [diff] [blame] | 618 | return std::make_tuple(getTypeId<AnnotatedC>(), |
| 619 | BindingData(createInjectedObjectForConstructor<C, AnnotatedSignature>, |
| 620 | deps, |
| 621 | true /* needs_allocation */)); |
| 622 | } |
| 623 | |
| 624 | template <typename I, typename C, typename AnnotatedSignature> |
| 625 | BindingData::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 Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 631 | } |
| 632 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 633 | template <typename AnnotatedSignature, typename AnnotatedI> |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 634 | inline std::tuple<TypeId, TypeId, BindingData> InjectorStorage::createBindingDataForCompressedConstructor() { |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 635 | using AnnotatedC = SignatureType<AnnotatedSignature>; |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 636 | using C = RemoveAnnotations<AnnotatedC>; |
| 637 | using I = RemoveAnnotations<AnnotatedI>; |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 638 | const BindingDeps* deps = getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>(); |
Marco Poletti | d1b46ee | 2017-05-20 13:06:21 +0100 | [diff] [blame] | 639 | return std::make_tuple(getTypeId<AnnotatedI>(), |
| 640 | getTypeId<AnnotatedC>(), |
| 641 | BindingData(createInjectedObjectForCompressedConstructor<I, C, AnnotatedSignature>, |
| 642 | deps, |
| 643 | true /* needs_allocation */)); |
| 644 | } |
| 645 | |
| 646 | template <typename I, typename C, typename AnnotatedCPtr> |
| 647 | MultibindingData::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 Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 653 | } |
| 654 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 655 | template <typename AnnotatedI, typename AnnotatedC> |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 656 | inline std::tuple<TypeId, MultibindingData> InjectorStorage::createMultibindingDataForBinding() { |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 657 | using AnnotatedCPtr = fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<fruit::impl::meta::AddPointerInAnnotatedType(fruit::impl::meta::Type<AnnotatedC>)>>; |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 658 | using I = RemoveAnnotations<AnnotatedI>; |
| 659 | using C = RemoveAnnotations<AnnotatedC>; |
Marco Poletti | d1b46ee | 2017-05-20 13:06:21 +0100 | [diff] [blame] | 660 | 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 Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 664 | } |
| 665 | |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 666 | template <typename AnnotatedC, typename C> |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 667 | inline std::tuple<TypeId, MultibindingData> InjectorStorage::createMultibindingDataForInstance(C& instance) { |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 668 | return std::make_tuple(getTypeId<AnnotatedC>(), MultibindingData(&instance, createMultibindingVector<AnnotatedC>)); |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 669 | } |
| 670 | |
Marco Poletti | d1b46ee | 2017-05-20 13:06:21 +0100 | [diff] [blame] | 671 | template <typename C, typename T, typename AnnotatedSignature, typename Lambda> |
| 672 | BindingData::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 Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 678 | template <typename AnnotatedSignature, typename Lambda> |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 679 | inline std::tuple<TypeId, MultibindingData> InjectorStorage::createMultibindingDataForProvider() { |
Marco Poletti | 16810cb | 2015-05-31 15:33:39 +0100 | [diff] [blame] | 680 | #ifdef FRUIT_EXTRA_DEBUG |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 681 | 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 Poletti | 16810cb | 2015-05-31 15:33:39 +0100 | [diff] [blame] | 683 | #endif |
| 684 | |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 685 | using AnnotatedT = SignatureType<AnnotatedSignature>; |
| 686 | using AnnotatedC = NormalizeType<AnnotatedT>; |
Marco Poletti | 3b95a51 | 2015-07-11 13:43:39 +0100 | [diff] [blame] | 687 | using T = RemoveAnnotations<AnnotatedT>; |
Marco Poletti | 79b01d6 | 2016-03-25 12:25:30 +0000 | [diff] [blame] | 688 | using C = NormalizeType<T>; |
Marco Poletti | cc97a16 | 2015-05-10 12:10:12 +0100 | [diff] [blame] | 689 | bool needs_allocation = !std::is_pointer<T>::value; |
| 690 | return std::make_tuple(getTypeId<AnnotatedC>(), |
Marco Poletti | d1b46ee | 2017-05-20 13:06:21 +0100 | [diff] [blame] | 691 | MultibindingData(createInjectedObjectForMultibindingProvider<C, T, AnnotatedSignature, Lambda>, |
| 692 | getBindingDeps<NormalizedSignatureArgs<AnnotatedSignature>>(), |
| 693 | InjectorStorage::createMultibindingVector<AnnotatedC>, |
Marco Poletti | a85fc03 | 2014-12-26 20:00:38 +0100 | [diff] [blame] | 694 | needs_allocation)); |
Marco Poletti | 224bd9c | 2014-11-24 12:34:51 +0000 | [diff] [blame] | 695 | } |
| 696 | |
Marco Poletti | fdbfcbe | 2014-08-31 08:57:47 +0100 | [diff] [blame] | 697 | } // namespace fruit |
| 698 | } // namespace impl |
| 699 | |
| 700 | |
Marco Poletti | 7f35b65 | 2014-11-01 10:11:37 +0000 | [diff] [blame] | 701 | #endif // FRUIT_INJECTOR_STORAGE_DEFN_H |