Thread overview
Convert this C macro kroundup32 to D mixin?
Apr 08, 2017
biocyberman
Apr 08, 2017
Mike Parker
Apr 08, 2017
Mike Parker
Apr 08, 2017
biocyberman
Apr 08, 2017
Nicholas Wilson
Apr 08, 2017
biocyberman
Apr 08, 2017
biocyberman
Apr 08, 2017
Ali Çehreli
Apr 09, 2017
biocyberman
April 08, 2017
What is the D mixin version equivalent to this macro:

#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))

The macro looks cryptic. What the macro does has been explained here: http://stackoverflow.com/questions/3384852/could-someone-help-explain-what-this-c-one-liner-does

But I still don't know how to convert that to D mixin. I would like 'mixin' instead of a function is to avoid function call overhead. Also because it is short, so I think a mixin is enough, not a 'template mixin'.


April 08, 2017
On Saturday, 8 April 2017 at 09:53:47 UTC, biocyberman wrote:
>
> What is the D mixin version equivalent to this macro:
>
> #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
>
> The macro looks cryptic. What the macro does has been explained here: http://stackoverflow.com/questions/3384852/could-someone-help-explain-what-this-c-one-liner-does
>
> But I still don't know how to convert that to D mixin. I would like 'mixin' instead of a function is to avoid function call overhead. Also because it is short, so I think a mixin is enough, not a 'template mixin'.

I would expect if you implement it as a function the compiler will inline it. You can always use the pragma(inline, true) [1] with -inline to verify.

[1] https://dlang.org/spec/pragma.html#inline
April 08, 2017
On Saturday, 8 April 2017 at 10:02:01 UTC, Mike Parker wrote:

>
> I would expect if you implement it as a function the compiler will inline it. You can always use the pragma(inline, true) [1] with -inline to verify.
>
> [1] https://dlang.org/spec/pragma.html#inline

This gives me no error, so it does inline it.

T kroundup32(T)(T x) {
    pragma(inline, true);
    --(x);
    (x)|=(x)>>1;
    (x)|=(x)>>2;
    (x)|=(x)>>4;
    (x)|=(x)>>8;
    (x)|=(x)>>16;
    return ++(x);
}
April 08, 2017
On Saturday, 8 April 2017 at 10:02:01 UTC, Mike Parker wrote:
>
> I would expect if you implement it as a function the compiler will inline it. You can always use the pragma(inline, true) [1] with -inline to verify.
>
> [1] https://dlang.org/spec/pragma.html#inline

Thanks for mentioning pragma. However, anyway to do it with mixin? It's so cool so I want to do more stuffs with it :)
April 08, 2017
On Saturday, 8 April 2017 at 10:09:47 UTC, Mike Parker wrote:
> T kroundup32(T)(T x) {
>     pragma(inline, true);
>     --(x);
>     (x)|=(x)>>1;
>     (x)|=(x)>>2;
>     (x)|=(x)>>4;
>     (x)|=(x)>>8;
>     (x)|=(x)>>16;
>     return ++(x);
> }


I also came up with this:

import std.stdio;
pragma( inline, true ):
static int kroundup32( int x){
--(x);
writeln("X: ",x);
 (x)|=(x)>>1;
writeln("X: ",x);
 (x)|=(x)>>2;
writeln("X: ",x);
(x)|=(x)>>4;
writeln("X: ",x);
 (x)|=(x)>>8;
writeln("X: ",x);
 (x)|=(x)>>16;
writeln("X: ",x);
 ++(x);
writeln("X: ",x);

 return x;
}

int main(){
  int num = 31;
  num = kroundup32(num);
  writeln("Num:", num);
  return 0;
}

Is this way of using pragma the same as your way? I am still new to this so I want to understand more.

And is it a good idea to do manipulate 'num' directly so I can omit 'return' and avoid re-assigning statement? That's what C version does.
April 08, 2017
On Saturday, 8 April 2017 at 11:01:34 UTC, biocyberman wrote:
> On Saturday, 8 April 2017 at 10:09:47 UTC, Mike Parker wrote:
>> T kroundup32(T)(T x) {
>>     pragma(inline, true);
>>     --(x);
>>     (x)|=(x)>>1;
>>     (x)|=(x)>>2;
>>     (x)|=(x)>>4;
>>     (x)|=(x)>>8;
>>     (x)|=(x)>>16;
>>     return ++(x);
>> }
>
>
> I also came up with this:
>
> import std.stdio;
> pragma( inline, true ):
> static int kroundup32( int x){
> --(x);
> writeln("X: ",x);
>  (x)|=(x)>>1;
> writeln("X: ",x);
>  (x)|=(x)>>2;
> writeln("X: ",x);
> (x)|=(x)>>4;
> writeln("X: ",x);
>  (x)|=(x)>>8;
> writeln("X: ",x);
>  (x)|=(x)>>16;
> writeln("X: ",x);
>  ++(x);
> writeln("X: ",x);
>
>  return x;
> }
>
> int main(){
>   int num = 31;
>   num = kroundup32(num);
>   writeln("Num:", num);
>   return 0;
> }
>
> Is this way of using pragma the same as your way? I am still new to this so I want to understand more.

