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
-
\$\begingroup\$ Is that exception from Playground? Have you tried the same thing in a non-Playground? \$\endgroup\$nhgrif– nhgrif2015年03月19日 20:46:27 +00:00Commented Mar 19, 2015 at 20:46
-
\$\begingroup\$ @nhgrif It isn't from playground, this is the actual code base that I need to optimize \$\endgroup\$Mazyod– Mazyod2015年03月19日 20:50:58 +00:00Commented Mar 19, 2015 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– nhgrif2015年03月19日 20:58:30 +00:00Commented Mar 19, 2015 at 20:58
-
\$\begingroup\$ Can you include the thing you're extending in the question (or at least a link to it)? \$\endgroup\$nhgrif– nhgrif2015年03月19日 21:22:36 +00:00Commented Mar 19, 2015 at 21:22
-
\$\begingroup\$ @nhgrif I already added it, thought it was obvious \$\endgroup\$Mazyod– Mazyod2015年03月19日 21:23:12 +00:00Commented Mar 19, 2015 at 21:23
1 Answer 1
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)
-
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– zondo2016年07月10日 04:42:03 +00:00Commented Jul 10, 2016 at 4:42