solinject  1.0.0
C++17 Dependency Injection header-only library
Container.hpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-or-later
2 
3 /*
4  * solinject - C++ Dependency Injection header-only library
5  * Copyright (C) 2022 SemperSolus0x3d
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  */
20 
22 
23 #pragma once
24 
25 #include <map>
26 #include <vector>
27 #include <algorithm>
28 #include <memory>
29 #include <typeinfo>
30 #include <typeindex>
31 #include <mutex>
32 
33 #include "Defines.hpp"
34 #include "IService.hpp"
35 #include "IServiceTyped.hpp"
36 #include "RegisteredServices.hpp"
38 #include "Utils.hpp"
39 
40 namespace sol::di
41 {
42  namespace impl { class IService; }
43 
48  class Container
49  {
50  public:
55  template <class T>
57 
62  template <class T>
64 
67 
70 
72  Container() : m_Mutex(std::make_shared<Mutex>()) {}
73 
75  Container(const Container& other) = delete;
76 
78  Container(Container&& other) noexcept : Container()
79  {
80  swap(*this, other);
81  }
82 
84  Container& operator=(const Container& other) = delete;
85 
87  Container& operator=(Container&& other) noexcept
88  {
89  swap(*this, other);
90  return *this;
91  }
92 
94  friend void swap(Container& a, Container& b) noexcept
95  {
96  using std::swap;
97 
98  if (&a == &b)
99  return;
100 
101  ScopedLock lock(*a.m_Mutex, *b.m_Mutex);
102 
103  swap(a.m_RegisteredServices, b.m_RegisteredServices);
104  swap(a.m_ScopedServiceBuilders, b.m_ScopedServiceBuilders);
105  swap(a.m_Mutex, b.m_Mutex);
106  }
107 
114  {
115  using namespace impl;
116 
117  auto lock = LockMutex();
118 
119  RegisteredServices diServices = m_RegisteredServices;
120  diServices.Merge(m_ScopedServiceBuilders.BuildDIServices());
121 
122  return Container(std::move(diServices), m_Mutex);
123  }
124 
131  bool IsScope() { return m_IsScope; }
132 
138  template<class T>
140  {
141  auto lock = LockMutex();
142  m_RegisteredServices.template RegisterSingletonService<T>(factory);
143  }
144 
150  template<class T>
152  {
153  solinject_assert(instance != nullptr);
154 
155  if (instance == nullptr)
156  throw std::invalid_argument("instance was nullptr");
157 
158  auto lock = LockMutex();
159  m_RegisteredServices.template RegisterSingletonService<T>(instance);
160  }
161 
167  template<class T>
169  {
170  auto lock = LockMutex();
171  m_RegisteredServices.template RegisterTransientService<T>(factory);
172  }
173 
179  template<class T>
181  {
182  auto lock = LockMutex();
183  m_RegisteredServices.template RegisterSharedService<T>(factory);
184  }
185 
191  template<class T>
193  {
194  auto lock = LockMutex();
195  m_ScopedServiceBuilders.template RegisterScopedService<T>(factory);
196  }
197 
206  {
207  m_RegisteredServices.RegisterService(type, diService);
208  }
209 
218  {
219  m_ScopedServiceBuilders.RegisterScopedService(type, serviceBuilder);
220  }
221 
228  template<class T>
230  {
231  auto lock = LockMutex();
232  return m_RegisteredServices.template GetRequiredService<T>(*this);
233  }
234 
241  template <class T>
243  {
244  auto lock = LockMutex();
245  return m_RegisteredServices.template GetService<T>(*this);
246  }
247 
254  template <class T>
256  {
257  auto lock = LockMutex();
258  return m_RegisteredServices.template GetServices<T>(*this);
259  }
260 
261  private:
262  #ifndef SOLINJECT_NOTHREADSAFE
263  using Mutex = std::recursive_mutex;
264  using Lock = std::lock_guard<Mutex>;
265  using ScopedLock = std::scoped_lock<Mutex, Mutex>;
266  #else
267  using Mutex = impl::Empty;
268  using Lock = impl::Empty;
269  using ScopedLock = impl::Empty;
270  #endif
271 
272  using MutexPtr = std::shared_ptr<Mutex>;
273 
279  Container(
280  impl::RegisteredServices&& services,
281  MutexPtr mutexPtr
282  ) :
283  m_RegisteredServices(std::move(services)),
284  m_Mutex(mutexPtr),
285  m_IsScope(true)
286  {
287  solinject_req_assert(mutexPtr != nullptr);
288  }
289 
291  impl::RegisteredServices m_RegisteredServices;
292 
294  impl::ScopedServiceBuilders m_ScopedServiceBuilders;
295 
297  MutexPtr m_Mutex;
298 
303  bool m_IsScope = false;
304 
309  Lock LockMutex() const
310  {
311  return Lock(*m_Mutex);
312  }
313  }; // class Container
314 } // sol::di
sol::di::Container::Container
Container(Container &&other) noexcept
Move constructor.
Definition: Container.hpp:78
solinject_assert
#define solinject_assert(expression)
assert() macro, which is disabled in tests project.
Definition: Defines.hpp:34
std::shared_ptr
sol::di::Container
Dependency Injection container.
Definition: Container.hpp:48
sol::di::Container::swap
friend void swap(Container &a, Container &b) noexcept
Swaps two Container instances.
Definition: Container.hpp:94
std::move
T move(T... args)
sol::di::impl::ScopedServiceBuilders::RegisterScopedService
void RegisterScopedService(Factory< T > factory)
Registers a scoped service.
Definition: ScopedServiceBuilders.hpp:75
std::vector
std::type_index
std::recursive_mutex
sol::di::Container::RegisterScopedServiceBuilder
void RegisterScopedServiceBuilder(std::type_index type, ScopedServiceBuilderPtr serviceBuilder)
Registers a scoped service builder.
Definition: Container.hpp:217
std::lock_guard
sol::di::impl::RegisteredServices
Registered DI services collection.
Definition: RegisteredServices.hpp:45
sol::di::Container::operator=
Container & operator=(Container &&other) noexcept
Move-assignment operator.
Definition: Container.hpp:87
solinject_req_assert
#define solinject_req_assert(expression)
Required assert, which is disabled only when the assert() macro from assert.h is disabled.
Definition: Defines.hpp:41
ScopedServiceBuilders.hpp
sol::di::Container::RegisterService
void RegisterService(std::type_index type, DIServicePtr diService)
Registers a service.
Definition: Container.hpp:205
sol::di::Container::RegisterScopedService
void RegisterScopedService(Factory< T > factory)
Registers a service with scoped lifetime.
Definition: Container.hpp:192
sol::di::Container::RegisterSingletonService
void RegisterSingletonService(ServicePtr< T > instance)
Registers a service with singleton lifetime.
Definition: Container.hpp:151
sol::di::Container::Factory
typename impl::IServiceTyped< T >::Factory Factory
Factory function that accepts a reference to a DI container and returns a pointer to an instance of a...
Definition: Container.hpp:56
sol::di::Container::Container
Container()
Default constructor.
Definition: Container.hpp:72
sol::di::Container::ServicePtr
typename impl::IServiceTyped< T >::ServicePtr ServicePtr
Pointer to an instance of a service.
Definition: Container.hpp:63
sol::di::Container::GetServices
std::vector< ServicePtr< T > > GetServices() const
Resolves services.
Definition: Container.hpp:255
sol::di::Container::RegisterTransientService
void RegisterTransientService(Factory< T > factory)
Registers a service with transient lifetime.
Definition: Container.hpp:168
sol::di::Container::CreateScope
Container CreateScope() const
Creates a scoped container from the current container.
Definition: Container.hpp:113
IServiceTyped.hpp
sol::di::Container::GetRequiredService
ServicePtr< T > GetRequiredService() const
Resolves a required service.
Definition: Container.hpp:229
Utils.hpp
std::invalid_argument
sol::di::impl::Empty
Empty class.
Definition: Utils.hpp:31
sol::di::Container::GetService
ServicePtr< T > GetService() const
Resolves an optional service.
Definition: Container.hpp:242
sol::di::impl::IServiceTyped::ServicePtr
typename std::shared_ptr< T > ServicePtr
Pointer to an instance of a service.
Definition: IServiceTyped.hpp:36
sol::di::Container::operator=
Container & operator=(const Container &other)=delete
Copy-assignment operator (deleted)
std::swap
T swap(T... args)
sol::di::impl::RegisteredServices::DIServicePtr
std::shared_ptr< IService > DIServicePtr
Pointer to a DI service instance.
Definition: RegisteredServices.hpp:63
sol::di::impl::ScopedServiceBuilders::ScopedServiceBuilderPtr
std::shared_ptr< IScopedServiceBuilder > ScopedServiceBuilderPtr
Pointer to a scoped service builder.
Definition: ScopedServiceBuilders.hpp:61
std
sol::di::impl::IServiceTyped::Factory
typename std::function< ServicePtr(const Container &)> Factory
Factory function that accepts a reference to a DI container and returns a pointer to an instance of a...
Definition: IServiceTyped.hpp:42
IService.hpp
sol::di::Container::RegisterSharedService
void RegisterSharedService(Factory< T > factory)
Registers a service with shared lifetime.
Definition: Container.hpp:180
sol::di::impl::RegisteredServices::RegisterService
void RegisterService(std::type_index type, DIServicePtr diService)
Registers a service.
Definition: RegisteredServices.hpp:181
sol::di::Container::IsScope
bool IsScope()
Tells if the container is a scope container.
Definition: Container.hpp:131
RegisteredServices.hpp
Defines.hpp
sol::di::Container::RegisterSingletonService
void RegisterSingletonService(Factory< T > factory)
Registers a service with singleton lifetime.
Definition: Container.hpp:139