DelegateMQ
Loading...
Searching...
No Matches
make_tuple_heap.h
Go to the documentation of this file.
1#ifndef _MAKE_TUPLE_HEAP_H
2#define _MAKE_TUPLE_HEAP_H
3
4// @see https://github.com/endurodave/DelegateMQ
5// David Lafreniere, Aug 2020.
6
19
20#include <tuple>
21#include <list>
22#include <memory>
23#include <type_traits>
24#include "DelegateOpt.h"
25
26namespace dmq
27{
28// std::shared_ptr reference arguments are not allowed with asynchronous delegates as the behavior is
29// undefined. In other words:
30// void MyFunc(std::shared_ptr<T> data) // Ok!
31// void MyFunc(std::shared_ptr<T>* data) // Error if DelegateAsync or DelegateSpAsync target!
32template<class T>
33struct is_shared_ptr : std::false_type {};
34
35template<class T>
36struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
37
38template<class T>
39struct is_shared_ptr<std::shared_ptr<T>&> : std::true_type {};
40
41template<class T>
42struct is_shared_ptr<const std::shared_ptr<T>&> : std::true_type {};
43
44template<class T>
45struct is_shared_ptr<std::shared_ptr<T>*> : std::true_type {};
46
47template<class T>
48struct is_shared_ptr<const std::shared_ptr<T>*> : std::true_type {};
49
50template<class T>
51struct is_unique_ptr : std::false_type {};
52
53template<class T>
54struct is_unique_ptr<std::unique_ptr<T>> : std::true_type {};
55
58{
59public:
60 virtual ~heap_arg_deleter_base() = default;
61
63};
64
66template<typename T>
68{
69public:
70 heap_arg_deleter(T& arg) : m_arg(arg) { }
72 xdelete(&m_arg);
73 }
74private:
75 T& m_arg;
76};
77
79template<typename T>
81{
82public:
83 heap_arg_deleter(T* arg) : m_arg(arg) { }
85 xdelete(m_arg);
86 }
87private:
88 T* m_arg;
89};
90
92template<typename T>
94{
95public:
96 // Capture the original inner pointer at construction so the destructor always
97 // frees the xnew'd copy, regardless of whether the target function overwrites
98 // *arg (e.g. an outgoing-argument pattern like (*s) = new T).
99 heap_arg_deleter(T** arg) : m_arg(arg), m_inner(*arg) {}
101 xdelete(m_inner); // free the original xnew'd inner copy (may be nullptr)
102 xdelete(m_arg); // free the outer pointer storage
103 }
104private:
105 T** m_arg;
106 T* m_inner; // original value of *arg at dispatch time
107};
108
110template <typename Arg, typename... TupleElem>
111auto tuple_append(xlist<std::shared_ptr<heap_arg_deleter_base>>& heapArgs, const std::tuple<TupleElem...> &tup, Arg** arg)
112{
113 Arg** heap_arg = nullptr;
114
115 // Check if arg is nullptr or *arg is nullptr
116 if (arg != nullptr && *arg != nullptr) {
117 // Allocate memory for heap_arg and copy the value
118 heap_arg = xnew<Arg*>();
119 if (!heap_arg) {
120 BAD_ALLOC();
121 }
122
123 *heap_arg = xnew<Arg>(**arg);
124 if (!*heap_arg) {
125 xdelete(heap_arg);
126 BAD_ALLOC();
127 }
128 }
129 else {
130 // If arg is nullptr or *arg is nullptr, create heap_arg as nullptr
131 heap_arg = xnew<Arg*>(nullptr);
132 if (!heap_arg) {
133 BAD_ALLOC();
134 }
135 }
136 auto deleter = xmake_shared<heap_arg_deleter<Arg**>>(heap_arg);
137 if (!deleter) {
138 xdelete(*heap_arg);
139 xdelete(heap_arg);
140 BAD_ALLOC();
141 }
142
143#if !defined(__cpp_exceptions) || defined(DMQ_ASSERTS)
144 heapArgs.push_back(deleter);
145 return std::tuple_cat(tup, std::make_tuple(heap_arg));
146#else
147 try {
148 heapArgs.push_back(deleter);
149 return std::tuple_cat(tup, std::make_tuple(heap_arg));
150 }
151 catch (const std::bad_alloc&) {
152 BAD_ALLOC();
153 throw;
154 }
155#endif
156}
157
159template <typename Arg, typename... TupleElem>
160auto tuple_append(xlist<std::shared_ptr<heap_arg_deleter_base>>& heapArgs, const std::tuple<TupleElem...> &tup, Arg* arg)
161{
162 Arg* heap_arg = nullptr;
163 if (arg != nullptr) {
164 heap_arg = xnew<Arg>(*arg);
165 if (!heap_arg) {
166 BAD_ALLOC();
167 }
168 }
169 auto deleter = xmake_shared<heap_arg_deleter<Arg*>>(heap_arg);
170 if (!deleter) {
171 xdelete(heap_arg);
172 BAD_ALLOC();
173 }
174
175#if !defined(__cpp_exceptions) || defined(DMQ_ASSERTS)
176 heapArgs.push_back(deleter);
177 return std::tuple_cat(tup, std::make_tuple(heap_arg));
178#else
179 try {
180 heapArgs.push_back(deleter);
181 return std::tuple_cat(tup, std::make_tuple(heap_arg));
182 }
183 catch (const std::bad_alloc&) {
184 BAD_ALLOC();
185 throw;
186 }
187#endif
188}
189
191template <typename Arg, typename... TupleElem>
192auto tuple_append(xlist<std::shared_ptr<heap_arg_deleter_base>>& heapArgs, const std::tuple<TupleElem...> &tup, Arg& arg)
193{
194 Arg* heap_arg = xnew<Arg>(arg);
195 if (!heap_arg) {
196 BAD_ALLOC();
197 }
198 auto deleter = xmake_shared<heap_arg_deleter<Arg*>>(heap_arg);
199 if (!deleter) {
200 xdelete(heap_arg);
201 BAD_ALLOC();
202 }
203
204#if !defined(__cpp_exceptions) || defined(DMQ_ASSERTS)
205 heapArgs.push_back(deleter);
206
207 auto temp = std::make_tuple(std::forward_as_tuple(*heap_arg)); // Dereference heap_arg when creating tuple element
208 auto new_type = std::get<0>(temp);
209 return std::tuple_cat(tup, new_type);
210#else
211 try {
212 heapArgs.push_back(deleter);
213
214 auto temp = std::make_tuple(std::forward_as_tuple(*heap_arg)); // Dereference heap_arg when creating tuple element
215 auto new_type = std::get<0>(temp);
216 return std::tuple_cat(tup, new_type);
217 }
218 catch (const std::bad_alloc&) {
219 BAD_ALLOC();
220 throw;
221 }
222#endif
223}
224
231template<typename... Ts>
232auto make_tuple_heap(xlist<std::shared_ptr<heap_arg_deleter_base>>& heapArgs, std::tuple<Ts...> tup)
233{
234 (void)heapArgs;
235 return tup;
236}
237
254template<typename Arg1, typename... Args, typename... Ts>
255auto make_tuple_heap(xlist<std::shared_ptr<heap_arg_deleter_base>>& heapArgs, std::tuple<Ts...> tup, Arg1 arg1, Args... args)
256{
257 static_assert(!(
258 (is_shared_ptr<Arg1>::value && (std::is_lvalue_reference_v<Arg1> || std::is_pointer_v<Arg1>))),
259 "std::shared_ptr reference argument not allowed");
260 static_assert(!std::is_same<Arg1, void*>::value, "void* argument not allowed");
261
262 auto new_tup = tuple_append(heapArgs, tup, arg1);
263 return make_tuple_heap(heapArgs, new_tup, args...);
264}
265
266}
267
268#endif
Delegate library options header file.
#define XALLOCATOR
Definition DelegateOpt.h:152
void xdelete(T *p)
Definition DelegateOpt.h:182
std::shared_ptr< T > xmake_shared(Args &&... args)
Definition DelegateOpt.h:170
#define BAD_ALLOC()
Definition DelegateOpt.h:123
T * xnew(Args &&... args)
Definition DelegateOpt.h:177
heap_arg_deleter(T *arg)
Definition make_tuple_heap.h:83
virtual ~heap_arg_deleter()
Definition make_tuple_heap.h:84
heap_arg_deleter(T **arg)
Definition make_tuple_heap.h:99
virtual ~heap_arg_deleter()
Definition make_tuple_heap.h:100
Base class for all deleter's.
Definition make_tuple_heap.h:58
virtual ~heap_arg_deleter_base()=default
Frees heap memory for reference heap argument.
Definition make_tuple_heap.h:68
virtual ~heap_arg_deleter()
Definition make_tuple_heap.h:71
heap_arg_deleter(T &arg)
Definition make_tuple_heap.h:70
Definition DelegateOpt.h:156
The delegate library namespace.
Definition Delegate.h:27
auto make_tuple_heap(xlist< std::shared_ptr< heap_arg_deleter_base > > &heapArgs, std::tuple< Ts... > tup)
Terminate the template metaprogramming argument loop. This function is called when there are no more ...
Definition make_tuple_heap.h:232
auto tuple_append(xlist< std::shared_ptr< heap_arg_deleter_base > > &heapArgs, const std::tuple< TupleElem... > &tup, Arg **arg)
Append a pointer to pointer argument to the tuple.
Definition make_tuple_heap.h:111
Definition make_tuple_heap.h:33
Definition make_tuple_heap.h:51