• 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_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