[swift-users] Can I use a tuple to force a certain memory layout?

Johannes Weiß johannesweiss at apple.com
Fri Jul 21 09:54:50 CDT 2017



> On 21 Jul 2017, at 1:45 am, Taylor Swift <kelvin13ma at gmail.com> wrote:
> 
> Okay, apparently layout is only guaranteed if the reference is to the tuple itself, not a member of the tuple. Don’t know if this is a bug or intended behavior. The above code works when written as 
> 
>         var buffers:(VBO:GL.UInt, EBO:GL.UInt) = (0, 0)
>         withUnsafeMutablePointer(to: &buffers)
>         {
>             $0.withMemoryRebound(to: UInt32.self, capacity: 2)
>             {
>                 glGenBuffers(n: 2, buffers: $0)
>             }
>         }

this is legal now as you're now observing the whole tuple rather than just one value. That means they're now guaranteed to be in standard C layout.

In other words, Swift could have the tuple in memory like this

+-----+----------+-----+
| VBO | whatever | EBO |
+-----+----------+-----+
   ^     ^         ^
   |     |         |
   a     b         c

when you now get a pointer to &buffers.VBO, you'll get the pointer 'a' and as you see, you'll not be guaranteed to have EBO right next to it.

It you however request a pointer to `buffers` as a whole, the Swift compiler will do whatever is necessary to give you a compound view in standard C layout. Ie. it might copy it into


+-----+-----+
| VBO | EBO |
+-----+-----+

and after the call returns put the VBO and EBO values back where they're supposed to be.

Does that make sense?

-- Johannes

> 
> 
> 
> On Thu, Jul 20, 2017 at 3:01 PM, Taylor Swift via swift-users <swift-users at swift.org> wrote:
> This does not seem to be the case…
> 
>     var buffers:(VBO:GL.UInt, EBO:GL.UInt) = (0, 0)
>     glGenBuffers(n: 2, buffers: &buffers.VBO)
>     print(buffers)
>     // > (VBO: 4, EBO: 0)
> 
>     var buffers:(VBO:GL.UInt, EBO:GL.UInt) = (0, 0)
>     glGenBuffers(n: 1, buffers: &buffers.VBO)
>     glGenBuffers(n: 1, buffers: &buffers.EBO)
>     print(buffers)
>     // > (VBO: 4, EBO: 5)
> 
> On Thu, Jul 20, 2017 at 1:18 PM, Johannes Weiß <johannesweiss at apple.com> wrote:
> Hi,
> 
> > On 20 Jul 2017, at 5:41 pm, Taylor Swift <kelvin13ma at gmail.com> wrote:
> >
> > Does addressof count as legally observing it?
> >
> >         var buffers:(GL.UInt, GL.UInt) = (0, 0)
> >         glGenBuffers(n: 2, buffers: &buffers.0)
> >
> > Also, I assume Swift performs a swizzle if the tuple is defined in a separate module from where the pointer to it is constructed?
> 
> yes, that's legal assuming the called function doesn't store the pointer and read/write it later.
> 
> 
> >
> > On Thu, Jul 20, 2017 at 4:59 AM, Johannes Weiß <johannesweiss at apple.com> wrote:
> > When you can (legally) observe it, tuples in Swift have guaranteed standard C-style layout.
> >
> > John McCall confirms this here: https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20170424/004481.html
> >
> > > On 20 Jul 2017, at 4:33 am, Taylor Swift via swift-users <swift-users at swift.org> wrote:
> > >
> > > Many APIs like OpenGL take arrays where the atomic unit is multiple elements long. For example, a buffer of coordinates laid out like
> > >
> > > :[Float] = [ x1, y1, z1, x2, y2, z2, ... , xn, yn, zn ]
> > >
> > > I want to be able to define in Swift (i.e., without creating and importing a Objective C module) a struct that preserves the layout, so that I can do withMemoryRebound(to:capacity:_) or something similar and treat the buffer as
> > >
> > > struct Point
> > > {
> > >     let x:Float,
> > >         y:Float,
> > >         z:Float
> > > }
> > >
> > > :[Point] = [ point1, point2, ... , pointn ]
> > >
> > > The memory layout of the struct isn’t guaranteed, but will the layout be guaranteed to be in declaration order if I use a tuple inside the struct instead?
> > >
> > > struct Point
> > > {
> > >     let _point:(x:Float, y:Float, z:Float)
> > >
> > >     var x:Float
> > >     {
> > >         return self._point.x
> > >     }
> > >
> > >     var y:Float
> > >     {
> > >         return self._point.y
> > >     }
> > >
> > >     var z:Float
> > >     {
> > >         return self._point.z
> > >     }
> > > }
> > >
> > > This is an ugly workaround, but I can’t really think of any alternatives that don’t involve “import something from Objective C”. I am aware that the implementation of structs currently lays them out in declaration order, but I’m looking for something that’s actually defined in the language.
> > >
> > >
> > > _______________________________________________
> > > swift-users mailing list
> > > swift-users at swift.org
> > > https://lists.swift.org/mailman/listinfo/swift-users
> >
> >
> 
> 
> 
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
> 
> 



More information about the swift-users mailing list