Skip to content

Type Punning with Pun Cast

template <typename T, typename U>
T pxart::pun_cast(U x);

Reinterprets object of type U as object of type T with the same bit representation. T and U need to have the same size. This function adheres to the strict-aliasing rules.

Typically, such type punning is done to reinterpret floating-point types as unsigned integers to manipulate their sign bit and compute the absolute value for example. Here, pun_cast can also be used to reinterpret an SIMD type as an arbitray vector type to be able to access single elements.

Include Scheme

#include <pxart/utility/pun_cast.hpp>

Complexity

Constant time complexity. The function should result in only one processor instruction but uses std::memcpy to not violate the strict-aliasing rules.

Exceptions

The function itself throws no exceptions. But the inner call to std::memcpy could throw.

Example

#include <array>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <random>
//
#include <pxart/simd256/mt19937.hpp>
#include <pxart/utility/pun_cast.hpp>

using namespace std;

int main() {
  // Define standard random number generator for comparisons.
  std::mt19937 rng{};

  // Define PRNG which uses 256-bit vector registers as output.
  pxart::simd256::mt19937 vrng{};
  using uint_type = decltype(vrng)::uint_type;
  constexpr size_t simd_size = decltype(vrng)::simd_size;

  constexpr size_t n = 10;
  for (int i = 0; i < n; i += simd_size) {
    // Generate random 256-bit vector and reinterpret it as 8-dimensional array
    // of 32-bit unsigned integers.
    const auto vrnd = pxart::pun_cast<array<uint_type, simd_size>>(vrng());

    // Output generated random numbers.
    for (int j = 0; j < simd_size; ++j) {
      const auto rnd = rng();
      cout << setw(20) << rnd << setw(20) << vrnd[j] << '\n';
    }
  }
}

Last update: January 18, 2021