typedef pointerArity for FFIOpaqueObjects

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

typedef pointerArity for FFIOpaqueObjects

Ben Coman
I have a type definition...
   typedef void *CXIndex;

which I believe reads "CXIndex is a pointer at void"
that is returned by...
    CXIndex clang_createIndex(int x, int y)

This seems an obvious candidate to be a FFIOpaqueObject defined like this...

  FFIOpaqueObject subclass: #CXIndex
      instanceVariableNames: ''
      classVariableNames: ''
      package: 'LibclangPractice'

  CXIndex class >> create
      ^ self ffiCall: #( CXIndex clang_createIndex ( 0, 0 ) )

however  "CXIndex create inspect"
produces an error ==> FFIDereferencedOpaqueObjectError.
because..."external objects have a natural arity of zero but they MUST be called with some arity,
because they are actually external addresses (pointers) and you need to always declare external objects as this example:
   self ffiCall: #( FFIExternalObject *c_function ( FFIExternalObject *handle ) )  
"

which is enforced by...
  FFIOpaqueObjectType>>validateAfterParse: typeAndArityTuple
      self pointerArity >= 1 ifTrue: [ ^ self ].  "@0"
      typeAndArityTuple second >= 1 ifTrue: [ ^ self ].
      FFIDereferencedOpaqueObjectError signal


where pointerArity seems set earlier just by counting the number of pointer stars in the functions return type, which in this case is none...
  FFICallout>>resolveType: aTypeName   "aTypeName==> 'CXIndex' "
      | name newName resolver binding ptrArity |
      newName := aTypeName.
      ptrArity := 0.
      "resolve aliases and pointers"
      [
            name := newName asString trimRight.  
            newName := self aliasForType: name.
            newName last = $* ifTrue: [
                  ptrArity := ptrArity + 1.
                  newName := newName allButLast ].
            name = newName
      ] whileFalse.
      resolver := requestor ifNil: [ self class ].    "resolver==> CXIndex class"
      binding := resolver ffiBindingOf: name asSymbol.   "binding==> #CXIndex->CXIndex"
      binding ifNotNil: [
          ^ (binding value "@1" asExternalTypeOn: self) "@2" pointerArity: ptrArity ] .

which @1 invokes...
  CXIndex(FFIOpaqueObject) class >> asExternalTypeOn: generator
       ^ FFIOpaqueObjectType objectClass: self

  FFIOpaqueObjectType(FFIExternalReferenceType) class >> objectClass: aClass
      ^ self new objectClass: aClass     
  
  FFIOpaqueObjectType(FFIExternalReferenceType) >> objectClass: aClass
objectClass := aClass.    "aClass==>CXIndex"
        pointerArity := 0.  "actually this was done in #initialize"   "@3"


Thus FFIOpaqueObjectType(CXIndex) is returned @2 which invokes...
  FFIOpaqueObjectType(FFIExternalType)>>pointerArity: additionalArity
pointerArity := pointerArity + additionalArity.
which sets pointerArity ==> 0.


But I hazard to suggest that...
    typedef void *CXIndex;

should make pointerArity:=1 when objectClass is assigned @3.  


So I hacked around this by....
  FFIExternalReference class >> pointerArity
      ^0

  CXIndex class >> pointerArity
      ^1
  
  FFIExternalReferenceType >> objectClass: aClass
objectClass := aClass.
pointerArity := aClass pointerArity.

but I wonder if this is the best way, or if external references these opaque objects should have a class-side method similar to #fieldDesc like... 
    typedef  
       ^#( void * )

Thus CXIndex create "==> a CXIndex((void*)@ 16rB6D514A8)"

I am yet to test out this returned object by passing it to another C-library function, but I thought the above was enough for one sitting.

cheers -ben


P.S. Further background...

Declarations...
    typedef void *CXIndex;  
    CXIndex clang_createIndex(int xx, int yy));
defined at...
https://github.com/llvm-mirror/clang/blob/release_39/include/clang-c/Index.h

   extern "C" {
      CXIndex clang_createIndex(  ) {
           ...
           CIndexer *CIdxr = new CIndexer();
           ...
           return CIndexer;
     } }

Reply | Threaded
Open this post in threaded view
|

Re: typedef pointerArity for FFIOpaqueObjects

EstebanLM
Hi Ben, 

here you do not need to use an opaque object (is not that what you want). 
in this case you have two paths to follow: 

1) you just declare CXIndex as an alias of ExternalAddress (or void*). This will work but is not cool because UFFI will answer you an ExternalAddress and probably you want to treat CXIndex as an object. 

