Transmuting dynamic arrays and corresponding slices

An fixed array of f64’s on the form {x0, y0, x1, y1, …}
is equivalent to an array of structs like {{x0,y0},{x1,y1}…

So it’s easy to transmute between them:

    xyData := [?]f64{12.3, 23.4, 34.5, 45.6}
    ptType :: struct{ x,y : f64 }
    ptArray := transmute([len(xyData)/2]ptType)xyData 

But I cannot find a way to do the equivalent with dynamic arrays or slices. Tips?

In your example there’s not a single dynamic array…

[?]T is a fixed array for which the compiler figures out the size. Your transmute type is also a wanna be fixed array, with the exception that len() is runtime so that wouldn’t even work. Casts/transmutes needs types at compile time.

Afaik, this would work for fixed ones:

arr := [?]f32{0.0, 1.0, 2.0, 3.0}
S :: struct { x, y: f32 }
structs := transmute([size_of(arr) / size_of(S)]S)arr

For slices and dynamic arrays the easiest is to just make them into their raw type, recalculate the length (and capacity) and cast it to the new type.

slice := []f32{0.0, 1.0, 2.0, 3.0}
raw := transmute(runtime.Raw_Slice)slice
raw.len = len(slice)/2
structs := transmute([]S)raw

Raw_Slice

Well spotted! Exactly what the OP said :wink:

Sure, but if you don’t put the code you tried and didn’t work with an error message from the compiler or a print of what you expected to see, it just makes the person trying to help scratch his/her head trying to guess what you mean.

OP asked about slices and dynamic array transmute, but showed a fixed array which was also incorrectly transmuted. This begs the question if there’s a misunderstanding of what [?]T is even before we talk about slices and dynamic arrays.

Since, to my knowledge, Odin does not have a predefined type for a 2-dimensional point or vector, I wanted to declare a function that would receive an array of such data independent of how it was implemented in that program. The user may have defined his/her own point struct. But to circumvent the problem, I decided to instead receive data on the form [[x,y][x,y],[x,y],…]. Which should be easier to cast into, fram whatever type the user has declared.

There isn’t really any need for it, because arrays already behave like mathematical vectors:

And there’s a bunch of predefined stuff in linalg including 2D vector type aliases.

So far I really only seen 2 ways of people writing a point type in Odin:

Point :: [2]f32
Point :: distinct [2]f32

The first one just works with all the predefined maths in linalg, the second is if you want to force casting and be a little bit more type safe. Structs not really used because you’d need to implement everything that arrays already support.

1 Like

For any future readers, there is a way to do this: subslice the input dynamic array of f64s and then use slice.reinterpret() to iterate over it as x,y structs.

In this case, if you just use transmute(), the length will be messed up, because transmute() does a raw bit cast, and the dynamic array length field will remain at 4 instead of changing to 2. So slice.reinterpret() is nice because it does that length calculation for you.

For example:

	xyDataDynamicArray : [dynamic]f64 = {}
	append_elems(&xyDataDynamicArray, 12.3, 23.4, 34.5, 45.6)

	// Bad code, could segfault
	fmt.println("Iterating dynamic array with transmute (bad - length is messed up - still 4 instead of 2):")
	ptDynamicArray := transmute([dynamic]ptType)xyDataDynamicArray
	for x, i in ptDynamicArray {
		fmt.println(i, "=>", x)
	}

	// Good code
	fmt.println("Iterating dynamic array with subslice and slice.reinterpret() (good):")
	xySlice := xyDataDynamicArray[:]
	ptSlice := slice.reinterpret([]ptType, xySlice)
	for x, i in ptSlice {
		fmt.println(i, "=>", x)
	}
}

output:

Iterating dynamic array with transmute (bad - length is messed up - still 4 instead of 2):
0 => ptType{x = 12.3, y = 23.4}
1 => ptType{x = 34.5, y = 45.6}
2 => ptType{x = 0, y = 0}
3 => ptType{x = 0, y = 0}
Iterating dynamic array with subslice and slice.reinterpret() (good):
0 => ptType{x = 12.3, y = 23.4}
1 => ptType{x = 34.5, y = 45.6}

See also Using transmute to iterate elements of a flattened 2d array with dynamic outer dimension

1 Like