How to Reinterpret_Cast in Swift

How to reinterpret_cast in Swift?

withMemoryRebound(to:capacity:_:) can be used

... when you have a pointer to memory bound to one type and you need to access that memory as instances of another type.

Example: Take the address of the general struct, then rebind and dereference the pointer:

let general = GeneralStruct()

let specific = withUnsafePointer(to: general) {
$0.withMemoryRebound(to: SpecificStruct.self, capacity: 1) {
$0.pointee
}
}

If both types have the same size and a compatible memory layout then you can also use unsafeBitCast(_:to:):

Use this function only to convert the instance passed as x to a layout-compatible type when conversion through other means is not possible.

Warning: Calling this function breaks the guarantees of the Swift type system; use with extreme care.

Example:

let specific = unsafeBitCast(general, to: SpecificStruct.self)

How to reinterpret_cast with pointer to MTLBuffer Swift adaptation

Obviously I can't verify this on my machine, but you should be able to do something like this.

var noiseRaw = noiseBuffer.contents()
let samples = noiseRaw.bindMemory(
to: RandomSample.self,
capacity: NOISE_BLOCK_SIZE * NOISE_BLOCK_SIZE
)

for i in 0..<NOISE_BLOCK_SIZE * NOISE_BLOCK_SIZE {
let sample = samples + i
sample.pointee.componentSample = Float.random(in: 0..<1)
sample.pointee.emitterSample = Float.random(in: 0..<1)
sample.pointee.rrSample = Float.random(in: 0..<1)
}

How to do a reinterpret_cast with Obj-C?

After the clarification you are after reinterpret_cast:

You are correct you can do it with a union. If you want to do it inline you can use a cast, address-of and indirection...

The C-style cast (type)expr in both (Objective-)C and C++ works similarly: if the equivalent of a static_cast is appropriate it does that, e.g. between int and float and other value types; otherwise it will do the equivalent of a reinterpret_cast, e.g. between pointer-types.

So you just need to convert to a pointer, cast, and indirect. E.g.:

int z = 0xDEADBEEF;
float y = *(float *)&z;
NSLog(@"%d -> %f", z, y);

Yes it's a bit ugly, but then what you are doing is as well ;-) To make it a bit nicer define it as a macro:

#define REINTERPRET(type, expr) (*(type *)&(expr))

which you can use as:

int z = 0xDEADBEEF;
float y = REINTERPRET(float, z);
NSLog(@"%d -> %f", z, y);

As with reinterpret_cast, you should use this sparingly and with care!

HTH

With or without reinterpret_cast

A C style cast is nothing but the C++ cast that succeeds from the predefined order of:

  • const_cast
  • static_cast
  • static_cast, then const_cast
  • reinterpret_cast
  • reinterpret_cast, then const_cast

In this case they are doing the same thing. However, if you are using C++ it is better to use C++ style of explicit casting because they are more indicative of the intent and also it's always better to be explicit about what casting you need than be at the mercy of the compiler to chose one for you.

Swift type casting and parenthesis

It looks like you can add an arbitrary number of parentheses (e.g. (((Int64)))). The main reason for the parentheses is to make a cast like (object as SomeClass).method()

reinterpret_cast vs strict aliasing

I know that char* is allowed to point to anything, but I also have a T* that points to a char*.

Right, and that is a problem. While the pointer cast itself has defined behaviour, using it to access a non-existent object of type T is not.

Unlike C, C++ does not allow impromptu creation of objects*. You cannot simply assign to some memory location as type T and have an object of that type be created, you need an object of that type to be there already. This requires placement new. Previous standards were ambiguous on it, but currently, per [intro.object]:

1 [...] An object is created by a definition (6.1), by a new-expression (8.3.4), when implicitly changing the active member of a union (12.3), or when a temporary object is created (7.4, 15.2). [...]

Since you are not doing any of these things, no object is created.

Furthermore, C++ does not implicitly consider pointers to different object at the same address as equivalent. Your &data[pos] computes a pointer to a char object. Casting it to T* does not make it point to any T object residing at that address, and dereferencing that pointer has undefined behaviour. C++17 adds std::launder, which is a way to let the compiler know that you want to access a different object at that address than what you have a pointer to.

When you modify your code to use placement new and std::launder, and ensure you have no misaligned accesses (I presume you left that out for brevity), your code will have defined behaviour.

* There is discussion on allowing this in a future version of C++.

Passing and Casting Object Types in Swift

Why you do that? You can simply implement Hashable protocol and override == operator to compare two objects. Then you can simply write: x == y without any loops.

Is it possible to pass a dynamically allocated array to a function that requires an array reference?

You can use reinterpret_cast for this. Using an alias for the array type to make the code easier to read, you would have something like:

void my_func(int (&arr)[10])
{
for (auto e : arr)
std::cout << e << " ";
}

int main()
{
using array_t = int[10];
int* my_arr = new int[10]{1,2,3,4,5,6,7,8,9,10};
my_func(reinterpret_cast<array_t&>(*my_arr));
}

And you can see that working at this live example.



Related Topics



Leave a reply



Submit