Checking if a vector of structs is contiguous in memory

question

#1

Hi,

So I have an vector of tuples of floats, i.e.: Array{Tuple{Float64,Float64},1}(). I know that tuples are immutables and so theoretically this array should be contiguous in memory and there should be no pointers in the vector or the tuples. Is this true? And more generally is there a way that I can check whether is type in contiguous in memory or whether it contains pointers in it?

Thanks.


#2

You could try something like that:

x = Array{Tuple{Float64,Float64},1}()
push!(x,(1.,1.),(2.,2.),(3.,3.))

ptr = pointer(x)
offset = sizeof(x[1])
unsafe_load(ptr)
unsafe_load(ptr+offset)
unsafe_load(ptr+2offset)

#3

You can get a pointer to the n-th element of a vector v using pointer(v,n). The difference between two consecutive indices gives accordingly the size occupied by one element in the vector. You can then compare that to the actual size of the elements of v:

v = Vector( [(1., 2., 3.), (4., 5., 6.), (7., 8., 9.)] )
d = Signed(pointer(v,2) - pointer(v,1))      # = 24
d == sizeof(eltype(v)) ? "contiguous" : "non-contiguous or padded"
# prints "contiguous"

If you work with Array then the above should always hold if eltype(v) is a bitstype; check with Base.isbits(eltype(v)). For other element types or AbstractArray in general, it is not necessarily the case.
Also, if v were a SubArray, you could directly use Base.iscontiguous(v), which unfortunately is not implemented for plain Array types…

s = SubArray( v, (1:3,))   # make a subarray from `v`
Base.iscontiguous(s)       # returns true

#4

This does not tell you if there’s indirection.

If you want to programatically check if an Array has no indirection, isbits(eltype(v)) should tell you. If you want to verify/see it yourself, you can use the unsafe_load in @jonathanBieler’s answer to check. Note that d == sizeof(eltype(v)) is wrong since it gives your wrong answer for mutable struct of the right size.


#5

True. Further, d == sizeof(eltype(v)) would give a false positive if eltype(v) were mutable and sizeof(eltype(v)) were of size of a pointer… A generalization of Base.iscontigous might indeed be quite useful.


#6

Base.iscontiguous is not meant for this. It’s only for indexing.


#7

Looks like isbits(eltype(x)) works for this particular case and the unsafe_load method works in general. Thanks for the prompt answers everyone.


#8

Just to be clear that you should not use this in real code. You can get a segfault if you made the wrong guess.


#9

Oh yes I got that. I just wanted to check that this data structure is continguous to make sure it won’t be too slow.