Example 2

Let's say you're using a
GLib Hashtable
inside an object to map names to ids.
You allocate the ids from a pool (each object has its own pool), and you want to ensure they get released
automatically when removed from the hash table.
g_hash_table_new_full() lets you specify a value destroy function, which seems
to fit the situation perfectly:
value_destroy_func: a function to free the memory allocated for the value used
when removing the entry from the GHashTable
The problem is it has to be of type
void (*GDestroyNotify) (guint id)
and there's no way to also pass the pointer to the pool.
Basically, unless you do some evil trickery with globals, you're screwed.
If you can do partial function application however, this is easy: you just specialize the pool
argument in pool_dealloc(pool, id) and pass that function as value destroy function :

So the CSPE_2_1() macro is where all the magic happens:
at runtime it generates code in the heap and stores the address of that code in value_destroy.
the generated asm is basically just a function call to pool_dealloc() hardcoding the specialized
arguments, and passing the others along.

When we don't need the function anymore, we call CSPE_FREE() to release memory.

The first number in CSPE_2_1() is the number of arguments of the
source function.
The second one is the number of arguments being
specialized.
So if we had a function taking 5 arguments and we specialized 3 of them,
we would use CSPE_5_3().

Providing the type of the source function and its arguments makes the
macros a lot uglier to use, but gives you type safety :
you will get a warning if the types don't match.

Supported types

all integer types up to long.

floats, doubles,

all pointer types

Note: if your compiler doesn't support typeof, you won't
be able to use function pointer types directly.
you have to use typedefs instead.

Unsupported types

long long on 32 bit architectures,

long double, complex types and other craziness

passing of structs by value

All of these will trigger an assertion if used.

Optimizations

Code generation is actually done only once :
Since for a given macro call the C types
will always be the same, we can reuse the work from previous runs. All we need to do is
update the specialized arguments' values, since they may be different.

jmp instead of call :
On architectures which support passing arguments in registers (ie everything except i386),
we avoid setting up a stack frame for the generated code and jump directly to the target function
(so we never return to the generated code).

Supported architectures

i386

Should run on pretty much anything. Tested on

Linux: Debian 3.1, Fedora(c2)

NetBSD 1.6.1, FreeBSD 4.8, OpenBSD 3.4

Solaris 9

sparc

Solaris 9 (ultrasparc) (32bit only)

powerpc

OSX (darwin6.8) and AIX (32bit only)

alpha

Linux Debian 3.0

x86_64 (AMD64) (32 and 64 bits modes)

Linux - Tested on opteron cpu.

Links

OCaml and other functional languages which solve
this much more elegantly.

libffi
lets you call a C function whose type is only known at runtime. also implements closures.
(see also ffcall)