Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I am burdened with the requirement of interacting with a C based library, which has a bunch of constant sized arrays (e.g. char[17]).

When trying to assign or read those properties from swift, they are represented as a Tuple type of that size..

As far as I know, you can't access tuples with subscripts, and it is not trivial to convert an array to a tuple .. so I am left with this ugly code to interact with the library:

Note for the curious: The C library uses the eatLength to determine which values of the tuple are valid, and which shouldn't be considered. That is why I don't care about what the padded value is.

typedef struct _DMMove
{
    uint8_t steps[17];
    uint8_t eats[16];
    uint8_t eatLength;
} DMMove;

extension DMMove {

    init(steps: [Int], eats: [Int]) {

        var paddedSteps = Array(0..<17) as [UInt8]
        var paddedEats = Array(0..<16) as [UInt8]

        for (i, v) in enumerate(steps) {
            paddedSteps[i] = Int8(v)
        }

        for (i, v) in enumerate(eats) {
            paddedEats[i] = Int8(v)
        }

        var stepsTuple = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) as (Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8)
        var eatsTuple = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) as (Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8)

        stepsTuple.0 = paddedSteps[0]
        stepsTuple.1 = paddedSteps[1]
        stepsTuple.2 = paddedSteps[2]
        stepsTuple.3 = paddedSteps[3]
        stepsTuple.4 = paddedSteps[4]
        stepsTuple.5 = paddedSteps[5]
        stepsTuple.6 = paddedSteps[6]
        stepsTuple.7 = paddedSteps[7]
        stepsTuple.8 = paddedSteps[8]
        stepsTuple.9 = paddedSteps[9]
        stepsTuple.10 = paddedSteps[10]
        stepsTuple.11 = paddedSteps[11]
        stepsTuple.12 = paddedSteps[12]
        stepsTuple.13 = paddedSteps[13]
        stepsTuple.14 = paddedSteps[14]
        stepsTuple.15 = paddedSteps[15]
        stepsTuple.16 = paddedSteps[16]

        eatsTuple.0 = paddedEats[0]
        eatsTuple.1 = paddedEats[1]
        eatsTuple.2 = paddedEats[2]
        eatsTuple.3 = paddedEats[3]
        eatsTuple.4 = paddedEats[4]
        eatsTuple.5 = paddedEats[5]
        eatsTuple.6 = paddedEats[6]
        eatsTuple.7 = paddedEats[7]
        eatsTuple.8 = paddedEats[8]
        eatsTuple.9 = paddedEats[9]
        eatsTuple.10 = paddedEats[10]
        eatsTuple.11 = paddedEats[11]
        eatsTuple.12 = paddedEats[12]
        eatsTuple.13 = paddedEats[13]
        eatsTuple.14 = paddedEats[14]
        eatsTuple.15 = paddedEats[15]

        self.init(
            steps: stepsTuple,
            eats: eatsTuple,
            eatLength: Int16(eats.count)
        )
    }

}

More Notes

If you don't know how a C struct is exposed to Swift, well it's as simple as though there is an actual Swift struct with an init that takes all the struct's attributes as parameters.


I am sure someone will suggest using Tuple initializers ... Here ya go:

Swift compiler fail

Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions

share|improve this question
    
Is that exception from Playground? Have you tried the same thing in a non-Playground? –  nhgrif Mar 19 at 20:46
    
@nhgrif It isn't from playground, this is the actual code base that I need to optimize –  Mazyod Mar 19 at 20:50
    
Okay, so for clarification... you've got an array of values you built in Swift, and you need to pass an array to a C-library? –  nhgrif Mar 19 at 20:58
    
Can you include the thing you're extending in the question (or at least a link to it)? –  nhgrif Mar 19 at 21:22
    
@nhgrif I already added it, thought it was obvious –  Mazyod Mar 19 at 21:23

2 Answers 2

up vote 0 down vote accepted

Hmm.. Quite simpler than expected. Mind you, it obviously won't work for collection types because of the underlying memory representation.

extension DMMove {

    typealias StepsType = (UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8)
    typealias EatsType = (UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8)

    init(steps: [Int], eats: [Int]) {

        var paddedSteps = steps.map { UInt8(GUIIndex: $0) }
        var paddedEats = eats.map { UInt8(GUIIndex: $0) }

        paddedSteps.extend(Array(UInt8(steps.count)..<17))
        paddedEats.extend(Array(UInt8(eats.count)..<16))

        var stepsTuple = UnsafeMutablePointer<StepsType>(malloc(UInt(sizeof(StepsType))))
        var eatsTuple = UnsafeMutablePointer<EatsType>(malloc(UInt(sizeof(EatsType))))

        memcpy(stepsTuple, paddedSteps, UInt(paddedSteps.count))
        memcpy(eatsTuple, paddedEats, UInt(paddedEats.count))

        self.init(
            steps: stepsTuple.memory,
            eats: eatsTuple.memory,
            eatLength: UInt8(eats.count)
        )
    }
}
share|improve this answer

I found this reflection based solution on Stack Overflow, and I tailored it a bit into the following:

func arrayForTuple<T,E>(tuple:T) -> [E] {
    let reflection = reflect(tuple)
    var arr : [E] = []
    for i in 0..<reflection.count {
        if let value = reflection[i].1.value as? E {
            arr.append(value)
        }
    }
    return arr
}

let name : (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8) = (65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74)
let nameArray : [Int8] = arrayForTuple(name)

It works almost like map() except it's not guaranteed to return a 1:1 array. E.g. if the tuple contains an element which is not an Int8, it will be skipped.

share|improve this answer
    
Thanks, this will be useful in the future, but per the title, the question is to convert an array to a tuple, not the other way around –  Mazyod Mar 20 at 14:08

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.