solinject  1.0.0
C++17 Dependency Injection header-only library
ContainerBuilder.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 #include <map>
25 #include <vector>
26 #include <variant>
27 #include <tuple>
28 #include <algorithm>
29 #include <typeinfo>
30 #include <typeindex>
31 #include "Container.hpp"
32 #include "Configuration.hpp"
33 #include "ConfigurationParser.hpp"
34 #include "Utils.hpp"
35 
36 namespace sol::di
37 {
40  {
41  public:
43  template <class T>
45 
48 
51 
55  template <class T>
57  {
58  m_RegisteredInterfaces.try_emplace(key, std::type_index(typeid(T)));
59  }
60 
67  template <class TService, class...TServiceParents>
69  {
70  using namespace impl;
71 
72  LifetimeToServiceMap services;
73 
74  services[ServiceLifetime::Singleton] = std::make_shared<SingletonService<TService, TServiceParents...>>(factory);
75  services[ServiceLifetime::Transient] = std::make_shared<TransientService<TService, TServiceParents...>>(factory);
76  services[ServiceLifetime::Shared] = std::make_shared<SharedService<TService, TServiceParents...>>(factory);
77 
78  m_RegisteredServices[key] = std::move(services);
79  m_RegisteredScopedServiceBuilders[key] =
80  std::make_shared<ScopedServiceBuilder<TService, TServiceParents...>>(factory);
81 
82  m_RegisteredInterfaces.try_emplace(key, std::type_index(typeid(TService)));
83  }
84 
88 
93  Container BuildContainer(const Configuration& configuration)
94  {
95  for (const auto& item : configuration.ConfigurationItems())
96  {
97  m_ServicesRegistration[item.InterfaceKey()].push_back(
98  std::make_tuple(item.ImplementationKey(), item.Lifetime())
99  );
100  }
101 
102  Container container;
103 
104  for (const auto& pair : m_ServicesRegistration)
105  {
106  auto interfaceKey = pair.first;
107 
108  std::type_index interfaceType =
109  m_RegisteredInterfaces.at(interfaceKey);
110 
111  for (const auto& item : pair.second)
112  {
113  auto resolvedServices = ResolveService(interfaceKey, item);
114 
115  for (const auto& service : resolvedServices)
116  {
117  if (std::holds_alternative<DIServicePtr>(service))
118  container.RegisterService(interfaceType, std::get<DIServicePtr>(service));
119  else
121  interfaceType,
122  std::get<ScopedServiceBuilderPtr>(service)
123  );
124  }
125  }
126  }
127 
128  m_ServicesRegistration.clear();
129 
130  return container;
131  }
132  private:
133  using ScopedServiceBuilderPtr = std::shared_ptr<impl::IScopedServiceBuilder>;
134  using LifetimeToServiceMap = std::map<ServiceLifetime, DIServicePtr>;
135  using KeyToTypeMap = std::map<Key, std::type_index>;
136  using RegisteredServicesMap = std::map<Key, LifetimeToServiceMap>;
137  using RegisteredScopedServiceBuildersMap = std::map<Key, ScopedServiceBuilderPtr>;
138  using KeyAndLifetime = std::tuple<Key, ServiceLifetime>;
139  using ServiceKeyToImplementationKeyMap = std::map<Key, std::vector<KeyAndLifetime>>;
140 
141  ServiceKeyToImplementationKeyMap m_ServicesRegistration;
142  RegisteredServicesMap m_RegisteredServices;
143  RegisteredScopedServiceBuildersMap m_RegisteredScopedServiceBuilders;
144  KeyToTypeMap m_RegisteredInterfaces;
145 
146  using ServiceOrBuilder = std::variant<DIServicePtr, ScopedServiceBuilderPtr>;
147 
148  std::vector<ServiceOrBuilder> ResolveService(Key interfaceKey, const KeyAndLifetime& item)
149  {
151 
152  const auto& key = std::get<0>(item);
153  const auto& lifetime = std::get<1>(item);
154 
155  if (interfaceKey != key)
156  if (auto it = m_ServicesRegistration.find(key);
157  it != m_ServicesRegistration.end())
158  {
159  for (const auto& item2 : it->second)
160  impl::ConcatenateVectors(
161  result,
162  ResolveService(it->first, item2)
163  );
164  }
165 
166  switch (lifetime)
167  {
168  case ServiceLifetime::None: break;
169  case ServiceLifetime::Scoped:
170  if (auto it = m_RegisteredScopedServiceBuilders.find(key);
171  it != m_RegisteredScopedServiceBuilders.end())
172  {
173  const auto& builder = it->second;
174  result.push_back(builder);
175  }
176  default:
177  if (auto it = m_RegisteredServices.find(key);
178  it != m_RegisteredServices.end())
179  {
180  auto& services = it->second;
181  result.push_back(services[lifetime]);
182  }
183  }
184 
185  return result;
186  }
187  };
188 }
std::make_tuple
T make_tuple(T... args)
std::string
std::shared_ptr
sol::di::ContainerBuilder::Key
ConfigurationItem::Key Key
Key, used to map classes, registered in a ContainerBuilder to the ones specified in a config file.
Definition: ContainerBuilder.hpp:47
sol::di::Container
Dependency Injection container.
Definition: Container.hpp:48
std::move
T move(T... args)
sol::di::ContainerBuilder::RegisterService
void RegisterService(Key key, Factory< TService > factory)
Registers a service.
Definition: ContainerBuilder.hpp:68
std::make_shared
T make_shared(T... args)
std::vector
std::type_index
sol::di::Container::RegisterScopedServiceBuilder
void RegisterScopedServiceBuilder(std::type_index type, ScopedServiceBuilderPtr serviceBuilder)
Registers a scoped service builder.
Definition: Container.hpp:217
std::tuple
sol::di::ContainerBuilder::BuildContainer
Container BuildContainer(const Configuration &configuration)
Builds a DI container.
Definition: ContainerBuilder.hpp:93
sol::di::Container::RegisterService
void RegisterService(std::type_index type, DIServicePtr diService)
Registers a service.
Definition: Container.hpp:205
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
std::vector::push_back
T push_back(T... args)
sol::di::ConfigurationItem::Key
std::string Key
Key, used to map classes, registered in a ContainerBuilder to the ones specified in a config file.
Definition: ConfigurationItem.hpp:45
sol::di::ContainerBuilder::RegisterInterface
void RegisterInterface(Key key)
Registers an interface.
Definition: ContainerBuilder.hpp:56
std::map::at
T at(T... args)
sol::di::Configuration
DI configuration.
Definition: Configuration.hpp:31
Utils.hpp
std::map
sol::di::Configuration::ConfigurationItems
const std::vector< ConfigurationItem > & ConfigurationItems() const
Configuration items property.
Definition: Configuration.hpp:73
sol::di::ContainerBuilder
DI Container builder.
Definition: ContainerBuilder.hpp:39
Configuration.hpp
sol::di::ContainerBuilder::Factory
Container::Factory< T > Factory
Factory function that accepts a reference to a DI container and returns a pointer to an instance of a...
Definition: ContainerBuilder.hpp:44
ConfigurationParser.hpp
Container.hpp