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/component_storage/component_storage.h>
27 #include <fruit/impl/data_structures/semistatic_graph.templates.h>
28 #include <fruit/impl/injector/injector_storage.h>
29 #include <fruit/impl/normalized_component_storage/binding_normalization.h>
30 #include <fruit/impl/normalized_component_storage/binding_normalization.templates.h>
31 
32 using std::cout;
33 using std::endl;
34 
35 namespace fruit {
36 namespace impl {
37 
fatal(const std::string & error)38 void InjectorStorage::fatal(const std::string& error) {
39   std::cerr << "Fatal injection error: " << error << std::endl;
40   exit(1);
41 }
42 
43 // LCOV_EXCL_START
44 namespace {
45 template <typename Id, typename Value>
46 struct DummyNode {
getIdfruit::impl::__anon6c16492e0111::DummyNode47   Id getId() {
48     return Id();
49   }
isTerminalfruit::impl::__anon6c16492e0111::DummyNode50   bool isTerminal() {
51     return false;
52   }
getEdgesBeginfruit::impl::__anon6c16492e0111::DummyNode53   Id* getEdgesBegin() {
54     return nullptr;
55   }
getEdgesEndfruit::impl::__anon6c16492e0111::DummyNode56   Id* getEdgesEnd() {
57     return nullptr;
58   }
getValuefruit::impl::__anon6c16492e0111::DummyNode59   Value getValue() {
60     return Value();
61   }
62 };
63 }
64 // LCOV_EXCL_STOP
65 
InjectorStorage(ComponentStorage && component,const std::vector<TypeId,ArenaAllocator<TypeId>> & exposed_types,MemoryPool & memory_pool)66 InjectorStorage::InjectorStorage(ComponentStorage&& component,
67                                  const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types,
68                                  MemoryPool& memory_pool)
69     : normalized_component_storage_ptr(new NormalizedComponentStorage(
70           std::move(component), exposed_types, memory_pool, NormalizedComponentStorage::WithPermanentCompression())),
71       allocator(normalized_component_storage_ptr->fixed_size_allocator_data),
72       bindings(normalized_component_storage_ptr->bindings, (DummyNode<TypeId, NormalizedBinding>*)nullptr,
73                (DummyNode<TypeId, NormalizedBinding>*)nullptr, memory_pool),
74       multibindings(std::move(normalized_component_storage_ptr->multibindings)) {
75 
76 #if FRUIT_EXTRA_DEBUG
77   bindings.checkFullyConstructed();
78 #endif
79 }
80 
InjectorStorage(const NormalizedComponentStorage & normalized_component,ComponentStorage && component,MemoryPool & memory_pool)81 InjectorStorage::InjectorStorage(const NormalizedComponentStorage& normalized_component, ComponentStorage&& component,
82                                  MemoryPool& memory_pool) {
83 
84   FixedSizeAllocator::FixedSizeAllocatorData fixed_size_allocator_data;
85   using new_bindings_vector_t = std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>;
86   new_bindings_vector_t new_bindings_vector = new_bindings_vector_t(ArenaAllocator<ComponentStorageEntry>(memory_pool));
87 
88   BindingNormalization::normalizeBindingsAndAddTo(std::move(component).release(), memory_pool, normalized_component,
89                                                   fixed_size_allocator_data, new_bindings_vector, multibindings);
90 
91   allocator = FixedSizeAllocator(fixed_size_allocator_data);
92 
93   bindings = Graph(normalized_component.bindings, BindingDataNodeIter{new_bindings_vector.begin()},
94                    BindingDataNodeIter{new_bindings_vector.end()}, memory_pool);
95 #if FRUIT_EXTRA_DEBUG
96   bindings.checkFullyConstructed();
97 #endif
98 }
99 
~InjectorStorage()100 InjectorStorage::~InjectorStorage() {}
101 
ensureConstructedMultibinding(NormalizedMultibindingSet & multibinding_set)102 void InjectorStorage::ensureConstructedMultibinding(NormalizedMultibindingSet& multibinding_set) {
103   for (NormalizedMultibinding& multibinding : multibinding_set.elems) {
104     if (!multibinding.is_constructed) {
105       multibinding.object = multibinding.create(*this);
106       multibinding.is_constructed = true;
107     }
108   }
109 }
110 
getMultibindings(TypeId typeInfo)111 void* InjectorStorage::getMultibindings(TypeId typeInfo) {
112   NormalizedMultibindingSet* multibinding_set = getNormalizedMultibindingSet(typeInfo);
113   if (multibinding_set == nullptr) {
114     // Not registered.
115     return nullptr;
116   }
117   return multibinding_set->get_multibindings_vector(*this).get();
118 }
119 
eagerlyInjectMultibindings()120 void InjectorStorage::eagerlyInjectMultibindings() {
121   std::lock_guard<std::recursive_mutex> lock(mutex);
122   for (auto& typeInfoInfoPair : multibindings) {
123     typeInfoInfoPair.second.get_multibindings_vector(*this);
124   }
125 }
126 
127 } // namespace impl
128 // We need a LCOV_EXCL_BR_LINE below because for some reason gcov/lcov think there's a branch there.
129 } // namespace fruit LCOV_EXCL_BR_LINE
130