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_COMPONENT_STORAGE_ENTRY_H 18 #define FRUIT_COMPONENT_STORAGE_ENTRY_H 19 20 #include <fruit/impl/component_storage/binding_deps.h> 21 #include <fruit/impl/data_structures/arena_allocator.h> 22 #include <fruit/impl/data_structures/semistatic_graph.h> 23 #include <fruit/impl/fruit_internal_forward_decls.h> 24 25 namespace fruit { 26 namespace impl { 27 28 /** 29 * This represents a generic entry in ComponentStorage. 30 * We use a single POD (this struct) to represent any binding so that ComponentStorage can hold a single vector, instead 31 * of having to hold multiple vectors (each of which potentially requiring allocation/deallocation when a 32 * ComponentStorage is constructed/destroyed). 33 * This way each ComponentStorage can hold a single vector and do a single allocation. 34 */ 35 struct ComponentStorageEntry { 36 enum class Kind { 37 #if FRUIT_EXTRA_DEBUG 38 INVALID, 39 #endif 40 BINDING_FOR_CONSTRUCTED_OBJECT, 41 BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION, 42 BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION, 43 BINDING_FOR_OBJECT_TO_CONSTRUCT_WITH_UNKNOWN_ALLOCATION, 44 COMPRESSED_BINDING, 45 MULTIBINDING_FOR_CONSTRUCTED_OBJECT, 46 MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION, 47 MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION, 48 // This is not an actual binding, it's an "addendum" to multibinding bindings that specifies how the multibinding 49 // vector can be created. Unlike real multibinding entries, this *can* be deduped. 50 MULTIBINDING_VECTOR_CREATOR, 51 52 LAZY_COMPONENT_WITH_NO_ARGS, 53 LAZY_COMPONENT_WITH_ARGS, 54 55 // Component replacements are stored as a REPLACEMENT_LAZY_COMPONENT_* entry followed by a REPLACED_LAZY_COMPONENT_* 56 // entry. Note that the args are independent: e.g. a component with args can be replaced by a component with no 57 // args. This also means that the type_id of the two entries can be different (since it's the type_id of the 58 // function signature rather than just of the Component<...>). 59 REPLACED_LAZY_COMPONENT_WITH_NO_ARGS, 60 REPLACED_LAZY_COMPONENT_WITH_ARGS, 61 REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS, 62 REPLACEMENT_LAZY_COMPONENT_WITH_ARGS, 63 64 // These markers are used in expandLazyComponents(), see the comments there for details. 65 COMPONENT_WITH_ARGS_END_MARKER, 66 COMPONENT_WITHOUT_ARGS_END_MARKER, 67 }; 68 69 #if FRUIT_EXTRA_DEBUG 70 mutable 71 #endif 72 Kind kind; 73 74 // This is usually the TypeId for the bound type, except: 75 // * when kind==COMPRESSED_BINDING, this is the interface's TypeId 76 // * when kind==*LAZY_COMPONENT_*, this is the TypeId of the 77 // Component<...>-returning function. 78 TypeId type_id; 79 80 /** 81 * This represents an entry in ComponentStorage for a binding (not a multibinding) that holds an already-constructed 82 * object. 83 */ 84 struct BindingForConstructedObject { 85 using object_ptr_t = const void*; 86 87 // The already-constructed object. We do *not* own this, this object must outlive the injector. 88 // This is a const pointer because in some cases it might be a const binding. 89 // We can cast this to a non-const pointer when we're sure that the original binding was for a non-const reference. 90 object_ptr_t object_ptr; 91 92 #if FRUIT_EXTRA_DEBUG 93 bool is_nonconst; 94 #endif 95 }; 96 97 /** 98 * This represents an entry in ComponentStorage for a binding (not a multibinding) that holds an object that needs to 99 * be constructed (potentially after injecting any dependencies). 100 */ 101 struct BindingForObjectToConstruct { 102 // This is a const pointer because this might be a const binding. If not, we'll cast this back to a non-const 103 // pointer when we need to. 104 using object_t = const void*; 105 using create_t = object_t (*)(InjectorStorage&, SemistaticGraph<TypeId, NormalizedBinding>::node_iterator); 106 107 // The return value of this function is a pointer to the constructed object (guaranteed to be !=nullptr). 108 // Once the object is constructed (at injection time), the injector owns that object. 109 create_t create; 110 111 // The type IDs that this type depends on. 112 const BindingDeps* deps; 113 114 #if FRUIT_EXTRA_DEBUG 115 bool is_nonconst; 116 #endif 117 }; 118 119 /** 120 * This represents an entry in ComponentStorage for a multibinding that holds an already-constructed 121 * object. 122 */ 123 struct MultibindingForConstructedObject { 124 using object_ptr_t = void*; 125 126 // The already-constructed object. We do *not* own this, this object must outlive the injector. 127 object_ptr_t object_ptr; 128 }; 129 130 /** 131 * This represents an entry in ComponentStorage for a multibinding that holds an object that needs to 132 * be constructed (potentially after injecting any dependencies). 133 */ 134 struct MultibindingForObjectToConstruct { 135 136 using object_t = void*; 137 using create_t = object_t (*)(InjectorStorage&); 138 139 // The return value of this function is a pointer to the constructed object (guaranteed to be !=nullptr). 140 // Once the object is constructed (at injection time), the injector owns that object. 141 create_t create; 142 143 // The type IDs that this type depends on. 144 const BindingDeps* deps; 145 }; 146 147 /** 148 * This is not an actual binding, it's an "addendum" to multibinding bindings that specifies how the multibinding 149 * vector can be created. Unlike real multibinding entries, this *can* be deduped. 150 */ 151 struct MultibindingVectorCreator { 152 153 using get_multibindings_vector_t = std::shared_ptr<char> (*)(InjectorStorage&); 154 155 // Returns the std::vector<T*> of instances, or nullptr if none. 156 // Caches the result in the `v' member of NormalizedMultibindingData. 157 get_multibindings_vector_t get_multibindings_vector; 158 }; 159 160 // A CompressedBinding with interface_id==getTypeId<I>() and class_id==getTypeId<C>() means that if: 161 // * C is not exposed by the component 162 // * I is the only node that depends on C 163 // * There are no multibindings that directly depend on C 164 // The BindingData for C is BindingForObjectToConstruct( 165 // Then, taken create1, needs_reallocation such that the ComponentStorageEntry for c_type_id is 166 // BindingForObjectToConstruct(createC, deps, needs_allocation), we can remove the binding for I and C and replace 167 // them 168 // with just a binding for I, with BindingForObjectToConstruct(create, deps, needs_allocation). 169 struct CompressedBinding { 170 171 using create_t = BindingForObjectToConstruct::create_t; 172 173 // TypeId for the implementation. 174 TypeId c_type_id; 175 176 // The return value of this function is a pointer to the constructed object (guaranteed to be !=nullptr). 177 // Once the object is constructed (at injection time), the injector owns that object. 178 create_t create; 179 }; 180 181 /** 182 * This represents an entry in ComponentStorage for a lazy component with no arguments. 183 */ 184 struct LazyComponentWithNoArgs { 185 // An arbitrary function type, used as type for the field `erased_fun`. 186 // Note that we can't use void* here, since data pointers might not have the same size as function pointers. 187 using erased_fun_t = void (*)(); 188 189 // The function that will be invoked to create the Component. 190 // Here we don't know the type, it's only known at construction time. 191 erased_fun_t erased_fun; 192 193 using entry_vector_t = std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>; 194 195 // The function that allows to add this component's bindings to the given ComponentStorage. 196 using add_bindings_fun_t = void (*)(erased_fun_t, entry_vector_t&); 197 add_bindings_fun_t add_bindings_fun; 198 199 template <typename Component> 200 static void addBindings(erased_fun_t erased_fun, entry_vector_t& entries); 201 202 template <typename Component> 203 static ComponentStorageEntry create(Component (*fun)()); 204 205 template <typename Component> 206 static ComponentStorageEntry create(fruit::ComponentFunction<Component> component_function); 207 208 template <typename Component> 209 static ComponentStorageEntry createReplacedComponentEntry(Component (*fun)()); 210 211 template <typename Component> 212 static ComponentStorageEntry createReplacementComponentEntry(Component (*fun)()); 213 214 bool operator==(const LazyComponentWithNoArgs&) const; 215 216 void addBindings(entry_vector_t& entries) const; 217 218 std::size_t hashCode() const; 219 220 bool isValid() const; 221 }; 222 223 /** 224 * This represents an entry in ComponentStorage for a lazy component with arguments. 225 */ 226 struct LazyComponentWithArgs { 227 class ComponentInterface { 228 public: 229 // An arbitrary function type, used as type for the field `erased_fun`. 230 // Note that we can't use void* here, since data pointers might not have the same size as function pointers. 231 using erased_fun_t = void (*)(); 232 233 // The function that will be invoked to create the Component. 234 // Here we don't know the type, it's only known to the LazyComponent implementation. 235 // We store this here instead of in the LazyComponent implementation so that we can do a quick comparison on the 236 // pointer without virtual calls (and we can then do the rest of the comparison via virtual call if needed). 237 erased_fun_t erased_fun; 238 239 using entry_vector_t = std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>; 240 241 ComponentInterface(erased_fun_t erased_fun); 242 243 virtual ~ComponentInterface() = default; 244 245 // Checks if *this and other are equal, assuming that this->fun and other.fun are equal. 246 virtual bool areParamsEqual(const ComponentInterface& other) const = 0; 247 248 bool operator==(const ComponentInterface& other) const; 249 250 virtual void addBindings(entry_vector_t& component_storage_entries) const = 0; 251 virtual std::size_t hashCode() const = 0; 252 virtual ComponentInterface* copy() const = 0; 253 254 /** 255 * Returns the type ID of the real `fun` object stored by the implementation. 256 * We use this instead of the `typeid` operator so that we don't require RTTI. 257 */ 258 virtual TypeId getFunTypeId() const = 0; 259 }; 260 261 template <typename Component, typename... Args> 262 static ComponentStorageEntry create(Component (*fun)(Args...), std::tuple<Args...> args_tuple); 263 264 template <typename Component, typename Arg, typename... Args> 265 static ComponentStorageEntry create(fruit::ComponentFunction<Component, Arg, Args...> component_function); 266 267 template <typename Component, typename... Args> 268 static ComponentStorageEntry createReplacedComponentEntry(Component (*fun)(Args...), 269 std::tuple<Args...> args_tuple); 270 271 template <typename Component, typename... Args> 272 static ComponentStorageEntry createReplacementComponentEntry(Component (*fun)(Args...), 273 std::tuple<Args...> args_tuple); 274 275 LazyComponentWithArgs(LazyComponentWithArgs&&) = default; 276 LazyComponentWithArgs& operator=(LazyComponentWithArgs&&) = default; 277 278 // Note: we must allow these (and use the default implementations) since this class is used in a union so it must be 279 // a POD. However when we need a real object we must call the other constructor above, and when we need a copy we 280 // must 281 // call copy() explicitly. 282 LazyComponentWithArgs() = default; // LCOV_EXCL_LINE 283 LazyComponentWithArgs(const LazyComponentWithArgs&) = default; 284 LazyComponentWithArgs& operator=(const LazyComponentWithArgs&) = default; 285 286 LazyComponentWithArgs copy() const; 287 void destroy() const; 288 289 ComponentInterface* component; 290 }; 291 292 union { 293 // Valid iff kind is BINDING_FOR_CONSTRUCTED_OBJECT. 294 BindingForConstructedObject binding_for_constructed_object; 295 296 // Valid iff kind is BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_[NO_]ALLOCATION 297 // or BINDING_FOR_OBJECT_TO_CONSTRUCT_WITH_UNKNOWN_ALLOCATION. 298 BindingForObjectToConstruct binding_for_object_to_construct; 299 300 // Valid iff kind is MULTIBINDING_FOR_CONSTRUCTED_OBJECT. 301 MultibindingForConstructedObject multibinding_for_constructed_object; 302 303 // Valid iff kind is MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_[NO_]ALLOCATION. 304 MultibindingForObjectToConstruct multibinding_for_object_to_construct; 305 306 // Valid iff kind is MULTIBINDING_VECTOR_CREATOR. 307 MultibindingVectorCreator multibinding_vector_creator; 308 309 // Valid iff kind is COMPRESSED_BINDING. 310 CompressedBinding compressed_binding; 311 312 // Valid iff kind is LAZY_COMPONENT_WITH_NO_ARGS, REPLACED_LAZY_COMPONENT_WITH_NO_ARGS or 313 // REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS. 314 LazyComponentWithNoArgs lazy_component_with_no_args; 315 316 // Valid iff kind is LAZY_COMPONENT_WITH_ARGS, REPLACED_LAZY_COMPONENT_WITH_ARGS or 317 // REPLACEMENT_LAZY_COMPONENT_WITH_ARGS. 318 LazyComponentWithArgs lazy_component_with_args; 319 }; 320 321 // We use a custom method instead of a real copy constructor so that all copies are explicit (since copying is a 322 // fairly expensive operation). 323 ComponentStorageEntry copy() const; 324 325 // We use a custom method instead of a real destructor, so that we can hold these in a std::vector but still destroy 326 // them when desired. 327 void destroy() const; 328 }; 329 330 // We can't have this assert in debug mode because we add debug-only fields that increase the size. 331 #if !FRUIT_EXTRA_DEBUG 332 // This is not required for correctness, but 4 64-bit words should be enough to hold this object, if not we'd end up 333 // using more memory/CPU than expected. 334 static_assert(sizeof(ComponentStorageEntry) <= 4 * sizeof(std::uint64_t), 335 "Error: a ComponentStorageEntry doesn't fit in 32 bytes as we expected"); 336 #endif 337 338 } // namespace impl 339 } // namespace fruit 340 341 #include <fruit/impl/component_storage/component_storage_entry.defn.h> 342 343 #endif // FRUIT_COMPONENT_STORAGE_ENTRY_H 344