forked from cpv-project/cpv-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Container.hpp
139 lines (119 loc) · 5.4 KB
/
Container.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#pragma once
#include <typeindex>
#include "./ServiceDescriptor.hpp"
#include "./ServiceFactory.hpp"
#include "./ServiceStorage.hpp"
namespace cpv {
/** Members of Container */
class ContainerData;
/**
* Dependency injection container.
* It can't use across cpu cores, please create one container for one cpu core.
*/
class Container {
public:
/** Register service with implementation type */
template <class TService, class TImplementation>
void add(ServiceLifetime lifetime = ServiceLifetime::Transient) {
addDescriptor(typeid(TService), ServiceDescriptor<TService>::create(
std::optional<TService>(),
std::make_unique<ServiceDependencyInjectionFactory<TService, TImplementation>>(*this),
lifetime));
}
/** Register service with instance */
template <class TService>
void add(TService instance) {
addDescriptor(typeid(TService), ServiceDescriptor<TService>::create(
std::move(instance),
std::make_unique<ServiceExceptionFactory<TService>>(
"it's registered with instance but still try to invoke factory"),
ServiceLifetime::Persistent));
}
/** Register service with function that returns instance of service */
template <class TService, class TFunc,
std::enable_if_t<std::is_base_of_v<
ServiceFactoryBase<TService>,
ServiceFunctionFactory<TService, TFunc>>, int> = 0>
void add(TFunc func, ServiceLifetime lifetime = ServiceLifetime::Transient) {
addDescriptor(typeid(TService), ServiceDescriptor<TService>::create(
std::optional<TService>(),
std::make_unique<ServiceFunctionFactory<TService, TFunc>>(std::move(func)),
lifetime));
}
/** Register service with custom factory object */
template <class TService>
void add(std::unique_ptr<ServiceFactoryBase<TService>>&& factory,
ServiceLifetime lifetime = ServiceLifetime::Transient) {
addDescriptor(typeid(TService), ServiceDescriptor<TService>::create(
std::optional<TService>(), std::move(factory), lifetime));
}
/** Get service instance, throws exception if not registered or registered multiple times */
template <class TService>
TService get() const {
// use built-in service storage
return get<TService>(getBuiltinStorage());
}
/** Get service instance, throws exception if not registered or registered multiple times */
template <class TService>
TService get(ServiceStorage& storage) const {
return get<TService>(storage, getDescriptors(typeid(TService)));
}
/** Get service instances and adding them to given collection, it will not clear items first */
template <class T, std::enable_if_t<ServiceTypeTrait<T>::IsCollection, int> = 0>
std::size_t getMany(T& collection) const {
return getMany<T>(collection, getBuiltinStorage());
}
/** Get service instances and adding them to given collection, it will not clear items first */
template <class T, std::enable_if_t<ServiceTypeTrait<T>::IsCollection, int> = 0>
std::size_t getMany(T& collection, ServiceStorage& storage) const {
using ActualType = typename ServiceTypeTrait<T>::ActualType;
return getMany<T>(collection, storage, getDescriptors(typeid(ActualType)));
}
/** Constructor */
Container();
/** Constructor for null container */
explicit Container(std::nullptr_t);
private:
template <class DependencyTypes, class ContainerType>
friend struct DependencyTypesExtensions;
template <class TService>
friend struct ServicePatcher;
friend struct Dummy;
/** Associate a descriptor to given service type */
void addDescriptor(const std::type_index& serviceType, ServiceDescriptorPtr&& serviceDescriptor);
/** Get all descriptors associated to given service type, return null pointer if not registered */
const ServiceDescriptorCollection& getDescriptors(const std::type_index& serviceType) const&;
/** Get all descriptors associated to given service type, return empty list if not registered */
ServiceDescriptorCollection& getOrCreateEmptyDescriptors(const std::type_index& serviceType) &;
/** Get built-in service storage */
ServiceStorage& getBuiltinStorage() const&;
/** Get service instance, throws exception if not registered or registered multiple times */
template <class TService>
TService get(ServiceStorage& storage, const ServiceDescriptorCollection& descriptors) const {
if (descriptors.get() == nullptr || descriptors->empty()) {
throw ContainerException(CPV_CODEINFO,
"get instance of type [", typeid(TService).name(), "] failed: not registered");
} else if (descriptors->size() > 1) {
throw ContainerException(CPV_CODEINFO,
"get instance of type [", typeid(TService).name(), "] failed: registered multiple times");
}
return ServiceDescriptor<TService>::cast(descriptors->front()).getInstance(*this, storage);
}
/** Get service instances and adding them to given collection, notice it will not clear the collection first */
template <class T, std::enable_if_t<ServiceTypeTrait<T>::IsCollection, int> = 0>
std::size_t getMany(
T& collection, ServiceStorage& storage, const ServiceDescriptorCollection& descriptors) const {
if (descriptors.get() == nullptr) {
return 0;
}
using ActualType = typename ServiceTypeTrait<T>::ActualType;
for (auto& descriptor : *descriptors) {
ServiceTypeTrait<T>::add(collection,
ServiceDescriptor<ActualType>::cast(descriptor).getInstance(*this, storage));
}
return descriptors->size();
}
private:
seastar::shared_ptr<ContainerData> data_;
};
}