From ca8ee16cfde42ea27d40f8e45fa6d96dc24cd5d9 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Mon, 13 Jul 2009 18:32:19 -0400 Subject: [PATCH] uobject: Implement an interface for loading/unloading. This allows, for example, an instance of Engine.Music to load its music data only when required. It may be useful to keep around an instance without allocating gobs of memory to store data that won't be used. --- src/Makefile.am | 4 ++-- src/engine/music.c | 49 +++++++++++++++++++++++++++++++++++++++++++++- src/loadable.c | 31 +++++++++++++++++++++++++++++ src/loadable.h | 29 +++++++++++++++++++++++++++ src/upkg.c | 10 ++++++++++ 5 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 src/loadable.c create mode 100644 src/loadable.h diff --git a/src/Makefile.am b/src/Makefile.am index 67e4d7b..128393a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,14 +2,14 @@ lib_LTLIBRARIES = libupkg.la libupkg_la_SOURCES = libupkg.c pack.c include_HEADERS = upkg.h -noinst_HEADERS = pack.h exportable.h uobject.h module.h avl.h +noinst_HEADERS = pack.h loadable.h exportable.h uobject.h module.h avl.h if BUILD_UPKG include engine/Makefile.inc bin_PROGRAMS = upkg -upkg_SOURCES = upkg.c avl.c module.c exportable.c uobject.c +upkg_SOURCES = upkg.c avl.c module.c loadable.c exportable.c uobject.c upkg_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib \ $(GLIB_CFLAGS) $(LTDLINCL) upkg_LDFLAGS = -L$(top_builddir)/lib -export-dynamic diff --git a/src/engine/music.c b/src/engine/music.c index 87a549b..f770662 100644 --- a/src/engine/music.c +++ b/src/engine/music.c @@ -3,6 +3,7 @@ #include #include "exportable.h" +#include "loadable.h" #include "uobject.h" #include "music.h" #include "upkg.h" @@ -12,14 +13,41 @@ struct music_priv { struct upkg_file *f; + unsigned loaded; }; static void exportable_init(UObjectExportable *); +static void loadable_init(UObjectLoadable *); G_DEFINE_DYNAMIC_TYPE_EXTENDED(EngineMusic, engine_music, U_OBJECT_TYPE, 0, G_IMPLEMENT_INTERFACE(U_OBJECT_TYPE_EXPORTABLE, exportable_init) + G_IMPLEMENT_INTERFACE(U_OBJECT_TYPE_LOADABLE, loadable_init) ); +static int load(GObject *o) +{ + struct music_priv *priv = MUSIC_GET_PRIV(o); + + if (!priv->loaded) { + g_return_val_if_fail(priv->f != NULL, -1); + + if (upkg_export_seek(priv->f, 0, SEEK_SET) != 0) { + return -1; + } + } + + priv->loaded++; + return 0; +} + +static void unload(GObject *o) +{ + struct music_priv *priv = MUSIC_GET_PRIV(o); + g_return_if_fail(priv->loaded > 0); + + --priv->loaded; +} + static int export(GObject *o, FILE *f) { struct music_priv *priv = MUSIC_GET_PRIV(o); @@ -54,6 +82,12 @@ static void exportable_init(UObjectExportable *e) e->export_name = export_name; } +static void loadable_init(UObjectLoadable *l) +{ + l->load = load; + l->unload = unload; +} + static int deserialize(UObject *o, struct upkg_file *f) { struct music_priv *priv = MUSIC_GET_PRIV(o); @@ -99,15 +133,28 @@ void music_register(GTypeModule *m) static void engine_music_init(EngineMusic *m) { + struct music_priv *priv = MUSIC_GET_PRIV(m); + *priv = (struct music_priv){0}; +} + +static void engine_music_finalize(GObject *o) +{ + struct music_priv *priv = MUSIC_GET_PRIV(o); + + if (priv->loaded >= 1) { + priv->loaded = 1; + unload(o); + } } static void engine_music_class_init(EngineMusicClass *class) { UObjectClass *uo = U_OBJECT_CLASS(class); - + GObjectClass *go = G_OBJECT_CLASS(class); g_type_class_add_private(class, sizeof (struct music_priv)); uo->deserialize = deserialize; + go->finalize = engine_music_finalize; } static void engine_music_class_finalize(EngineMusicClass *class) diff --git a/src/loadable.c b/src/loadable.c new file mode 100644 index 0000000..26b81fd --- /dev/null +++ b/src/loadable.c @@ -0,0 +1,31 @@ +#include +#include +#include "loadable.h" + +GType u_object_loadable_get_type(void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (UObjectLoadable), + NULL, + NULL, + }; + + type = g_type_register_static(G_TYPE_INTERFACE, + "UObjectLoadable", &info, 0); + } + return type; +} + +int u_object_load(GObject *obj) +{ + g_return_val_if_fail(U_OBJECT_IS_LOADABLE(obj), -1); + return U_OBJECT_LOADABLE_GET_INTERFACE(obj)->load(obj); +} + +void u_object_unload(GObject *obj) +{ + g_return_if_fail(U_OBJECT_IS_LOADABLE(obj)); + U_OBJECT_LOADABLE_GET_INTERFACE(obj)->unload(obj); +} diff --git a/src/loadable.h b/src/loadable.h new file mode 100644 index 0000000..88d25e3 --- /dev/null +++ b/src/loadable.h @@ -0,0 +1,29 @@ +#ifndef LOADABLE_H_ +#define LOADABLE_H_ + +#include +#include + +#define U_OBJECT_TYPE_LOADABLE (u_object_loadable_get_type()) +#define U_OBJECT_LOADABLE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, \ + U_OBJECT_TYPE_LOADABLE, UObjectLoadable) +#define U_OBJECT_IS_LOADABLE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, \ + U_OBJECT_TYPE_LOADABLE) +#define U_OBJECT_LOADABLE_GET_INTERFACE(inst) G_TYPE_INSTANCE_GET_INTERFACE \ + (inst, U_OBJECT_TYPE_LOADABLE, UObjectLoadable) + +typedef struct UObjectLoadable UObjectLoadable; + +struct UObjectLoadable { + GTypeInterface parent; + + int (*load)(GObject *obj); + void (*unload)(GObject *obj); +}; + +GType u_object_loadable_get_type(void); + +int u_object_load(GObject *obj); +void u_object_unload(GObject *obj); + +#endif diff --git a/src/upkg.c b/src/upkg.c index 82a673d..87794cb 100644 --- a/src/upkg.c +++ b/src/upkg.c @@ -28,6 +28,7 @@ #include "module.h" #include "uobject.h" #include "exportable.h" +#include "loadable.h" enum { MODE_INFO, @@ -161,6 +162,11 @@ static int export(struct upkg *pkg, GObject *obj, unsigned idx) if (u_object_deserialize(obj, f) != 0) { goto out; } + + if (U_OBJECT_IS_LOADABLE(obj) && u_object_load(obj) != 0) { + goto out; + } + u_object_export_name(obj, name, sizeof name); printf("exporting %s to %s\n", upkg_export_name(pkg, idx), name); @@ -178,6 +184,10 @@ static int export(struct upkg *pkg, GObject *obj, unsigned idx) goto out; } + if (U_OBJECT_IS_LOADABLE(obj)) { + u_object_unload(obj); + } + out: upkg_export_close(f); return rc; -- 2.43.2