Skip to content

Instantly share code, notes, and snippets.

@wrl
Last active December 24, 2015 12:59
Show Gist options
  • Save wrl/6801788 to your computer and use it in GitHub Desktop.
Save wrl/6801788 to your computer and use it in GitHub Desktop.
/*
** keeping track of objects that exist in both C and mruby is tricky! in
** situations where you're binding to a library which maintains its own
** internal lists of child objects (say, in a UI toolkit, a container
** object with a list of contained widgets), you want to do the least
** amount of bookkeeping possible, lest you do your bookkeeping wrong.
**
** here's a simple solution. it works by mapping a cptr to a ruby object,
** which preferably you'd use to wrap around said cptr with a MRB_TT_DATA
** object. the way you use it is simple: whenever you get a pointer back
** from the API you're wrapping, look it up in this here GC map. if it
** exists, there's your wrapped object. if it doesn't, you can take the
** pointer and wrap an object around it, then store it in the map.
**
** there are two benefits to this method:
** - ruby-allocated objects will not be garbage collected while they're in
** the map, since instance variables are traversed by the garbage
** collector.
**
** - for a given cptr, you keep a reference around to the same ruby
** object, and you can easily wrap around objects which were not
** allocated in ruby but that you'd still like to interact with.
**
** released under the unlicense <http://unlicense.org/>
*/
struct gc_map {
mrb_value hash;
};
static int
gc_map_init(mrb_state *mrb, struct gc_map *m, mrb_value on_obj)
{
m->hash = mrb_hash_new(mrb);
mrb_iv_set(mrb, on_obj, mrb_intern2(mrb, "__gc_map__", 10), m->hash);
return 0;
}
static mrb_value
gc_map_get(mrb_state *mrb, struct gc_map *m, void *p)
{
return mrb_hash_get(mrb, m->hash, mrb_cptr_value(mrb, p));
}
static void
gc_map_set(mrb_state *mrb, struct gc_map *m, void *p,
mrb_value object)
{
mrb_hash_set(mrb, m->hash, mrb_cptr_value(mrb, p), object);
}
static mrb_value
gc_map_delete(mrb_state *mrb, struct gc_map *m, void *p)
{
return mrb_hash_delete_key(mrb, m->hash, mrb_cptr_value(mrb, p));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment