digitalmars.D.learn - avoid extra variable during void pointer cast
- Kevin Brogan (36/36) May 14 2017 I have a piece of code that takes a callback function.
- Moritz Maxeiner (11/47) May 14 2017 First: Any decent compiler will optimize both the variable
- Marco Leise (23/70) May 14 2017 No, that is not possible. An alias can only be assigned a
- Bauss (4/27) May 15 2017 pragma(inline, true); doesn't actually do what you think it does.
- Marco Leise (12/15) May 17 2017
- Mike B Johnson (16/52) May 14 2017 1. Use template, that is what they are for
- Stanislav Blinov (14/14) May 14 2017 On the point of "not possible...", "only a symbol...", etc:
- Moritz Maxeiner (8/18) May 14 2017 That's a pretty cool workaround, but not an alias to the cast,
- ag0aep6g (9/14) May 14 2017 [...]
- Stanislav Blinov (6/21) May 14 2017 Yep, it's an alias to template function instantiation, that is,
- Moritz Maxeiner (4/10) May 14 2017 Which just reinforces my personal mantra: Develop with dmd,
- Moritz Maxeiner (3/18) May 14 2017 You're right. I forgot about the alias to a symbol rule (event
I have a piece of code that takes a callback function. The callback has the signature void callback(void* state, void* data) There are several of these functions. All of them use state and data as differing types. As an example, let's look at one that uses both of them as int*. addInt(void* state, void* data) { *cast(int*)state += *cast(int*)data; } Is it not possible to specify the cast as an alias so that I can declare the cast once at the beginning of the function? Something like this? addInt(void* state, void* data) { alias _state = cast(int*)state; // Error: basic type expected, not cast alias _data = cast(int*)data; // Error: basic type expected, not cast *_state += *_data; } I can always do this: addInt(void* state, void* data) { int* _state = cast(int*)state; int* _data = cast(int*)data; *_state += *_data; } But I don't want to create a new variable and assign it everytime I call the function. The examples I'm using are contrived, but in the c code I am porting this from, the callback gets called thousands of times a second, every optimization matters, and the variables are used many times per function. I don't want to riddle the code with casts if i can avoid it and I don't want to create and destroy useless proxy variables every time the function is called.
May 14 2017
On Sunday, 14 May 2017 at 20:18:24 UTC, Kevin Brogan wrote:I have a piece of code that takes a callback function. The callback has the signature void callback(void* state, void* data) There are several of these functions. All of them use state and data as differing types. As an example, let's look at one that uses both of them as int*. addInt(void* state, void* data) { *cast(int*)state += *cast(int*)data; } Is it not possible to specify the cast as an alias so that I can declare the cast once at the beginning of the function? Something like this? addInt(void* state, void* data) { alias _state = cast(int*)state; // Error: basic type expected, not cast alias _data = cast(int*)data; // Error: basic type expected, not cast *_state += *_data; } I can always do this: addInt(void* state, void* data) { int* _state = cast(int*)state; int* _data = cast(int*)data; *_state += *_data; } But I don't want to create a new variable and assign it everytime I call the function. The examples I'm using are contrived, but in the c code I am porting this from, the callback gets called thousands of times a second, every optimization matters, and the variables are used many times per function. I don't want to riddle the code with casts if i can avoid it and I don't want to create and destroy useless proxy variables every time the function is called.First: Any decent compiler will optimize both the variable _state, as well as the variable _data out[1][2], this sounds like a classic case of *evil* early optimization. Trust your compiler to get it right; and if you're not sure, check the generated assembly. Second: No, it is not possible, because an alias is a symbol that stands in for another type[3], not for an expression. [1] https://godbolt.org/g/X4D02i [2] https://godbolt.org/g/6i52Tt [3] https://dlang.org/spec/declaration.html#alias
May 14 2017
Am Sun, 14 May 2017 20:18:24 +0000 schrieb Kevin Brogan <kevin brogan.ca>:I have a piece of code that takes a callback function. The callback has the signature void callback(void* state, void* data) There are several of these functions. All of them use state and data as differing types. As an example, let's look at one that uses both of them as int*. addInt(void* state, void* data) { *cast(int*)state += *cast(int*)data; } Is it not possible to specify the cast as an alias so that I can declare the cast once at the beginning of the function? Something like this? addInt(void* state, void* data) { alias _state = cast(int*)state; // Error: basic type expected, not cast alias _data = cast(int*)data; // Error: basic type expected, not cast *_state += *_data; }No, that is not possible. An alias can only be assigned a symbol.I can always do this: addInt(void* state, void* data) { int* _state = cast(int*)state; int* _data = cast(int*)data; *_state += *_data; } But I don't want to create a new variable and assign it everytime I call the function. The examples I'm using are contrived, but in the c code I am porting this from, the callback gets called thousands of times a second, every optimization matters, and the variables are used many times per function. I don't want to riddle the code with casts if i can avoid it and I don't want to create and destroy useless proxy variables every time the function is called.Let the compiler optimize the assignment away and don't worry much about it. Inlining also works well within the same module. In this case here I would probably use "consume" functions as I dub them: import std.traits; pragma(inline, true) /* Not really needed I hope ;) */ ref T consume(T)(ref void* data) if (!hasIndirections!T) { T* ptr = cast(T*)data; data += T.sizeof; return *ptr; } You can then rewrite your addInt function like this: void add(T)(void* state, void* data) if (isNumeric!T) { state.consume!T += data.consume!T; } -- Marco
May 14 2017
On Sunday, 14 May 2017 at 21:07:36 UTC, Marco Leise wrote:Am Sun, 14 May 2017 20:18:24 +0000 schrieb Kevin Brogan <kevin brogan.ca>:pragma(inline, true); doesn't actually do what you think it does. In lining is always done whenever possible and that only tells the compiler to spit out an error if it can't inline it.[...]No, that is not possible. An alias can only be assigned a symbol.[...]Let the compiler optimize the assignment away and don't worry much about it. Inlining also works well within the same module. In this case here I would probably use "consume" functions as I dub them: import std.traits; pragma(inline, true) /* Not really needed I hope ;) */ ref T consume(T)(ref void* data) if (!hasIndirections!T) { T* ptr = cast(T*)data; data += T.sizeof; return *ptr; } You can then rewrite your addInt function like this: void add(T)(void* state, void* data) if (isNumeric!T) { state.consume!T += data.consume!T; }
May 15 2017
Am Mon, 15 May 2017 19:30:00 +0000 schrieb Bauss <jj_1337 live.dk>:pragma(inline, true); doesn't actually do what you think it does. In lining is always done whenever possible and that only tells the compiler to spit out an error if it can't inline it.A compiler doesn't simply inline whenever it can. A big function that's called often would lead to massive code duplication in that case. What I meant pragma(inline, true) to do is overrule this cost calculation. Since the OP asked for no extra function calls, the error on failure to inline seemed appropriate. Cross-module inlining may fail for example on some compiler(s) or with separate compilation. -- Marco
May 17 2017
On Sunday, 14 May 2017 at 20:18:24 UTC, Kevin Brogan wrote:I have a piece of code that takes a callback function. The callback has the signature void callback(void* state, void* data) There are several of these functions. All of them use state and data as differing types. As an example, let's look at one that uses both of them as int*. addInt(void* state, void* data) { *cast(int*)state += *cast(int*)data; } Is it not possible to specify the cast as an alias so that I can declare the cast once at the beginning of the function? Something like this? addInt(void* state, void* data) { alias _state = cast(int*)state; // Error: basic type expected, not cast alias _data = cast(int*)data; // Error: basic type expected, not cast *_state += *_data; } I can always do this: addInt(void* state, void* data) { int* _state = cast(int*)state; int* _data = cast(int*)data; *_state += *_data; } But I don't want to create a new variable and assign it everytime I call the function. The examples I'm using are contrived, but in the c code I am porting this from, the callback gets called thousands of times a second, every optimization matters, and the variables are used many times per function. I don't want to riddle the code with casts if i can avoid it and I don't want to create and destroy useless proxy variables every time the function is called.1. Use template, that is what they are for addInt(A, B)(A* state, B* data) { static if(is(B == int)) { // B is an int if this block is called so no reason to cast. } } 2. Use overloads, basically same as templates. addInt(int* state, int* data) { } 3. Don't worry about it, any extra temp variables will almost surely be optimized away.
May 14 2017
On the point of "not possible...", "only a symbol...", etc: T* ptrCast(T, alias ptr)() { return cast(T*)ptr; } void addInt(void* state, void* data) { alias _state = ptrCast!(int, state); alias _data = ptrCast!(int, data); static assert(!is(typeof(_state) == int*)); static assert(!is(typeof(_data) == int*)); *_state += *_data; } But take heed to the compiler optimization advice. DMD generates pretty horrendous code for this. LDC does rather well though. Since speed matters, always look at the assembly. Look at it even if it doesn't ;)
May 14 2017
On Sunday, 14 May 2017 at 21:16:04 UTC, Stanislav Blinov wrote:On the point of "not possible...", "only a symbol...", etc: T* ptrCast(T, alias ptr)() { return cast(T*)ptr; } void addInt(void* state, void* data) { alias _state = ptrCast!(int, state); alias _data = ptrCast!(int, data); static assert(!is(typeof(_state) == int*)); static assert(!is(typeof(_data) == int*)); *_state += *_data; }That's a pretty cool workaround, but not an alias to the cast, but an alias to a parametrized function template (a type), so I will stick to my statement of "not possible". AFAIK, this would also invoke the respective function template instance for ptrCast every time _state or _data are referenced, so if we're going with the spirit of the question that's still going to be horrible if the compiler doesn't optimize ;p
May 14 2017
On 05/14/2017 11:35 PM, Moritz Maxeiner wrote:On Sunday, 14 May 2017 at 21:16:04 UTC, Stanislav Blinov wrote:[...][...]T* ptrCast(T, alias ptr)() { return cast(T*)ptr; }[...]alias _state = ptrCast!(int, state);That's a pretty cool workaround, but not an alias to the cast, but an alias to a parametrized function template (a type),Not sure if I'm reading that right, but `_state` is not an alias of a (parametrized function) template. The template instantiation results in a function. `_state` is an alias of that function. `alias foo = ptrCast;` would make an alias of the template. Neither of them is a type.
May 14 2017
On Sunday, 14 May 2017 at 21:55:01 UTC, ag0aep6g wrote:On 05/14/2017 11:35 PM, Moritz Maxeiner wrote:Yep, it's an alias to template function instantiation, that is, concrete function - a symbol. But of course, it *is* going to be called on every "dereference". GDC optimizes the call away starting at -O1, LDC needs -O2. DMD makes temporaries :)On Sunday, 14 May 2017 at 21:16:04 UTC, Stanislav Blinov wrote:[...][...]T* ptrCast(T, alias ptr)() { return cast(T*)ptr; }[...]alias _state = ptrCast!(int, state);That's a pretty cool workaround, but not an alias to the cast, but an alias to a parametrized function template (a type),Not sure if I'm reading that right, but `_state` is not an alias of a (parametrized function) template. The template instantiation results in a function. `_state` is an alias of that function. `alias foo = ptrCast;` would make an alias of the template. Neither of them is a type.
May 14 2017
On Sunday, 14 May 2017 at 22:00:58 UTC, Stanislav Blinov wrote:[...] Yep, it's an alias to template function instantiation, that is, concrete function - a symbol.Yes, my bad :(But of course, it *is* going to be called on every "dereference". GDC optimizes the call away starting at -O1, LDC needs -O2. DMD makes temporaries :)Which just reinforces my personal mantra: Develop with dmd, release with ldc or gdc.
May 14 2017
On Sunday, 14 May 2017 at 21:55:01 UTC, ag0aep6g wrote:On 05/14/2017 11:35 PM, Moritz Maxeiner wrote:You're right. I forgot about the alias to a symbol rule (event though I myself just linked to it :/ ). Sorry about that.On Sunday, 14 May 2017 at 21:16:04 UTC, Stanislav Blinov wrote:[...][...]T* ptrCast(T, alias ptr)() { return cast(T*)ptr; }[...]alias _state = ptrCast!(int, state);That's a pretty cool workaround, but not an alias to the cast, but an alias to a parametrized function template (a type),Not sure if I'm reading that right, but `_state` is not an alias of a (parametrized function) template. The template instantiation results in a function. `_state` is an alias of that function. `alias foo = ptrCast;` would make an alias of the template. Neither of them is a type.
May 14 2017