1 /* 2 * Copyright 2014 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef FRUIT_INJECTOR_STORAGE_H 18 #define FRUIT_INJECTOR_STORAGE_H 19 20 #include <fruit/fruit_forward_decls.h> 21 #include <fruit/impl/data_structures/fixed_size_allocator.h> 22 #include <fruit/impl/meta/component.h> 23 #include <fruit/impl/normalized_component_storage/normalized_bindings.h> 24 25 #include <unordered_map> 26 #include <vector> 27 #include <mutex> 28 #include <thread> 29 30 namespace fruit { 31 namespace impl { 32 33 template <typename T> 34 struct GetHelper; 35 36 /** 37 * A component where all types have to be explicitly registered, and all checks are at runtime. 38 * Used to implement Component<>, don't use directly. 39 * 40 * This class handles the creation of types of the forms: 41 * - shared_ptr<C>, [const] C*, [const] C&, C (where C is an atomic type) 42 * - Injector<T1, ..., Tk> (with T1, ..., Tk of the above forms). 43 */ 44 class InjectorStorage { 45 public: 46 // TODO: remove. 47 // using BindingVectors = std::pair<std::vector<std::pair<TypeId, BindingData>>, 48 // std::vector<std::pair<TypeId, MultibindingData>>>; 49 using Graph = SemistaticGraph<TypeId, NormalizedBinding>; 50 51 template <typename AnnotatedT> 52 using RemoveAnnotations = fruit::impl::meta::UnwrapType< 53 fruit::impl::meta::Eval<fruit::impl::meta::RemoveAnnotations(fruit::impl::meta::Type<AnnotatedT>)>>; 54 55 // MSVC 14 has trouble specializing alias templates using expanded pack elements. 56 // This is a known issue: 57 // https://stackoverflow.com/questions/43411542/metaprogramming-failed-to-specialize-alias-template 58 // The workaround is just to use a struct directly. 59 template <typename AnnotatedT> 60 struct AnnotationRemover { 61 using type = RemoveAnnotations<AnnotatedT>; 62 }; 63 64 template <typename T> 65 using NormalizeType = fruit::impl::meta::UnwrapType< 66 fruit::impl::meta::Eval<fruit::impl::meta::NormalizeType(fruit::impl::meta::Type<T>)>>; 67 68 template <typename T> 69 struct TypeNormalizer { 70 using type = NormalizeType<T>; 71 }; 72 73 template <typename Signature> 74 using SignatureType = fruit::impl::meta::UnwrapType< 75 fruit::impl::meta::Eval<fruit::impl::meta::SignatureType(fruit::impl::meta::Type<Signature>)>>; 76 77 template <typename Signature> 78 using NormalizedSignatureArgs = fruit::impl::meta::Eval<fruit::impl::meta::NormalizeTypeVector( 79 fruit::impl::meta::SignatureArgs(fruit::impl::meta::Type<Signature>))>; 80 81 // Prints the specified error and calls exit(1). 82 static void fatal(const std::string& error); 83 84 template <typename AnnotatedI, typename AnnotatedC> 85 static ComponentStorageEntry createComponentStorageEntryForBind(); 86 87 template <typename AnnotatedI, typename AnnotatedC> 88 static ComponentStorageEntry createComponentStorageEntryForConstBind(); 89 90 template <typename AnnotatedC, typename C> 91 static ComponentStorageEntry createComponentStorageEntryForBindInstance(C& instance); 92 93 template <typename AnnotatedC, typename C> 94 static ComponentStorageEntry createComponentStorageEntryForBindConstInstance(const C& instance); 95 96 template <typename AnnotatedSignature, typename Lambda> 97 static ComponentStorageEntry createComponentStorageEntryForProvider(); 98 99 template <typename AnnotatedSignature, typename Lambda, typename AnnotatedI> 100 static ComponentStorageEntry createComponentStorageEntryForCompressedProvider(); 101 102 template <typename AnnotatedSignature> 103 static ComponentStorageEntry createComponentStorageEntryForConstructor(); 104 105 template <typename AnnotatedSignature, typename AnnotatedI> 106 static ComponentStorageEntry createComponentStorageEntryForCompressedConstructor(); 107 108 template <typename AnnotatedT> 109 static ComponentStorageEntry createComponentStorageEntryForMultibindingVectorCreator(); 110 111 template <typename AnnotatedI, typename AnnotatedC> 112 static ComponentStorageEntry createComponentStorageEntryForMultibinding(); 113 114 template <typename AnnotatedC, typename C> 115 static ComponentStorageEntry createComponentStorageEntryForInstanceMultibinding(C& instance); 116 117 template <typename AnnotatedSignature, typename Lambda> 118 static ComponentStorageEntry createComponentStorageEntryForMultibindingProvider(); 119 120 private: 121 // The NormalizedComponentStorage owned by this object (if any). 122 // Only used for the 1-argument constructor, otherwise it's nullptr. 123 std::unique_ptr<NormalizedComponentStorage> normalized_component_storage_ptr; 124 125 FixedSizeAllocator allocator; 126 127 // A graph with injected types as nodes (each node stores the NormalizedBindingData for the type) and dependencies as 128 // edges. 129 // For types that have a constructed object already, the corresponding node is stored as terminal node. 130 SemistaticGraph<TypeId, NormalizedBinding> bindings; 131 132 // Maps the type index of a type T to the corresponding NormalizedMultibindingSet object (that stores all 133 // multibindings). 134 std::unordered_map<TypeId, NormalizedMultibindingSet> multibindings; 135 136 // This mutex is used to synchronize concurrent accesses to this InjectorStorage object. 137 std::recursive_mutex mutex; 138 139 private: 140 template <typename AnnotatedC> 141 static std::shared_ptr<char> createMultibindingVector(InjectorStorage& storage); 142 143 // If not bound, returns nullptr. 144 NormalizedMultibindingSet* getNormalizedMultibindingSet(TypeId type); 145 146 // Looks up the location where the type is (or will be) stored, but does not construct the class. 147 template <typename AnnotatedC> 148 Graph::node_iterator lazyGetPtr(); 149 150 // getPtr() is equivalent to getPtrInternal(lazyGetPtr()) 151 template <typename C> 152 const C* getPtr(Graph::node_iterator itr); 153 154 // Similar to the previous, but takes a node_iterator. Use this when the node_iterator is known, it's faster. 155 const void* getPtrInternal(Graph::node_iterator itr); 156 157 // getPtr(typeInfo) is equivalent to getPtr(lazyGetPtr(typeInfo)). 158 Graph::node_iterator lazyGetPtr(TypeId type); 159 160 // getPtr(deps, index) is equivalent to getPtr(lazyGetPtr(deps, index)). 161 Graph::node_iterator lazyGetPtr(Graph::edge_iterator deps, std::size_t dep_index); 162 163 // Similar to getPtr, but the binding might not exist. Returns nullptr if it doesn't. 164 const void* unsafeGetPtr(TypeId type); 165 166 void* getPtrForMultibinding(TypeId type); 167 168 // Returns a std::vector<T*>*, or nullptr if there are no multibindings. 169 void* getMultibindings(TypeId type); 170 171 // Constructs any necessary instances, but NOT the instance set. 172 void ensureConstructedMultibinding(NormalizedMultibindingSet& multibinding_set); 173 174 template <typename T> 175 friend struct GetFirstStage; 176 177 template <typename T> 178 friend class fruit::Provider; 179 180 using object_ptr_t = void*; 181 using const_object_ptr_t = const void*; 182 183 template <typename I, typename C, typename AnnotatedC> 184 static const_object_ptr_t createInjectedObjectForBind(InjectorStorage& injector, 185 InjectorStorage::Graph::node_iterator node_itr); 186 187 template <typename C, typename T, typename AnnotatedSignature, typename Lambda> 188 static const_object_ptr_t createInjectedObjectForProvider(InjectorStorage& injector, Graph::node_iterator node_itr); 189 190 template <typename I, typename C, typename T, typename AnnotatedSignature, typename Lambda> 191 static const_object_ptr_t createInjectedObjectForCompressedProvider(InjectorStorage& injector, 192 Graph::node_iterator node_itr); 193 194 template <typename C, typename AnnotatedSignature> 195 static const_object_ptr_t createInjectedObjectForConstructor(InjectorStorage& injector, 196 Graph::node_iterator node_itr); 197 198 template <typename I, typename C, typename AnnotatedSignature> 199 static const_object_ptr_t createInjectedObjectForCompressedConstructor(InjectorStorage& injector, 200 Graph::node_iterator node_itr); 201 202 template <typename I, typename C, typename AnnotatedCPtr> 203 static object_ptr_t createInjectedObjectForMultibinding(InjectorStorage& m); 204 205 template <typename C, typename T, typename AnnotatedSignature, typename Lambda> 206 static object_ptr_t createInjectedObjectForMultibindingProvider(InjectorStorage& injector); 207 208 public: 209 // Wraps a std::vector<ComponentStorageEntry>::iterator as an iterator on tuples 210 // (typeId, normalizedBindingData, isTerminal, edgesBegin, edgesEnd) 211 struct BindingDataNodeIter { 212 std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>::iterator itr; 213 214 BindingDataNodeIter* operator->(); 215 216 void operator++(); 217 218 bool operator==(const BindingDataNodeIter& other) const; 219 bool operator!=(const BindingDataNodeIter& other) const; 220 221 std::ptrdiff_t operator-(BindingDataNodeIter other) const; 222 223 TypeId getId(); 224 NormalizedBinding getValue(); 225 bool isTerminal(); 226 const TypeId* getEdgesBegin(); 227 const TypeId* getEdgesEnd(); 228 }; 229 230 /** 231 * The MemoryPool is only used during construction, the constructed object *can* outlive the memory pool. 232 */ 233 InjectorStorage(ComponentStorage&& storage, const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types, 234 MemoryPool& memory_pool); 235 236 /** 237 * The MemoryPool is only used during construction, the constructed object *can* outlive the memory pool. 238 */ 239 InjectorStorage(const NormalizedComponentStorage& normalized_storage, ComponentStorage&& storage, 240 MemoryPool& memory_pool); 241 242 // This is just the default destructor, but we declare it here to avoid including 243 // normalized_component_storage.h in fruit.h. 244 ~InjectorStorage(); 245 246 InjectorStorage(InjectorStorage&&) = delete; 247 InjectorStorage& operator=(InjectorStorage&&) = delete; 248 249 InjectorStorage(const InjectorStorage& other) = delete; 250 InjectorStorage& operator=(const InjectorStorage& other) = delete; 251 252 // Usually get<T>() returns a T. 253 // However, get<Annotated<Annotation1, T>>() returns a T, not an Annotated<Annotation1, T>. 254 template <typename AnnotatedT> 255 RemoveAnnotations<AnnotatedT> get(); 256 257 // Similar to the above, but specifying the node_iterator of the type. Use this together with lazyGetPtr when the 258 // node_iterator is known, it's faster. 259 // Note that T should *not* be annotated. 260 template <typename T> 261 T get(InjectorStorage::Graph::node_iterator node_iterator); 262 263 // Looks up the location where the type is (or will be) stored, but does not construct the class. 264 // get<AnnotatedT>() is equivalent to get<AnnotatedT>(lazyGetPtr<Apply<NormalizeType, AnnotatedT>>(deps, dep_index)) 265 // and also to get<T> (lazyGetPtr<Apply<NormalizeType, AnnotatedT>>(deps, dep_index)) 266 // dep_index is the index of the dep in `deps'. 267 template <typename AnnotatedC> 268 Graph::node_iterator lazyGetPtr(Graph::edge_iterator deps, std::size_t dep_index, 269 Graph::node_iterator bindings_begin) const; 270 271 // Returns nullptr if AnnotatedC was not bound. 272 template <typename AnnotatedC> 273 const RemoveAnnotations<AnnotatedC>* unsafeGet(); 274 275 template <typename AnnotatedC> 276 const std::vector<RemoveAnnotations<AnnotatedC>*>& getMultibindings(); 277 278 void eagerlyInjectMultibindings(); 279 }; 280 281 } // namespace impl 282 } // namespace fruit 283 284 #include <fruit/impl/injector/injector_storage.defn.h> 285 286 #endif // FRUIT_INJECTOR_STORAGE_H 287