The ':' means that it applies to everything that follows it, so while it doesn't matters in this example if you had
pragma( inline, true ):
int kroundup32( int x) { ... }

auto someVeryLargeFunction( Args args)
{
    // ...
}

and then you used someVeryLargeFunction in a bunch of places then that would cause a lot of binary bloat.
>
> And is it a good idea to do manipulate 'num' directly so I can omit 'return' and avoid re-assigning statement? That's what C version does.

if you want the the function to affect the variable use a 'ref' as in

 void kroundup32(T)(ref T x) {
     pragma(inline, true);
     --(x);
     (x)|=(x)>>1;
     (x)|=(x)>>2;
     (x)|=(x)>>4;
     (x)|=(x)>>8;
     (x)|=(x)>>16;
     return ++(x);
 }

 int main(){
   int num = 31;
   writeln("Before: ",num); // 31
   kroundup32(num);
   writeln("After: ", num);   //32
   return 0;
 }

is it a good idea? I would not think it is necessary.

As an aside the C version has parentheses around the "x" because it is a macro and it is substituted as text not symbolically, they are not needed in D.
April 08, 2017
On Saturday, 8 April 2017 at 11:24:02 UTC, Nicholas Wilson wrote:

> The ':' means that it applies to everything that follows it, so while it doesn't matters in this example if you had
> pragma( inline, true ):
> int kroundup32( int x) { ... }
>
> auto someVeryLargeFunction( Args args)
> {
>     // ...
> }
>
> and then you used someVeryLargeFunction in a bunch of places then that would cause a lot of binary bloat.

That's big difference! Thank you for pointing this out for me.


> if you want the the function to affect the variable use a 'ref' as in
>
>  void kroundup32(T)(ref T x) {
>      pragma(inline, true);
>      --(x);
>      (x)|=(x)>>1;
>      (x)|=(x)>>2;
>      (x)|=(x)>>4;
>      (x)|=(x)>>8;
>      (x)|=(x)>>16;
>      return ++(x);
>  }
>
>  int main(){
>    int num = 31;
>    writeln("Before: ",num); // 31
>    kroundup32(num);
>    writeln("After: ", num);   //32
>    return 0;
>  }
>
> is it a good idea? I would not think it is necessary.
>
> As an aside the C version has parentheses around the "x" because it is a macro and it is substituted as text not symbolically, they are not needed in D.

This thing now is clear and settled while I try to navigate my mind around many new things. Really appreciate your help, Nicolas.


April 08, 2017
On 04/08/2017 03:11 AM, biocyberman wrote:
> On Saturday, 8 April 2017 at 10:02:01 UTC, Mike Parker wrote:
>>
>> I would expect if you implement it as a function the compiler will
>> inline it. You can always use the pragma(inline, true) [1] with
>> -inline to verify.
>>
>> [1] https://dlang.org/spec/pragma.html#inline
>
> Thanks for mentioning pragma. However, anyway to do it with mixin? It's
> so cool so I want to do more stuffs with it :)

You can mixin declarations with a template but I don't see how it can help here. A string mixin would work but it's really ugly at the use site:

string roundUp(alias x)()
if (is (typeof(x) == uint)) {

    import std.string : format;
    return format(q{
        --%1$s;
        %1$s |= %1$s >>  1;
        %1$s |= %1$s >>  2;
        %1$s |= %1$s >>  4;
        %1$s |= %1$s >>  8;
        %1$s |= %1$s >> 16;
        ++%1$s;
        }, x.stringof);
}

void main() {
    uint i = 42;
    mixin (roundUp!i);    // <-- Ugly

    assert(i == 64);
}

Compare that to the following natural syntax that a function provides:

void roundUp(ref uint x) {
    // ...
}

void main() {
    uint i = 42;
    i.roundUp();    // <-- Natural
}

Ali

April 09, 2017
On Saturday, 8 April 2017 at 21:34:30 UTC, Ali Çehreli wrote:
> You can mixin declarations with a template but I don't see how it can help here. A string mixin would work but it's really ugly at the use site:
>
> string roundUp(alias x)()
> if (is (typeof(x) == uint)) {
>
>     import std.string : format;
>     return format(q{
>         --%1$s;
>         %1$s |= %1$s >>  1;
>         %1$s |= %1$s >>  2;
>         %1$s |= %1$s >>  4;
>         %1$s |= %1$s >>  8;
>         %1$s |= %1$s >> 16;
>         ++%1$s;
>         }, x.stringof);
> }
>
> void main() {
>     uint i = 42;
>     mixin (roundUp!i);    // <-- Ugly
>
>     assert(i == 64);
> }
>
> Compare that to the following natural syntax that a function provides:
>
> void roundUp(ref uint x) {
>     // ...
> }
>
> void main() {
>     uint i = 42;
>     i.roundUp();    // <-- Natural
> }
>
> Ali

You made the point, it looks really ugly :). However, sometimes if this ugliness offer better performance, I would - in a desperate mood - use it. That's only 'if'. I put two other variant to a test, and this ugly version does worst as well. You can check out here: https://gist.github.com/biocyberman/0ad27721780e66546cbb6a39c0770d99

Maybe it is because string formating cost. Moving the import statement out of the function does not speed things up.