• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define IN_FRUIT_CPP_FILE 1
18 
19 #include <algorithm>
20 #include <cstdlib>
21 #include <fruit/impl/util/type_info.h>
22 #include <iostream>
23 #include <memory>
24 #include <vector>
25 
26 #include <fruit/impl/data_structures/semistatic_graph.templates.h>
27 #include <fruit/impl/injector/injector_storage.h>
28 #include <fruit/impl/normalized_component_storage/binding_normalization.h>
29 #include <fruit/impl/normalized_component_storage/binding_normalization.templates.h>
30 #include <fruit/impl/normalized_component_storage/normalized_component_storage.h>
31 
32 using std::cout;
33 using std::endl;
34 
35 namespace fruit {
36 namespace impl {
37 
printLazyComponentInstallationLoop(const std::vector<ComponentStorageEntry,ArenaAllocator<ComponentStorageEntry>> & entries_to_process,const ComponentStorageEntry & last_entry)38 void BindingNormalization::printLazyComponentInstallationLoop(
39     const std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>& entries_to_process,
40     const ComponentStorageEntry& last_entry) {
41   std::cerr << "Found a loop while expanding components passed to PartialComponent::install()." << std::endl;
42   std::cerr << "Component installation trace (from top-level to the most deeply-nested):" << std::endl;
43   for (const ComponentStorageEntry& entry : entries_to_process) {
44     switch (entry.kind) {
45     case ComponentStorageEntry::Kind::COMPONENT_WITH_ARGS_END_MARKER:
46       if (entry.type_id == last_entry.type_id &&
47           last_entry.kind == ComponentStorageEntry::Kind::LAZY_COMPONENT_WITH_ARGS &&
48           *entry.lazy_component_with_args.component == *last_entry.lazy_component_with_args.component) {
49         std::cerr << "<-- The loop starts here" << std::endl;
50       }
51       std::cerr << std::string(entry.lazy_component_with_args.component->getFunTypeId()) << std::endl;
52       break;
53 
54     case ComponentStorageEntry::Kind::COMPONENT_WITHOUT_ARGS_END_MARKER:
55       if (entry.type_id == last_entry.type_id &&
56           last_entry.kind == ComponentStorageEntry::Kind::LAZY_COMPONENT_WITH_NO_ARGS &&
57           entry.lazy_component_with_no_args.erased_fun == last_entry.lazy_component_with_no_args.erased_fun) {
58         std::cerr << "<-- The loop starts here" << std::endl;
59       }
60       std::cerr << std::string(entry.type_id) << std::endl;
61       break;
62 
63     default:
64       break;
65     }
66   }
67 
68   switch (last_entry.kind) { // LCOV_EXCL_BR_LINE
69   case ComponentStorageEntry::Kind::LAZY_COMPONENT_WITH_ARGS:
70     std::cerr << std::string(last_entry.lazy_component_with_args.component->getFunTypeId()) << std::endl;
71     break;
72 
73   case ComponentStorageEntry::Kind::LAZY_COMPONENT_WITH_NO_ARGS:
74     std::cerr << std::string(last_entry.type_id) << std::endl;
75     break;
76 
77   default:
78     FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
79   }
80 
81   exit(1);
82 }
83 
printMultipleBindingsError(TypeId type)84 void BindingNormalization::printMultipleBindingsError(TypeId type) {
85   std::cerr << "Fatal injection error: the type " << type.type_info->name()
86             << " was provided more than once, with different bindings." << std::endl
87             << "This was not caught at compile time because at least one of the involved components bound this type "
88             << "but didn't expose it in the component signature." << std::endl
89             << "If the type has a default constructor or an Inject annotation, this problem may arise even if this "
90             << "type is bound/provided by only one component (and then hidden), if this type is auto-injected in "
91             << "another component." << std::endl
92             << "If the source of the problem is unclear, try exposing this type in all the component signatures where "
93             << "it's bound; if no component hides it this can't happen." << std::endl;
94   exit(1);
95 }
96 
printIncompatibleComponentReplacementsError(const ComponentStorageEntry & replaced_component_entry,const ComponentStorageEntry & replacement_component_entry1,const ComponentStorageEntry & replacement_component_entry2)97 void BindingNormalization::printIncompatibleComponentReplacementsError(
98     const ComponentStorageEntry& replaced_component_entry, const ComponentStorageEntry& replacement_component_entry1,
99     const ComponentStorageEntry& replacement_component_entry2) {
100   using fun_t = void (*)();
101 
102   fun_t replaced_fun_address;
103   switch (replaced_component_entry.kind) {
104   case ComponentStorageEntry::Kind::REPLACED_LAZY_COMPONENT_WITH_ARGS:
105     replaced_fun_address = replaced_component_entry.lazy_component_with_args.component->erased_fun;
106     break;
107 
108   case ComponentStorageEntry::Kind::REPLACED_LAZY_COMPONENT_WITH_NO_ARGS:
109     replaced_fun_address = replaced_component_entry.lazy_component_with_no_args.erased_fun;
110     break;
111 
112   default:
113     FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
114   }
115 
116   fun_t replacement_fun_address1;
117   switch (replacement_component_entry1.kind) {
118   case ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_ARGS:
119     replacement_fun_address1 = replacement_component_entry1.lazy_component_with_args.component->erased_fun;
120     break;
121 
122   case ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS:
123     replacement_fun_address1 = replacement_component_entry1.lazy_component_with_no_args.erased_fun;
124     break;
125 
126   default:
127     FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
128   }
129 
130   fun_t replacement_fun_address2;
131   switch (replacement_component_entry2.kind) {
132   case ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_ARGS:
133     replacement_fun_address2 = replacement_component_entry2.lazy_component_with_args.component->erased_fun;
134     break;
135 
136   case ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS:
137     replacement_fun_address2 = replacement_component_entry2.lazy_component_with_no_args.erased_fun;
138     break;
139 
140   default:
141     FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
142   }
143 
144   constexpr static bool function_pointers_have_same_size = sizeof(void*) == sizeof(fun_t);
145   if (function_pointers_have_same_size) {
146     std::cerr << "Fatal injection error: the component function at " << reinterpret_cast<void*>(replaced_fun_address)
147               << " with signature " << std::string(replaced_component_entry.type_id)
148               << " was replaced (using .replace(...).with(...)) with both the component function at "
149               << reinterpret_cast<void*>(replacement_fun_address1) << " with signature "
150               << std::string(replacement_component_entry1.type_id) << " and the component function at "
151               << reinterpret_cast<void*>(replacement_fun_address2) << " with signature "
152               << std::string(replacement_component_entry2.type_id) << " ." << std::endl;
153   } else {
154     std::cerr << "Fatal injection error: a component function with signature "
155               << std::string(replaced_component_entry.type_id)
156               << " was replaced (using .replace(...).with(...)) with both a component function with signature "
157               << std::string(replacement_component_entry1.type_id) << " and another component function with signature "
158               << std::string(replacement_component_entry2.type_id) << " ." << std::endl;
159   }
160   exit(1);
161 }
162 
printComponentReplacementFailedBecauseTargetAlreadyExpanded(const ComponentStorageEntry & replaced_component_entry,const ComponentStorageEntry & replacement_component_entry)163 void BindingNormalization::printComponentReplacementFailedBecauseTargetAlreadyExpanded(
164     const ComponentStorageEntry& replaced_component_entry, const ComponentStorageEntry& replacement_component_entry) {
165   using fun_t = void (*)();
166 
167   fun_t replaced_fun_address;
168   switch (replaced_component_entry.kind) {
169   case ComponentStorageEntry::Kind::REPLACED_LAZY_COMPONENT_WITH_ARGS:
170     replaced_fun_address = replaced_component_entry.lazy_component_with_args.component->erased_fun;
171     break;
172 
173   case ComponentStorageEntry::Kind::REPLACED_LAZY_COMPONENT_WITH_NO_ARGS:
174     replaced_fun_address = replaced_component_entry.lazy_component_with_no_args.erased_fun;
175     break;
176 
177   default:
178     FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
179   }
180 
181   fun_t replacement_fun_address1;
182   switch (replacement_component_entry.kind) {
183   case ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_ARGS:
184     replacement_fun_address1 = replacement_component_entry.lazy_component_with_args.component->erased_fun;
185     break;
186 
187   case ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS:
188     replacement_fun_address1 = replacement_component_entry.lazy_component_with_no_args.erased_fun;
189     break;
190 
191   default:
192     FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
193   }
194 
195   constexpr static bool function_pointers_have_same_size = sizeof(void*) == sizeof(fun_t);
196   if (function_pointers_have_same_size) {
197     std::cerr << "Fatal injection error: unable to replace (using .replace(...).with(...)) the component function at "
198               << reinterpret_cast<void*>(replaced_fun_address) << " with signature "
199               << std::string(replaced_component_entry.type_id) << " with the component function at "
200               << reinterpret_cast<void*>(replacement_fun_address1) << " with signature "
201               << std::string(replacement_component_entry.type_id)
202               << " because the former component function was installed before the .replace(...).with(...)." << std::endl
203               << "You should change the order of installation of subcomponents so that .replace(...).with(...) is "
204               << "processed before the installation of the component to replace.";
205   } else {
206     std::cerr << "Fatal injection error: unable to replace (using .replace(...).with(...)) a component function with "
207               << "signature " << std::string(replaced_component_entry.type_id)
208               << " with a component function at with signature " << std::string(replacement_component_entry.type_id)
209               << " because the former component function was installed before the .replace(...).with(...)." << std::endl
210               << "You should change the order of installation of subcomponents so that .replace(...).with(...) is "
211               << "processed before the installation of the component to replace.";
212   }
213   exit(1);
214 }
215 
addMultibindings(std::unordered_map<TypeId,NormalizedMultibindingSet> & multibindings,FixedSizeAllocator::FixedSizeAllocatorData & fixed_size_allocator_data,const multibindings_vector_t & multibindingsVector)216 void BindingNormalization::addMultibindings(std::unordered_map<TypeId, NormalizedMultibindingSet>& multibindings,
217                                             FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data,
218                                             const multibindings_vector_t& multibindingsVector) {
219 
220 #if FRUIT_EXTRA_DEBUG
221   std::cout << "InjectorStorage: adding multibindings:" << std::endl;
222 #endif
223   // Now we must merge multiple bindings for the same type.
224   for (auto i = multibindingsVector.begin(); i != multibindingsVector.end(); ++i) {
225     const ComponentStorageEntry& multibinding_entry = i->first;
226     const ComponentStorageEntry& multibinding_vector_creator_entry = i->second;
227     FruitAssert(multibinding_entry.kind ==
228                     ComponentStorageEntry::Kind::MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION ||
229                 multibinding_entry.kind ==
230                     ComponentStorageEntry::Kind::MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION ||
231                 multibinding_entry.kind == ComponentStorageEntry::Kind::MULTIBINDING_FOR_CONSTRUCTED_OBJECT);
232     FruitAssert(multibinding_vector_creator_entry.kind == ComponentStorageEntry::Kind::MULTIBINDING_VECTOR_CREATOR);
233     NormalizedMultibindingSet& b = multibindings[multibinding_entry.type_id];
234 
235     // Might be set already, but we need to set it if there was no multibinding for this type.
236     b.get_multibindings_vector = multibinding_vector_creator_entry.multibinding_vector_creator.get_multibindings_vector;
237 
238     switch (i->first.kind) { // LCOV_EXCL_BR_LINE
239     case ComponentStorageEntry::Kind::MULTIBINDING_FOR_CONSTRUCTED_OBJECT: {
240       NormalizedMultibinding normalized_multibinding;
241       normalized_multibinding.is_constructed = true;
242       normalized_multibinding.object = i->first.multibinding_for_constructed_object.object_ptr;
243       b.elems.push_back(normalized_multibinding);
244     } break;
245 
246     case ComponentStorageEntry::Kind::MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION: {
247       fixed_size_allocator_data.addExternallyAllocatedType(i->first.type_id);
248       NormalizedMultibinding normalized_multibinding;
249       normalized_multibinding.is_constructed = false;
250       normalized_multibinding.create = i->first.multibinding_for_object_to_construct.create;
251       b.elems.push_back(normalized_multibinding);
252     } break;
253 
254     case ComponentStorageEntry::Kind::MULTIBINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION: {
255       fixed_size_allocator_data.addType(i->first.type_id);
256       NormalizedMultibinding normalized_multibinding;
257       normalized_multibinding.is_constructed = false;
258       normalized_multibinding.create = i->first.multibinding_for_object_to_construct.create;
259       b.elems.push_back(normalized_multibinding);
260     } break;
261 
262     default:
263 #if FRUIT_EXTRA_DEBUG
264       std::cerr << "Unexpected kind: " << (std::size_t)i->first.kind << std::endl;
265 #endif
266       FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
267     }
268   }
269 }
270 
normalizeBindingsWithUndoableBindingCompression(FixedSizeVector<ComponentStorageEntry> && toplevel_entries,FixedSizeAllocator::FixedSizeAllocatorData & fixed_size_allocator_data,MemoryPool & memory_pool,MemoryPool & memory_pool_for_fully_expanded_components_maps,MemoryPool & memory_pool_for_component_replacements_maps,const std::vector<TypeId,ArenaAllocator<TypeId>> & exposed_types,std::vector<ComponentStorageEntry,ArenaAllocator<ComponentStorageEntry>> & bindings_vector,std::unordered_map<TypeId,NormalizedMultibindingSet> & multibindings,BindingCompressionInfoMap & bindingCompressionInfoMap,LazyComponentWithNoArgsSet & fully_expanded_components_with_no_args,LazyComponentWithArgsSet & fully_expanded_components_with_args,LazyComponentWithNoArgsReplacementMap & component_with_no_args_replacements,LazyComponentWithArgsReplacementMap & component_with_args_replacements)271 void BindingNormalization::normalizeBindingsWithUndoableBindingCompression(
272     FixedSizeVector<ComponentStorageEntry>&& toplevel_entries,
273     FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data, MemoryPool& memory_pool,
274     MemoryPool& memory_pool_for_fully_expanded_components_maps, MemoryPool& memory_pool_for_component_replacements_maps,
275     const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types,
276     std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>& bindings_vector,
277     std::unordered_map<TypeId, NormalizedMultibindingSet>& multibindings,
278     BindingCompressionInfoMap& bindingCompressionInfoMap,
279     LazyComponentWithNoArgsSet& fully_expanded_components_with_no_args,
280     LazyComponentWithArgsSet& fully_expanded_components_with_args,
281     LazyComponentWithNoArgsReplacementMap& component_with_no_args_replacements,
282     LazyComponentWithArgsReplacementMap& component_with_args_replacements) {
283 
284   FruitAssert(bindingCompressionInfoMap.empty());
285 
286   normalizeBindingsWithBindingCompression(
287       std::move(toplevel_entries), fixed_size_allocator_data, memory_pool,
288       memory_pool_for_fully_expanded_components_maps, memory_pool_for_component_replacements_maps, exposed_types,
289       bindings_vector, multibindings,
290       [&bindingCompressionInfoMap](TypeId c_type_id, NormalizedComponentStorage::CompressedBindingUndoInfo undo_info) {
291         bindingCompressionInfoMap[c_type_id] = undo_info;
292       },
293       [&fully_expanded_components_with_no_args, &memory_pool](LazyComponentWithNoArgsSet& fully_expanded_components) {
294         fully_expanded_components_with_no_args = std::move(fully_expanded_components);
295         fully_expanded_components = NormalizedComponentStorage::createLazyComponentWithNoArgsSet(0, memory_pool);
296       },
297       [&fully_expanded_components_with_args, &memory_pool](LazyComponentWithArgsSet& fully_expanded_components) {
298         fully_expanded_components_with_args = std::move(fully_expanded_components);
299         fully_expanded_components = NormalizedComponentStorage::createLazyComponentWithArgsSet(0, memory_pool);
300       },
301       [&component_with_no_args_replacements, &memory_pool](LazyComponentWithNoArgsReplacementMap& component_replacements) {
302         component_with_no_args_replacements = std::move(component_replacements);
303         component_replacements = NormalizedComponentStorage::createLazyComponentWithNoArgsReplacementMap(0, memory_pool);
304       },
305       [&component_with_args_replacements, &memory_pool](LazyComponentWithArgsReplacementMap& component_replacements) {
306         component_with_args_replacements = std::move(component_replacements);
307         component_replacements = NormalizedComponentStorage::createLazyComponentWithArgsReplacementMap(0, memory_pool);
308       });
309 }
310 
normalizeBindingsWithPermanentBindingCompression(FixedSizeVector<ComponentStorageEntry> && toplevel_entries,FixedSizeAllocator::FixedSizeAllocatorData & fixed_size_allocator_data,MemoryPool & memory_pool,const std::vector<TypeId,ArenaAllocator<TypeId>> & exposed_types,std::vector<ComponentStorageEntry,ArenaAllocator<ComponentStorageEntry>> & bindings_vector,std::unordered_map<TypeId,NormalizedMultibindingSet> & multibindings)311 void BindingNormalization::normalizeBindingsWithPermanentBindingCompression(
312     FixedSizeVector<ComponentStorageEntry>&& toplevel_entries,
313     FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data, MemoryPool& memory_pool,
314     const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types,
315     std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>& bindings_vector,
316     std::unordered_map<TypeId, NormalizedMultibindingSet>& multibindings) {
317   normalizeBindingsWithBindingCompression(
318       std::move(toplevel_entries), fixed_size_allocator_data, memory_pool, memory_pool, memory_pool, exposed_types,
319       bindings_vector, multibindings, [](TypeId, NormalizedComponentStorage::CompressedBindingUndoInfo) {},
320       [](LazyComponentWithNoArgsSet&) {}, [](LazyComponentWithArgsSet&) {},
321       [](LazyComponentWithNoArgsReplacementMap&) {}, [](LazyComponentWithArgsReplacementMap&) {});
322 }
323 
normalizeBindingsAndAddTo(FixedSizeVector<ComponentStorageEntry> && toplevel_entries,MemoryPool & memory_pool,const NormalizedComponentStorage & base_normalized_component,FixedSizeAllocator::FixedSizeAllocatorData & fixed_size_allocator_data,std::vector<ComponentStorageEntry,ArenaAllocator<ComponentStorageEntry>> & new_bindings_vector,std::unordered_map<TypeId,NormalizedMultibindingSet> & multibindings)324 void BindingNormalization::normalizeBindingsAndAddTo(
325     FixedSizeVector<ComponentStorageEntry>&& toplevel_entries, MemoryPool& memory_pool,
326     const NormalizedComponentStorage& base_normalized_component,
327     FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data,
328     std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>& new_bindings_vector,
329     std::unordered_map<TypeId, NormalizedMultibindingSet>& multibindings) {
330 
331   multibindings = base_normalized_component.multibindings;
332 
333   fixed_size_allocator_data = base_normalized_component.fixed_size_allocator_data;
334 
335   multibindings_vector_t multibindings_vector =
336       multibindings_vector_t(ArenaAllocator<multibindings_vector_elem_t>(memory_pool));
337 
338   HashMapWithArenaAllocator<TypeId, ComponentStorageEntry> binding_data_map =
339       createHashMapWithArenaAllocator<TypeId, ComponentStorageEntry>(20 /* capacity */, memory_pool);
340 
341   using Graph = NormalizedComponentStorage::Graph;
342 
343   normalizeBindings(
344       std::move(toplevel_entries), fixed_size_allocator_data, memory_pool, memory_pool, memory_pool, binding_data_map,
345       [](ComponentStorageEntry) {},
346       [&multibindings_vector](ComponentStorageEntry multibinding, ComponentStorageEntry multibinding_vector_creator) {
347         multibindings_vector.emplace_back(multibinding, multibinding_vector_creator);
348       },
349       [&base_normalized_component](TypeId type_id) { return base_normalized_component.bindings.find(type_id); },
350       [&base_normalized_component](Graph::const_node_iterator itr) {
351         return !(itr == base_normalized_component.bindings.end());
352       },
353       [](Graph::const_node_iterator itr) { return itr.isTerminal(); },
354       [](Graph::const_node_iterator itr) { return itr.getNode().object; },
355       [](Graph::const_node_iterator itr) { return itr.getNode().create; },
356       [&base_normalized_component](const LazyComponentWithNoArgs& lazy_component) {
357         return base_normalized_component.fully_expanded_components_with_no_args.count(lazy_component) != 0;
358       },
359       [&base_normalized_component](const LazyComponentWithArgs& lazy_component) {
360         return base_normalized_component.fully_expanded_components_with_args.count(lazy_component) != 0;
361       },
362       [](LazyComponentWithNoArgsSet&) {}, [](LazyComponentWithArgsSet&) {},
363       [&base_normalized_component](const LazyComponentWithNoArgs& lazy_component) {
364         return base_normalized_component.component_with_no_args_replacements.find(lazy_component);
365       },
366       [&base_normalized_component](const LazyComponentWithArgs& lazy_component) {
367         return base_normalized_component.component_with_args_replacements.find(lazy_component);
368       },
369       [&base_normalized_component](typename LazyComponentWithNoArgsReplacementMap::const_iterator itr) {
370         return itr != base_normalized_component.component_with_no_args_replacements.end();
371       },
372       [&base_normalized_component](typename LazyComponentWithArgsReplacementMap::const_iterator itr) {
373         return itr != base_normalized_component.component_with_args_replacements.end();
374       },
375       [](typename LazyComponentWithNoArgsReplacementMap::const_iterator itr) { return itr->second; },
376       [](typename LazyComponentWithArgsReplacementMap::const_iterator itr) { return itr->second; },
377       [](LazyComponentWithNoArgsReplacementMap&) {}, [](LazyComponentWithArgsReplacementMap&) {});
378 
379   // Copy the normalized bindings into the result vector.
380   new_bindings_vector.clear();
381   new_bindings_vector.reserve(binding_data_map.size());
382   for (auto& p : binding_data_map) {
383     new_bindings_vector.push_back(p.second);
384   }
385 
386   // Determine what binding compressions must be undone.
387 
388   HashSetWithArenaAllocator<TypeId> binding_compressions_to_undo =
389       createHashSetWithArenaAllocator<TypeId>(20 /* capacity */, memory_pool);
390   for (const ComponentStorageEntry& entry : new_bindings_vector) {
391     switch (entry.kind) { // LCOV_EXCL_BR_LINE
392     case ComponentStorageEntry::Kind::BINDING_FOR_CONSTRUCTED_OBJECT:
393       break;
394 
395     case ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION:
396     case ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_ALLOCATION:
397     case ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_WITH_UNKNOWN_ALLOCATION: {
398       const BindingDeps* entry_deps = entry.binding_for_object_to_construct.deps;
399       for (std::size_t i = 0; i < entry_deps->num_deps; ++i) {
400         auto binding_compression_itr = base_normalized_component.binding_compression_info_map.find(entry_deps->deps[i]);
401         if (binding_compression_itr != base_normalized_component.binding_compression_info_map.end() &&
402             binding_compression_itr->second.i_type_id != entry.type_id) {
403           // The binding compression for `p.second.getDeps()->deps[i]' must be undone because something
404           // different from binding_compression_itr->iTypeId is now bound to it.
405           binding_compressions_to_undo.insert(entry_deps->deps[i]);
406         }
407       }
408     } break;
409 
410     default:
411 #if FRUIT_EXTRA_DEBUG
412       std::cerr << "Unexpected kind: " << (std::size_t)entry.kind << std::endl;
413 #endif
414       FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
415       break;
416     }
417   }
418 
419   // Step 3: undo any binding compressions that can no longer be applied.
420   for (TypeId cTypeId : binding_compressions_to_undo) {
421     auto binding_compression_itr = base_normalized_component.binding_compression_info_map.find(cTypeId);
422     FruitAssert(binding_compression_itr != base_normalized_component.binding_compression_info_map.end());
423     FruitAssert(!(base_normalized_component.bindings.find(binding_compression_itr->second.i_type_id) ==
424                   base_normalized_component.bindings.end()));
425 
426     ComponentStorageEntry c_binding;
427     c_binding.type_id = cTypeId;
428     c_binding.kind = ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_WITH_UNKNOWN_ALLOCATION;
429     c_binding.binding_for_object_to_construct = binding_compression_itr->second.c_binding;
430 
431     ComponentStorageEntry i_binding;
432     i_binding.type_id = binding_compression_itr->second.i_type_id;
433     i_binding.kind = ComponentStorageEntry::Kind::BINDING_FOR_OBJECT_TO_CONSTRUCT_THAT_NEEDS_NO_ALLOCATION;
434     i_binding.binding_for_object_to_construct = binding_compression_itr->second.i_binding;
435 
436     new_bindings_vector.push_back(c_binding);
437     // This TypeId is already in normalized_component.bindings, we overwrite it here.
438     new_bindings_vector.push_back(i_binding);
439 
440 #if FRUIT_EXTRA_DEBUG
441     std::cout << "InjectorStorage: undoing binding compression for: " << binding_compression_itr->second.i_type_id
442               << "->" << cTypeId << std::endl;
443 #endif
444   }
445 
446   // Step 4: Add multibindings.
447   BindingNormalization::addMultibindings(multibindings, fixed_size_allocator_data, multibindings_vector);
448 }
449 
handlePreexistingLazyComponentWithArgsReplacement(ComponentStorageEntry & replaced_component_entry,const ComponentStorageEntry & preexisting_replacement,ComponentStorageEntry & new_replacement)450 void BindingNormalization::handlePreexistingLazyComponentWithArgsReplacement(
451     ComponentStorageEntry& replaced_component_entry, const ComponentStorageEntry& preexisting_replacement,
452     ComponentStorageEntry& new_replacement) {
453   switch (new_replacement.kind) { // LCOV_EXCL_BR_LINE
454   case ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS:
455     if (preexisting_replacement.kind != ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS ||
456         preexisting_replacement.lazy_component_with_no_args.erased_fun !=
457             new_replacement.lazy_component_with_no_args.erased_fun) {
458       printIncompatibleComponentReplacementsError(replaced_component_entry, new_replacement, preexisting_replacement);
459       FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
460     }
461 
462     // Duplicate but consistent replacement, we'll ignore it.
463     replaced_component_entry.lazy_component_with_args.destroy();
464     break;
465 
466   case ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_ARGS:
467     if (preexisting_replacement.kind != ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_ARGS ||
468         !(*preexisting_replacement.lazy_component_with_args.component ==
469           *new_replacement.lazy_component_with_args.component)) {
470       printIncompatibleComponentReplacementsError(replaced_component_entry, new_replacement, preexisting_replacement);
471       FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
472     }
473 
474     // Duplicate but consistent replacement, we'll ignore it.
475     replaced_component_entry.lazy_component_with_args.destroy();
476     new_replacement.lazy_component_with_args.destroy();
477     break;
478 
479   default:
480     FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
481   }
482 }
483 
handlePreexistingLazyComponentWithNoArgsReplacement(ComponentStorageEntry & replaced_component_entry,const ComponentStorageEntry & preexisting_replacement,ComponentStorageEntry & new_replacement)484 void BindingNormalization::handlePreexistingLazyComponentWithNoArgsReplacement(
485     ComponentStorageEntry& replaced_component_entry, const ComponentStorageEntry& preexisting_replacement,
486     ComponentStorageEntry& new_replacement) {
487   switch (new_replacement.kind) { // LCOV_EXCL_BR_LINE
488   case ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS:
489     if (preexisting_replacement.kind != ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS ||
490         preexisting_replacement.lazy_component_with_no_args.erased_fun !=
491             new_replacement.lazy_component_with_no_args.erased_fun) {
492       printIncompatibleComponentReplacementsError(replaced_component_entry, new_replacement, preexisting_replacement);
493       FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
494     }
495 
496     // Duplicate but consistent replacement, we'll ignore it.
497     break;
498 
499   case ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_ARGS:
500     if (new_replacement.kind != ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_ARGS ||
501         !(*preexisting_replacement.lazy_component_with_args.component ==
502           *new_replacement.lazy_component_with_args.component)) {
503       printIncompatibleComponentReplacementsError(replaced_component_entry, new_replacement, preexisting_replacement);
504       FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
505     }
506 
507     // Duplicate but consistent replacement, we'll ignore it.
508     new_replacement.lazy_component_with_args.destroy();
509     break;
510 
511   default:
512     FRUIT_UNREACHABLE; // LCOV_EXCL_LINE
513   }
514 }
515 
516 } // namespace impl
517 // We need a LCOV_EXCL_BR_LINE below because for some reason gcov/lcov think there's a branch there.
518 } // namespace fruit LCOV_EXCL_BR_LINE
519