blob: 46ffdf8113b5fc1e563d6f32f260f11cf544df6e [file] [log] [blame]
Marco Polettifdbfcbe2014-08-31 08:57:47 +01001/*
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_INJECTOR_STORAGE_H
18#define FRUIT_INJECTOR_STORAGE_H
19
Marco Polettif2895102016-01-30 13:38:37 +000020#include <fruit/fruit_forward_decls.h>
21#include <fruit/impl/binding_data.h>
22#include <fruit/impl/data_structures/fixed_size_allocator.h>
23#include <fruit/impl/meta/component.h>
Marco Polettifdbfcbe2014-08-31 08:57:47 +010024
Marco Polettifdbfcbe2014-08-31 08:57:47 +010025#include <vector>
Marco Poletti886289c2016-05-29 10:31:31 +010026#include <unordered_map>
Marco Polettifdbfcbe2014-08-31 08:57:47 +010027
28namespace fruit {
29
30namespace impl {
31
32template <typename T>
33struct GetHelper;
34
35/**
36 * A component where all types have to be explicitly registered, and all checks are at runtime.
37 * Used to implement Component<>, don't use directly.
38 *
39 * This class handles the creation of types of the forms:
40 * - shared_ptr<C>, [const] C*, [const] C&, C (where C is an atomic type)
41 * - Injector<T1, ..., Tk> (with T1, ..., Tk of the above forms).
42 */
43class InjectorStorage {
Marco Poletti4e9594b2014-11-09 13:52:46 +000044public:
45 using BindingVectors = std::pair<std::vector<std::pair<TypeId, BindingData>>,
46 std::vector<std::pair<TypeId, MultibindingData>>>;
47 using Graph = SemistaticGraph<TypeId, NormalizedBindingData>;
48
Marco Poletti3b95a512015-07-11 13:43:39 +010049 template <typename AnnotatedT>
50 using RemoveAnnotations = fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<
51 fruit::impl::meta::RemoveAnnotations(fruit::impl::meta::Type<AnnotatedT>)
52 >>;
53
Marco Poletti79b01d62016-03-25 12:25:30 +000054 template <typename T>
55 using NormalizeType = fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<
56 fruit::impl::meta::NormalizeType(fruit::impl::meta::Type<T>)
57 >>;
58
59 template <typename Signature>
60 using SignatureType = fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval<
61 fruit::impl::meta::SignatureType(fruit::impl::meta::Type<Signature>)
62 >>;
63
64 template <typename Signature>
65 using NormalizedSignatureArgs = fruit::impl::meta::Eval<
66 fruit::impl::meta::NormalizeTypeVector(fruit::impl::meta::SignatureArgs(fruit::impl::meta::Type<Signature>))
67 >;
Marco Polettibb7442f2014-12-26 17:49:03 +010068
Marco Poletti224bd9c2014-11-24 12:34:51 +000069 // Prints the specified error and calls exit(1).
70 static void fatal(const std::string& error);
71
Marco Poletticc97a162015-05-10 12:10:12 +010072 // Returns a tuple (getTypeId<AnnotatedI>(), bindingData)
73 template <typename AnnotatedI, typename AnnotatedC>
Marco Poletti224bd9c2014-11-24 12:34:51 +000074 static std::tuple<TypeId, BindingData> createBindingDataForBind();
75
Marco Poletticc97a162015-05-10 12:10:12 +010076 // Returns a tuple (getTypeId<AnnotatedC>(), bindingData)
77 template <typename AnnotatedC, typename C>
Marco Poletti224bd9c2014-11-24 12:34:51 +000078 static std::tuple<TypeId, BindingData> createBindingDataForBindInstance(C& instance);
79
Marco Poletticc97a162015-05-10 12:10:12 +010080 // Returns a tuple (getTypeId<AnnotatedC>(), bindingData)
81 template <typename AnnotatedSignature, typename Lambda>
Marco Poletti224bd9c2014-11-24 12:34:51 +000082 static std::tuple<TypeId, BindingData> createBindingDataForProvider();
83
Marco Poletticc97a162015-05-10 12:10:12 +010084 // Returns a tuple (getTypeId<AnnotatedI>(), getTypeId<AnnotatedC>(), bindingData)
85 template <typename AnnotatedSignature, typename Lambda, typename AnnotatedI>
Marco Poletti224bd9c2014-11-24 12:34:51 +000086 static std::tuple<TypeId, TypeId, BindingData> createBindingDataForCompressedProvider();
87
Marco Poletticc97a162015-05-10 12:10:12 +010088 // Returns a tuple (getTypeId<AnnotatedC>(), bindingData)
89 template <typename AnnotatedSignature>
Marco Poletti224bd9c2014-11-24 12:34:51 +000090 static std::tuple<TypeId, BindingData> createBindingDataForConstructor();
91
Marco Poletticc97a162015-05-10 12:10:12 +010092 // Returns a tuple (getTypeId<AnnotatedI>(), getTypeId<AnnotatedC>(), bindingData)
93 template <typename AnnotatedSignature, typename AnnotatedI>
Marco Poletti224bd9c2014-11-24 12:34:51 +000094 static std::tuple<TypeId, TypeId, BindingData> createBindingDataForCompressedConstructor();
95
Marco Poletticc97a162015-05-10 12:10:12 +010096 // Returns a tuple (getTypeId<AnnotatedI>(), bindingData)
97 template <typename AnnotatedI, typename AnnotatedC>
Marco Poletti224bd9c2014-11-24 12:34:51 +000098 static std::tuple<TypeId, MultibindingData> createMultibindingDataForBinding();
99
Marco Poletticc97a162015-05-10 12:10:12 +0100100 // Returns a tuple (getTypeId<AnnotatedC>(), bindingData)
101 template <typename AnnotatedC, typename C>
Marco Poletti224bd9c2014-11-24 12:34:51 +0000102 static std::tuple<TypeId, MultibindingData> createMultibindingDataForInstance(C& instance);
103
Marco Poletticc97a162015-05-10 12:10:12 +0100104 // Returns a tuple (getTypeId<AnnotatedC>(), multibindingData)
105 template <typename AnnotatedSignature, typename Lambda>
Marco Poletti224bd9c2014-11-24 12:34:51 +0000106 static std::tuple<TypeId, MultibindingData> createMultibindingDataForProvider();
107
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100108private:
Marco Poletti52005582014-11-09 15:13:26 +0000109 // The NormalizedComponentStorage owned by this object (if any).
110 // Only used for the 1-argument constructor, otherwise it's nullptr.
Marco Poletti9491d652014-11-24 15:47:14 +0000111 std::unique_ptr<NormalizedComponentStorage> normalized_component_storage_ptr;
Marco Poletti52005582014-11-09 15:13:26 +0000112
Marco Poletti5c913af2014-11-20 12:55:31 +0000113 FixedSizeAllocator allocator;
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100114
Marco Poletti85aea002014-11-24 13:15:27 +0000115 // A graph with injected types as nodes (each node stores the NormalizedBindingData for the type) and dependencies as edges.
Marco Poletti4e9594b2014-11-09 13:52:46 +0000116 // For types that have a constructed object already, the corresponding node is stored as terminal node.
Marco Poletti85aea002014-11-24 13:15:27 +0000117 SemistaticGraph<TypeId, NormalizedBindingData> bindings;
Marco Poletti4e9594b2014-11-09 13:52:46 +0000118
Marco Poletti85aea002014-11-24 13:15:27 +0000119 // Maps the type index of a type T to the corresponding NormalizedMultibindingData object (that stores all multibindings).
Marco Poletti886289c2016-05-29 10:31:31 +0100120 std::unordered_map<TypeId, NormalizedMultibindingData> multibindings;
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100121
Marco Polettib1d265c2014-10-19 21:24:11 -0700122private:
Marco Polettifbcb38b2014-10-19 23:58:07 -0700123
Marco Poletticc97a162015-05-10 12:10:12 +0100124 template <typename AnnotatedC>
Marco Poletti6c130032014-11-24 15:09:05 +0000125 static std::shared_ptr<char> createMultibindingVector(InjectorStorage& storage);
Marco Poletti224bd9c2014-11-24 12:34:51 +0000126
Marco Polettic8e80a52014-08-31 17:18:27 +0100127 // If not bound, returns nullptr.
Marco Poletti9491d652014-11-24 15:47:14 +0000128 NormalizedMultibindingData* getNormalizedMultibindingData(TypeId type);
Marco Polettic8e80a52014-08-31 17:18:27 +0100129
Marco Poletti934689f2014-11-16 14:28:16 +0000130 // Looks up the location where the type is (or will be) stored, but does not construct the class.
Marco Poletticc97a162015-05-10 12:10:12 +0100131 template <typename AnnotatedC>
Marco Poletti934689f2014-11-16 14:28:16 +0000132 Graph::node_iterator lazyGetPtr();
133
Marco Polettibfcb7ed2015-02-28 18:55:16 +0000134 // getPtr() is equivalent to getPtrInternal(lazyGetPtr())
Marco Polettie4647132015-05-31 14:35:27 +0100135 template <typename C>
136 C* getPtr(Graph::node_iterator itr);
Marco Poletti934689f2014-11-16 14:28:16 +0000137
Marco Polettib1d265c2014-10-19 21:24:11 -0700138 // Similar to the previous, but takes a node_iterator. Use this when the node_iterator is known, it's faster.
Marco Polettibfcb7ed2015-02-28 18:55:16 +0000139 void* getPtrInternal(Graph::node_iterator itr);
Marco Poletti934689f2014-11-16 14:28:16 +0000140
141 // getPtr(typeInfo) is equivalent to getPtr(lazyGetPtr(typeInfo)).
Marco Poletti9491d652014-11-24 15:47:14 +0000142 Graph::node_iterator lazyGetPtr(TypeId type);
Marco Poletti934689f2014-11-16 14:28:16 +0000143
144 // getPtr(deps, index) is equivalent to getPtr(lazyGetPtr(deps, index)).
Marco Poletti0bfbe052014-11-24 17:11:27 +0000145 Graph::node_iterator lazyGetPtr(Graph::edge_iterator deps, std::size_t dep_index);
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100146
Marco Poletti1576a732014-10-18 12:35:17 -0700147 // Similar to getPtr, but the binding might not exist. Returns nullptr if it doesn't.
Marco Poletti9491d652014-11-24 15:47:14 +0000148 void* unsafeGetPtr(TypeId type);
Marco Poletti1576a732014-10-18 12:35:17 -0700149
Marco Poletti9491d652014-11-24 15:47:14 +0000150 void* getPtrForMultibinding(TypeId type);
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100151
Marco Poletti1fd26492014-09-28 12:31:13 +0100152 // Returns a std::vector<T*>*, or nullptr if there are no multibindings.
Marco Poletti9491d652014-11-24 15:47:14 +0000153 void* getMultibindings(TypeId type);
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100154
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100155 // Constructs any necessary instances, but NOT the instance set.
Marco Poletti9491d652014-11-24 15:47:14 +0000156 void ensureConstructedMultibinding(NormalizedMultibindingData& multibinding_data);
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100157
158 template <typename T>
Marco Polettifdc79902017-05-21 13:27:57 +0100159 friend struct GetFirstStage;
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100160
Marco Poletti934689f2014-11-16 14:28:16 +0000161 template <typename T>
162 friend class fruit::Provider;
Marco Polettid1b46ee2017-05-20 13:06:21 +0100163
164 template <typename I, typename C, typename AnnotatedC>
165 static BindingData::object_t createInjectedObjectForBind(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr);
Marco Poletti934689f2014-11-16 14:28:16 +0000166
Marco Polettid1b46ee2017-05-20 13:06:21 +0100167 template <typename C, typename T, typename AnnotatedSignature, typename Lambda>
168 static BindingData::object_t createInjectedObjectForProvider(InjectorStorage& injector, Graph::node_iterator node_itr);
169
170 template <typename I, typename C, typename T, typename AnnotatedSignature, typename Lambda>
171 static BindingData::object_t createInjectedObjectForCompressedProvider(InjectorStorage& injector, Graph::node_iterator node_itr);
172
173 template <typename C, typename AnnotatedSignature>
174 static BindingData::object_t createInjectedObjectForConstructor(InjectorStorage& injector, Graph::node_iterator node_itr);
175
176 template <typename I, typename C, typename AnnotatedSignature>
177 static BindingData::object_t createInjectedObjectForCompressedConstructor(InjectorStorage& injector, Graph::node_iterator node_itr);
178
179 template <typename I, typename C, typename AnnotatedCPtr>
180 static MultibindingData::object_t createInjectedObjectForMultibinding(InjectorStorage& m);
181
182 template <typename C, typename T, typename AnnotatedSignature, typename Lambda>
183 static BindingData::object_t createInjectedObjectForMultibindingProvider(InjectorStorage& injector);
184
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100185public:
Marco Poletti0bfbe052014-11-24 17:11:27 +0000186
187 // Wraps a std::vector<std::pair<TypeId, BindingData>>::iterator as an iterator on tuples
188 // (typeId, normalizedBindingData, isTerminal, edgesBegin, edgesEnd)
189 struct BindingDataNodeIter {
190 std::vector<std::pair<TypeId, BindingData>>::iterator itr;
191
192 BindingDataNodeIter* operator->();
193
194 void operator++();
195
196 bool operator==(const BindingDataNodeIter& other) const;
197 bool operator!=(const BindingDataNodeIter& other) const;
198
Marco Polettie99fdb72016-05-22 12:26:08 +0100199 std::ptrdiff_t operator-(BindingDataNodeIter other) const;
200
Marco Poletti0bfbe052014-11-24 17:11:27 +0000201 TypeId getId();
202 NormalizedBindingData getValue();
203 bool isTerminal();
204 const TypeId* getEdgesBegin();
205 const TypeId* getEdgesEnd();
206 };
207
Marco Poletti0316a002016-08-29 16:43:10 +0100208 InjectorStorage(const ComponentStorage& storage, const std::vector<TypeId>& exposed_types);
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100209
Marco Poletti9491d652014-11-24 15:47:14 +0000210 InjectorStorage(const NormalizedComponentStorage& normalized_storage,
Marco Poletti0316a002016-08-29 16:43:10 +0100211 const ComponentStorage& storage,
Marco Poletti5c354a62015-01-29 18:40:34 +0100212 std::vector<TypeId>&& exposed_types);
Marco Poletti4e9594b2014-11-09 13:52:46 +0000213
Marco Poletti3e576c22016-06-19 16:34:08 +0100214 // This is just the default destructor, but we declare it here to avoid including
215 // normalized_component_storage.h in fruit.h.
216 ~InjectorStorage();
217
Marco Poletti52005582014-11-09 15:13:26 +0000218 InjectorStorage(InjectorStorage&&) = delete;
219 InjectorStorage& operator=(InjectorStorage&&) = delete;
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100220
221 InjectorStorage(const InjectorStorage& other) = delete;
222 InjectorStorage& operator=(const InjectorStorage& other) = delete;
223
Marco Poletticc97a162015-05-10 12:10:12 +0100224 // Usually get<T>() returns a T.
225 // However, get<Annotated<Annotation1, T>>() returns a T, not an Annotated<Annotation1, T>.
226 template <typename AnnotatedT>
Marco Poletti3b95a512015-07-11 13:43:39 +0100227 RemoveAnnotations<AnnotatedT> get();
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100228
Marco Poletti80c7bb42015-02-28 16:42:43 +0000229 // Similar to the above, but specifying the node_iterator of the type. Use this together with lazyGetPtr when the node_iterator is known, it's faster.
Marco Poletti31f638a2015-05-10 21:21:25 +0100230 // Note that T should *not* be annotated.
231 template <typename T>
232 T get(InjectorStorage::Graph::node_iterator node_iterator);
Marco Poletti7eab28b2014-11-24 15:06:54 +0000233
Marco Poletti80c7bb42015-02-28 16:42:43 +0000234 // Looks up the location where the type is (or will be) stored, but does not construct the class.
Marco Polettib9c9cef2015-05-31 15:31:12 +0100235 // get<AnnotatedT>() is equivalent to get<AnnotatedT>(lazyGetPtr<Apply<NormalizeType, AnnotatedT>>(deps, dep_index))
236 // and also to get<T> (lazyGetPtr<Apply<NormalizeType, AnnotatedT>>(deps, dep_index))
Marco Poletti80c7bb42015-02-28 16:42:43 +0000237 // dep_index is the index of the dep in `deps'.
Marco Poletticc97a162015-05-10 12:10:12 +0100238 template <typename AnnotatedC>
Marco Poletti80c7bb42015-02-28 16:42:43 +0000239 Graph::node_iterator lazyGetPtr(Graph::edge_iterator deps, std::size_t dep_index, Graph::node_iterator bindings_begin);
240
Marco Poletticc97a162015-05-10 12:10:12 +0100241 // Returns nullptr if AnnotatedC was not bound.
242 template <typename AnnotatedC>
Marco Poletti3b95a512015-07-11 13:43:39 +0100243 RemoveAnnotations<AnnotatedC>* unsafeGet();
Marco Poletti1576a732014-10-18 12:35:17 -0700244
Marco Poletticc97a162015-05-10 12:10:12 +0100245 template <typename AnnotatedC>
Marco Poletti3b95a512015-07-11 13:43:39 +0100246 const std::vector<RemoveAnnotations<AnnotatedC>*>& getMultibindings();
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100247
248 void eagerlyInjectMultibindings();
249};
250
251} // namespace impl
252} // namespace fruit
253
Marco Polettif2895102016-01-30 13:38:37 +0000254#include <fruit/impl/storage/injector_storage.defn.h>
Marco Polettifdbfcbe2014-08-31 08:57:47 +0100255
256
257#endif // FRUIT_INJECTOR_STORAGE_H