digitalmars.D.learn - Translating C precompiler macros to D
- solidstate1991 (20/20) Nov 08 2023 Here's this precompiler macro from Pipewire, on which many
- evilrat (46/66) Nov 09 2023 Not sure if it will work in real situations, expect memory errors.
Here's this precompiler macro from Pipewire, on which many important inline functions depend on, like this one: ```c /** * Invoke method named \a method in the \a callbacks. * The \a method_type defines the type of the method struct. * Returns true if the method could be called, false otherwise. */ #define spa_callbacks_call(callbacks,type,method,vers,...) \ ({ \ const type *_f = (const type *) (callbacks)->funcs; \ bool _res = SPA_CALLBACK_CHECK(_f,method,vers); \ if (SPA_LIKELY(_res)) \ _res; \ }) ``` So far, the only way out I see is to turn it into a string mixin. (SPA_LIKELY is just a needless precompiler macro for labeling things.)
Nov 08 2023
On Wednesday, 8 November 2023 at 20:43:21 UTC, solidstate1991 wrote:Here's this precompiler macro from Pipewire, on which many important inline functions depend on, like this one: ```c /** * Invoke method named \a method in the \a callbacks. * The \a method_type defines the type of the method struct. * Returns true if the method could be called, false otherwise. */ #define spa_callbacks_call(callbacks,type,method,vers,...) \ ({ \ const type *_f = (const type *) (callbacks)->funcs; \ bool _res = SPA_CALLBACK_CHECK(_f,method,vers); \ if (SPA_LIKELY(_res)) \ _res; \ }) ``` So far, the only way out I see is to turn it into a string mixin. (SPA_LIKELY is just a needless precompiler macro for labeling things.)Not sure if it will work in real situations, expect memory errors. Also I used a fixed type, you should use CTFE to cast data to proper function argument types. ```d import std.stdio; bool SPA_CALLBACK_CHECK(T)(const (T)* f, string method, uint version_) { // do some checks... return true; } bool spa_callbacks_call(alias callbacks, alias type, alias method, uint vers, Args...)(Args) { const (type)* _f = cast(type*) callbacks.funcs; bool _res = SPA_CALLBACK_CHECK(_f, __traits(identifier, method), vers); if (_res) __traits(getMember, _f, __traits(identifier, method))(cast(int) callbacks.data, Args); // callback call return _res; } // your callback, see pipewire docs for real examples struct Foo { void bar(int x) const { import std.stdio; writeln(x); } } // pipewire internals struct spa_callback { const(void)* funcs; void* data; } void main() { Foo foo; // instead of this naive approach you should use provided initialization method // but roughly first parameter is pointer to struct of function pointers spa_callback cb = { cast(void*) &foo, cast(void*) 42 }; spa_callbacks_call!(cb, Foo, Foo.bar, 0)(); } ```
Nov 09 2023