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
