16
16
#include < umf/memory_provider.h>
17
17
#include < umf/memory_provider_ops.h>
18
18
19
+ #include < array>
19
20
#include < functional>
20
21
#include < memory>
21
22
#include < stdexcept>
@@ -48,6 +49,55 @@ using provider_unique_handle_t =
48
49
} \
49
50
}
50
51
52
+ namespace detail {
53
+ template <typename T, typename ArgsTuple>
54
+ umf_result_t initialize (T *obj, ArgsTuple &&args) {
55
+ try {
56
+ auto ret = std::apply (&T::initialize,
57
+ std::tuple_cat (std::make_tuple (obj),
58
+ std::forward<ArgsTuple>(args)));
59
+ if (ret != UMF_RESULT_SUCCESS) {
60
+ delete obj;
61
+ }
62
+ return ret;
63
+ } catch (...) {
64
+ delete obj;
65
+ return UMF_RESULT_ERROR_UNKNOWN;
66
+ }
67
+ }
68
+
69
+ template <typename T, typename ArgsTuple>
70
+ umf_memory_pool_ops_t poolMakeUniqueOps () {
71
+ umf_memory_pool_ops_t ops;
72
+
73
+ ops.version = UMF_VERSION_CURRENT;
74
+ ops.initialize = [](umf_memory_provider_handle_t *providers,
75
+ size_t numProviders, void *params, void **obj) {
76
+ try {
77
+ *obj = new T;
78
+ } catch (...) {
79
+ return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
80
+ }
81
+
82
+ return detail::initialize<T>(
83
+ reinterpret_cast <T *>(*obj),
84
+ std::tuple_cat (std::make_tuple (providers, numProviders),
85
+ *reinterpret_cast <ArgsTuple *>(params)));
86
+ };
87
+ ops.finalize = [](void *obj) { delete reinterpret_cast <T *>(obj); };
88
+
89
+ UMF_ASSIGN_OP (ops, T, malloc, ((void *)nullptr ));
90
+ UMF_ASSIGN_OP (ops, T, calloc, ((void *)nullptr ));
91
+ UMF_ASSIGN_OP (ops, T, aligned_malloc, ((void *)nullptr ));
92
+ UMF_ASSIGN_OP (ops, T, realloc, ((void *)nullptr ));
93
+ UMF_ASSIGN_OP (ops, T, malloc_usable_size, ((size_t )0 ));
94
+ UMF_ASSIGN_OP_NORETURN (ops, T, free);
95
+ UMF_ASSIGN_OP (ops, T, get_last_allocation_error, UMF_RESULT_ERROR_UNKNOWN);
96
+
97
+ return ops;
98
+ }
99
+ } // namespace detail
100
+
51
101
// / @brief creates UMF memory provider based on given T type.
52
102
// / T should implement all functions defined by
53
103
// / umf_memory_provider_ops_t, except for finalize (it is
@@ -60,28 +110,15 @@ auto memoryProviderMakeUnique(Args &&...args) {
60
110
61
111
ops.version = UMF_VERSION_CURRENT;
62
112
ops.initialize = [](void *params, void **obj) {
63
- auto *tuple = reinterpret_cast <decltype (argsTuple) *>(params);
64
- T *provider;
65
113
try {
66
- provider = new T;
114
+ *obj = new T;
67
115
} catch (...) {
68
116
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
69
117
}
70
118
71
- *obj = provider;
72
-
73
- try {
74
- auto ret =
75
- std::apply (&T::initialize,
76
- std::tuple_cat (std::make_tuple (provider), *tuple));
77
- if (ret != UMF_RESULT_SUCCESS) {
78
- delete provider;
79
- }
80
- return ret;
81
- } catch (...) {
82
- delete provider;
83
- return UMF_RESULT_ERROR_UNKNOWN;
84
- }
119
+ return detail::initialize<T>(
120
+ reinterpret_cast <T *>(*obj),
121
+ *reinterpret_cast <decltype (argsTuple) *>(params));
85
122
};
86
123
ops.finalize = [](void *obj) { delete reinterpret_cast <T *>(obj); };
87
124
@@ -108,51 +145,42 @@ auto memoryProviderMakeUnique(Args &&...args) {
108
145
template <typename T, typename ... Args>
109
146
auto poolMakeUnique (umf_memory_provider_handle_t *providers,
110
147
size_t numProviders, Args &&...args) {
111
- umf_memory_pool_ops_t ops;
112
148
auto argsTuple = std::make_tuple (std::forward<Args>(args)...);
149
+ auto ops = detail::poolMakeUniqueOps<T, decltype (argsTuple)>();
113
150
114
- ops. version = UMF_VERSION_CURRENT ;
115
- ops. initialize = []( umf_memory_provider_handle_t * providers,
116
- size_t numProviders, void *params, void **obj) {
117
- auto *tuple = reinterpret_cast < decltype (argsTuple) *>(params) ;
118
- T *pool;
151
+ umf_memory_pool_handle_t hPool = nullptr ;
152
+ auto ret = umfPoolCreate (&ops, providers, numProviders, &argsTuple, &hPool);
153
+ return std::pair< umf_result_t , pool_unique_handle_t > {
154
+ ret, pool_unique_handle_t (hPool, &umfPoolDestroy)} ;
155
+ }
119
156
120
- try {
121
- pool = new T;
122
- } catch (...) {
123
- return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
124
- }
157
+ // / @brief creates UMF memory pool based on given T type.
158
+ // / This overload takes ownership of memory providers and destroys
159
+ // / them after memory pool is destroyed.
160
+ template <typename T, size_t N, typename ... Args>
161
+ auto poolMakeUnique (std::array<provider_unique_handle_t , N> providers,
162
+ Args &&...args) {
163
+ auto argsTuple = std::make_tuple (std::forward<Args>(args)...);
164
+ auto ops = detail::poolMakeUniqueOps<T, decltype (argsTuple)>();
125
165
126
- *obj = pool;
166
+ std::array<umf_memory_provider_handle_t , N> provider_handles;
167
+ for (size_t i = 0 ; i < N; i++) {
168
+ provider_handles[i] = providers[i].release ();
169
+ }
127
170
128
- try {
129
- auto ret = std::apply (
130
- &T::initialize,
131
- std::tuple_cat (std::make_tuple (pool, providers, numProviders),
132
- *tuple));
133
- if (ret != UMF_RESULT_SUCCESS) {
134
- delete pool;
135
- }
136
- return ret;
137
- } catch (...) {
138
- delete pool;
139
- return UMF_RESULT_ERROR_UNKNOWN;
171
+ // capture providers and destroy them after the pool is destroyed
172
+ auto poolDestructor = [provider_handles](umf_memory_pool_handle_t hPool) {
173
+ umfPoolDestroy (hPool);
174
+ for (auto &provider : provider_handles) {
175
+ umfMemoryProviderDestroy (provider);
140
176
}
141
177
};
142
- ops.finalize = [](void *obj) { delete reinterpret_cast <T *>(obj); };
143
-
144
- UMF_ASSIGN_OP (ops, T, malloc, ((void *)nullptr ));
145
- UMF_ASSIGN_OP (ops, T, calloc, ((void *)nullptr ));
146
- UMF_ASSIGN_OP (ops, T, aligned_malloc, ((void *)nullptr ));
147
- UMF_ASSIGN_OP (ops, T, realloc, ((void *)nullptr ));
148
- UMF_ASSIGN_OP (ops, T, malloc_usable_size, ((size_t )0 ));
149
- UMF_ASSIGN_OP_NORETURN (ops, T, free);
150
- UMF_ASSIGN_OP (ops, T, get_last_allocation_error, UMF_RESULT_ERROR_UNKNOWN);
151
178
152
179
umf_memory_pool_handle_t hPool = nullptr ;
153
- auto ret = umfPoolCreate (&ops, providers, numProviders, &argsTuple, &hPool);
180
+ auto ret = umfPoolCreate (&ops, provider_handles.data (),
181
+ provider_handles.size (), &argsTuple, &hPool);
154
182
return std::pair<umf_result_t , pool_unique_handle_t >{
155
- ret, pool_unique_handle_t (hPool, &umfPoolDestroy )};
183
+ ret, pool_unique_handle_t (hPool, std::move (poolDestructor) )};
156
184
}
157
185
158
186
template <typename Type> umf_result_t &getPoolLastStatusRef () {
0 commit comments