Use a union in Variant for safe type punning
Create a `VaraintUnion` that is an actual C++ `union` to store the data in a `Variant`. You may be asking yourself, why not just use an `std::aligned_union` rather than a real union type? That was our first implementation, but the problem is that the `std::aligned_union` reference needs to be recast to the actual type. Typically you would do that with `reinterpret_cast`. However, doing that leads to undefined behavior. The C++ compiler assumes that 2 pointers of different types point to different memory (even if it is clear that they are set to the same address). That means optimizers can remove code because it "knows" that data in one type cannot affect data in another type. To safely change the type of an `std::aligned_union`, you really have to do an `std::memcpy`. This is problematic for types that cannot be trivially copied. Another problem is that we found that device compilers do not optimize the memcpy as well as most CPU compilers. Likely, memcpy is used much less frequently on GPU devices.
Showing with 2664 additions and 1865 deletions