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