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_COMPONENT_STORAGE_ENTRY_DEFN_H
18 #define FRUIT_COMPONENT_STORAGE_ENTRY_DEFN_H
19
20 #include <fruit/impl/component_storage/component_storage_entry.h>
21 #include <fruit/impl/util/call_with_tuple.h>
22 #include <fruit/impl/util/hash_codes.h>
23 #include <fruit/component_function.h>
24
25 namespace fruit {
26 namespace impl {
27
28 // We use a custom method instead of a real copy constructor so that all copies are explicit (since copying is a
29 // fairly expensive operation).
copy()30 inline ComponentStorageEntry ComponentStorageEntry::copy() const {
31 FruitAssert(kind != Kind::INVALID);
32 ComponentStorageEntry result;
33 switch (kind) {
34 case Kind::LAZY_COMPONENT_WITH_ARGS:
35 case Kind::REPLACED_LAZY_COMPONENT_WITH_ARGS:
36 case Kind::REPLACEMENT_LAZY_COMPONENT_WITH_ARGS:
37 result.kind = kind;
38 result.type_id = type_id;
39 result.lazy_component_with_args = lazy_component_with_args.copy();
40 break;
41
42 default:
43 result = *this;
44 }
45 return result;
46 }
47
48 // We use a custom method instead of a real destructor, so that we can hold these in a std::vector but still destroy
49 // them when desired.
destroy()50 inline void ComponentStorageEntry::destroy() const {
51 FruitAssert(kind != Kind::INVALID);
52 switch (kind) {
53 case Kind::LAZY_COMPONENT_WITH_ARGS:
54 case Kind::REPLACED_LAZY_COMPONENT_WITH_ARGS:
55 case Kind::REPLACEMENT_LAZY_COMPONENT_WITH_ARGS:
56 lazy_component_with_args.destroy();
57 #if FRUIT_EXTRA_DEBUG
58 kind = Kind::INVALID;
59 #endif
60 break;
61
62 default:
63 break;
64 }
65 }
66
ComponentInterface(erased_fun_t erased_fun)67 inline ComponentStorageEntry::LazyComponentWithArgs::ComponentInterface::ComponentInterface(erased_fun_t erased_fun)
68 : erased_fun(erased_fun) {}
69
70 template <typename Component, typename... Args>
71 class ComponentInterfaceImpl : public ComponentStorageEntry::LazyComponentWithArgs::ComponentInterface {
72 private:
73 using ComponentInterface = ComponentStorageEntry::LazyComponentWithArgs::ComponentInterface;
74
75 using fun_t = Component (*)(Args...);
76 std::tuple<Args...> args_tuple;
77
78 public:
ComponentInterfaceImpl(fun_t fun,std::tuple<Args...> args_tuple)79 inline ComponentInterfaceImpl(fun_t fun, std::tuple<Args...> args_tuple)
80 : ComponentInterface(reinterpret_cast<erased_fun_t>(fun)), args_tuple(std::move(args_tuple)) {}
81
82 inline bool
areParamsEqual(const ComponentStorageEntry::LazyComponentWithArgs::ComponentInterface & other)83 areParamsEqual(const ComponentStorageEntry::LazyComponentWithArgs::ComponentInterface& other) const final {
84 if (getFunTypeId() != other.getFunTypeId()) {
85 return false;
86 }
87 const auto& casted_other = static_cast<const ComponentInterfaceImpl<Component, Args...>&>(other);
88 return args_tuple == casted_other.args_tuple;
89 }
90
addBindings(entry_vector_t & entries)91 inline void addBindings(entry_vector_t& entries) const final {
92 Component component = callWithTuple<Component, Args...>(reinterpret_cast<fun_t>(erased_fun), args_tuple);
93 FixedSizeVector<ComponentStorageEntry> component_entries = std::move(component.storage).release();
94 entries.insert(entries.end(), component_entries.begin(), component_entries.end());
95 }
96
hashCode()97 inline std::size_t hashCode() const final {
98 std::size_t fun_hash = std::hash<fun_t>()(reinterpret_cast<fun_t>(erased_fun));
99 std::size_t args_hash = hashTuple(args_tuple);
100 return combineHashes(fun_hash, args_hash);
101 }
102
copy()103 inline ComponentInterface* copy() const final {
104 return new ComponentInterfaceImpl{reinterpret_cast<fun_t>(erased_fun), args_tuple};
105 }
106
getFunTypeId()107 inline TypeId getFunTypeId() const final {
108 return fruit::impl::getTypeId<Component (*)(Args...)>();
109 }
110 };
111
112 template <typename Component, typename... Args>
create(Component (* fun)(Args...),std::tuple<Args...> args_tuple)113 inline ComponentStorageEntry ComponentStorageEntry::LazyComponentWithArgs::create(Component (*fun)(Args...),
114 std::tuple<Args...> args_tuple) {
115 ComponentStorageEntry result;
116 result.type_id = getTypeId<Component (*)(Args...)>();
117 result.kind = ComponentStorageEntry::Kind::LAZY_COMPONENT_WITH_ARGS;
118 result.lazy_component_with_args.component =
119 new ComponentInterfaceImpl<Component, Args...>(fun, std::move(args_tuple));
120 return result;
121 }
122
123 template <typename Component, typename Arg, typename... Args>
create(fruit::ComponentFunction<Component,Arg,Args...> component_function)124 inline ComponentStorageEntry ComponentStorageEntry::LazyComponentWithArgs::create(
125 fruit::ComponentFunction<Component, Arg, Args...> component_function) {
126 return LazyComponentWithArgs::create(component_function.getComponent, component_function.args_tuple);
127 }
128
129 template <typename Component, typename... Args>
130 inline ComponentStorageEntry
createReplacedComponentEntry(Component (* fun)(Args...),std::tuple<Args...> args_tuple)131 ComponentStorageEntry::LazyComponentWithArgs::createReplacedComponentEntry(Component (*fun)(Args...),
132 std::tuple<Args...> args_tuple) {
133 ComponentStorageEntry result;
134 result.type_id = getTypeId<Component (*)(Args...)>();
135 result.kind = ComponentStorageEntry::Kind::REPLACED_LAZY_COMPONENT_WITH_ARGS;
136 result.lazy_component_with_args.component =
137 new ComponentInterfaceImpl<Component, Args...>(fun, std::move(args_tuple));
138 return result;
139 }
140
141 template <typename Component, typename... Args>
142 inline ComponentStorageEntry
createReplacementComponentEntry(Component (* fun)(Args...),std::tuple<Args...> args_tuple)143 ComponentStorageEntry::LazyComponentWithArgs::createReplacementComponentEntry(Component (*fun)(Args...),
144 std::tuple<Args...> args_tuple) {
145 ComponentStorageEntry result;
146 result.type_id = getTypeId<Component (*)(Args...)>();
147 result.kind = ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_ARGS;
148 result.lazy_component_with_args.component =
149 new ComponentInterfaceImpl<Component, Args...>(fun, std::move(args_tuple));
150 return result;
151 }
152
copy()153 inline ComponentStorageEntry::LazyComponentWithArgs ComponentStorageEntry::LazyComponentWithArgs::copy() const {
154 LazyComponentWithArgs result;
155 result.component = component->copy();
156 return result;
157 }
158
destroy()159 inline void ComponentStorageEntry::LazyComponentWithArgs::destroy() const {
160 delete component;
161 }
162
163 inline bool ComponentStorageEntry::LazyComponentWithArgs::ComponentInterface::
164 operator==(const ComponentInterface& other) const {
165 return erased_fun == other.erased_fun && areParamsEqual(other);
166 }
167
168 template <typename Component>
addBindings(erased_fun_t erased_fun,entry_vector_t & entries)169 void ComponentStorageEntry::LazyComponentWithNoArgs::addBindings(erased_fun_t erased_fun, entry_vector_t& entries) {
170 Component component = reinterpret_cast<Component (*)()>(erased_fun)();
171 FixedSizeVector<ComponentStorageEntry> component_entries = std::move(component.storage).release();
172 entries.insert(entries.end(), component_entries.begin(), component_entries.end());
173 }
174
175 template <typename Component>
create(Component (* fun)())176 inline ComponentStorageEntry ComponentStorageEntry::LazyComponentWithNoArgs::create(Component (*fun)()) {
177 FruitAssert(fun != nullptr);
178 ComponentStorageEntry result;
179 result.kind = ComponentStorageEntry::Kind::LAZY_COMPONENT_WITH_NO_ARGS;
180 result.type_id = getTypeId<Component (*)()>();
181 result.lazy_component_with_no_args.erased_fun = reinterpret_cast<erased_fun_t>(fun);
182 result.lazy_component_with_no_args.add_bindings_fun = LazyComponentWithNoArgs::addBindings<Component>;
183 return result;
184 }
185
186 template <typename Component>
create(fruit::ComponentFunction<Component> component_function)187 inline ComponentStorageEntry ComponentStorageEntry::LazyComponentWithNoArgs::create(
188 fruit::ComponentFunction<Component> component_function) {
189 return LazyComponentWithNoArgs::create(component_function.getComponent);
190 }
191
192 template <typename Component>
193 inline ComponentStorageEntry
createReplacedComponentEntry(Component (* fun)())194 ComponentStorageEntry::LazyComponentWithNoArgs::createReplacedComponentEntry(Component (*fun)()) {
195 FruitAssert(fun != nullptr);
196 ComponentStorageEntry result;
197 result.kind = ComponentStorageEntry::Kind::REPLACED_LAZY_COMPONENT_WITH_NO_ARGS;
198 result.type_id = getTypeId<Component (*)()>();
199 result.lazy_component_with_no_args.erased_fun = reinterpret_cast<erased_fun_t>(fun);
200 result.lazy_component_with_no_args.add_bindings_fun = LazyComponentWithNoArgs::addBindings<Component>;
201 return result;
202 }
203
204 template <typename Component>
205 inline ComponentStorageEntry
createReplacementComponentEntry(Component (* fun)())206 ComponentStorageEntry::LazyComponentWithNoArgs::createReplacementComponentEntry(Component (*fun)()) {
207 FruitAssert(fun != nullptr);
208 ComponentStorageEntry result;
209 result.kind = ComponentStorageEntry::Kind::REPLACEMENT_LAZY_COMPONENT_WITH_NO_ARGS;
210 result.type_id = getTypeId<Component (*)()>();
211 result.lazy_component_with_no_args.erased_fun = reinterpret_cast<erased_fun_t>(fun);
212 result.lazy_component_with_no_args.add_bindings_fun = LazyComponentWithNoArgs::addBindings<Component>;
213 return result;
214 }
215
isValid()216 inline bool ComponentStorageEntry::LazyComponentWithNoArgs::isValid() const {
217 return erased_fun != nullptr;
218 }
219
220 inline bool ComponentStorageEntry::LazyComponentWithNoArgs::
221 operator==(const ComponentStorageEntry::LazyComponentWithNoArgs& other) const {
222 if (erased_fun == other.erased_fun) {
223 // These must be equal in this case, no need to compare them.
224 FruitAssert(add_bindings_fun == other.add_bindings_fun);
225 return true;
226 } else {
227 // type_id and add_bindings_fun may or may not be different from the ones in `other`.
228 return false;
229 }
230 }
231
addBindings(entry_vector_t & entries)232 inline void ComponentStorageEntry::LazyComponentWithNoArgs::addBindings(entry_vector_t& entries) const {
233 FruitAssert(isValid());
234 add_bindings_fun(erased_fun, entries);
235 }
236
hashCode()237 inline std::size_t ComponentStorageEntry::LazyComponentWithNoArgs::hashCode() const {
238 // We only need to hash this field (for the same reason that we only compare this field in operator==).
239 return std::hash<erased_fun_t>()(erased_fun);
240 }
241
242 } // namespace impl
243 } // namespace fruit
244
245 #endif // FRUIT_COMPONENT_STORAGE_ENTRY_DEFN_H
246