Calling variadic C function from Swift with pointers - swift

I'm trying to figure out how to call variadic C functions that write to pointers from Swift, such as vsscanf, but I don't understand how to actually construct the list of pointers to Swift variables.
I figure that if I have a string, I can get an UnsafePointer<CChar> and call vsscanf on it, but... how do I tell it where to actually write the data? How do I construct the CVaListPointer to pass to vsscanf?
var a: Int
var b: Float
"(5, 3.14)".withCString{buffer in
let r = vsscanf(buffer, "(%d, %f)", /* how do I put a and b here? */)
}
Basically, doing the same thing as here (C):
#include <stdio.h>
#include <stdarg.h>
int parse(const char *buffer, char *format, ...)
{
va_list args;
va_start(args, format);
int result = vsscanf(buffer, format, args);
va_end(args);
return result;
}
int main(int argc, char const *argv[])
{
int a;
float b;
char s[] = "(5, 3.14)";
int r = parse(s, "(%d, %f)", &a, &b);
printf("a: %d, b: %f\n", a, b);
// "a: 5, b: 3.140000"
return 0;
}
UPDATE: Thanks to the answers so far, I feel like I understand how this works a bit better, but what I'm still struggling with is populating the CVaListPointer in an easier way. Here's an example of parsing a triplet of Doubles out of a string:
func parseVec3(s: String) -> (Double, Double, Double)? {
var x: Double = 0
var y: Double = 0
var z: Double = 0
let r = s.withCString { buffer in
withUnsafeMutablePointer(to: &x) { ptrx in
withUnsafeMutablePointer(to: &y) { ptry in
withUnsafeMutablePointer(to: &z) { ptrz in
withVaList([ptrx, ptry, ptrz]) { va in
return vsscanf(buffer, "(%lf %lf %lf)", va)
}
}
}
}
}
return r == 3 ? (x, y, z) : nil
}
if let v = parseVec3(s: "(1 2 3)") {
print(v)
}
Now, this does work. But my problem is that I'm parsing a file where the bulk of the lines (thousands upon thousands of them) are six groups of triplets of numbers. The towering structure of withUnsafeMutablePointer would look downright ridiculous. I'm sure I could parse it using some more Swift-native approach (or just regex) but I was hoping to just use vsscanf because parsing this file in C is outrageously simple:
int main(int argc, char const *argv[])
{
char s[] = "(1 2 3) (5 9 1) (0 5 8)";
Vec3 a, b, c = {0, 0, 0};
sscanf(s,
"(%f %f %f) (%f %f %f) (%f %f %f)",
&(a.x), &(a.y), &(a.z),
&(b.x), &(b.y), &(b.z),
&(c.x), &(c.y), &(c.z)
);
printf("a: (x: %f, y: %f, z: %f)\n", a.x, a.y, a.z);
printf("b: (x: %f, y: %f, z: %f)\n", b.x, b.y, b.z);
printf("c: (x: %f, y: %f, z: %f)\n", c.x, c.y, c.z);
return 0;
}
Doing this with the withUnsafeMutablePointer approach in Swift as above would result in 11 with<Whatever> scopes, and that's only half of the floats parsed...
I figure I should be able to do something like this, but I can't figure out how to get the pointer offset to the other struct members:
func parseVec3_3(s: String) -> Vector3? {
var output = Vector3(x: 0, y: 0, z: 0)
var r: CInt = 0
s.withCString { buffer in
withUnsafeMutablePointer(to: &output) { ptr in
withVaList([ptr, /* offset pointer here */]) { va in
r = vsscanf(buffer, "(%lf %lf %lf)", va)
}
}
}
return r == 3 ? output : nil
}

