[OT] Checked opCast

Timon Gehr via Digitalmars-d digitalmars-d at puremagic.com
Sat Jul 2 17:57:04 PDT 2016


On 02.07.2016 14:26, Andrei Alexandrescu wrote:
>
> How would you reshape this? It's important that the call to hook is
> physically at the end of the function and issued just in that place, and
> that the code does not do any redundant work.
>
> U hook(U, T)(T value) { return U.init; }
>
> U opCast(U, T)(T payload)
> {
>      import std.traits;
>      do
>      {
>          static if (!isUnsigned!T && isUnsigned!U &&
>                     T.sizeof <= U.sizeof)
>          {
>              if (payload < 0) break; // extra check needed
>          }
>          auto result = cast(U) payload;
>          if (result != payload) break;
>          static if (isUnsigned!T && !isUnsigned!U)
>          {
>              static assert(U.sizeof <= T.sizeof);
>              if (result < 0) break;
>          }
>          return result;
>      } while (0);
>      return hook!U(payload);
> }
>
> void main()
> {
>      opCast!short(42);
> }
>
>
> Thanks,
>
> Andrei

How do you decide what 'redundant work' is? Is this combination of 
branches and type casts really particularly cheap to execute? Could 
masking out the "sign bit" from the unsigned value before comparison be 
faster? Also, isn't the result != payload check redundant if sizeof(U) 
== sizeof(T)?

Anyway, this is the kind of optimization that compilers are supposed to 
be good at, it should pick whatever procedure is optimal, not 
necessarily the one specified. Personally, I'd just write something like:

U opCast(U,T)(T payload)if(...){
     auto result = cast(U)payload;
     if(result == payload && (result<0) == (payload<0))
         return result;
     return hook!U(payload);
}


More information about the Digitalmars-d mailing list