Sauce-0.10.1
A C++ Dependency Injection Framework
injector.h
1 #ifndef SAUCE_INJECTOR_H_
2 #define SAUCE_INJECTOR_H_
3 
4 #include <cassert>
5 #include <string>
6 
7 #include <sauce/memory.h>
8 #include <sauce/named.h>
9 #include <sauce/scopes.h>
10 #include <sauce/internal/base_injector.h>
11 #include <sauce/internal/key.h>
12 #include <sauce/internal/locker_factory.h>
13 #include <sauce/internal/scope_cache.h>
14 #include <sauce/internal/type_id.h>
15 
16 namespace sauce {
17 
18 class Modules;
19 class Injector;
20 
21 namespace internal {
22 class ImplicitBindings;
23 class InjectorFriend;
24 typedef sauce::shared_ptr<Injector> InjectorPtr;
25 }
26 
27 class Injector {
28  i::TypeId const scopeKey;
29  i::ScopeCache scopeCache;
30  sauce::weak_ptr<Injector> weak;
31  i::InjectorPtr const next;
32  sauce::shared_ptr<i::BaseInjector<i::ImplicitBindings> > const base;
33 
34  friend class Modules;
35  friend class i::InjectorFriend;
36 
37  Injector(i::TypeId scopeKey, i::InjectorPtr next):
38  scopeKey(scopeKey),
39  scopeCache(),
40  weak(),
41  next(next),
42  base() {}
43 
44  Injector(sauce::shared_ptr<i::BaseInjector<i::ImplicitBindings> > const base):
45  scopeKey(i::typeIdOf<SingletonScope>()),
46  scopeCache(),
47  weak(),
48  next(),
49  base(base) {}
50 
51  void setSelfPtr(i::InjectorPtr shared) {
52  assert(shared.get() == this);
53  weak = shared;
54  }
55 
56  i::InjectorPtr getSelf() const {
57  i::InjectorPtr self = weak.lock();
58  assert(self.get() == this);
59  return self;
60  }
61 
62  template<typename Dependency>
63  void validateAcyclic(bool validateProviding, i::InjectorPtr injector, i::TypeIds & ids, std::string const name) {
64  if (base.get() == NULL) {
65  next->validateAcyclic<Dependency>(validateProviding, injector, ids, name);
66  } else {
67  base->validateAcyclic<Dependency>(validateProviding, injector, ids, name);
68  }
69  }
70 
71  template<typename Dependency>
72  void inject(typename i::Key<Dependency>::Ptr & injected, i::InjectorPtr injector, std::string const name) {
73  if (base.get() == NULL) {
74  next->inject<Dependency>(injected, injector, name);
75  } else {
76  base->inject<Dependency>(injected, injector, name);
77  }
78  }
79 
83  sauce::auto_ptr<i::Lock> acquireLock() {
84  if (base.get() == NULL) {
85  return next->acquireLock();
86  } else {
87  return base->acquireLock();
88  }
89  }
90 
91  template<typename Scope>
92  void eagerlyInject(i::InjectorPtr injector) {
93  if (base.get() == NULL) {
94  next->eagerlyInject<Scope>(injector);
95  } else {
96  base->eagerlyInject<Scope>(injector);
97  }
98  }
99 
100  template<typename Dependency>
101  void cache(typename i::Key<Dependency>::Ptr pointer, i::TypeId dependencyScopeKey) {
102  if (scopeKey == dependencyScopeKey) {
103  scopeCache.template put<Dependency>(pointer);
104  } else if (next.get() == NULL) {
105  dependencyScopeKey.throwOutOfScopeException();
106  } else {
107  next->cache<Dependency>(pointer, dependencyScopeKey);
108  }
109  }
110 
111  template<typename Dependency>
112  bool probe(typename i::Key<Dependency>::Ptr & out, i::TypeId dependencyScopeKey) const {
113  if (scopeKey == dependencyScopeKey) {
114  return scopeCache.template get<Dependency>(out);
115  } else if (next.get() == NULL) {
116  dependencyScopeKey.throwOutOfScopeException();
117  return false; // never reached
118  } else {
119  return next->probe<Dependency>(out, dependencyScopeKey);
120  }
121  }
122 
123  template<typename Scope>
124  bool alreadyInScope() const {
125  if (scopeKey == i::typeIdOf<Scope>()) {
126  return true;
127  } else if (next.get() == NULL) {
128  return false;
129  } else {
130  return next->alreadyInScope<Scope>();
131  }
132  }
133 
134 public:
135 
136  template<typename Dependency>
137  void inject(typename i::Key<Dependency>::Ptr & injected, std::string const name = unnamed()) {
138  typedef typename i::Key<Dependency>::Ptr Ptr;
139  typedef typename i::Key<Dependency>::Normalized Normalized;
140 
141  sauce::auto_ptr<i::Lock> lock = acquireLock();
142 
143  i::TypeIds ids;
144  bool validateProviding = (injected.get() == NULL);
145  validateAcyclic<Normalized>(validateProviding, getSelf(), ids, name); // TODO Make this check optional.
146 
147  inject<Normalized>(injected, getSelf(), name);
148  }
149 
150  template<typename Iface, typename Name>
151  void inject(typename i::Key<Named<Iface, Name> >::Ptr & injected, std::string const name = unnamed()) {
152  inject<Named<Iface, Name> >(injected, name);
153  }
154 
155  template<typename Dependency>
156  typename i::Key<Dependency>::Ptr get(std::string const name = unnamed()) {
157  typename i::Key<Dependency>::Ptr injected;
158  inject<Dependency>(injected, name);
159  return injected;
160  }
161 
162  template<typename Iface, typename Name>
163  typename i::Key<Named<Iface, Name> >::Ptr get(std::string const name = unnamed()) {
164  return get<Named<Iface, Name> >(name);
165  }
166 
167  template<typename Scope>
168  i::InjectorPtr enter() const {
169  if (alreadyInScope<Scope>()) {
171  }
172 
173  i::InjectorPtr scoped(new Injector(i::typeIdOf<Scope>(), getSelf()));
174  scoped->setSelfPtr(scoped);
175  return scoped;
176  }
177 
178  i::InjectorPtr exit() const {
179  if (next.get() == NULL) {
181  } else {
182  return next;
183  }
184  }
185 
186  template<typename Scope>
187  void eagerlyInject() {
188  sauce::auto_ptr<i::Lock> lock = acquireLock();
189  eagerlyInject<Scope>(getSelf());
190  }
191 
192 };
193 
194 namespace internal {
195 
197 protected:
198 
199  template<typename Dependency>
200  void validateAcyclicHelper(InjectorPtr injector, TypeIds & ids, std::string const name) const {
201  injector->validateAcyclic<Dependency>(true, injector, ids, name);
202  }
203 
204  template<typename Dependency>
205  void injectHelper(typename Key<Dependency>::Ptr & injected, InjectorPtr injector, std::string const name) const {
206  injector->inject<Dependency>(injected, injector, name);
207  }
208 
209  template<typename Dependency>
210  void cache(InjectorPtr injector, typename Key<Dependency>::Ptr injected, i::TypeId scope) const {
211  injector->template cache<Dependency>(injected, scope);
212  }
213 
214  template<typename Dependency>
215  bool probe(InjectorPtr injector, typename Key<Dependency>::Ptr & injected, i::TypeId scope) const {
216  return injector->template probe<Dependency>(injected, scope);
217  }
218 
219 };
220 
221 }
222 
223 }
224 
225 #endif // SAUCE_INJECTOR_H_
Definition: scope_cache.h:19
Thrown when re-entering the given scope, which is already open.
Definition: exceptions.h:103
Definition: injector.h:196
Wrap dependency requests with Named to choose one of several (statically) named alternatives.
Definition: named.h:12
virtual void throwOutOfScopeException() const
Throw an OutOfScopeException appropriate for the hidden type, assuming it is a Scope.
Definition: type_id.h:64
Definition: base_injector.h:22
A factory that accepts Modules and creates Injectors.
Definition: modules.h:77
A TypeSignature equipped with specific helper methods dealing in the hidden type. ...
Definition: type_id.h:34
Definition: binder.h:21
Thrown when exiting the singleton scope.
Definition: exceptions.h:111
A complete specification of a dependency request.
Definition: key.h:15
Definition: injector.h:27