Like this:
var a: Int = 0
var b: Float = 0
withUnsafePointer(to: &a) { pointerToA in
withUnsafePointer(to: &b) { pointerToB in
withVaList([pointerToA, pointerToB]) { va_list in
"(5, 3.14)".withCString { buffer in
let r = vsscanf(buffer, "(%d, %f)", va_list)
}
}
}
}
print(a)
print(b)
outputs
5
3.14
Update
The answer for OP edit including question about Vector3(x: 0, y: 0, z: 0) should become:
public struct Vector3: Equatable {
public var x: CGFloat
public var y: CGFloat
public var z: CGFloat
public init(x: CGFloat, y: CGFloat, z: CGFloat) {
self.x = x
self.y = y
self.z = z
}
}
func parseVec3_3(s: String) -> Vector3? {
var output = Vector3(x: 0, y: 0, z: 0)
var r: CInt = 0
s.withCString { buffer in
withUnsafePointer(to: &output) { (outputPointer: UnsafePointer<Vector3>) in
outputPointer.withMemoryRebound(to: CGFloat.self, capacity: 3) {
withVaList([OpaquePointer($0), OpaquePointer($0.advanced(by: 1)), OpaquePointer($0.advanced(by: 2))]) { va in
r = vsscanf(buffer, "(%lf %lf %lf)", va)
}
}
}
}
return r == 3 ? output : nil
}
if let vector: Vector3 = parseVec3_3(s: "(1.0 2.0 3.0)") {
print(vector)
}
outputs
Vector3(x: 1.0, y: 2.0, z: 3.0)

From the documentation on CVarArgs:
To create a wrapper for the c_api function, write a function that takes CVarArg arguments, and then call the imported C function using the withVaList(_:_:) function.
Swift only imports C variadic functions that use a va_list for their arguments. C functions that use the ... syntax for variadic arguments are not imported, and therefore can’t be called using CVarArg arguments.
Your wrapper function could look like:
func vsscanfSwiftWrapper(
buffer: UnsafePointer<CChar>,
format: UnsafePointer<CChar>,
_ arguments: CVarArg...
) -> CInt {
withVaList(arguments) { vaList in
vsscanf(buffer, format, vaList)
}
}

Related

ambiguous use of init with default values

I have class that have two similar looking initializers:
public init(
contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6),
midToLeftSpacing: CGFloat = 0,
rightToMidSpacing: CGFloat = 0
)
public init(
contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6),
midToLeftSpacing: MyInsetLevel = .level0,
rightToMidSpacing: MyInsetLevel = .level0
)
Now i run into problem, looks like when i trying to call initializer compiler can't figure out which one to chose:
init(
vertical: .level0,
left: .level22,
right: .level0
)
Gives error - Ambiguous use of 'init'
It could be easily fixed with modifying initializer or adding next argument with default value, but it doesn't look right, is there any other way to specify init method called?
Your example doesn't match your code (there is no init(vertical:left:right) defined), so I'm going to try to generalize this problem a bit with a full example that avoids the extra types. I'll just use Double and Int here.
Imagine a struct X that internally stores three Doubles:
struct X {
var x: Double
var y: Double
var z: Double
init(x: Double = 0, y: Double = 0, z: Double = 0) {
self.x = x
self.y = y
self.z = z
}
}
You also want to be able to pass three Ints instead, but all three must either be Doubles or Ints, and you want default values. Every use of default values is just a shorthand for an extra method with fewer parameters. To avoid conflicts, you need to include at least one of the parameters as non-default:
extension X {
init(x: Int, y: Int = 0, z: Int = 0) {
self.init(x: Double(x), y: Double(y), z: Double(z))
}
init(y: Int, z: Int = 0) { self.init(x: 0, y: y, z: z) }
init(z: Int) { self.init(x: 0, y: 0, z: z) }
}
Now, every combination is legal, but there are no ambiguities.
This is nice when there's just one extra way to call the init. But maybe you want there to be many. Then a protocol is useful. For example, this approach allows either Int or Double for every parameter:
protocol XParameter {
var xParameterValue: Double { get }
}
extension Double: XParameter {
var xParameterValue: Double { self }
}
extension Int: XParameter {
var xParameterValue: Double { Double(self) }
}
struct X {
var x: Double
var y: Double
var z: Double
init(x: some XParameter = 0, y: some XParameter = 0, z: some XParameter = 0) {
self.x = x.xParameterValue
self.y = y.xParameterValue
self.z = z.xParameterValue
}
}

How can I convert Generic type SignedNumeric to Float?

