1/* Copyright (C) 2017 Povilas Kanapickas <povilas@radix.lt>
2
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at
5 http://www.boost.org/LICENSE_1_0.txt)
6*/
7
8#ifndef LIBSIMDPP_DISPATCH_MAKE_DISPATCHER_H
9#define LIBSIMDPP_DISPATCH_MAKE_DISPATCHER_H
10
11#include <simdpp/dispatch/macros_generated.h>
12#include <simdpp/detail/preprocessor/punctuation/remove_parens.hpp>
13#include <simdpp/detail/preprocessor/seq/for_each.hpp>
14#include <simdpp/detail/preprocessor/variadic/to_seq.hpp>
15
16#if SIMDPP_EMIT_DISPATCHER
17#include <simdpp/detail/preprocessor/punctuation/comma_if.hpp>
18#include <simdpp/detail/preprocessor/seq/elem.hpp>
19#include <simdpp/detail/preprocessor/seq/for_each_i.hpp>
20#include <simdpp/detail/preprocessor/tuple/rem.hpp>
21#include <simdpp/dispatch/collect_macros_generated.h>
22
23// When debugging this code, it's a good idea to familiarize yourself with
24// advanced preprocessor techniques first. Several resources follow:
25// http://jhnet.co.uk/articles/cpp_magic
26// https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
27// https://stackoverflow.com/questions/11632219/c-preprocessor-macro-specialisation-based-on-an-argument
28// https://stackoverflow.com/questions/44758329/c-or-macro-magic-to-generate-method-and-forward-arguments
29// https://stackoverflow.com/questions/11031062/c-preprocessor-avoid-code-repetition-of-member-variable-list
30// https://stackoverflow.com/questions/11729168/how-to-get-function-signature-via-preprocessor-define-written-before-it
31// Some ideas have been taken from these pages.
32
33// The libsimdpp library includes a partial copy of boost.preprocessor library
34// with BOOST_ prefix replaced with SIMDPP_ and variadics support enabled
35// unconditionally. If implementing new features, feel free to add any headers
36// that are needed but are missing. In case a header becomes no longer used,
37// please remove it from the repository.
38
39// The implementation has been affected by the following MSVC preprocessor
40// bugs / non-standard behavior:
41//
42// - MSVC treats expanded variadic arguments as single token in other function
43// argument lists. SIMDPP_DETAIL_MSVC_DEFER_MACRO_ARGS has been used as a
44// workaround in these cases.
45//
46// - MSVC does not accept empty token as valid argument in function macros. In
47// cases when this matter, SIMDPP_PP_EMPTY() was passed after the real
48// arguments.
49//
50// - MSVC is eager to expand function macros before its arguments are fully
51// expanded. This has been worked around with placing one or more
52// SIMDPP_PP_EMPTY between the function macro and its argument list to defer
53// the expansion.
54//
55// - MSVC sometimes stops the expansion of macros even when the expansion should
56// continue. This is worked around by wrapping the code in SIMDPP_PP_EXPAND
57
58#define SIMDPP_DETAIL_MSVC_DEFER_MACRO_ARGS(macro, args) macro args
59
60#if ~SIMDPP_PP_CONFIG_FLAGS() & SIMDPP_PP_CONFIG_MSVC()
61 #define SIMDPP_DETAIL_IGNORE_PARENS(x) SIMDPP_PP_EAT x
62#else
63 #define SIMDPP_DETAIL_IGNORE_PARENS_DEFER(x) SIMDPP_PP_EAT x
64 #define SIMDPP_DETAIL_IGNORE_PARENS(x) SIMDPP_DETAIL_IGNORE_PARENS_DEFER(x)
65#endif
66
67#define SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST(x) \
68 SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST_STRIP_REST_DEFER(SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST_ADD_COMMA x,)
69
70#if ~SIMDPP_PP_CONFIG_FLAGS() & SIMDPP_PP_CONFIG_MSVC()
71 #define SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST_STRIP_REST_DEFER(...) \
72 SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST_STRIP_REST(__VA_ARGS__)
73
74 #define SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST_STRIP_REST(x, ...) SIMDPP_PP_REM x
75#else
76 #define SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST_STRIP_REST_DEFER(...) \
77 SIMDPP_DETAIL_MSVC_DEFER_MACRO_ARGS(SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST_STRIP_REST, (__VA_ARGS__))
78
79 #define SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST_STRIP_REST(x, ...) \
80 SIMDPP_DETAIL_MSVC_DEFER_MACRO_ARGS(SIMDPP_PP_REM, x)
81#endif
82
83#define SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST_ADD_COMMA(...) (__VA_ARGS__),
84
85// We can't just use SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST or
86// SIMDPP_DETAIL_EXTRACT_ARG_IMPL directly, because the argument list may be
87// empty, so SIMDPP_DETAIL_EXTRACT_* may be invoked with the argument being
88// empty token. The argument otherwise always starts with a parenthesis, so
89// let's check that.
90#define SIMDPP_DETAIL_EXTRACT_TYPE(T) \
91 SIMDPP_PP_IIF(SIMDPP_PP_IS_BEGIN_PARENS(T), \
92 SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST, \
93 SIMDPP_PP_EAT \
94 )(T)
95
96#define SIMDPP_DETAIL_EXTRACT_ARG_IMPL(T) SIMDPP_PP_REM T
97#define SIMDPP_DETAIL_EXTRACT_ARG(T) \
98 SIMDPP_PP_IIF(SIMDPP_PP_IS_BEGIN_PARENS(T), \
99 SIMDPP_DETAIL_EXTRACT_ARG_IMPL, \
100 SIMDPP_PP_EAT \
101 )(T)
102
103#define SIMDPP_DETAIL_EXTRACT_FORWARD_IMPL(T) SIMDPP_PP_EAT T
104#define SIMDPP_DETAIL_EXTRACT_FORWARD(T) \
105 SIMDPP_PP_IIF(SIMDPP_PP_IS_BEGIN_PARENS(T), \
106 SIMDPP_DETAIL_EXTRACT_FORWARD_IMPL, \
107 SIMDPP_PP_EAT \
108 )(T)
109
110#define SIMDPP_DETAIL_TYPES_EACH(r, data, i, x) \
111 SIMDPP_PP_COMMA_IF(i) SIMDPP_DETAIL_EXTRACT_TYPE(x)
112
113#define SIMDPP_DETAIL_ARGS_EACH(r, data, i, x) \
114 SIMDPP_PP_COMMA_IF(i) SIMDPP_DETAIL_EXTRACT_ARG(x)
115
116#define SIMDPP_DETAIL_FORWARD_EACH(r, data, i, x) \
117 SIMDPP_PP_COMMA_IF(i) SIMDPP_DETAIL_EXTRACT_FORWARD(x)
118
119// The following 3 macros expand a given function argument list with the
120// following format '(A) a, (B) b, (C) c' into different results.
121
122// Will expand to 'A, B, C'
123#define SIMDPP_DETAIL_TYPES(args) \
124 SIMDPP_PP_SEQ_FOR_EACH_I(SIMDPP_DETAIL_TYPES_EACH, data, SIMDPP_PP_VARIADIC_TO_SEQ args)
125
126// Will expand to 'A a, B b, C c'
127#define SIMDPP_DETAIL_ARGS(args) \
128 SIMDPP_PP_SEQ_FOR_EACH_I(SIMDPP_DETAIL_ARGS_EACH, data, SIMDPP_PP_VARIADIC_TO_SEQ args)
129
130// Will expand to 'a, b, c'
131#define SIMDPP_DETAIL_FORWARD(args) \
132 SIMDPP_PP_SEQ_FOR_EACH_I(SIMDPP_DETAIL_FORWARD_EACH, data, SIMDPP_PP_VARIADIC_TO_SEQ args)
133
134// Will expand to 1 if argument contains SIMDPP_PP_PROBE macro anywhere, 0 otherwise
135#if ~SIMDPP_PP_CONFIG_FLAGS() & SIMDPP_PP_CONFIG_MSVC()
136 #define SIMDPP_PP_PROBE_TO_BOOL(...) \
137 SIMDPP_PP_PROBE_TO_BOOL_I(__VA_ARGS__, 0)
138
139#else
140 // Note that we can't use SIMDPP_DETAIL_MSVC_DEFER_MACRO_ARGS because this
141 // would interfere with the expansion of that macro itself
142
143 #define SIMDPP_PP_PROBE_TO_BOOL(...) \
144 SIMDPP_PP_PROBE_TO_BOOL_MSVC_DEFER(SIMDPP_PP_PROBE_TO_BOOL_I, (__VA_ARGS__, 0))
145 #define SIMDPP_PP_PROBE_TO_BOOL_MSVC_DEFER(macro, args) macro args
146#endif
147
148#define SIMDPP_PP_PROBE_TO_BOOL_I(n1, n2, ...) n2
149#define SIMDPP_PP_PROBE() ~, 1, 0
150
151// Given a single argument R, potentially consisting of multiple tokens,
152// expands to SIMDPP_PP_PROBE() if R is empty, otherwise expands to nothing.
153#if ~SIMDPP_PP_CONFIG_FLAGS() & SIMDPP_PP_CONFIG_MSVC()
154 #define SIMDPP_DETAIL_PROBE_IF_VOID_EMPTY(R) \
155 SIMDPP_PP_IIF( \
156 SIMDPP_PP_PROBE_TO_BOOL(SIMDPP_DETAIL_IS_EMPTY_PROBE R ()), \
157 SIMDPP_PP_PROBE, \
158 SIMDPP_PP_EMPTY \
159 )()
160#else
161 #define SIMDPP_DETAIL_PROBE_IF_VOID_EMPTY(R) \
162 SIMDPP_PP_IIF SIMDPP_PP_EMPTY()( \
163 SIMDPP_PP_PROBE_TO_BOOL(SIMDPP_DETAIL_IS_EMPTY_PROBE R ()), \
164 SIMDPP_PP_PROBE, \
165 SIMDPP_PP_EMPTY \
166 )()
167#endif
168
169#define SIMDPP_DETAIL_IS_EMPTY_PROBE(...) SIMDPP_PP_PROBE()
170
171// Given a single argument R, potentially consisting of multiple tokens or
172// parenthesized token groups, expands to nothing if R starts with a parenthesis.
173// Otherwise expands to SIMDPP_DETAIL_PROBE_IF_VOID_EMPTY with R
174// passed as an argument.
175#if ~SIMDPP_PP_CONFIG_FLAGS() & SIMDPP_PP_CONFIG_MSVC()
176 #define SIMDPP_DETAIL_PROBE_IF_VOID_1PAREN(R) \
177 SIMDPP_PP_IIF(SIMDPP_PP_IS_BEGIN_PARENS(R), \
178 SIMDPP_PP_EAT, \
179 SIMDPP_DETAIL_PROBE_IF_VOID_EMPTY \
180 )(R)
181#else
182 // R might be empty token, thus workarounds are needed (see top of the file)
183
184 #define SIMDPP_DETAIL_PROBE_IF_VOID_1PAREN(R) \
185 SIMDPP_PP_IIF(SIMDPP_PP_IS_BEGIN_PARENS(R), \
186 SIMDPP_PP_EAT, \
187 SIMDPP_DETAIL_PROBE_IF_VOID_EMPTY \
188 )(R SIMDPP_PP_EMPTY())
189#endif
190
191// Given a single argument R, potentially consisting of multiple tokens or
192// parenthesized token groups, expands to nothing if R starts with a 'void'
193// token. Otherwise expands to SIMDPP_DETAIL_PROBE_IF_VOID_1PAREN
194// passing R with the first 'void' token removed as an argument.
195
196#if ~SIMDPP_PP_CONFIG_FLAGS() & SIMDPP_PP_CONFIG_MSVC()
197 #define SIMDPP_DETAIL_PROBE_IF_VOID_1PARAM(R) \
198 SIMDPP_PP_IIF( \
199 SIMDPP_PP_PROBE_TO_BOOL(SIMDPP_DETAIL_STARTS_WITH_VOID_PROBE(R)), \
200 SIMDPP_DETAIL_PROBE_IF_VOID_1PAREN, \
201 SIMDPP_PP_EAT \
202 )(SIMDPP_PP_CAT(SIMDPP_DETAIL_STARTS_WITH_VOID_STRIP_, R))
203#else
204 // SIMDPP_PP_IIF is expanded one expansion too early and R might be empty
205 // token, thus workarounds are needed (see top of the file)
206
207 #define SIMDPP_DETAIL_PROBE_IF_VOID_1PARAM(R) \
208 SIMDPP_PP_IIF SIMDPP_PP_EMPTY()( \
209 SIMDPP_PP_PROBE_TO_BOOL(SIMDPP_DETAIL_STARTS_WITH_VOID_PROBE(R SIMDPP_PP_EMPTY())), \
210 SIMDPP_DETAIL_PROBE_IF_VOID_1PAREN, \
211 SIMDPP_PP_EAT \
212 )(SIMDPP_PP_CAT(SIMDPP_DETAIL_STARTS_WITH_VOID_STRIP_, R) SIMDPP_PP_EMPTY SIMDPP_PP_EMPTY()())
213#endif
214
215#define SIMDPP_DETAIL_STARTS_WITH_VOID_CHECK_void SIMDPP_PP_PROBE()
216#define SIMDPP_DETAIL_STARTS_WITH_VOID_STRIP_void
217#define SIMDPP_DETAIL_STARTS_WITH_VOID_PROBE(R) \
218 SIMDPP_DETAIL_STARTS_WITH_VOID_PROBE_I(SIMDPP_DETAIL_STARTS_WITH_VOID_CHECK_ ## R)
219#define SIMDPP_DETAIL_STARTS_WITH_VOID_PROBE_I(R) R
220
221// Given a parenthesized list of arguments R, expands to nothing if R contains
222// more than one argument. Otherwise expands SIMDPP_DETAIL_PROBE_IF_VOID_1PARAM
223// passing R with removed outer parentheses
224#define SIMDPP_DETAIL_PROBE_IF_VOID(R) \
225 SIMDPP_PP_IF(SIMDPP_PP_DEC(SIMDPP_PP_VARIADIC_SIZE(SIMDPP_PP_REM R)), \
226 SIMDPP_PP_EAT, \
227 SIMDPP_DETAIL_PROBE_IF_VOID_1PARAM \
228 )(SIMDPP_PP_REMOVE_PARENS(R))
229
230// Given a parenthesized list of arguments R, expands to nothing if R is
231// parenthesized void token, otherwise expands to return token
232#if ~SIMDPP_PP_CONFIG_FLAGS() & SIMDPP_PP_CONFIG_MSVC()
233
234 #define SIMDPP_DETAIL_RETURN_IF_NOT_VOID(R) \
235 SIMDPP_PP_IIF(SIMDPP_PP_PROBE_TO_BOOL(SIMDPP_DETAIL_PROBE_IF_VOID(R)), \
236 SIMDPP_PP_EMPTY, \
237 SIMDPP_DETAIL_RETURN_TOKEN \
238 )()
239#else
240 // The following problems have been worked around on MSVC (see top of the
241 // file):
242 // - SIMDPP_PP_IIF is expanded two expansions too early
243 // - the result of SIMDPP_DETAIL_PROBE_IF_VOID is not passed back to
244 // SIMDPP_PP_PROBE_TO_BOOL properly
245 // - the final SIMDPP_PP_IIF is not expanded for some reason.
246
247 #define SIMDPP_DETAIL_RETURN_IF_NOT_VOID(R) \
248 SIMDPP_PP_EXPAND( \
249 SIMDPP_PP_IIF SIMDPP_PP_EMPTY SIMDPP_PP_EMPTY()()( \
250 SIMDPP_DETAIL_MSVC_DEFER_MACRO_ARGS( \
251 SIMDPP_PP_PROBE_TO_BOOL, (SIMDPP_DETAIL_PROBE_IF_VOID(R)) \
252 ), \
253 SIMDPP_PP_EMPTY, \
254 SIMDPP_DETAIL_RETURN_TOKEN \
255 )() \
256 )
257#endif
258
259#define SIMDPP_DETAIL_RETURN_TOKEN() return
260
261#define SIMDPP_DETAIL_MAKE_DISPATCHER_IMPL(TEMPLATE_PREFIX, TEMPLATE_ARGS, R, NAME, ARGS) \
262 \
263SIMDPP_DISPATCH_DECLARE_FUNCTIONS( \
264 (SIMDPP_PP_REMOVE_PARENS(TEMPLATE_PREFIX) \
265 SIMDPP_PP_REMOVE_PARENS(R) NAME (SIMDPP_DETAIL_TYPES(ARGS)))) \
266 \
267SIMDPP_PP_REMOVE_PARENS(TEMPLATE_PREFIX) \
268SIMDPP_PP_REMOVE_PARENS(R) NAME(SIMDPP_DETAIL_ARGS(ARGS)) \
269{ \
270 using FunPtr = SIMDPP_PP_REMOVE_PARENS(R)(*)(SIMDPP_DETAIL_TYPES(ARGS)); \
271 static FunPtr selected = nullptr; \
272 if (selected == nullptr) { \
273 ::simdpp::detail::FnVersion versions[SIMDPP_DISPATCH_MAX_ARCHS] = {}; \
274 SIMDPP_DISPATCH_COLLECT_FUNCTIONS(versions, \
275 (NAME SIMDPP_PP_REMOVE_PARENS(TEMPLATE_ARGS)), FunPtr) \
276 ::simdpp::detail::FnVersion version = \
277 ::simdpp::detail::select_version_any(versions, \
278 SIMDPP_DISPATCH_MAX_ARCHS, SIMDPP_USER_ARCH_INFO); \
279 selected = reinterpret_cast<FunPtr>(version.fun_ptr); \
280 } \
281 SIMDPP_DETAIL_RETURN_IF_NOT_VOID(R) selected(SIMDPP_DETAIL_FORWARD(ARGS)); \
282}
283
284#define SIMDPP_DETAIL_IGNORE_PARENS2(x) \
285 SIMDPP_DETAIL_IGNORE_PARENS(SIMDPP_DETAIL_IGNORE_PARENS(x))
286
287#define SIMDPP_DETAIL_IGNORE_PARENS3(x) \
288 SIMDPP_DETAIL_IGNORE_PARENS(SIMDPP_DETAIL_IGNORE_PARENS( \
289 SIMDPP_DETAIL_IGNORE_PARENS(x) \
290 ))
291
292#define SIMDPP_DETAIL_IGNORE_PARENS4(x) \
293 SIMDPP_DETAIL_IGNORE_PARENS(SIMDPP_DETAIL_IGNORE_PARENS( \
294 SIMDPP_DETAIL_IGNORE_PARENS(SIMDPP_DETAIL_IGNORE_PARENS(x)) \
295 ))
296
297// SIMDPP_PP_SEQ_ELEM does not work with sequence elements containing commas,
298// so we use a workaround
299#define SIMDPP_DETAIL_MAKE_DISPATCHER1(DESC) SIMDPP_ERROR_INCORRECT_NUMBER_OF_ARGUMENTS
300#define SIMDPP_DETAIL_MAKE_DISPATCHER2(DESC) SIMDPP_ERROR_INCORRECT_NUMBER_OF_ARGUMENTS
301#define SIMDPP_DETAIL_MAKE_DISPATCHER3(DESC) \
302 SIMDPP_DETAIL_MAKE_DISPATCHER_IMPL( \
303 (), \
304 (), \
305 (SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST(DESC)), \
306 SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST(SIMDPP_DETAIL_IGNORE_PARENS(DESC)), \
307 (SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST(SIMDPP_DETAIL_IGNORE_PARENS2(DESC))))
308
309#define SIMDPP_DETAIL_MAKE_DISPATCHER4(DESC) SIMDPP_ERROR_INCORRECT_NUMBER_OF_ARGUMENTS
310#define SIMDPP_DETAIL_MAKE_DISPATCHER5(DESC) \
311 SIMDPP_DETAIL_MAKE_DISPATCHER_IMPL( \
312 (SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST(DESC)), \
313 (SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST(SIMDPP_DETAIL_IGNORE_PARENS(DESC))), \
314 (SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST(SIMDPP_DETAIL_IGNORE_PARENS2(DESC))), \
315 SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST(SIMDPP_DETAIL_IGNORE_PARENS3(DESC)), \
316 (SIMDPP_DETAIL_EXTRACT_PARENS_IGNORE_REST(SIMDPP_DETAIL_IGNORE_PARENS4(DESC))))
317
318
319#define SIMDPP_DETAIL_MAKE_DISPATCHER6(DESC) SIMDPP_ERROR_INCORRECT_NUMBER_OF_ARGUMENTS
320#define SIMDPP_DETAIL_MAKE_DISPATCHER7(DESC) SIMDPP_ERROR_INCORRECT_NUMBER_OF_ARGUMENTS
321
322/** Builds a dispatcher for a specific non-member function. The same macro is
323 used for functions with or without return value, with different parameter
324 counts and for template functions.
325
326 The function accepts a sequence of 3 or 5 parenthesized token groups. Each
327 group conveys the following information:
328 - (optional) the full template prefix, e.g. (template<class T>)
329 - (optional) the template argument list enclosed in brackets, e.g. (<T,U>)
330 - the return type, e.g. (void), or (float)
331 - the function name, e.g. (my_function)
332 - comma separated list of function arguments. Each argument is specified as
333 a parenthesized type name and argument name which follows immediately.
334 For example ((float) x, (int) y, (std::pair<int, int>) z).
335
336 The following examples show several ways to invoke the
337 SIMDPP_MAKE_DISPATCHER macro:
338
339 SIMDPP_MAKE_DISPATCHER((void)(my_function1)())
340 SIMDPP_MAKE_DISPATCHER((void)(my_function1)((int) x, (float)z))
341 SIMDPP_MAKE_DISPATCHER((int)(my_function1)((int) x, (float)z))
342 SIMDPP_MAKE_DISPATCHER((template<class A, class B>)(<A,B>)(A)(my_function1)())
343 SIMDPP_MAKE_DISPATCHER((template<class A, class B>)(<A,B>)(A)(my_function1)((B) x, (B)z))
344
345 SIMDPP_ARCH_NAMESPACE::NAME (where NAME refers to the name of the function
346 supplied to the SIMDPP_MAKE_DISPATCHER macro) must refer to the function to
347 be disptached relative to the namespace in which the SIMDPP_MAKE_DISPATCHER
348 macro is used in. That is, the macro must be used in a namespace one level
349 up than the dispatched function, and that namespace must be
350 SIMDPP_ARCH_NAMESPACE.
351
352 The return and parameter types must be exactly the same as those of the
353 function to be dispatched. The dispatched function may be overloaded.
354
355 When dispatching function templates, each used template must be explicitly
356 dispatched in all architecture-specific compilation units. For example,
357 when using simdpp_multiarch (see cmake/SimdppMultiarch.cmake), these
358 instantiations must be defined in SRC_FILE source file.
359
360 The macro defines a function with the same signature as the dispatched
361 function in the namespace the macro is used. The body of that function
362 implements the dispatch mechanism.
363
364 The dispatch functions check the enabled instruction set and select the
365 best function on first call. The initialization does not introduce race
366 conditions when done concurrently.
367
368 The generated dispatching code links to all versions of the dispatched
369 function statically, so techniques to prevent linkers from stripping
370 unreferenced object files are not needed.
371*/
372#define SIMDPP_MAKE_DISPATCHER(DESC) \
373 SIMDPP_PP_CAT(SIMDPP_DETAIL_MAKE_DISPATCHER, SIMDPP_PP_SEQ_SIZE(DESC))(DESC)
374#else // #if SIMDPP_EMIT_DISPATCHER
375#define SIMDPP_MAKE_DISPATCHER(DESC)
376#endif
377
378#define SIMDPP_DETAIL_SIGNATURE_EACH(r, data, x) SIMDPP_PP_REMOVE_PARENS(x) ;
379#define SIMDPP_DETAIL_SIGNATURES(signatures) \
380 SIMDPP_PP_SEQ_FOR_EACH(SIMDPP_DETAIL_SIGNATURE_EACH, data, \
381 SIMDPP_PP_VARIADIC_TO_SEQ signatures)
382
383#if SIMDPP_EMIT_DISPATCHER
384/** Defines a one or more template instantiations for a dispatcher. Accepts one
385 or more parenthesized token groups separated by commas defining one or more
386 full template instantiations. For example:
387 SIMDPP_INSTANTIATE_DISPATCHER((template void foo<int>(int x))
388
389 or
390
391 SIMDPP_INSTANTIATE_DISPATCHER(
392 (template void foo<int>(int x)),
393 (template void foo<char>(char x))
394 )
395
396 The macro forces instantiation of the dispatch function defined by the
397 SIMDPP_MAKE_DISPATCHER macro and also of the functions referenced by the
398 dispatcher function. The latter is necessary because the dispatcher is
399 compiled into a only single object file out of the set of multiversioned
400 object files. The referenced functions will be instantiated in all of them.
401*/
402// Implementation note: we can't accept the signatures as a sequence, e.g.
403// (a)(b)(c), because SIMDPP_PP_SEQ_FOR_EACH does not support sequence elements
404// containing commas at the top level
405#define SIMDPP_INSTANTIATE_DISPATCHER(...) \
406SIMDPP_DETAIL_SIGNATURES((__VA_ARGS__)) \
407namespace SIMDPP_ARCH_NAMESPACE { \
408 SIMDPP_DETAIL_SIGNATURES((__VA_ARGS__)) \
409}
410#else // SIMDPP_EMIT_DISPATCHER
411#define SIMDPP_INSTANTIATE_DISPATCHER(...) \
412namespace SIMDPP_ARCH_NAMESPACE { \
413 SIMDPP_DETAIL_SIGNATURES((__VA_ARGS__)) \
414}
415#endif
416
417#endif // LIBSIMDPP_DISPATCH_MAKE_DISPATCHER_H
418