I recently started to learn Golang for a work project. I come from a 'c' background and have some confusion about the technicalities of Pointer Receivers in functions. Am I to assume receiver are generalized and don't care if the object is actually a pointer or a literal, it will translate it to whatever the receiver type is.
I know my question wording may be confusing so here is some code for example:
func (v *clients) makePtr() {
(*v).slice = make([]client, 0)
return
}
func (v clients) makeLit() []client {
return make([]client, 0)
}
func main() {
clsPtr := &clients{} // pointer
clsLit := clients{} // literal
clsLit.makePtr() // literal with pointer reciever
clsLit.makeLit() // literal with pointer reciever
clsPtr.makePtr() // pointer with literal reciever
clsPtr.makeLit() // pointer with pointer reciever
}
I expected the the functions with pointer receivers to only work on pointers and vice versa. from this am I just suppose to assume receivers are a blanket statement and don't care if its a pointer, literal?
EDIT:
Apologizes guys, I may not have been to clear with my question, I understand that a pointer receiver is used to modify a object but I'm more confused as to the syntax, why does a pointer receiver work for both a literal and a pointer, since it receives a pointer shouldn't it only work on a pointer?
The pointer receiver means if you mutate the object on the method it will change the underlying struct.
When you call it, it doesnt make a difference.
package main
import (
"fmt"
)
type data struct {
val int
}
func (d data) changeNonPersistent(newval int) {
d.val = newval
}
func (d *data) changePersistent(newval int) {
d.val = newval
}
func main() {
// initialize both ptr and val version to 5
dptr := &data{val: 5}
dval := data{val: 5}
fmt.Println(*dptr)
fmt.Println(dval)
// non persistent val change to 10
dptr.changeNonPersistent(10)
dval.changeNonPersistent(10)
fmt.Println("Non Persistent-")
fmt.Println(*dptr)
fmt.Println(dval)
// persistent val change to 15
dptr.changePersistent(15)
dval.changePersistent(15)
fmt.Println("Persistent-")
fmt.Println(*dptr)
fmt.Println(dval)
}
or see the code here https://play.golang.org/p/jwOUwsso3PZ
tl;dr; the object or reference does not make a difference, as long as the receiver is right.
And you usually only want to have pointer receiver if your goal is to mutate. Other wise just send a copy.
In golang these are called methods which are function with receiver.
The receiver argument can be passed by value or by pointer.
You can write functions like below which are plain functions.
type Client struct{}
//A pointer to Client
func makePtr(c *Client){
//do something with c
}
//A copy of client is made.
func makeLit(cs Client){
//do something with c
}
Instead if you write methods then it gives association with struct.
type Client struct{}
func (c *Client) makePtr(){
//do something with c
}
//A copy of client is made.
func (c Client)makeLit(){
//do something with c
}
The main purpose of methods I see in golang is for interface implementation
It is by virtue of methods structs implement (or satisfy) interfaces.
Related
I have a C function mapped to Swift defined as
predictX010(inputString: UnsafePointer<emxArray_char_T>!, ypred: UnsafeMutablePointer<emxArray_real_T>!)
I want to input a string in the inputString, but in order to do that I have to play around with emxArray_char_T which is
emxArray_char_T.init(data: UnsafeMutablePointer<Int8>!, size: UnsafeMutablePointer<Int32>!, allocatedSize: Int32, numDimensions: Int32, canFreeData: boolean_T)
My string will consist of let x = ":1580222503,GCP001,007,Male,30,Left,1,IL8 and IL10,0000; 0,281411,-78,521074,-3,344657,132,347776,-93,25,44" and I just cannot figure out how to input it in data of the emxArray_char_T
First you should write a wrapper function in your bridging header that accepts char pointers then cast/create the emxArray_char_T in c IE:
// casting the func as void because you didn't specify
void predictWrapper(const char *aChar, char *bChar) {
// do your casting and call original func predictX010(...)
}
Then in swift (This isn't going to be pretty)
var arg: String = "some arg"
var arg2: String = "another arg"
// use closure to prevent dangling pointer
arg.withCString{ body in // body is UnsafePointer<Int8>
arg2.withCString{ body2 in // we'll cast this to UnsafeMutablePointer
var arg2Mutable = UnsafeMutablePointer<Int8>(mutating: body2)
//call your wrapper
predictWrapper(body, arg2Mutable)
}
}
You may be able to use the original types and function, but i've always found it easier (less banging my head on the desk) to use the most standard c types you can in swift and casting to custom/complex types in c
I need to interface C code to LabVIEW, and my C function needs to give back a two dimensional array of strings. I would rather not be forced to predetermine the size of the array in advance. So I want to know, what is the right data format to use (handle to array of C string pointers? Handle to array of string handles?), how to properly do the allocation, and whether it is better to use an array parameter or a return type. The dialog provided for Call Library Function Node only supports arrays of numeric types, so I'm a little bit lost on how to structure this.
You need the LabVIEW Code Interface Reference Manual to figure this stuff out.
You are writing a C function that will return a 2D array of strings to LabVIEW. That means you need to be returning LabVIEW's data structure and using LabVIEW's memory allocator. Include "extcode.h" in your C file (ships with LabVIEW). Then create the following C code:
#include "extcode.h"
struct String2DArrayBlock {
int32 dimensionSize1;
int32 dimensionSize2;
LStrHandle stringArray[1]; // Yes, this is intentional. Do not use LStrHandle* because that syntax changes the memory allocation. Old-school C code. LabVIEW's own C++ code has wrappers for managing this with more type safety.
};
typedef String2DArrayBlock** String2DArrayHandle;
MgErr GenerateMyStrings(String2DArrayHandle *ptrToHandle) {
if (!ptrToHandle)
return mgArgErr; // Gotta pass a location for us to allocate.
if (*ptrToHandle) {
// This handle is already allocated. I'm not going to walk you through all the code needed to deallocate.
return mgArgErr;
}
const int32 dimSize1 = ComputeHeight(); // This is your function... whereever your data is coming from.
const int32 dimSize2 = ComputeWidth(); // Same here.
const int32 numberOfElements = dimSize1 * dimSize2;
if (numberOfElements == 0) {
return mgNoErr; // Done. NULL means empty array, and the handle is already NULL.
}
// DSNewHClr allocates the block and flood fills it with all zeros.
*ptrToHandle = (String2DArrayHandle)DSNewHClr(sizeof(String2DArrayBlock) + ((numberOfElements - 1) * sizeof(LStrHandle))); // -1 because the sizeof block has 1 element.
if (!*ptrToHandle)
return mFullErr; // Out of memory
(**ptrToHandle)->dimensionSize1 = dimSize1;
(**ptrToHandle)->dimensionSize2 = dimSize2;
LStrHandle *current = (**ptrToHandle)->stringArray;
for (int32 i = 0; i < numberOfElements; ++i, ++current) {
std::string myCurrentString = GetMyCurrentString(i); // You write this however you look up the individual strings.
if (myCurrentString.empty())
continue; // NULL means empty string
*current = (LStrHandle)DSNewHClr(sizeof(LStr)); // Allocates a zero-length LStrHandle.
if (!*current)
return mFullErr; // The array will be partially filled, but it is in a safe state for early return.
MgErr err = LStrPrintf(*current, (CStr)"%s", myCurrentString.c_str());
if (err)
return err; // The array will be partially filled, but it is in a safe state for early return.
}
return mgNoErr;
}
Compile your code against the LabVIEW run-time engine (lvrt.dll).
In your G code, drop a Call Library Node, add a parameter that is "Adapt to type" and "Pointers to Handles", and wire it with an empty 2D array. And you're done.
I realize there are a million variations of the "how do I convert char[]/char* to a Swift Sting" question out there, and their inverse, all of which have been asked and answered.
I'm not asking that.
All I want to do, in Swift, is to simply pass the address of a C char array (obtained via a C function) to the C char* pointer argument of another C function.
Specifically, I'm trying to replicate the following C code, where the address of the char array contained in the stat.f_mntonname field gets passed as the first parameter of getattrlist(const char*, ...) call:
// Get volume stat
const char* path = ...;
struct statfs volStat;
if (statfs(path,&volStat)==-1) { error }
// statfs has the mount point of the volume; use that to get attributes
struct attrlist request;
// ... set up request here
struct volAttrs {
// ... response values
}
if (getattrlist(volStat.f_mntonname,&request,&volAttrs,sizeof(volAttrs),FSOPT_NOFOLLOW)==-1) { error }
The problem seems to be that Swift interprets the stat.f_mntonname field, not as an array, but as a tuple containing MAXPATHLEN number of Int8 values; in other words, (Int8,Int8,Int8,Int8,Int8,...,Int8).
After much poking around on the internet, I was ultimately able to find this workaround:
var volStat = statfs()
guard statfs(fileURL.path, &volStat) != -1 else {
ErrorExit(cause: "statfs")
}
var attrRequest = attrlist()
// set up getattrlist request ...
var attrs = XtraVolumeAttrs()
guard getattrlist(UnsafeRawPointer(&volStat.f_mntonname.0).bindMemory(to: CChar.self, capacity: Int(MAXPATHLEN)),
&attrRequest,
&attrs,
MemoryLayout<XtraVolumeAttrs>.size,
UInt32(FSOPT_NOFOLLOW)) != -1 else {
ErrorExit(cause: "getattrlist")
}
So the magic UnsafeRawPointer(&volStat.f_mntonname.0).bindMemory(to: CChar.self, capacity: Int(MAXPATHLEN) seems to accomplish the task of casting the char[MAXPATHLEN] array into a char*, but boy is it ugly, unintuitive, and—if I'm being completely honest—I'm not even sure this is correct (other than the fact that the code works).
I feel there's got to be a better way and I was hoping someone would post it.
It is ugly because Swift imports C arrays as tuples, and there is no automatic conversion to arrays or pointers.
As pointed out by Hamish, the use of UnsafeRawPointer(&volStat.f_mntonname.0) is incorrect, because the created pointer might be invalid on return from the initializer.
A safe version is
let retval = withUnsafeBytes(of: volStat.f_mntonname) {
getattrlist($0.bindMemory(to: Int8.self).baseAddress, /* other args */)
}
Here bindMemory() is called on the “buffer pointer” covering the raw bytes of the tuple, so that we don't have to specify the capacity explicitly.
I am working on a project that implements a C library using Swift. So far I have been able to manage how to get String from C strings and some others.
Now I am facing an issue when dealing with a C callback that returns OUT variables type char**. The swift code needs to reallocate memory and change the value. These variables are used for String type.
The Header for the C function is:
DllExport void STDCALL DvProviderGetProtocolInfo(THandle aProvider, CallbackGetProtocolInfo aCallback, void* aPtr);
And the header for the C Callback is:
typedef int32_t (STDCALL *CallbackGetProtocolInfo)(void* aPtr, IDvInvocationC* aInvocation, void* aInvocationPtr, char** aSource, char** aSink);
In swift I call the function like that:
DvProviderGetProtocolInfo(prvHandleId, { (pointer, aInvocation, aInvocationPtr, aSource, aSink) -> Int32 in
let senderClass:SenderClass = bridgeToTypeUnretained(ptr: pointer!)
senderClass.writeCStringValue(from: aSource, withValue: senderClass.sourceProtocolInfoArray)
senderClass.writeCStringValue(from: aSink, withValue: senderClass.sinkProtocolInfoArray)
return 0
}, bridgeToPointerRetained(obj: self))
The functions used are:
public func writeCStringValue(from pointer:UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?, withValue value:String){
pointer!.pointee = UnsafeMutablePointer<Int8>.allocate(capacity:value.utf8.count)
strcpy(pointer!.pointee, value)
}
And declared in another Swift File:
/*** Convert const void* To Any T ***/
func bridgeToTypeRetained<T : AnyObject>(ptr : UnsafeMutableRawPointer) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()
}
func bridgeToTypeUnretained<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}
/*** Convert const void* To Any T ***/
func bridgeToPointerRetained<T : AnyObject>(obj : T) -> UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(Unmanaged.passRetained(obj).toOpaque())
}
func bridgeToPointerUnretained<T : AnyObject>(obj : T) -> UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
}
So far, for small values, writeCStringValue function works fine but when I try to send a long String like:
let aTest = "http-get:*:audio/m4a:*,http-get:*:audio/x-m4a:*,http-get:*:audio/aiff:*,http-get:*:audio/x-aiff:*,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3,http-get:*:audio/mp4:*,http-get:*:audio/wav:*,http-get:*:audio/wave:*,http-get:*:audio/x-wav:*,http-get:*:video/mpeg:*,http-get:*:video/mp4:*,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG,http-get:*:image/png:DLNA.ORG_PN=PNG_TN,http-get:*:image/png:DLNA.ORG_PN=PNG_LRG"
I get a EXC_BAD_ACCESS at the end of writeCStringValue function.
If I include the code in writeCStringValue function inside the callback, then there is no crash.
Ideally i would like to use writeCStringValue function.
Am i changing the values of char** correctly?
Thank you
strcpy(pointer!.pointee, value)
creates a temporary C string representation of the Swift string value,
and copies that to the address given by pointer!.pointee.
C strings are delimited by a trailing null character and that is not
taken into account in the allocation
pointer!.pointee = UnsafeMutablePointer<Int8>.allocate(capacity:value.utf8.count)
Therefore strcpy() copies one char more than is allocated. That may or may
not cause a crash, but is undefined behavior in any case.
strdup() does both the allocation and the copy, so a simpler solution is
pointer?.pointee = strdup(value)
That may be better anyway, if the C function (eventually) releases the string with free().
Creating a time base info struct in C is easy, but in Swift the following does not work in the playground:
let timebaseInfo: mach_timebase_info_data_t = mach_timebase_info(&timebaseInfo)
The error is Variable used within its own initial value
I understand the error, but I am unable to think of a way to do this without dropping down to C. Is there a Swift only way that I am missing? Any help would be greatly appreciated. :-)
Edit: Actually I see "A" problem with the above, the "=" doesn't make sense. But I did try the following also:
let timebaseInfo: mach_timebase_info_data_t
mach_timebase_info(&timebaseInfo)'
With an error stating timebasedInfo used before initialization. :-(
The mach_timebase_info function is declared as
typealias mach_timebase_info_t = UnsafeMutablePointer<mach_timebase_info>
// ...
func mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t
which means that you can pass an (initialized) mach_timebase_info variable
as an "in-out expression" with &:
var timebaseInfo = mach_timebase_info(numer: 0, denom: 0)
let status = mach_timebase_info(&timebaseInfo)
if status == KERN_SUCCESS {
// ...
}
For more information, see Interacting with C APIs in the "Using Swift with Cocoa and Objective-C" manual:
Mutable Pointers
When a function is declared as taking an UnsafeMutablePointer<Type>
argument, it can accept any of the following:
nil, which is passed as a null pointer
An UnsafeMutablePointer<Type> value
An in-out expression whose operand is a stored lvalue of type Type,
which is passed as the address of the lvalue
An in-out [Type] value, which is passed as a pointer to the start of
the array, and lifetime-extended for the duration of the call
You'll need to use UnsafeMutablePointer<Type>, as follows:
let p = UnsafeMutablePointer<mach_timebase_info_data_t>.alloc(1)
mach_timebase_info(&p.memory)
swift 5.5:
let timebaseInfo: mach_timebase_info_data_t = {
let pointer = UnsafeMutablePointer<mach_timebase_info_data_t>.allocate(capacity: 1)
precondition(mach_timebase_info(pointer) == KERN_SUCCESS)
let info = pointer.pointee
defer { pointer.deallocate() }
return info
}()
func convertToNanoseconds(_ value: UInt64) -> UInt64 {
return (value * UInt64(timebaseInfo.numer)) / UInt64(timebaseInfo.denom)
}