Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning values to tuple in for loop

Tags:

swift

There is a tuple of UInt8's in a struct MIDIPacket. Normal assignment is like this:

import CoreMIDI
let packet = MIDIPacket()
packet.data.0 = 0x02
packet.data.1 = 0x5f

and so on.

This tuple has length of ~128+. There is an array of values, converted, which I would like to assign to the packet beginning at a certain index.

let converted = [0x01, 0x02, 0x5e,...]
var k = packet starting index of assignment
for i in 0..<converted.count {
    packet.data(k) = converted[i]
    k += 1
}

How do I do this? subscripting doesn't work: e.g. packet.data[i], while I believe Mirror simply creates a copy of the packet, so assigning to it would not work..

let bytes = Mirror(reflecting: packet.data).children;
        for (_, b) in bytes.enumerated() {
                       
                   }
like image 280
Cheetaiean Avatar asked Dec 21 '25 20:12

Cheetaiean


1 Answers

There's no official API for doing this, but IIRC, tuples of homogeneous element types are guaranteed to have a contiguous memory layout. You take advantage of this by using UnsafeBufferPointer to read/write to the tuple.

Usually this requires you to manually hard-code the tuple's element count, but I wrote some helper functions that can do this for you. There's two variants, a mutable one, which lets you obtain an UnsafeBufferPointer, which you can read (e.g. to create an Array), and a mutable one, which gives you a UnsafeMutableBufferPointer, through which you can assign elements.

enum Tuple {
    static func withUnsafeBufferPointer<Tuple, TupleElement, Result>(
        to value: Tuple,
        element: TupleElement.Type,
        _ body: (UnsafeBufferPointer<TupleElement>) throws -> Result
    ) rethrows -> Result {
        try withUnsafePointer(to: value) { tuplePtr in
            let count = MemoryLayout<Tuple>.size / MemoryLayout<TupleElement>.size
            
            return try tuplePtr.withMemoryRebound(
                to: TupleElement.self,
                capacity: count
            ) { elementPtr in
                try body(UnsafeBufferPointer(start: elementPtr, count: count))
            }
            
        }
    }
    
    static func withUnsafeMutableBufferPointer<Tuple, TupleElement, Result>(
        to value: inout Tuple,
        element: TupleElement.Type,
        _ body: (UnsafeMutableBufferPointer<TupleElement>) throws -> Result
    ) rethrows -> Result {
        try withUnsafeMutablePointer(to: &value) { tuplePtr in
            let count = MemoryLayout<Tuple>.size / MemoryLayout<TupleElement>.size
            
            return try tuplePtr.withMemoryRebound(
                to: TupleElement.self,
                capacity: count
            ) { elementPtr in
                try body(UnsafeMutableBufferPointer(start: elementPtr, count: count))
            }
            
        }
    }
}

var destinationTouple: (Int, Int, Int, Int) = (0, 0, 0, 0) // => (0, 0, 0, 0)
var sourceArray = Array(1...4)

print("before:", destinationTouple)

Tuple.withUnsafeMutableBufferPointer(to: &destinationTouple, element: Int.self) { (destBuffer: UnsafeMutableBufferPointer<Int>) -> Void in
    sourceArray.withUnsafeMutableBufferPointer { sourceBuffer in
    //  buffer[...] = 1...
        destBuffer[destBuffer.indices] = sourceBuffer[destBuffer.indices]
        return ()
    }
}

print("after:", destinationTouple) // => (1, 2, 3, 4)
like image 110
Alexander Avatar answered Dec 23 '25 15:12

Alexander



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!