2
\$\begingroup\$

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

\$\endgroup\$
  • \$\begingroup\$ Is that exception from Playground? Have you tried the same thing in a non-Playground? \$\endgroup\$ – nhgrif Mar 19 '15 at 20:46
  • \$\begingroup\$ @nhgrif It isn't from playground, this is the actual code base that I need to optimize \$\endgroup\$ – Mazyod Mar 19 '15 at 20:50
  • \$\begingroup\$ 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? \$\endgroup\$ – nhgrif Mar 19 '15 at 20:58
  • \$\begingroup\$ Can you include the thing you're extending in the question (or at least a link to it)? \$\endgroup\$ – nhgrif Mar 19 '15 at 21:22
  • \$\begingroup\$ @nhgrif I already added it, thought it was obvious \$\endgroup\$ – Mazyod Mar 19 '15 at 21:23
3
\$\begingroup\$

Today I had to do something that looks like this, so I am posting my answer in case someone needs this. I needed to create a C struct for passing to pulseaudio in linux, the struct is like this:

struct pa_cvolume{
    uint32 channels;
    uint32 values[32];
}

what I was trying to do was to set newVolume in as much fields as the value of channels was:

let newVolume = 23123 // some random value

var paVolume = pa_cvolume() // create struct
paVolume.channels = 2 // read channels from other place

var volumeChannels = withUnsafeMutablePointer(&paVolume.values) {
  return UnsafeMutablePointer<UInt32>($0)
}

//iterate as if it was C
for i in 0..<Int(paVolume.channels) {  // Int required to subscript UnsafePointers
  volumeChannels[i] = newVolume
}

print(paVolume)

this way you don't need padding (because creating the struct comes with memory already zeroed)

\$\endgroup\$
  • 4
    \$\begingroup\$ Welcome to Code Review! You may have missed that this site is for reviewing other people's code. If you want to provide another solution, that's fantastic! Just keep in mind that the review is more important because that's the purpose of the site. \$\endgroup\$ – zondo Jul 10 '16 at 4:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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