Minimal Dependency Injection Framework for C++
Single file library for implementing the dependency injection pattern
dip.hpp
Go to the documentation of this file.
1
14#pragma once
15
16#include <memory>
17#include <type_traits>
18#include <cassert>
19#include <functional>
20#include <vector>
21
22// #include <iostream> // For testing
23
28namespace dip
29{
35 template <class Service>
36 struct Injector
37 {
42 typedef std::function<Service *()> AcquireFunction;
43
48 typedef std::function<void(Service *)> ReleaseFunction;
49
56
63 };
64
70 template <class Service>
71 struct instance
72 {
73 static_assert(
74 std::is_abstract<Service>::value,
75 "Only abstract classes are injectable");
76 static_assert(
77 std::has_virtual_destructor<Service>::value,
78 "An injectable service must declare a virtual destructor");
79
81 typedef Service *service_type;
82
84 typedef const Service *const_service_type;
85
91 {
92 assert(_injector.acquire && "Missing dependency injection");
93 _instance = _injector.acquire();
94 assert(_instance && "An injector retrieved a null provider");
95 }
96
101 ~instance() noexcept
102 {
103 if (_injector.release)
104 _injector.release(_instance);
105 }
106
114 [[nodiscard]]
115 service_type operator->() const noexcept
116 {
117 return _instance;
118 }
119
125 [[nodiscard]]
126 Service &operator*() const noexcept
127 {
128 return *_instance;
129 }
130
131 instance(const instance &) = delete;
132 instance(instance &&) = delete;
133 instance &operator=(const instance &) = delete;
134 instance &operator=(instance &&) = delete;
135
141 static void inject(const Injector<Service> &injector) noexcept
142 {
143 assert(
144 (_injector.acquire == nullptr) &&
145 (_injector.release == nullptr) &&
146 "Dependency already injected");
147 assert(injector.acquire && "Invalid injector");
148 _injector = injector;
149 }
150
158 template <class Provider, typename... _Args>
159 static void inject_singleton(_Args &&...__args)
160 {
161 static_assert(
162 std::is_base_of<Service, Provider>::value,
163 "Provider does not implement Service");
164 assert(
165 (_injector.acquire == nullptr) &&
166 (_injector.release == nullptr) &&
167 "Dependency already injected");
168 _injector.release = nullptr;
169 _injector.acquire = [... args = std::forward<_Args>(__args)]() -> Service *
170 {
171 static Provider p(args...);
172 return &p;
173 };
174 }
175
183 template <class Provider, typename... _Args>
184 static void inject_thread_singleton(_Args &&...__args)
185 {
186 static_assert(
187 std::is_base_of<Service, Provider>::value,
188 "Provider does not implement Service");
189 assert(
190 (_injector.acquire == nullptr) &&
191 (_injector.release == nullptr) &&
192 "Dependency already injected");
193 _injector.release = nullptr;
194 _injector.acquire = [... args = std::forward<_Args>(__args)]() -> Service *
195 {
196 static thread_local Provider p(args...);
197 return &p;
198 };
199 }
200
208 template <class Provider, typename... _Args>
209 static void inject_transient(_Args &&...__args)
210 {
211 static_assert(
212 std::is_base_of<Service, Provider>::value,
213 "Provider does not implement Service");
214 assert(
215 (_injector.acquire == nullptr) &&
216 (_injector.release == nullptr) &&
217 "Dependency already injected");
218 _injector.acquire =
219 [... args = std::forward<_Args>(__args)]() -> Service *
220 {
221 return new Provider(args...);
222 };
223 _injector.release = [](Service *provider) -> void
224 {
225 delete provider;
226 };
227 }
228
236 static void clear_injection() noexcept
237 {
238 _injector.acquire = nullptr;
239 _injector.release = nullptr;
240 }
241
242 private:
244 service_type _instance = nullptr;
246 inline static Injector<Service> _injector;
247 }; // struct instance
248
257 template <class Service>
258 inline void inject(const Injector<Service> &injector)
259 {
261 }
262
273 template <class Service, class Provider, typename... _Args>
274 inline void inject_transient(_Args &&...args)
275 {
276 instance<Service>::template inject_transient<Provider>(
277 std::forward<_Args>(args)...);
278 }
279
290 template <class Service, class Provider, typename... _Args>
291 inline void inject_singleton(_Args &&...args)
292 {
293 instance<Service>::template inject_singleton<Provider>(
294 std::forward<_Args>(args)...);
295 }
296
305 template <class Service, class Provider, typename... _Args>
306 inline void inject_thread_singleton(_Args &&...args)
307 {
308 instance<Service>::template inject_thread_singleton<Provider>(
309 std::forward<_Args>(args)...);
310 }
311
317 template <class Service>
319 {
320 static_assert(
321 std::is_abstract<Service>::value,
322 "Only abstract classes are injectable");
323 static_assert(
324 std::has_virtual_destructor<Service>::value,
325 "An injectable service must declare a virtual destructor");
326
328 typedef Service *service_type;
330 typedef const Service *const_service_type;
332 using iterator = std::vector<service_type>::iterator;
334 using const_iterator = std::vector<service_type>::const_iterator;
336 using reverse_iterator = std::vector<service_type>::reverse_iterator;
339 std::vector<service_type>::const_reverse_iterator;
340
346 {
347 assert(!_injectors.empty() && "No dependency injections");
348 for (auto injector : _injectors)
349 {
350 assert(injector.acquire && "Missing dependency injection");
351 auto instance = injector.acquire();
352 assert(instance && "An injector retrieved a null provider");
353 _instances.push_back(instance);
354 }
355 }
356
361 ~instance_set() noexcept
362 {
363 for (std::size_t i = 0; i < _injectors.size(); i++)
364 if (_injectors[i].release)
365 _injectors[i].release(_instances.at(i));
366 }
367
368 instance_set(const instance_set &) = delete;
369 instance_set(instance_set &&) = delete;
370 instance_set &operator=(const instance_set &) = delete;
371 instance_set &operator=(instance_set &&) = delete;
372
378 constexpr std::size_t size() const noexcept
379 {
380 return _instances.size();
381 }
382
389 service_type operator[](std::size_t index)
390 {
391 return _instances[index];
392 }
393
400 const_service_type operator[](std::size_t index) const
401 {
402 return _instances[index];
403 }
404
411 service_type at(std::size_t index)
412 {
413 return _instances.at(index);
414 }
415
422 const_service_type at(std::size_t index) const
423 {
424 return _instances.at(index);
425 }
426
429 iterator begin() { return _instances.begin(); }
432 const_iterator begin() const { return _instances.begin(); }
435 const_iterator cbegin() const noexcept { return _instances.begin(); }
438 iterator end() { return _instances.end(); }
441 const_iterator end() const { return _instances.end(); }
444 const_iterator cend() const noexcept { return _instances.cend(); }
447 reverse_iterator rbegin() { return _instances.rbegin(); }
450 const_reverse_iterator rbegin() const { return _instances.rbegin(); }
454 {
455 return _instances.crbegin();
456 }
459 reverse_iterator rend() { return _instances.rend(); }
462 const_reverse_iterator rend() const { return _instances.rend(); }
466 {
467 return _instances.crend();
468 }
469
475 static void add(const Injector<Service> &injector) noexcept
476 {
477 assert(injector.acquire && "Invalid injector");
478 _injectors.push_back(injector);
479 }
480
488 template <class Provider, typename... _Args>
489 static void add_singleton(_Args &&...__args)
490 {
491 static_assert(
492 std::is_base_of<Service, Provider>::value,
493 "Provider does not implement Service");
494 Injector<Service> injector{
495 .acquire =
496 [... args = std::forward<_Args>(__args)]() -> Service *
497 {
498 static Provider p(args...);
499 return &p;
500 }};
501 add(injector);
502 }
503
511 template <class Provider, typename... _Args>
512 static void add_thread_singleton(_Args &&...__args)
513 {
514 static_assert(
515 std::is_base_of<Service, Provider>::value,
516 "Provider does not implement Service");
517 Injector<Service> injector{
518 .acquire =
519 [... args = std::forward<_Args>(__args)]() -> Service *
520 {
521 static thread_local Provider p(args...);
522 return &p;
523 }};
524 add(injector);
525 }
526
534 template <class Provider, typename... _Args>
535 static void add_transient(_Args &&...__args)
536 {
537 static_assert(
538 std::is_base_of<Service, Provider>::value,
539 "Provider does not implement Service");
540 Injector<Service> injector{
541 .acquire =
542 [... args = std::forward<_Args>(__args)]() -> Service *
543 {
544 static thread_local Provider p(args...);
545 return &p;
546 },
547 .release = [](Service *provider) -> void
548 {
549 delete provider;
550 }};
551 add(injector);
552 }
553
562 static void clear_injections() noexcept
563 {
564 _injectors.clear();
565 }
566
567 private:
568 std::vector<service_type> _instances;
569 inline static std::vector<Injector<Service>> _injectors;
570 }; // struct instances
571
580 template <class Service>
581 inline void add(const Injector<Service> &injector)
582 {
584 }
585
596 template <class Service, class Provider, typename... _Args>
597 inline void add_transient(_Args &&...args)
598 {
599 instance_set<Service>::template add_transient<Provider>(
600 std::forward<_Args>(args)...);
601 }
602
613 template <class Service, class Provider, typename... _Args>
614 inline void add_singleton(_Args &&...args)
615 {
616 instance_set<Service>::template add_singleton<Provider>(
617 std::forward<_Args>(args)...);
618 }
619
630 template <class Service, class Provider, typename... _Args>
631 inline void add_thread_singleton(_Args &&...args)
632 {
633 instance_set<Service>::template add_thread_singleton<Provider>(
634 std::forward<_Args>(args)...);
635 }
636}; // namespace dip
Dependency injection pattern.
Definition: dip.hpp:29
void inject_transient(_Args &&...args)
Inject a transient instance to a Service.
Definition: dip.hpp:274
void inject_singleton(_Args &&...args)
Inject a singleton instance to a Service.
Definition: dip.hpp:291
void add_transient(_Args &&...args)
Inject a transient instance to a Service.
Definition: dip.hpp:597
void add_singleton(_Args &&...args)
Inject a singleton instance to a Service.
Definition: dip.hpp:614
void inject_thread_singleton(_Args &&...args)
Inject a per-thread singleton instance to a Service.
Definition: dip.hpp:306
void inject(const Injector< Service > &injector)
Inject a service provider using a custom injector.
Definition: dip.hpp:258
void add_thread_singleton(_Args &&...args)
Inject a per-thread singleton instance to a Service.
Definition: dip.hpp:631
void add(const Injector< Service > &injector)
Inject a service provider using a custom injector.
Definition: dip.hpp:581
Custom injector.
Definition: dip.hpp:37
AcquireFunction acquire
Custom function to retrieve instances.
Definition: dip.hpp:55
std::function< Service *()> AcquireFunction
Type of a function able to retrieve instances.
Definition: dip.hpp:42
std::function< void(Service *)> ReleaseFunction
Type of a function able to remove unneeded instances.
Definition: dip.hpp:48
ReleaseFunction release
Custom function to remove uneeded instances.
Definition: dip.hpp:62
Set of injected instances of a service.
Definition: dip.hpp:319
reverse_iterator rbegin()
returns a reverse iterator to the beginning
Definition: dip.hpp:447
const_service_type operator[](std::size_t index) const
Get a service provider instance in the set.
Definition: dip.hpp:400
const Service * const_service_type
Const type of the instances of the service provider.
Definition: dip.hpp:330
service_type operator[](std::size_t index)
Get a service provider instance in the set.
Definition: dip.hpp:389
service_type at(std::size_t index)
Get a service provider instance in the set.
Definition: dip.hpp:411
iterator end()
returns an iterator to the end
Definition: dip.hpp:438
const_iterator begin() const
returns an iterator to the beginning
Definition: dip.hpp:432
const_reverse_iterator rend() const
returns a reverse iterator to the end
Definition: dip.hpp:462
const_service_type at(std::size_t index) const
Get a service provider instance in the set.
Definition: dip.hpp:422
std::vector< service_type >::const_reverse_iterator const_reverse_iterator
Const reverse iterator.
Definition: dip.hpp:339
std::vector< service_type >::const_iterator const_iterator
Const forward iterator.
Definition: dip.hpp:334
std::vector< service_type >::iterator iterator
Forward iterator.
Definition: dip.hpp:332
instance_set()
Retrieve a set of instances providing the service.
Definition: dip.hpp:345
const_iterator cend() const noexcept
returns an iterator to the end
Definition: dip.hpp:444
static void add_transient(_Args &&...__args)
Inject a service provider with transient life cycle.
Definition: dip.hpp:535
const_iterator end() const
returns an iterator to the end
Definition: dip.hpp:441
const_iterator cbegin() const noexcept
returns an iterator to the end
Definition: dip.hpp:435
Service * service_type
Type of the instances of the service provider.
Definition: dip.hpp:328
const_reverse_iterator crend() const noexcept
returns a reverse iterator to the end
Definition: dip.hpp:465
const_reverse_iterator rbegin() const
returns a reverse iterator to the beginning
Definition: dip.hpp:450
static void add(const Injector< Service > &injector) noexcept
Inject a service provider using a custom injector.
Definition: dip.hpp:475
static void clear_injections() noexcept
Clear all the injected dependencies for testing purposes.
Definition: dip.hpp:562
reverse_iterator rend()
returns a reverse iterator to the end
Definition: dip.hpp:459
constexpr std::size_t size() const noexcept
Get the count of instances injected into the service.
Definition: dip.hpp:378
static void add_thread_singleton(_Args &&...__args)
Inject a service provider with per-thread singleton life cycle.
Definition: dip.hpp:512
const_reverse_iterator crbegin() const noexcept
returns a reverse iterator to the beginning
Definition: dip.hpp:453
std::vector< service_type >::reverse_iterator reverse_iterator
Reverse iterator.
Definition: dip.hpp:336
static void add_singleton(_Args &&...__args)
Inject a service provider with singleton life cycle.
Definition: dip.hpp:489
iterator begin()
returns an iterator to the beginning
Definition: dip.hpp:429
~instance_set() noexcept
Remove the set of instances providing the service.
Definition: dip.hpp:361
Injected instance of a service.
Definition: dip.hpp:72
static void clear_injection() noexcept
Clear the injected dependency for testing purposes.
Definition: dip.hpp:236
~instance() noexcept
Remove the instance providing the service.
Definition: dip.hpp:101
service_type operator->() const noexcept
Access the instance providing the service.
Definition: dip.hpp:115
Service & operator*() const noexcept
Get the instance providing the service.
Definition: dip.hpp:126
Service * service_type
Type of the injected instances.
Definition: dip.hpp:81
static void inject_transient(_Args &&...__args)
Inject a service provider with transient life cycle.
Definition: dip.hpp:209
const Service * const_service_type
Const type of the injected instances.
Definition: dip.hpp:84
static void inject_singleton(_Args &&...__args)
Inject a service provider with singleton life cycle.
Definition: dip.hpp:159
static void inject(const Injector< Service > &injector) noexcept
Inject a service provider using a custom injector.
Definition: dip.hpp:141
instance()
Retrieve an instance providing the service.
Definition: dip.hpp:90
static void inject_thread_singleton(_Args &&...__args)
Inject a service provider with per-thread singleton life cycle.
Definition: dip.hpp:184