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_NORMALIZED_COMPONENT_STORAGE_H 18 #define FRUIT_NORMALIZED_COMPONENT_STORAGE_H 19 20 #if !IN_FRUIT_CPP_FILE 21 // We don't want to include it in public headers to save some compile time. 22 #error "normalized_component_storage.h included in non-cpp file." 23 #endif 24 25 #include <fruit/impl/component_storage/component_storage_entry.h> 26 #include <fruit/impl/data_structures/fixed_size_allocator.h> 27 #include <fruit/impl/data_structures/semistatic_graph.h> 28 #include <fruit/impl/data_structures/semistatic_map.h> 29 #include <fruit/impl/fruit_internal_forward_decls.h> 30 #include <fruit/impl/normalized_component_storage/normalized_bindings.h> 31 #include <fruit/impl/util/hash_helpers.h> 32 #include <fruit/impl/util/type_info.h> 33 34 #include <memory> 35 #include <unordered_map> 36 37 namespace fruit { 38 namespace impl { 39 40 /** 41 * Similar to ComponentStorage, but used a normalized representation to minimize the amount 42 * of work needed to turn this into an injector. However, adding bindings to a normalized 43 * component is slower than adding them to a simple component. 44 */ 45 class NormalizedComponentStorage { 46 public: 47 struct CompressedBindingUndoInfo { 48 TypeId i_type_id; 49 ComponentStorageEntry::BindingForObjectToConstruct i_binding; 50 ComponentStorageEntry::BindingForObjectToConstruct c_binding; 51 }; 52 53 // A map from c_type_id to the corresponding CompressedBindingUndoInfo (if binding compression was performed for 54 // c_type_id). 55 using BindingCompressionInfoMap = HashMapWithArenaAllocator<TypeId, CompressedBindingUndoInfo>; 56 using BindingCompressionInfoMapAllocator = BindingCompressionInfoMap::allocator_type; 57 58 using LazyComponentWithNoArgs = ComponentStorageEntry::LazyComponentWithNoArgs; 59 using LazyComponentWithArgs = ComponentStorageEntry::LazyComponentWithArgs; 60 61 struct HashLazyComponentWithNoArgs { operatorHashLazyComponentWithNoArgs62 std::size_t operator()(const LazyComponentWithNoArgs& x) const { 63 return x.hashCode(); 64 } 65 }; 66 67 struct LazyComponentWithArgsEqualTo { operatorLazyComponentWithArgsEqualTo68 bool operator()(const LazyComponentWithArgs& x, const LazyComponentWithArgs& y) const { 69 return *x.component == *y.component; 70 } 71 }; 72 73 struct HashLazyComponentWithArgs { operatorHashLazyComponentWithArgs74 std::size_t operator()(const LazyComponentWithArgs& x) const { 75 return x.component->hashCode(); 76 } 77 }; 78 79 using LazyComponentWithNoArgsSet = HashSetWithArenaAllocator<LazyComponentWithNoArgs, HashLazyComponentWithNoArgs, 80 std::equal_to<LazyComponentWithNoArgs>>; 81 using LazyComponentWithArgsSet = 82 HashSetWithArenaAllocator<LazyComponentWithArgs, HashLazyComponentWithArgs, LazyComponentWithArgsEqualTo>; 83 84 using LazyComponentWithNoArgsReplacementMap = 85 HashMapWithArenaAllocator<LazyComponentWithNoArgs, ComponentStorageEntry, 86 NormalizedComponentStorage::HashLazyComponentWithNoArgs, 87 std::equal_to<LazyComponentWithNoArgs>>; 88 using LazyComponentWithArgsReplacementMap = 89 HashMapWithArenaAllocator<LazyComponentWithArgs, ComponentStorageEntry, 90 NormalizedComponentStorage::HashLazyComponentWithArgs, 91 NormalizedComponentStorage::LazyComponentWithArgsEqualTo>; 92 93 static LazyComponentWithNoArgsSet createLazyComponentWithNoArgsSet(size_t capacity, MemoryPool& memory_pool); 94 static LazyComponentWithArgsSet createLazyComponentWithArgsSet(size_t capacity, MemoryPool& memory_pool); 95 96 static LazyComponentWithNoArgsReplacementMap createLazyComponentWithNoArgsReplacementMap(size_t capacity, 97 MemoryPool& memory_pool); 98 static LazyComponentWithArgsReplacementMap createLazyComponentWithArgsReplacementMap(size_t capacity, 99 MemoryPool& memory_pool); 100 101 private: 102 // A graph with types as nodes (each node stores the BindingData for the type) and dependencies as edges. 103 // For types that have a constructed object already, the corresponding node is stored as terminal node. 104 SemistaticGraph<TypeId, NormalizedBinding> bindings; 105 106 // Maps the type index of a type T to the corresponding NormalizedMultibindingSet. 107 std::unordered_map<TypeId, NormalizedMultibindingSet> multibindings; 108 109 // Contains data on the set of types that can be allocated using this component. 110 FixedSizeAllocator::FixedSizeAllocatorData fixed_size_allocator_data; 111 112 // The MemoryPool used to allocate bindingCompressionInfoMap, fully_expanded_components_with_no_args and 113 // fully_expanded_components_with_args. 114 MemoryPool normalized_component_memory_pool; 115 116 // Stores information on binding compression that was performed in bindings of this object. 117 // See also the documentation for BindingCompressionInfoMap. 118 BindingCompressionInfoMap binding_compression_info_map; 119 120 LazyComponentWithNoArgsSet fully_expanded_components_with_no_args; 121 LazyComponentWithArgsSet fully_expanded_components_with_args; 122 123 LazyComponentWithNoArgsReplacementMap component_with_no_args_replacements; 124 LazyComponentWithArgsReplacementMap component_with_args_replacements; 125 126 friend class InjectorStorage; 127 friend class BindingNormalization; 128 129 public: 130 using Graph = SemistaticGraph<TypeId, NormalizedBinding>; 131 132 NormalizedComponentStorage() = delete; 133 134 NormalizedComponentStorage(NormalizedComponentStorage&&) = delete; 135 NormalizedComponentStorage(const NormalizedComponentStorage&) = delete; 136 137 NormalizedComponentStorage& operator=(NormalizedComponentStorage&&) = delete; 138 NormalizedComponentStorage& operator=(const NormalizedComponentStorage&) = delete; 139 140 // These are just used as tags to select the desired constructor. 141 struct WithUndoableCompression {}; 142 struct WithPermanentCompression {}; 143 144 /** 145 * The MemoryPool is only used during construction, the constructed object *can* outlive the memory pool. 146 */ 147 NormalizedComponentStorage(ComponentStorage&& component, 148 const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types, MemoryPool& memory_pool, 149 WithUndoableCompression); 150 151 /** 152 * The MemoryPool is only used during construction, the constructed object *can* outlive the memory pool. 153 */ 154 NormalizedComponentStorage(ComponentStorage&& component, 155 const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types, MemoryPool& memory_pool, 156 WithPermanentCompression); 157 158 // We don't use the default destructor because that will require the inclusion of 159 // the Boost's hashmap header. We define this in the cpp file instead. 160 ~NormalizedComponentStorage() noexcept; 161 }; 162 163 } // namespace impl 164 } // namespace fruit 165 166 #include <fruit/impl/normalized_component_storage/normalized_component_storage.defn.h> 167 168 #endif // FRUIT_NORMALIZED_COMPONENT_STORAGE_H 169