# Mapping non-refcounted pointer based interfaces

## Recommended Posts

B-ZaR    122

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

Problem:

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)
{
foo(&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 on other sites
WitchLord    4677

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 on other sites
B-ZaR    122

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

##### Share on other sites
B-ZaR    122

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!