2) then you need to declare CXIndex as FFIExternalObject (not OpaqueObject).

FFIExternalObject subclass: #CXIndex. 

this will work as you expected.

Opaque objects are structures that you do not care content, so it is not  what you wan here: https://en.wikipedia.org/wiki/Opaque_data_type

instead FFIExternalObject is precisely meant to manage pointer types (and you do not need to do all that hacking around).

cheers, 
Esteban



On 09 Sep 2016, at 16:53, Ben Coman <[hidden email]> wrote:

I have a type definition...
   typedef void *CXIndex;

which I believe reads "CXIndex is a pointer at void"
that is returned by...
    CXIndex clang_createIndex(int x, int y)

This seems an obvious candidate to be a FFIOpaqueObject defined like this...

  FFIOpaqueObject subclass: #CXIndex
      instanceVariableNames: ''
      classVariableNames: ''
      package: 'LibclangPractice'

  CXIndex class >> create
      ^ self ffiCall: #( CXIndex clang_createIndex ( 0, 0 ) )

however  "CXIndex create inspect"
produces an error ==> FFIDereferencedOpaqueObjectError.
because..."external objects have a natural arity of zero but they MUST be called with some arity,
because they are actually external addresses (pointers) and you need to always declare external objects as this example:
   self ffiCall: #( FFIExternalObject *c_function ( FFIExternalObject *handle ) )  
"

which is enforced by...
  FFIOpaqueObjectType>>validateAfterParse: typeAndArityTuple
      self pointerArity >= 1 ifTrue: [ ^ self ].  "@0"
      typeAndArityTuple second >= 1 ifTrue: [ ^ self ].
      FFIDereferencedOpaqueObjectError signal


where pointerArity seems set earlier just by counting the number of pointer stars in the functions return type, which in this case is none...
  FFICallout>>resolveType: aTypeName   "aTypeName==> 'CXIndex' "
      | name newName resolver binding ptrArity |
      newName := aTypeName.
      ptrArity := 0.
      "resolve aliases and pointers"
      [
            name := newName asString trimRight.  
            newName := self aliasForType: name.
            newName last = $* ifTrue: [
                  ptrArity := ptrArity + 1.
                  newName := newName allButLast ].
            name = newName
      ] whileFalse.
      resolver := requestor ifNil: [ self class ].    "resolver==> CXIndex class"
      binding := resolver ffiBindingOf: name asSymbol.   "binding==> #CXIndex->CXIndex"
      binding ifNotNil: [
          ^ (binding value "@1" asExternalTypeOn: self) "@2" pointerArity: ptrArity ] .

which @1 invokes...
  CXIndex(FFIOpaqueObject) class >> asExternalTypeOn: generator
       ^ FFIOpaqueObjectType objectClass: self

  FFIOpaqueObjectType(FFIExternalReferenceType) class >> objectClass: aClass
      ^ self new objectClass: aClass     
  
  FFIOpaqueObjectType(FFIExternalReferenceType) >> objectClass: aClass
objectClass := aClass.    "aClass==>CXIndex"
        pointerArity := 0.  "actually this was done in #initialize"   "@3"


Thus FFIOpaqueObjectType(CXIndex) is returned @2 which invokes...
  FFIOpaqueObjectType(FFIExternalType)>>pointerArity: additionalArity
pointerArity := pointerArity + additionalArity.
which sets pointerArity ==> 0.


But I hazard to suggest that...
    typedef void *CXIndex;

should make pointerArity:=1 when objectClass is assigned @3.  


So I hacked around this by....
  FFIExternalReference class >> pointerArity
      ^0

  CXIndex class >> pointerArity
      ^1
  
  FFIExternalReferenceType >> objectClass: aClass
objectClass := aClass.
pointerArity := aClass pointerArity.

but I wonder if this is the best way, or if external references these opaque objects should have a class-side method similar to #fieldDesc like... 
    typedef  
       ^#( void * )

Thus CXIndex create "==> a CXIndex((void*)@ 16rB6D514A8)"

I am yet to test out this returned object by passing it to another C-library function, but I thought the above was enough for one sitting.

cheers -ben


P.S. Further background...

Declarations...
    typedef void *CXIndex;  
    CXIndex clang_createIndex(int xx, int yy));
defined at...
https://github.com/llvm-mirror/clang/blob/release_39/include/clang-c/Index.h

   extern "C" {
      CXIndex clang_createIndex(  ) {
           ...
           CIndexer *CIdxr = new CIndexer();
           ...
           return CIndexer;
     } }