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_BINDING_NORMALIZATION_H 18 #define FRUIT_BINDING_NORMALIZATION_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 "binding_normalization.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/arena_allocator.h> 27 #include <fruit/impl/data_structures/fixed_size_allocator.h> 28 #include <fruit/impl/normalized_component_storage/normalized_component_storage.h> 29 #include <fruit/impl/util/hash_helpers.h> 30 31 namespace fruit { 32 namespace impl { 33 34 /** 35 * This struct contains helper functions used for binding normalization. 36 * They are wrapped in a struct so that Fruit classes can easily declare to be friend 37 * of all these. 38 */ 39 class BindingNormalization { 40 public: 41 // Stores an element of the form (c_type_id, -> undo_info) for each binding compression that was 42 // performed. 43 // These are used to undo binding compression after applying it (if necessary). 44 using BindingCompressionInfoMap = 45 HashMapWithArenaAllocator<TypeId, NormalizedComponentStorage::CompressedBindingUndoInfo>; 46 47 using LazyComponentWithNoArgs = ComponentStorageEntry::LazyComponentWithNoArgs; 48 using LazyComponentWithArgs = ComponentStorageEntry::LazyComponentWithArgs; 49 50 using LazyComponentWithNoArgsSet = NormalizedComponentStorage::LazyComponentWithNoArgsSet; 51 using LazyComponentWithArgsSet = NormalizedComponentStorage::LazyComponentWithArgsSet; 52 53 using LazyComponentWithNoArgsReplacementMap = NormalizedComponentStorage::LazyComponentWithNoArgsReplacementMap; 54 using LazyComponentWithArgsReplacementMap = NormalizedComponentStorage::LazyComponentWithArgsReplacementMap; 55 56 /** 57 * Normalizes the toplevel entries and performs binding compression. 58 * This does *not* keep track of what binding compressions were performed, so they can't be undone. When we might need 59 * to undo the binding compression, use normalizeBindingsWithUndoableBindingCompression() instead. 60 */ 61 static void normalizeBindingsWithPermanentBindingCompression( 62 FixedSizeVector<ComponentStorageEntry>&& toplevel_entries, 63 FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data, MemoryPool& memory_pool, 64 const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types, 65 std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>& bindings_vector, 66 std::unordered_map<TypeId, NormalizedMultibindingSet>& multibindings); 67 68 /** 69 * Normalizes the toplevel entries and performs binding compression, but keeps track of which compressions were 70 * performed so that we can later undo some of them if needed. 71 * This is more expensive than normalizeBindingsWithPermanentBindingCompression(), use that when it suffices. 72 */ 73 static void normalizeBindingsWithUndoableBindingCompression( 74 FixedSizeVector<ComponentStorageEntry>&& toplevel_entries, 75 FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data, MemoryPool& memory_pool, 76 MemoryPool& memory_pool_for_fully_expanded_components_maps, 77 MemoryPool& memory_pool_for_component_replacements_maps, 78 const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types, 79 std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>& bindings_vector, 80 std::unordered_map<TypeId, NormalizedMultibindingSet>& multibindings, 81 BindingCompressionInfoMap& bindingCompressionInfoMap, 82 LazyComponentWithNoArgsSet& fully_expanded_components_with_no_args, 83 LazyComponentWithArgsSet& fully_expanded_components_with_args, 84 LazyComponentWithNoArgsReplacementMap& component_with_no_args_replacements, 85 LazyComponentWithArgsReplacementMap& component_with_args_replacements); 86 87 static void normalizeBindingsAndAddTo( 88 FixedSizeVector<ComponentStorageEntry>&& toplevel_entries, MemoryPool& memory_pool, 89 const NormalizedComponentStorage& base_normalized_component, 90 FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data, 91 std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>& new_bindings_vector, 92 std::unordered_map<TypeId, NormalizedMultibindingSet>& multibindings); 93 94 private: 95 using multibindings_vector_elem_t = std::pair<ComponentStorageEntry, ComponentStorageEntry>; 96 using multibindings_vector_t = std::vector<multibindings_vector_elem_t, ArenaAllocator<multibindings_vector_elem_t>>; 97 98 /** 99 * Adds the multibindings in multibindings_vector to the `multibindings' map. 100 * Each element of multibindings_vector is a pair, where the first element is the multibinding and the second is the 101 * corresponding MULTIBINDING_VECTOR_CREATOR entry. 102 */ 103 static void addMultibindings(std::unordered_map<TypeId, NormalizedMultibindingSet>& multibindings, 104 FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data, 105 const multibindings_vector_t& multibindings_vector); 106 107 static void printLazyComponentInstallationLoop( 108 const std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>& entries_to_process, 109 const ComponentStorageEntry& last_entry); 110 111 /** 112 * Normalizes the toplevel entries (but doesn't perform binding compression). 113 */ 114 template <typename... Functors> 115 static void normalizeBindings(FixedSizeVector<ComponentStorageEntry>&& toplevel_entries, 116 FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data, 117 MemoryPool& memory_pool, MemoryPool& memory_pool_for_fully_expanded_components_maps, 118 MemoryPool& memory_pool_for_component_replacements_maps, 119 HashMapWithArenaAllocator<TypeId, ComponentStorageEntry>& binding_data_map, 120 Functors... functors); 121 122 struct BindingCompressionInfo { 123 TypeId i_type_id; 124 ComponentStorageEntry::BindingForObjectToConstruct::create_t create_i_with_compression; 125 }; 126 127 /** 128 * Normalizes the toplevel entries and performs binding compression. 129 * - SaveCompressedBindingUndoInfo should have an operator()(TypeId, CompressedBindingUndoInfo) that will be called 130 * with (c_type_id, undo_info) for each binding compression that was applied (and that therefore might need to be 131 * undone later). 132 */ 133 template <typename SaveCompressedBindingUndoInfo, typename SaveFullyExpandedComponentsWithNoArgs, 134 typename SaveFullyExpandedComponentsWithArgs, typename SaveComponentReplacementsWithNoArgs, 135 typename SaveComponentReplacementsWithArgs> 136 static void normalizeBindingsWithBindingCompression( 137 FixedSizeVector<ComponentStorageEntry>&& toplevel_entries, 138 FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data, MemoryPool& memory_pool, 139 MemoryPool& memory_pool_for_fully_expanded_components_maps, 140 MemoryPool& memory_pool_for_component_replacements_maps, 141 const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types, 142 std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>& bindings_vector, 143 std::unordered_map<TypeId, NormalizedMultibindingSet>& multibindings, 144 SaveCompressedBindingUndoInfo save_compressed_binding_undo_info, 145 SaveFullyExpandedComponentsWithNoArgs save_fully_expanded_components_with_no_args, 146 SaveFullyExpandedComponentsWithArgs save_fully_expanded_components_with_args, 147 SaveComponentReplacementsWithNoArgs save_component_replacements_with_no_args, 148 SaveComponentReplacementsWithArgs save_component_replacements_with_args); 149 150 /** 151 * bindingCompressionInfoMap is an output parameter. This function will store information on all performed binding 152 * compressions in that map, to allow them to be undone later, if necessary. 153 * compressed_bindings_map is a map CtypeId -> (ItypeId, bindingData) 154 * - SaveCompressedBindingUndoInfo should have an operator()(TypeId, CompressedBindingUndoInfo) that will be called 155 * with (c_type_id, undo_info) for each binding compression that was applied (and that therefore might need to be 156 * undone later). 157 */ 158 template <typename SaveCompressedBindingUndoInfo> 159 static std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>> 160 performBindingCompression(HashMapWithArenaAllocator<TypeId, ComponentStorageEntry>&& binding_data_map, 161 HashMapWithArenaAllocator<TypeId, BindingCompressionInfo>&& compressed_bindings_map, 162 MemoryPool& memory_pool, const multibindings_vector_t& multibindings_vector, 163 const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types, 164 SaveCompressedBindingUndoInfo save_compressed_binding_undo_info); 165 166 static void handlePreexistingLazyComponentWithArgsReplacement(ComponentStorageEntry& replaced_component_entry, 167 const ComponentStorageEntry& preexisting_replacement, 168 ComponentStorageEntry& new_replacement); 169 170 static void handlePreexistingLazyComponentWithNoArgsReplacement(ComponentStorageEntry& replaced_component_entry, 171 const ComponentStorageEntry& preexisting_replacement, 172 ComponentStorageEntry& new_replacement); 173 174 template <typename HandleCompressedBinding, typename HandleMultibinding, typename FindNormalizedBinding, 175 typename IsValidItr, typename IsNormalizedBindingItrForConstructedObject, typename GetObjectPtr, 176 typename GetCreate, typename IsComponentWithNoArgsAlreadyExpandedInNormalizedComponent, 177 typename IsComponentWithArgsAlreadyExpandedInNormalizedComponent, 178 typename SaveFullyExpandedComponentsWithNoArgs, typename SaveFullyExpandedComponentsWithArgs, 179 typename GetComponentWithNoArgsReplacementInNormalizedComponent, 180 typename GetComponentWithArgsReplacementInNormalizedComponent, 181 typename IsLazyComponentWithNoArgsIteratorValid, typename IsLazyComponentWithArgsIteratorValid, 182 typename DereferenceLazyComponentWithNoArgsIterator, typename DereferenceLazyComponentWithArgsIterator, 183 typename SaveComponentReplacementsWithNoArgs, typename SaveComponentReplacementsWithArgs> 184 struct BindingNormalizationFunctors { 185 186 /** 187 * This should have an operator()(ComponentStorageEntry&) that will be called for each COMPRESSED_BINDING entry. 188 */ 189 HandleCompressedBinding handle_compressed_binding; 190 191 /** 192 * This should have an 193 * operator()(ComponentStorageEntry& multibinding_entry, ComponentStorageEntry& multibinding_vector_creator_entry) 194 * that will be called for each multibinding entry. 195 */ 196 HandleMultibinding handle_multibinding; 197 198 /** 199 * This should have a 200 * NormalizedBindingItr operator()(TypeId) 201 * that returns a NormalizedBindingItr describing whether the binding is present in a base component (if any). 202 */ 203 FindNormalizedBinding find_normalized_binding; 204 205 /** 206 * This should have a 207 * bool operator()(NormalizedBindingItr) 208 */ 209 IsValidItr is_valid_itr; 210 211 /** 212 * This should have a 213 * bool operator()(NormalizedBindingItr) 214 * (that can only be used when IsValidItr returns true). 215 */ 216 IsNormalizedBindingItrForConstructedObject is_normalized_binding_itr_for_constructed_object; 217 218 /** 219 * This should have a 220 * ComponentStorageEntry::BindingForConstructedObject::object_ptr_t operator()(NormalizedBindingItr) 221 * (that can only be used when IsNormalizedBindingItrForConstructedObject returns true). 222 */ 223 GetObjectPtr get_object_ptr; 224 225 /** 226 * This should have a 227 * ComponentStorageEntry::BindingForObjectToConstruct::create_t operator()(NormalizedBindingItr) 228 * (that can only be used when IsNormalizedBindingItrForConstructedObject returns false). 229 */ 230 GetCreate get_create; 231 232 IsComponentWithNoArgsAlreadyExpandedInNormalizedComponent 233 is_component_with_no_args_already_expanded_in_normalized_component; 234 IsComponentWithArgsAlreadyExpandedInNormalizedComponent 235 is_component_with_args_already_expanded_in_normalized_component; 236 SaveFullyExpandedComponentsWithNoArgs save_fully_expanded_components_with_no_args; 237 SaveFullyExpandedComponentsWithArgs save_fully_expanded_components_with_args; 238 239 /** 240 * Gets a LazyComponentWithNoArgsIterator pointing to the replacement for the given lazy component in the normalized 241 * component (if any). 242 */ 243 GetComponentWithNoArgsReplacementInNormalizedComponent 244 get_component_with_no_args_replacement_in_normalized_component; 245 246 /** 247 * Gets a LazyComponentWithArgsIterator pointing to the replacement for the given lazy component in the normalized 248 * component (if any). 249 */ 250 GetComponentWithArgsReplacementInNormalizedComponent get_component_with_args_replacement_in_normalized_component; 251 252 IsLazyComponentWithNoArgsIteratorValid is_lazy_component_with_no_args_iterator_valid; 253 IsLazyComponentWithArgsIteratorValid is_lazy_component_with_args_iterator_valid; 254 255 DereferenceLazyComponentWithNoArgsIterator dereference_lazy_component_with_no_args_iterator; 256 DereferenceLazyComponentWithArgsIterator dereference_lazy_component_with_args_iterator; 257 258 SaveComponentReplacementsWithNoArgs save_component_replacements_with_no_args; 259 SaveComponentReplacementsWithArgs save_component_replacements_with_args; 260 }; 261 262 /** 263 * This struct groups all data structures available during binding normalization, to avoid mentioning them in all 264 * handle*Binding functions below. 265 */ 266 template <typename... Functors> 267 struct BindingNormalizationContext { 268 FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data; 269 MemoryPool& memory_pool; 270 MemoryPool& memory_pool_for_fully_expanded_components_maps; 271 MemoryPool& memory_pool_for_component_replacements_maps; 272 HashMapWithArenaAllocator<TypeId, ComponentStorageEntry>& binding_data_map; 273 BindingNormalizationFunctors<Functors...> functors; 274 275 // These are in reversed order (note that toplevel_entries must also be in reverse order). 276 std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>> entries_to_process; 277 278 // These sets contain the lazy components whose expansion has already completed. 279 LazyComponentWithNoArgsSet fully_expanded_components_with_no_args = 280 NormalizedComponentStorage::createLazyComponentWithNoArgsSet(20 /* capacity */, 281 memory_pool_for_fully_expanded_components_maps); 282 LazyComponentWithArgsSet fully_expanded_components_with_args = 283 NormalizedComponentStorage::createLazyComponentWithArgsSet(20 /* capacity */, 284 memory_pool_for_fully_expanded_components_maps); 285 286 // These sets contain the elements with kind *_END_MARKER in entries_to_process. 287 // For component with args, these sets do *not* own the objects, entries_to_process does. 288 LazyComponentWithNoArgsSet components_with_no_args_with_expansion_in_progress = 289 NormalizedComponentStorage::createLazyComponentWithNoArgsSet(20 /* capacity */, memory_pool); 290 LazyComponentWithArgsSet components_with_args_with_expansion_in_progress = 291 NormalizedComponentStorage::createLazyComponentWithArgsSet(20 /* capacity */, memory_pool); 292 293 // These sets contain Component replacements, as mappings componentToReplace->replacementComponent. 294 LazyComponentWithNoArgsReplacementMap component_with_no_args_replacements = 295 NormalizedComponentStorage::createLazyComponentWithNoArgsReplacementMap( 296 20 /* capacity */, memory_pool_for_component_replacements_maps); 297 LazyComponentWithArgsReplacementMap component_with_args_replacements = 298 NormalizedComponentStorage::createLazyComponentWithArgsReplacementMap( 299 20 /* capacity */, memory_pool_for_component_replacements_maps); 300 301 BindingNormalizationContext(FixedSizeVector<ComponentStorageEntry>& toplevel_entries, 302 FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data, 303 MemoryPool& memory_pool, MemoryPool& memory_pool_for_fully_expanded_components_maps, 304 MemoryPool& memory_pool_for_component_replacements_maps, 305 HashMapWithArenaAllocator<TypeId, ComponentStorageEntry>& binding_data_map, 306 BindingNormalizationFunctors<Functors...> functors); 307 308 BindingNormalizationContext(const BindingNormalizationContext&) = delete; 309 BindingNormalizationContext(BindingNormalizationContext&&) = delete; 310 311 BindingNormalizationContext& operator=(const BindingNormalizationContext&) = delete; 312 BindingNormalizationContext& operator=(BindingNormalizationContext&&) = delete; 313 314 ~BindingNormalizationContext(); 315 }; 316 317 template <typename... Params> 318 static void handleBindingForConstructedObject(BindingNormalizationContext<Params...>& context); 319 320 template <typename... Params> 321 static void handleBindingForObjectToConstructThatNeedsAllocation(BindingNormalizationContext<Params...>& context); 322 323 template <typename... Params> 324 static void handleBindingForObjectToConstructThatNeedsNoAllocation(BindingNormalizationContext<Params...>& context); 325 326 template <typename... Params> 327 static void handleCompressedBinding(BindingNormalizationContext<Params...>& context); 328 329 template <typename... Params> 330 static void handleMultibinding(BindingNormalizationContext<Params...>& context); 331 332 template <typename... Params> 333 static void handleMultibindingVectorCreator(BindingNormalizationContext<Params...>& context); 334 335 template <typename... Params> 336 static void handleComponentWithoutArgsEndMarker(BindingNormalizationContext<Params...>& context); 337 338 template <typename... Params> 339 static void handleComponentWithArgsEndMarker(BindingNormalizationContext<Params...>& context); 340 341 template <typename... Params> 342 static void handleReplacedLazyComponentWithArgs(BindingNormalizationContext<Params...>& context); 343 344 template <typename... Params> 345 static void handleReplacedLazyComponentWithNoArgs(BindingNormalizationContext<Params...>& context); 346 347 template <typename... Params> 348 static void handleLazyComponentWithArgs(BindingNormalizationContext<Params...>& context); 349 350 template <typename... Params> 351 static void handleLazyComponentWithNoArgs(BindingNormalizationContext<Params...>& context); 352 353 template <typename... Params> 354 static void performComponentReplacement(BindingNormalizationContext<Params...>& context, 355 const ComponentStorageEntry& replacement); 356 357 static void printMultipleBindingsError(TypeId type); 358 359 static void printIncompatibleComponentReplacementsError(const ComponentStorageEntry& replaced_component_entry, 360 const ComponentStorageEntry& replacement_component_entry1, 361 const ComponentStorageEntry& replacement_component_entry2); 362 363 static void 364 printComponentReplacementFailedBecauseTargetAlreadyExpanded(const ComponentStorageEntry& replaced_component_entry, 365 const ComponentStorageEntry& replacement_component_entry); 366 }; 367 368 } // namespace impl 369 } // namespace fruit 370 371 #endif // FRUIT_BINDING_NORMALIZATION_H 372