[NativeBoost] Calling a function in a struct
Hi. I have a situation with libgit2 where the function I need to call is a field in a struct (the field gets populated with different functions with the same signature depending on certain conditions). Iâm facing two problems now: 1. how do I define a function as the field type of an NBExternalStructure? 2. how can I call the function? Iâve tried using callbacks as field types. That works as far as I can access the functions by pointer. But how would I then call that function? Iâve looked at NBNativeFunction and NBNativeFunctionGen but I canât see how I should use either of those to make a plain call. Hereâs a more precise description of my problem: writepack := LG2GitOdbWritepackS new. ⦠âinitialize the struct externallyâ ânow call the function âcommitâ and pass the arguments (this is how I imagine it could workâ¦)" writepack commit value: writepack value: anotherStruct. Needed struct fields: backend: git_odb_backend * append: int (*)(git_odb_writepack *, const void *, size_t, git_transfer_progress *) commit: int (*)(git_odb_writepack *, git_transfer_progress *) free: void (*)(git_odb_writepack *) My current (ad hoc) struct fields: fieldsDesc ^#( LG2GitOdbO backend; LG2WritePackAppendCb append; LG2WritePackCommitCb commit; LG2WritePackFreeCb free; ) Iâd even be happy if I have to implement a method on LG2GitOdbWritepackS for every function call (e.g. âwritepack commit: arg1 and: arg2â) but how would I make the call? Any ideas? Max
2015-02-22 0:06 GMT+01:00 Max Leske <maxleske@gmail.com>:
Hi.
I have a situation with libgit2 where the function I need to call is a field in a struct (the field gets populated with different functions with the same signature depending on certain conditions).
Iâm facing two problems now: 1. how do I define a function as the field type of an NBExternalStructure?
Athens creates a structure with callbacks as a surface plugin for the bitblter (SQSurfaceDispatch). But this is a structur with functions (generated with NB) that are called "from the outside"
2. how can I call the function?
I don't know of any example in the image, where we are calling a function defined in a struct. Maybe you can extend NBFFICallout to generate a call from a function spec + function address NBFFICallout>>#generateCall:module: does this, it generates a call from a function spec and and address loockuped in a module, maybe you can do something similiar, but use the function address from the structure isntead of calling nbGetSymbolAddress:module:
Iâve tried using callbacks as field types. That works as far as I can access the functions by pointer. But how would I then call that function? Iâve looked at NBNativeFunction and NBNativeFunctionGen but I canât see how I should use either of those to make a plain call.
Hereâs a more precise description of my problem:
writepack := LG2GitOdbWritepackS new. ⦠âinitialize the struct externallyâ
ânow call the function âcommitâ and pass the arguments (this is how I imagine it could workâ¦)" writepack commit value: writepack value: anotherStruct.
Needed struct fields:
backend: git_odb_backend * append: int (*)(git_odb_writepack *, const void *, size_t, git_transfer_progress *) commit: int (*)(git_odb_writepack *, git_transfer_progress *) free: void (*)(git_odb_writepack *)
For what is this needed? Do you want to write your own git backend? I find this strange. I only know of two use cases for function pointers in a structs. 1. to define the callbacks (like athens does it for the SQSurfaceDispatch). But we only define the functions and don't call them. 2. a library defines a public api and delegates the implementation to different backends, but structure and backend functions are hidden. Users of the library don't call them.
My current (ad hoc) struct fields:
fieldsDesc ^#( LG2GitOdbO backend; LG2WritePackAppendCb append; LG2WritePackCommitCb commit; LG2WritePackFreeCb free; )
Iâd even be happy if I have to implement a method on LG2GitOdbWritepackS for every function call (e.g. âwritepack commit: arg1 and: arg2â) but how would I make the call?
Any ideas? Max
On 22 Feb 2015, at 01:19, Nicolai Hess <nicolaihess@web.de> wrote:
2015-02-22 0:06 GMT+01:00 Max Leske <maxleske@gmail.com <mailto:maxleske@gmail.com>>: Hi.
I have a situation with libgit2 where the function I need to call is a field in a struct (the field gets populated with different functions with the same signature depending on certain conditions).
Iâm facing two problems now: 1. how do I define a function as the field type of an NBExternalStructure?
Athens creates a structure with callbacks as a surface plugin for the bitblter (SQSurfaceDispatch). But this is a structur with functions (generated with NB) that are called "from the outside"
2. how can I call the function?
I don't know of any example in the image, where we are calling a function defined in a struct. Maybe you can extend NBFFICallout to generate a call from a function spec + function address
NBFFICallout>>#generateCall:module: does this, it generates a call from a function spec and and address loockuped in a module, maybe you can do something similiar, but use the function address from the structure isntead of calling nbGetSymbolAddress:module:
Iâll give that a try, thanks.
Iâve tried using callbacks as field types. That works as far as I can access the functions by pointer. But how would I then call that function? Iâve looked at NBNativeFunction and NBNativeFunctionGen but I canât see how I should use either of those to make a plain call.
Hereâs a more precise description of my problem:
writepack := LG2GitOdbWritepackS new. ⦠âinitialize the struct externallyâ
ânow call the function âcommitâ and pass the arguments (this is how I imagine it could workâ¦)" writepack commit value: writepack value: anotherStruct.
Needed struct fields:
backend: git_odb_backend * append: int (*)(git_odb_writepack *, const void *, size_t, git_transfer_progress *) commit: int (*)(git_odb_writepack *, git_transfer_progress *) free: void (*)(git_odb_writepack *)
For what is this needed? Do you want to write your own git backend?
No. I need to implement packing of loose objects to save space. libgit2 only does this for network transport. For this I need to work with the pack backend directly and the backend provides the function I need to call for finishing the write in the âcommitâ field of the struct. Of course, I know which function that will be since Iâm working with one particular backend. But if I wanted to support multiple backends in the future it would be better to call the provided function instead of explicitly naming it.
I find this strange. I only know of two use cases for function pointers in a structs. 1. to define the callbacks (like athens does it for the SQSurfaceDispatch). But we only define the functions and don't call them. 2. a library defines a public api and delegates the implementation to different backends, but structure and backend functions are hidden. Users of the library don't call them.
Exactly. Iâm dipping deeper here than one usually needs to. Thanks Nicolai.
My current (ad hoc) struct fields:
fieldsDesc ^#( LG2GitOdbO backend; LG2WritePackAppendCb append; LG2WritePackCommitCb commit; LG2WritePackFreeCb free; )
Iâd even be happy if I have to implement a method on LG2GitOdbWritepackS for every function call (e.g. âwritepack commit: arg1 and: arg2â) but how would I make the call?
Any ideas? Max
Yay, got it! Itâs actually really straight forward if you know the stuff⦠The magic is in NBFFICalloutAPI. This class provides the method #function:address:. So if I let NB create an external object (subclass of NBExternalObject) for the struct field that provides the function, the address of the function is in the handle variable and I can define a method on that external object like so: writepack: writepack buffer: buffer length: length progress: progress <primitive: #primitiveNativeCall module: #NativeBoostPlugin error: errorCode> ^ self nbCallout function: #(NBInt32 (LG2GitOdbWritepackS * writepack, const void * buffer, NBInt32 length, LG2GitTransferProgressS * progress)) address: [ handle ] This even installs native code, so call generation only happens on the first pass (Iâll have to see if NB is smart enough here to take changes in the handle into account).
On 22 Feb 2015, at 01:19, Nicolai Hess <nicolaihess@web.de <mailto:nicolaihess@web.de>> wrote:
2015-02-22 0:06 GMT+01:00 Max Leske <maxleske@gmail.com <mailto:maxleske@gmail.com>>: Hi.
I have a situation with libgit2 where the function I need to call is a field in a struct (the field gets populated with different functions with the same signature depending on certain conditions).
Iâm facing two problems now: 1. how do I define a function as the field type of an NBExternalStructure?
Athens creates a structure with callbacks as a surface plugin for the bitblter (SQSurfaceDispatch). But this is a structur with functions (generated with NB) that are called "from the outside"
2. how can I call the function?
I don't know of any example in the image, where we are calling a function defined in a struct. Maybe you can extend NBFFICallout to generate a call from a function spec + function address
NBFFICallout>>#generateCall:module: does this, it generates a call from a function spec and and address loockuped in a module, maybe you can do something similiar, but use the function address from the structure isntead of calling nbGetSymbolAddress:module:
Iâll give that a try, thanks.
Iâve tried using callbacks as field types. That works as far as I can access the functions by pointer. But how would I then call that function? Iâve looked at NBNativeFunction and NBNativeFunctionGen but I canât see how I should use either of those to make a plain call.
Hereâs a more precise description of my problem:
writepack := LG2GitOdbWritepackS new. ⦠âinitialize the struct externallyâ
ânow call the function âcommitâ and pass the arguments (this is how I imagine it could workâ¦)" writepack commit value: writepack value: anotherStruct.
Needed struct fields:
backend: git_odb_backend * append: int (*)(git_odb_writepack *, const void *, size_t, git_transfer_progress *) commit: int (*)(git_odb_writepack *, git_transfer_progress *) free: void (*)(git_odb_writepack *)
For what is this needed? Do you want to write your own git backend?
No. I need to implement packing of loose objects to save space. libgit2 only does this for network transport. For this I need to work with the pack backend directly and the backend provides the function I need to call for finishing the write in the âcommitâ field of the struct. Of course, I know which function that will be since Iâm working with one particular backend. But if I wanted to support multiple backends in the future it would be better to call the provided function instead of explicitly naming it.
I find this strange. I only know of two use cases for function pointers in a structs. 1. to define the callbacks (like athens does it for the SQSurfaceDispatch). But we only define the functions and don't call them. 2. a library defines a public api and delegates the implementation to different backends, but structure and backend functions are hidden. Users of the library don't call them.
Exactly. Iâm dipping deeper here than one usually needs to.
Thanks Nicolai.
My current (ad hoc) struct fields:
fieldsDesc ^#( LG2GitOdbO backend; LG2WritePackAppendCb append; LG2WritePackCommitCb commit; LG2WritePackFreeCb free; )
Iâd even be happy if I have to implement a method on LG2GitOdbWritepackS for every function call (e.g. âwritepack commit: arg1 and: arg2â) but how would I make the call?
Any ideas? Max
participants (2)
-
Max Leske -
Nicolai Hess