I'm creating some utility class stores numeric values(Int, Float, Double etc...).
It has minimum and maximum value, too.
I need convert a value to percent.
So I write the class as below on Playground:
import UIKit
class Series<T: SignedNumeric> {
let minValue: T
let maxValue: T
var datas: [T] = []
let range: T
init(minValue: T, maxValue: T) {
self.minValue = minValue
self.maxValue = maxValue
self.range = (maxValue - minValue)
self.datas = []
}
func percent(value: T) -> Float {
let v: Float = value as! Float
let m: Float = minValue as! Float
let r: Float = range as! Float
return (v - m) / r
}
}
let s = Series<Int>(minValue: -100, maxValue: 100)
s.datas = [20, 0, 40, -100, 100]
Float(s.datas[0] - s.minValue) / Float(s.range)
Float(s.datas[1] - s.minValue) / Float(s.range)
Float(s.datas[2] - s.minValue) / Float(s.range)
Float(s.datas[3] - s.minValue) / Float(s.range)
Float(s.datas[4] - s.minValue) / Float(s.range)
s.percent(value: s.datas[0]) // ERROR !!!
When call s.percent(value: s.datas[0]), it crashed.
How can I write percent() function?
Not every SignedNumeric can be converted to a Float. Recall that to be a SignedNumeric, you need to be able to:
be negative and positive
be multiplied
be added and subtracted
have a magnitude that is Comparable and Numeric
can be converted from an integer
The last 4 requirements are all inherited from Numeric. We can easily build our own type that can do all those things. Here's a contrived example:
struct MyNumber: SignedNumeric, Comparable {
private var secret: [String]
private var isNegative: Bool
private var number: Int { secret.count }
static func *= (lhs: inout MyNumber, rhs: MyNumber) {
lhs = lhs * rhs
}
static func * (lhs: MyNumber, rhs: MyNumber) -> MyNumber {
MyNumber(secret: Array(repeating: "", count: lhs.number * rhs.number), isNegative: lhs.isNegative != rhs.isNegative)
}
init(integerLiteral value: Int) {
let int = value
isNegative = int < 0
secret = Array(repeating: "", count: abs(int))
}
static func < (lhs: MyNumber, rhs: MyNumber) -> Bool {
lhs.number < rhs.number
}
init?<T>(exactly source: T) where T : BinaryInteger {
guard let int = Int(exactly: source) else {
return nil
}
self.init(integerLiteral: int)
}
var magnitude: MyNumber {
MyNumber(secret: secret, isNegative: false)
}
static func - (lhs: MyNumber, rhs: MyNumber) -> MyNumber {
if lhs < rhs {
return -(rhs - lhs)
} else {
return MyNumber(secret: Array(repeating: "", count: lhs.number - rhs.number))
}
}
prefix static func - (operand: MyNumber) -> MyNumber {
MyNumber(secret: operand.secret, isNegative: !operand.isNegative)
}
mutating func negate() {
isNegative.toggle()
}
init(secret: [String], isNegative: Bool = false) {
self.secret = secret
self.isNegative = isNegative
}
typealias Magnitude = MyNumber
static func + (lhs: MyNumber, rhs: MyNumber) -> MyNumber {
MyNumber(secret: lhs.secret + rhs.secret)
}
typealias IntegerLiteralType = Int
}
How on earth is <insert whoever is doing the conversion here> going to know that, to convert MyNumber to Float, it has to do Float(aMyNumber.secret.count)!? Not to mention that secret is private.
On the other hand, Float.init does know how to convert BinaryFloatingPoints and BinaryIntegers to Float, because those protocols define the necessary properties such that Float.init can understand how they are represented. For example, BinaryIntegers are represented by words, which is a RandomAccessCollection of UInts, indexed by Ints.
I suggest that you only add the percent method to types of Series where it actually makes sense:
extension Series where T : BinaryInteger {
func percent(value: T) -> Float {
let v: Float = Float(value)
let m: Float = Float(minValue)
let r: Float = Float(range)
return (v - m) / r
}
}
IMO, it would make sense for any T : FloatingPoint, not just T : BinaryFloatingPoint:
extension Series where T : FloatingPoint {
func percent(value: T) -> T {
let v = value
let m = minValue
let r = range
return (v - m) / r
}
}
Since FloatingPoint supports division too, you don't need to convert to Float!
thank you very much!
I added two extensions:
extension Series where T : BinaryInteger {
func percent(value: T) -> Float {
let v: Float = Float(value)
let m: Float = Float(minValue)
let r: Float = Float(range)
return (v - m) / r
}
}
extension Series where T : FloatingPoint {
func percent(value: T) -> T {
let v = value
let m = minValue
let r = range
return (v - m) / r
}
}
And now I can use percent() with Int, Float, Int16... !

