This is the best approach that I’m aware of. It does bake in an ABI assumption 
that the tuple layout will be contiguous and strided/addressable. Monitor 
https://bugs.swift.org/browse/SR-3726 for changes here. Note that you can also 
a little more “pure” in a sense if you construct an UnsafeBufferPointer from 
your UnsafeRawPointer and operate on that. Currently, the compiler does not 
always elide the copy in the getter, see https://bugs.swift.org/browse/SR-4581


> On Apr 17, 2017, at 2:07 PM, Jens Persson via swift-evolution 
> <[email protected]> wrote:
> 
> I've used code like the following example in similar situations and I've 
> always (after a lot of profiling, trial and error) managed to get the (ugly) 
> Swift code as fast as the C/C++ code.
> 
> struct UnsafeStatic19x19<E> {
>     var storage: (
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,
>     E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E
>     )
>     subscript(x: Int, y: Int) -> E {
>         get {
>             // No index out of bounds check
>             var m = self // <-- This workaround will be optimized away.
>             return withUnsafeBytes(of: &m) {
>                 let byteOffset = MemoryLayout<E>.stride * (x + y*19)
>                 return $0.load(fromByteOffset: byteOffset, as: E.self)
>             }
>         }
>         set {
>             withUnsafeMutableBytes(of: &self) {
>                 let byteOffset = MemoryLayout<E>.stride * (x + y*19)
>                 $0.storeBytes(of: newValue, toByteOffset: byteOffset, as: 
> E.self)
>             }
>         }
>     }
> }
> 
> It isn't pretty but it works (haven't tried this code example though, but you 
> get the idea).
> 
> 
> I wish it was possible to write something like
> struct StaticArray<Element, Count> {
>     ...
> }
> instead (a statically allocated array with type-level Count as well as 
> Element).
> 
> /Jens
> 
> 
> On Mon, Apr 17, 2017 at 7:52 PM, Anders Kierulf via swift-evolution 
> <[email protected] <mailto:[email protected]>> wrote:
> Swift needs a datatype that contains a fixed number of a given type; 
> basically a simple fixed-size array.
> 
> Motivation: I’ve been porting code for Monte Carlo Tree Search in my 
> Go-playing program from C++ to Swift. Performance is crucial for this code, 
> as more simulations lead to better play. After the initial port, the Swift 
> code was more than 10x slower than my C++ code. After several weeks of 
> optimizing, profiling, and digging through disassembly, I’ve gotten to within 
> a factor of 2. Most of that gain came from using the ugly workaround of 
> importing fixed-size arrays from C.
> 
> My app is designed for a 19x19 (or smaller) Go board, not an arbitrary N x N 
> board, so I don’t want to pay the high cost of variable-size data structures 
> in the lowest levels of my app. Most apps are not like this, and most of my 
> app is not, but this kernel of my app needs to be fast. Heap allocations, 
> reference counting, and indirections all slow down the code. I just need a 
> fixed size of memory that I can access like an array, and Swift doesn’t let 
> me do that.
> 
> Workaround: By importing an array from C, I can allocate a blob of memory on 
> the stack or include it in a struct. I can then use UnsafeRawPointer to 
> access that blob like an array (see details in SR-4548). This is ugly, but it 
> works, and it is much faster than using a Swift array. However, I’m stymied 
> by SR-4542, which causes mutability to spread like a plague through client 
> code.
> 
> (SR-4542: Calling a function taking an UnsafeRawPointer forces the parameter 
> to be passed as inout, which means the method must be mutating. 
> UnsafeMutableRawPointer should require inout, UnsafeRawPointer should not.)
> 
> Proposal: UnsafeMutablePointer almost provides what I need. However, it can 
> only allocate memory on the heap, or it can take a given blob of memory and 
> interpret it as something else. What’s missing is a way to allocate typed 
> memory of a certain size on the stack or in a struct. For example, something 
> like this, with support for subscripts, limited to value types:
> 
>     var foo = UnsafeMemory<Int64>(count: 6)
> or
>     var bar = FixedSizeArray<UInt32>(repeating: 0, count: 380)
> 
> Alternatives:
> (1) C arrays are currently imported as tuples, so extending tuples with 
> subscripts and adding a way to create tuples with a specific count of the 
> same type could address this need. However, I don’t think this fits well with 
> the concept of tuples.
> (2) Changing the Array type to allow a fixed size could be considered in the 
> future. ‘count’ and ‘capacity’ would be fixed and only known to the compiler, 
> not stored with the data. However, I suspect the consequences would be 
> far-reaching, and thus I don’t see this happening soon.
> 
> An UnsafeMemory type would be a limited addition that fits in well with the 
> existing low-level Pointer module, and fills a gap in the capabilities of 
> Swift. The Pointer module helps implement low-level, performance-critical 
> code, and not being able to create data on the stack is a serious omission. 
> Jumping through C hoops is not a solution.
> 
> Anders Kierulf
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected] <mailto:[email protected]>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to