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