1 module gfx.core.util;
2 
3 /// Down cast of a reference to a child class reference
4 /// runtime check is disabled in release build
5 /// If T is a base class of U, this does a blind cast to the same address.
6 /// If T is an interface implemented by U, it first offset address to the object base address
7 /// and does a blind cast to that address.
8 template unsafeCast(U) if (!is(U == const))
9 {
10     static assert (!is(U == interface), "unsafeCast cannot be used to return interfaces");
11     static assert (is(U == class), "unsafeCast can only be used with objects");
12 
13     @system
14     U unsafeCast(T)(T obj)
15             if ((is(T==class) || is(T==interface)) && is(U : T))
16     {
17         if (!obj) return null;
18         debug {
19             auto uObj = cast(U)obj;
20             assert(uObj, "unsafeCast from "~T.stringof~" to "~U.stringof~" failed");
21             return uObj;
22         }
23         else {
24             static if (is(T == interface)) {
25                 return cast(U)(cast(void*)(cast(Object)obj));
26             }
27             else {
28                 return cast(U)(cast(void*)obj);
29             }
30         }
31     }
32 
33 }
34 
35 /// ditto
36 template unsafeCast(U) if (is(U == const))
37 {
38     static assert (!is(U == interface), "unsafeCast cannot be used to return interfaces");
39     static assert (is(U == class), "unsafeCast can only be used with objects");
40 
41     @system
42     U unsafeCast(T)(const(T) obj)
43             if ((is(T==class) || is(T==interface)) && is(U : const(T)))
44     {
45         if (!obj) return null;
46         debug {
47             auto uObj = cast(U)obj;
48             assert(uObj, "unsafeCast from "~T.stringof~" to "~U.stringof~" failed");
49             return uObj;
50         }
51         else {
52             static if (is(T == interface)) {
53                 return cast(U)(cast(const(void*))(cast(const(Object))obj));
54             }
55             else {
56                 return cast(U)(cast(const(void*))obj);
57             }
58         }
59     }
60 }
61 
62 
63 /// Return a bit by bit unchecked identical representation of the passed argument
64 template transmute(U)
65 {
66     import std.traits : isDynamicArray;
67 
68     static if (!isDynamicArray!U) {
69         @system @nogc nothrow pure
70         U transmute(T)(in T value)
71         {
72             static assert(T.sizeof == U.sizeof, "can only transmute to identical type size");
73             static assert(!is(T == class) && !is(T == interface), "cannot used transmute on objects");
74             static assert(!is(U == class) && !is(U == interface), "cannot used transmute on objects");
75 
76             return *cast(U*)cast(void*)&value;
77         }
78     }
79     else {
80         @system @nogc nothrow pure
81         U transmute(T)(T[] value)
82         {
83             import std.traits : isMutable;
84 
85             alias V = typeof(U.init[0]);
86 
87             static assert(T.sizeof == V.sizeof, "can only transmute to identical type size");
88             static assert(!is(T == class) && !is(T == interface), "cannot used transmute on objects");
89             static assert(!is(V == class) && !is(V == interface), "cannot used transmute on objects");
90             static if (!isMutable!V) {
91                 static assert(!isMutable!T, "transmute is not meant to cast constness away");
92             }
93 
94             return (cast(V*)cast(void*)value.ptr)[0 .. value.length];
95         }
96     }
97 }