Swift - declare 2d array contains

I want to say that if some 2d array contains the "point" format [Int,Int], then regenerate the random numbers, not counting the iteration.
for _ in 0..<33{
let j = Int(arc4random_uniform(10))
let k = Int(arc4random_uniform(10))
while live.contains(//The point j,k){
live.append(Array(arrayLiteral: j,k))
cells[j][k] = true
}
}
From what I understood your question, you want to generate an array of 2D points excluding repetition, you can use CGPoint or define your own Point
struct Point: Equatable {
let x: Int
let y: Int
}
func == (lhs: Point, rhs: Point) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
var live: [Point] = []
for _ in 0..<10{
var candidate = Point(x: Int(arc4random_uniform(10)), y: Int(arc4random_uniform(10)))
while live.contains(candidate) {
candidate = Point(x: Int(arc4random_uniform(10)), y: Int(arc4random_uniform(10)))
}
live.append(candidate)
}
or you can use tuple like so
var live: [(Int, Int)] = []
for _ in 0..<10{
var j = Int(arc4random_uniform(10))
var k = Int(arc4random_uniform(10))
while live.contains({$0 == (j, k)}) {
j = Int(arc4random_uniform(10))
k = Int(arc4random_uniform(10))
}
live.append((j,k))
}
Depending on your problem size, it might be more optimal to build an array of all possible values, and then shuffle and take first X elements every time you need new set of random points. You can optimize it further, but the code'd look similar to:
var possibleValues: [Point] = []
for x in 0..<5 {
for y in 0..<5 {
possibleValues.append(Point(x: x, y: y))
}
}
func randomPoints(numberOfPoints: Int) -> [Point] {
// shuffle original array without changing it
let shuffled = possibleValues.sorted { _ in arc4random_uniform(10) > 5 }
// take first X elements
return Array(shuffled[0..<numberOfPoints])
}
randomPoints(numberOfPoints: 10)
You can optimize this solution even further but that'd require to know more about your data set. Hope this helps

Is it possible to add function definitions programmatically in swift

I'm creating a struct that holds 3 float values,
struct Col {
var r: Float
var g: Float
var b: Float
}
and I'd like to add a bunch of function definitions that are equivalent to the built in math functions, but that operate piecewise on the members of my struct
I can do it by hand, eg
func pow(a: Col, b: Col) -> Col {
return Col(r: pow(a.r, b.r), g: pow(a.g, b.g), b: pow(a.b, b.b))
}
but this is tedious and error prone.
What I'd like to do is create a function to turn the original math function into my Col version, so that I could call it like this:
defineColVersion(pow, noArgs: 2)
and it defines the new version, without overwriting the built in function that operates on Doubles
Is there any way to do this in Swift?
Thanks
I actually think this is exactly what you want:
func toCol(f: (Float, Float) -> Float) -> (Col, Col) -> Col {
return { a, b in
Col(r: f(a.r, b.r), g: f(a.g, b.g), b: f(a.b, b.b))
}
}
func toCol(f: Float -> Float) -> Col -> Col {
return { c in
Col(r: f(c.r), g: f(c.g), b: f(c.b))
}
}
let pow = toCol(Darwin.pow)
let sin = toCol(Darwin.sin)
let log = toCol(Darwin.log)
let a = Col(r: 0.4, g: 0.2, b: 0.7)
let b = Col(r: 0.3, g: 0.9, b: 0.3)
pow(a, b)
sin(a)
log(b)
The two overloaded functions toCol take a unary/binary function on Floats and returns a new function which does the same on your Col type. With those two, you can easily create a pow function for your Col type.
It is not possible to programmatically define new functions in a static language like Swift. What you can do, however, is to make a higher-kinded function:
func init(a: Col, b: Col, function: (Float, Float) -> Float) -> Col {
return self.init(r: function(a.r, b.r), g: function(a.g, b.g), b: function(a.b, b.b))
}
Col(Col(1, 2, 3), Col(3, 4, 5)) { $0 * $1 }
Col(Col(1, 2, 3), Col(3, 4, 5)) { pow($0, $1) }
func init(first: Col, second: Col, function: (Float, Float) -> Float ) {
newR = function(first.r,second.r)
newG = function(first.g,second.g)
newB = function(first.b,second.b)
return self.init(r:newR,g:newG,b:newB)
}
I'm not in a position to compile this so it probably has some errors but hopefully it will be useful. You would use it like so:
first = Col(r:1,g:2,b:3)
second = Col(r:1,g:2,b:3)
combined = Col(first:first,second:second) { pow($0,$1) }

