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