Jump to content
  • Advertisement
Sign in to follow this  

Mapping non-refcounted pointer based interfaces

This topic is 2048 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I'm mapping a C library interface to angelscript, and have mostly managed to make it work nicely.



One problem I have is how to handle non-refcounted pointer parameters. I haven't find a good non-kludgy solution to it so far. Consider the following function declaration:

void foo(Bar* fp);

I could make a wrapper function like so:

void fooWrapper(Bar& f)

...but doing that for a lot of functions is not very nice. One typical case of this is C-style objects with large-ish function parameters:

void setFoo(FooObject* fo, BarValue const* bv);
BarValue const* bv getFoo(FooObject* fo);

The setter here copies values inside bv, and getter returns a pointer to the actual member.


Main question:

Is there a pattern to map cases like this into angelscript?


I can't make BarValue a value type because then I can't call pointer-type functions, and I can't make it a reference type because there's no refcounting included. I can't make it a NOCOUNT reference either because BarValues need to be created inside the script to pass them as parameters.


I've tried to make quite a few generic template-based solutions to this, transparently generating wrapper functions as above, but AS's function system doesn't seem to like them. I've tried creating separate refcounters but they end up being as verbose solutions as the wrapper functions.


Proposed solution:

What would create a viable solution would be std::function support:

  1. Lambda expressions would make the wrapper function solution a lot cleaner (BarValue could be mapped as a value type)
  2. Possibility of using a simple generic templated external reference counting mechanism (BarValue could be mapped as a reference type)

For example:

engine->RegisterObjectMethod("FooObject", "void set_bar(const BarValue &in)", asSTDFUNCTION([](FooObject* o, BarValue const& v){ setFoo(o, &v); }), asCALL_CDECL_OBJFIRST);
engine->RegisterObjectMethod("FooObject", "BarValue get_bar()", asSTDFUNCTION([](FooObject* o){ return getFoo(o); }), asCALL_CDECL_OBJFIRST);


Would this be possible to implement? Am I completely off the mark here? Is mapping interfaces like this possible without wrapper functions and/or types?

Share this post

Link to post
Share on other sites

There is no need to wrap a function that receives a pointer. Just tell AngelScript that the pointer is really a reference. Pointers and references in C++ use the same ABI so there is really no difference.


// C++
void foo(Bar*);
engine->RegisterGlobalFunction("void foo(Bar &)", asFUNCTION(foo), asCALL_CDECL);


If you're not worried about the script writer not doing the proper memory management you can certainly use asOBJ_NOCOUNT. This flag just tells AngelScript that the type is not reference counted and that the application will be responsible for making sure the memory is properly cleaned up.


Another option is to register a value type to hold a Bar*, e.g.


void ClearPtr(void *p) { *reinterpret_cast<void**>(p) = 0; }
engine->RegisterObjectType("BarPtr", sizeof(Bar*), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE);
engine->RegisterObjectBehaviour("BarPtr", "void f()", asFUNCTION(ClearPtr), asCALL_CDECL_OBJLAST);
void foo(Bar*);
engine->RegisterGlobalFunction("void foo(BarPtr)", asFUNCTION(foo), asCALL_CDECL);


It is definitely possible to use external reference counting. The AddRef and Release behaviours can for example use the object pointer to quickly find the external reference counter in a hash map. This look up is obviously going to add an overhead, but depending on what you intend to use the scripting for, this overhead is possibly quite negligible.



Although I've never tried it. If you want to use std::function, you ought to be able to do so by registering it with the calling convention asCALL_THISCALL_ASGLOBAL, and using the asMETHOD to take the address of the operator() method.

Edited by Andreas Jonsson

Share this post

Link to post
Share on other sites

Thanks for the quick response! I'll try these solutions and report back my results for future reference to others.

Share this post

Link to post
Share on other sites

The first one works like a charm. I now have the "Bar" type defined as a value type and use references in AS function signatures to denote pointers. This discovery will bring quite a few good things to my codebase, so thanks again!

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!