I'm working with a third party API, and trying to translate the following C# code into F#:
[DllImport("libfsdk.so", EntryPoint = "FSDK_FeedFrame", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
private static extern int FSDK_FeedFrame_Old(int Tracker, long CameraIdx, int Image, ref long FaceCount, [Out, MarshalAs(UnmanagedType.LPArray)] long[] IDs, long MaxSizeInBytes);
public static int FeedFrame(int Tracker, long CameraIdx, int Image, ref long FaceCount, out long[] IDs, long MaxSizeInBytes)
{
IDs = new long[MaxSizeInBytes/8];
return FSDK_FeedFrame_Old(Tracker, CameraIdx, Image, ref FaceCount, IDs, MaxSizeInBytes);
}
My attempt so far is this:
[<DllImport("libfsdk.so", EntryPoint = "FSDK_FeedFrame", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)>]
extern int private FSDK_FeedFrame(int Tracker, int64 CameraIdx, int Image, int64& FaceCount, [<Out; MarshalAs(UnmanagedType.LPArray)>] int64[] IDs, int64 MaxSizeInBytes);
let FeedFrame(Tracker: int, CameraIdx: int64, Image: int, faceCount: int64 byref, [<Out>] IDs: int64[] byref, MaxSizeInBytes: int64) =
let ids = Array.create (int MaxSizeInBytes) 0L
let mutable fc = 0L
let res = FSDK_FeedFrame(Tracker, CameraIdx, Image, &fc, ids, MaxSizeInBytes)
res
I have tried variants of byref in the argument list, but the result code always indicates an invalid argument. Is there any special variant I need so that I can use this P/Invoke method?
Related
I managed to get a basic dylib that I have included in a framework that allows me to pass in an Int and returns and Int working but how would I pass and return more complex datatypes like pointer, byte arrays or actual data structures from swift to the C dylib?
Are there any tutorials or resources to map/pass/convert from swift datatype to to C datatype and vice versa like in JNI for java?
An example of interpreting a C struct and dynamically extract functions from the c-dylib on Swift side could look like this:
.c File
Person *get_person() {
Person *p = malloc(sizeof(Person));
p->first_name = strdup("Branford");
p->last_name = strdup("Marsalis");
p->age = 60;
return p;
}
void free_person(Person *person) {
free(person->first_name);
free(person->last_name);
free(person);
}
.h File
typedef struct {
char *first_name;
char *last_name;
int age;
} Person;
Swift
typealias getPersonFunc = #convention(c) () -> UnsafeMutablePointer<Person>
typealias freePersonFunc = #convention(c) (UnsafeMutablePointer<Person>) -> Void
...
let handle = dlopen("libsimple.dylib", RTLD_LOCAL|RTLD_NOW)
let get_person_sym = dlsym(handle, "get_person")
let getPerson = unsafeBitCast(get_person_sym, to: getPersonFunc.self)
let cPerson = getPerson()
let person = cPerson.withMemoryRebound(to: Person.self, capacity: 1) { $0.pointee }
let firstName = String(cString: UnsafeRawPointer(person.first_name).assumingMemoryBound(to: CChar.self))
let lastName = String(cString: UnsafeRawPointer(person.last_name).assumingMemoryBound(to: CChar.self))
print(firstName)
print(lastName)
print(person.age)
let free_person_sym = dlsym(handle, "free_person")
let freePerson = unsafeBitCast(free_person_sym, to: freePersonFunc.self)
freePerson(cPerson)
dlclose(handle)
Test
Output on the debug console for this example would look like:
Branford
Marsalis
60
From Swift to C
Assume this in .c:
void print_person(Person *person) {
printf("%s %s is %d years old\n",
person->first_name,
person->last_name,
person->age);
}
Then on Swift side one could write:
typealias printPersonFunc = #convention(c) (UnsafeMutablePointer<Person>) -> Void
...
let newPerson = UnsafeMutablePointer<Person>.allocate(capacity: 1)
newPerson.pointee.first_name = UnsafeMutablePointer<Int8>(mutating: ("Norah" as NSString).utf8String)
newPerson.pointee.last_name = UnsafeMutablePointer<Int8>(mutating: ("Jones" as NSString).utf8String)
newPerson.pointee.age = 41
let print_person_sym = dlsym(handle, "print_person")
let printPerson = unsafeBitCast(print_person_sym, to: printPersonFunc.self)
printPerson(newPerson)
newPerson.deallocate()
This would give the following output on the console:
Norah Jones is 41 years old
With this type:
let Empty =
{
Buy = new Dictionary<int64, int64 * float>()
Sell = new Dictionary<int64, int64 * float>()
}
if I assign it to several entities through the code:
let a = Empty
let b = Empty
they'll represent the same dictionaries.
How can I generate a new instance every time?
let makeEmpty () = {
Buy = new Dictionary<int64, int64 * float>()
Sell = new Dictionary<int64, int64 * float>()
}
I'm trying to convert an integer variable
var int counter = 0;
into a string variable
var String $counter = "0";
I searched but I only found something like
var myInt = int.parse('12345');
that doesn't work with
var myInt = int.parse(counter);
Use toString and/or toRadixString
int intValue = 1;
String stringValue = intValue.toString();
String hexValue = intValue.toRadixString(16);
or, as in the commment
String anotherValue = 'the value is $intValue';
// String to int
String s = "45";
int i = int.parse(s);
// int to String
int j = 45;
String t = "$j";
// If the latter one looks weird, look into string interpolation on https://dart.dev
You can use the .toString() function in the int class.
int age = 23;
String tempAge = age.toString();
then you can simply covert integers to the Strings.
I am using Accord.NET in F# for the first time and I am having problems creating the function to calculate the distance for KNN.
Here is my code
static member RunKNN =
let inputs = MachineLearningEngine.TrainingInputClass
let outputs = MachineLearningEngine.TrainingOutputClass
let knn = new KNearestNeighbors<int*int*int*int>(1,inputs,outputs,null)
let input = 1,1,1,1
knn.Compute(input)
When I swap out the null for a function like this
let distanceFunction = fun (a:int,b:int,c:int,d:int)
(e:int,f:int,g:int,h:int)
(i:float) ->
0
I get an exception like this:
*Error 1 This expression was expected to have type
System.Func<(int * int * int * int),(int * int * int * int),float> but here has type
int * int * int * int -> int * int * int * int -> float -> int*
So far, the only article I found close to my problem is this one. Apparently, there is a problem with how F# and C# handle delegates?
I posted this same question on the Google group for Accord.NET here.
Thanks in advance
Declare the distance function like this:
let distanceFunction (a:int,b:int,c:int,d:int) (e:int,f:int,g:int,h:int) =
0.0
(it takes two tuples in input and returns a float), and then create a delegate from it:
let distanceDelegate =
System.Func<(int * int * int * int),(int * int * int * int),float>(distanceFunction)
Passing this delegate to Accord.NET should do the trick.
I would guess you should use the tuple form like so
let distanceFunction = fun ((a:int,b:int,c:int,d:int),
(e:int,f:int,g:int,h:int),
(i:float)) ->
How do I go about using the TryTake method on a BlockingCollection<'a> passing in a timeout period in milliseconds?
Heres the signature:
BlockingCollection.TryTake(item: byref, millisecondsTimeout: int) : bool
is it possible to use the Tuple method of avoiding passing a ref type like on the Dictionary.TryGet methods?
i.e.
let success, item = myDictionary.TryGetValue(client)
Im struggling with this particular signature, any suggestions would be great.
Cheers!
I believe that you can only use that technique for byref parameters which occur at the end of the parameter list (this is similar to the rule for optional parameters). So if BlockingCollection.TryTake were defined with signature int * 'T byref -> bool it would work, but since it's defined as 'T byref * int -> bool it won't.
For example:
open System.Runtime.InteropServices
type T =
static member Meth1(a:int, [<Out>]b:string byref, [<Out>]c:bool byref) : char =
b <- sprintf "%i" a
c <- a % 2 = 0
char a
static member Meth2([<Out>]b:string byref, [<Out>]c:bool byref, a:int) : char =
b <- sprintf "%i" a
c <- a % 2 = 0
char a
// ok
let (r,b,c) = T.Meth1(5)
// ok
let (r,c) = T.Meth1(5,ref "test")
// ok
let r = T.Meth1(5, ref "test", ref true)
// doesn't compile
let (r,b,c) = T.Meth2(5)
// doesn't compile
let (r,c) = T.Meth2(ref "test", 5)
// ok
let r = T.Meth2(ref "test", ref true, 5)