Is there a specific way to use tuples as set elements in Swift?

I want to do set operations on co-ordinate pair elements from an x-y grid.
E.g. {(0,0),(1,4),(1,5),(2,3)} union with {(2,3),(1,4),(2,6)} = {(0,0),(1,4),(1,5),(2,3),(2,6)}
Unfortunately I can't work out a way of inserting tuples into Swift's Set commands as it says that they do not conform to the 'hashable' protocol.
Error: type '(Int, Int)' does not conform to protocol 'Hashable'
I believe I've got a work around but it involves a lot of code. Is there a simple way that I'm missing before I hit the grindstone?
Rather than using tuples to represent points, use the built in type CGPoint. You can extend CGPoint to be hashable by extending it:
import UIKit
extension CGPoint: Hashable {
public var hashValue: Int {
return self.x.hashValue << sizeof(CGFloat) ^ self.y.hashValue
}
}
// Hashable requires Equatable, so define the equality function for CGPoints.
public func ==(lhs: CGPoint, rhs: CGPoint) -> Bool {
return CGPointEqualToPoint(lhs, rhs)
}
Now that CGPoint is Hashable, you can use it in sets. For example:
let point1 = CGPoint(x: 0, y: 1)
let point2 = CGPoint(x: 0, y: 2)
let point3 = CGPoint(x: 1, y: 1)
let point4 = CGPoint(x: 3, y: 3)
let point5 = CGPoint(x: 3, y: 3) // Intentionally the same as point4 to see the effect in union and difference.
let set1 = Set([point1, point2 , point5])
let set2 = Set([point4, point3])
let union = set1.union(set2) // -> {{x 0 y 2}, {x 3 y 3}, {x 0 y 1}, {x 1 y 1}}
let difference = set1.intersect(set2) // -> {{x 3 y 3}}
You could make a struct as a Hashable type:
struct Point: Hashable {
let x: Int
let y: Int
}
Now that you have a hashable tuple, normal Set operations can be used:
let set1 = Set([
Point(x:0,y:0),
Point(x:1,y:4),
Point(x:1,y:5),
Point(x:2,y:3)
])
let set2 = Set([
Point(x:2,y:3),
Point(x:1,y:4),
Point(x:2,y:6)
])
let setUnion = set1.union(set2)
/*
setUnion = {
Point(x: 1, y: 5),
Point(x: 0, y: 0),
Point(x: 1, y: 4),
Point(x: 2, y: 3),
Point(x: 2, y: 6)
}
*/
Here you go:
class Pair {
var x: Int
var y: Int
init(x: Int, y:Int){
self.x = x
self.y = y
}
func isExisted(inPairs pairs:[Pair]) -> Bool {
for p in pairs {
if p.y == self.y && p.x == self.x{
return true
}
}
return false
}
static func union (pairs1: [Pair], pairs2: [Pair]) -> [Pair] {
var pairsFinal = [Pair]()
for p in pairs1 {
pairsFinal.append(p)
}
for p in pairs2 {
if !p.isExisted(inPairs: pairsFinal){
pairsFinal.append(p)
}
}
return pairsFinal
}
}
let pari1 = Pair(x: 4, y: 7)
let pair2 = Pair(x: 5, y: 2)
let pair3 = Pair(x: 4, y: 7)
let pair4 = Pair(x: 3, y: 9)
let pairs1 = [pari1, pair2]
let pairs2 = [pair3, pair4]
let f = Pair.union(pairs1, pairs2: pairs2)
And this is the result of the union: