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