<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">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 <a href="https://bugs.swift.org/browse/SR-3726" class="">https://bugs.swift.org/browse/SR-3726</a> 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&nbsp;<a href="https://bugs.swift.org/browse/SR-4581" class="">https://bugs.swift.org/browse/SR-4581</a></div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On Apr 17, 2017, at 2:07 PM, Jens Persson via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">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.<div class=""><br class=""></div><div class=""><div class="">struct UnsafeStatic19x19&lt;E&gt; {</div><div class="">&nbsp; &nbsp; var storage: (</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E,</div><div class="">&nbsp; &nbsp; E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E</div><div class="">&nbsp; &nbsp; )</div><div class="">&nbsp; &nbsp; subscript(x: Int, y: Int) -&gt; E {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; get {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // No index out of bounds check</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var m = self // &lt;-- This workaround will be optimized away.</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return withUnsafeBytes(of: &amp;m) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let byteOffset = MemoryLayout&lt;E&gt;.stride * (x + y*19)</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return $0.load(fromByteOffset: byteOffset, as: E.self)</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; set {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; withUnsafeMutableBytes(of: &amp;self) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let byteOffset = MemoryLayout&lt;E&gt;.stride * (x + y*19)</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $0.storeBytes(of: newValue, toByteOffset: byteOffset, as: E.self)</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; }</div><div class="">}</div></div><div class=""><br class=""></div><div class="">It isn't pretty but it works (haven't tried this code example though, but you get the idea).</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">I wish it was possible to write something like<br class=""></div><div class="">struct StaticArray&lt;Element, Count&gt; {</div><div class="">&nbsp; &nbsp; ...</div><div class="">}</div><div class="">instead (a statically allocated array with type-level Count as well as Element).</div><div class=""><br class=""></div><div class="">/Jens</div><div class=""><br class=""></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Mon, Apr 17, 2017 at 7:52 PM, Anders Kierulf via swift-evolution <span dir="ltr" class="">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt;</span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Swift needs a datatype that contains a fixed number of a given type; basically a simple fixed-size array.<br class="">
<br class="">
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.<br class="">
<br class="">
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.<br class="">
<br class="">
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.<br class="">
<br class="">
(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.)<br class="">
<br class="">
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:<br class="">
<br class="">
&nbsp; &nbsp; var foo = UnsafeMemory&lt;Int64&gt;(count: 6)<br class="">
or<br class="">
&nbsp; &nbsp; var bar = FixedSizeArray&lt;UInt32&gt;(<wbr class="">repeating: 0, count: 380)<br class="">
<br class="">
Alternatives:<br class="">
(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.<br class="">
(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.<br class="">
<br class="">
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.<br class="">
<br class="">
Anders Kierulf<br class="">
<br class="">
______________________________<wbr class="">_________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class="">
</blockquote></div><br class=""></div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>