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