First commit of an experimental low-level object system. At some point

GIB will be reworked to use it, and hopefully Rua will also so that the
two languages can share objects, events, etc.

Warning: This uses quite a few hacks and tortured macros, it might cause
breakage.
This commit is contained in:
Brian Koropoff 2003-11-29 04:40:25 +00:00
parent 37a64e59ab
commit 55181621bd
5 changed files with 458 additions and 2 deletions

View file

@ -4,7 +4,7 @@ includedir = $(prefix)/include/QF
include_HEADERS = bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \
console.h crc.h csqc.h cvar.h dstring.h draw.h gib.h hash.h hl.h \
idparse.h image.h in_event.h info.h input.h joystick.h keys.h link.h \
llist.h locs.h mathlib.h mdfour.h model.h modelgen.h msg.h pak.h \
llist.h locs.h mathlib.h mdfour.h model.h modelgen.h msg.h object.h pak.h \
pakfile.h pcx.h png.h plugin.h pr_comp.h pr_debug.h pr_obj.h progs.h \
qargs.h qdefs.h qendian.h qfplist.h qtypes.h quakefs.h quakeio.h render.h \
riff.h screen.h sizebuf.h skin.h sound.h spritegn.h sys.h teamplay.h \

106
include/QF/object.h Normal file
View file

@ -0,0 +1,106 @@
/*
object.h
Provides a primitive object framework to back objects
in higher level languages of QF so that they can share
objects. For example, Ruamoko and GIB would be able to
pass String objects to each other, even if the higher
-level implementations of String in each language differ.
Copyright (C) 2003 Brian Koropoff
Author: Brian Koropoff
Date: November 28, 2003
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifndef __object_h
#define __object_h
#include "QF/qtypes.h"
#define classDecl(name,extends,def) typedef struct name##_s {struct extends##_s base; def} name; extern Class * name##_class
#define superInit(cl, obj, ...) (cl##_class->parent->init ((obj), ##__VA_ARGS__))
#define new(cl, ...) ((void *) (cl##_class->abstract ? NULL : retain(cl##_class->init (Object_Create(cl##_class), ##__VA_ARGS__))))
#define newFloat(cl, ...) ((void *) (cl##_class->abstract ? NULL : cl##_class->init (Object_Create(cl##_class), ##__VA_ARGS__)))
#define methodCall(obj, m, ...) ((obj)->m(obj, ##__VA_ARGS__))
#define methodDecl(type, name, ...) (* name) (struct type##_s *self, ##__VA_ARGS__)
#define retain(obj) (Object_Retain((Object *)obj))
#define release(obj) (Object_Release((Object *)obj))
typedef struct Object_s {
struct Class_s *cl;
int refs;
struct String_s *(*toString)(struct Object_s *obj);
} Object;
#define OBJECT(o) ((Object *)(o))
typedef Object *(*Object_Init_t) (Object *obj, ...);
typedef void (*Object_Deinit_t) (Object *obj);
classDecl (Class, Object,
qboolean abstract;
unsigned int size;
const char *name;
struct Class_s *parent;
Object_Init_t init;
Object_Deinit_t deinit;
);
#define CLASS(o) ((Class *)(o))
classDecl (String, Object,
const char *str;
);
#define STRING(o) ((String *)(o))
classDecl (List, Object,
unsigned int count;
Object * methodDecl (List, get, unsigned int index);
qboolean methodDecl (List, add, Object *o);
);
#define LIST(o) ((List *)(o))
classDecl (ArrayList, List,
Object **elements;
);
#define ARRAYLIST(o) ((ArrayList *)(o))
classDecl (Number, Object,
int methodDecl (Number, intValue);
double methodDecl (Number, doubleValue);
);
#define NUMBER(o) ((Number *)(o))
classDecl (Integer, Number,
int value;
);
#define INTEGER(o) ((Integer *)(o))
Object *Object_Create (Class *cl);
void Object_Delete (Object *obj);
Object *Object_Retain (Object *obj);
Object *Object_Release (Object *obj);
void Object_Init (void);
#endif

View file

@ -28,7 +28,7 @@ libQFutil_la_DEPENDENCIES= libasm.la
libQFutil_la_SOURCES= \
bspfile.c buildnum.c cbuf.c checksum.c cmd.c crc.c cvar.c dstring.c \
fendian.c getopt.c getopt1.c hash.c idparse.c info.c link.c llist.c \
mathlib.c mdfour.c msg.c pakfile.c plugin.c qargs.c qendian.c \
mathlib.c mdfour.c msg.c object.c pakfile.c plugin.c qargs.c qendian.c \
qfplist.c quakefs.c quakeio.c riff.c sizebuf.c string.c sys.c \
va.c ver_check.c wad.c zone.c $(fnmatch)

346
libs/util/object.c Normal file
View file

@ -0,0 +1,346 @@
/*
object.c
Provides a primitive object framework to back objects
in higher level languages of QF so that they can share
objects. For example, Ruamoko and GIB would be able to
pass String objects to each other, even if the higher
-level implementations of String in each language differ.
Copyright (C) 2003 Brian Koropoff
Author: Brian Koropoff
Date: November 28, 2003
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((unused)) const char rcsid[] =
"$Id$";
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include "QF/dstring.h"
#include "QF/sys.h"
#include "QF/object.h"
#include "QF/va.h"
static String *
Object_ToString_f (Object *self)
{
return newFloat(String, va("%s@%p", self->cl->name, self));
}
static void
Object_Init_f (Object *self)
{
self->refs = -1; // Floating reference
self->toString = Object_ToString_f;
Sys_DPrintf("%s@%p initing...\n", self->cl->name, self);
}
static void
Object_Deinit_f (Object *self)
{
Sys_DPrintf("%s@%p deiniting...\n", self->cl->name, self);
free (self);
}
static String *
Class_ToString_f (Object *self)
{
return newFloat(String, CLASS(self)->name);
}
static Object *
Class_Init_f (Object *self, const char *name, unsigned int size, Class *parent, void *init, void *deinit, qboolean abstract)
{
superInit(Class, self);
CLASS(self)->name = strdup(name);
CLASS(self)->size = size;
CLASS(self)->parent = parent;
CLASS(self)->init = (Object_Init_t) init;
CLASS(self)->deinit = (Object_Deinit_t) deinit;
self->toString = Class_ToString_f;
return self;
}
static void
Class_Deinit_f (Object *self) {
free ((void *)CLASS(self)->name);
}
static String *
String_ToString_f (Object *self)
{
return STRING(self);
}
static Object *
String_Init_f (Object *self, const char *value)
{
superInit(String, self);
self->toString = String_ToString_f;
STRING(self)->str = strdup (value);
return self;
}
static void
String_Deinit_f (Object *self)
{
free((void *)STRING(self)->str);
}
Object *
Object_Create (Class *cl)
{
Object *new = malloc (cl->size);
new->cl = cl;
return new;
}
void
Object_Delete (Object *obj)
{
Class *c;
for (c = obj->cl; c; c = c->parent)
c->deinit (obj);
}
Object *
Object_Retain (Object *obj)
{
if (obj->refs == -1) {
obj->refs = 1;
} else {
obj->refs++;
}
return obj;
}
Object *
Object_Release (Object *obj)
{
if (obj->refs == -1)
Sys_Error ("%s@%p with floating reference released.", obj->cl->name, obj);
if (--obj->refs < 1) {
Object_Delete (obj);
return NULL;
}
return obj;
}
static String *
List_ToString_f (Object *self)
{
List *list = LIST(self);
String *str;
unsigned int i;
dstring_t *dstr = dstring_newstr();
dstring_appendstr (dstr, "{");
for (i = 0; i < list->count; i++) {
str = methodCall(methodCall(list, get, i), toString);
retain(str);
dstring_appendstr (dstr, str->str);
release(str);
if (i < list->count - 1)
dstring_appendstr (dstr, ", ");
}
dstring_appendstr (dstr, "}");
str = newFloat(String, dstr->str);
dstring_delete (dstr);
return str;
}
static Object *
List_Init_f (Object *self)
{
superInit(List, self);
LIST(self)->count = 0;
LIST(self)->get = NULL;
LIST(self)->add = NULL;
self->toString = List_ToString_f;
return self;
}
static void
List_Deinit_f (Object *self)
{
}
static Object *
ArrayList_Get_f (List *self, unsigned int index)
{
if (index >= self->count)
return NULL;
return ARRAYLIST(self)->elements[index];
}
static qboolean
ArrayList_Add_f (List *self, Object *o)
{
self->count++;
ARRAYLIST(self)->elements = realloc (ARRAYLIST(self)->elements, self->count);
ARRAYLIST(self)->elements[self->count-1] = o;
retain (o);
return true;
}
static Object *
ArrayList_Init_f (Object *self)
{
superInit (ArrayList, self);
ARRAYLIST(self)->elements = NULL;
LIST(self)->get = ArrayList_Get_f;
LIST(self)->add = ArrayList_Add_f;
return self;
}
static void
ArrayList_Deinit_f (Object *self)
{
unsigned int i;
Object **elements = ARRAYLIST(self)->elements;
for (i = 0; i < LIST(self)->count; i++)
release (elements[i]);
if (elements)
free (elements);
}
static Object *
Number_Init_f (Object *self)
{
superInit (Number, self);
NUMBER(self)->intValue = NULL;
NUMBER(self)->doubleValue = NULL;
return self;
}
static void
Number_Deinit_f (Object *self)
{
}
static String *
Integer_ToString_f (Object *self)
{
return newFloat(String, va("%i", INTEGER(self)->value));
}
static int
Integer_IntValue_f (Number *self)
{
return INTEGER(self)->value;
}
static double
Integer_DoubleValue_f (Number *self)
{
return (double) INTEGER(self)->value;
}
static Object *
Integer_Init_f (Object *self, int value)
{
superInit (Integer, self);
INTEGER(self)->value = value;
NUMBER(self)->intValue = Integer_IntValue_f;
NUMBER(self)->doubleValue = Integer_DoubleValue_f;
self->toString = Integer_ToString_f;
return self;
}
static void
Integer_Deinit_f (Object *self)
{
}
Class *Object_class;
Class *Class_class;
Class *String_class;
Class *List_class;
Class *ArrayList_class;
Class *Number_class;
Class *Integer_class;
static void
Object_Test (void)
{
List *l = new(ArrayList);
String *str;
methodCall(l, add, newFloat(Integer, 5));
methodCall(l, add, newFloat(String, "Daisy"));
methodCall(l, add, newFloat(Integer, 42));
str = methodCall(OBJECT(l), toString);
retain(str);
Sys_DPrintf("List: %s\n", str->str);
release(str);
release(l);
}
void
Object_Init (void)
{
/* There is somewhat of a chicken and egg problem
here.
*/
Object_class = malloc (sizeof (struct Class_s));
Class_class = malloc (sizeof (struct Class_s));
OBJECT(Object_class)->cl = Class_class;
OBJECT(Class_class)->cl = Class_class;
Class_class->parent = Object_class;
Object_class->init = (Object_Init_t) Object_Init_f;
Class_Init_f (OBJECT(Object_class), "Object", sizeof(Object), NULL, Object_Init_f, Object_Deinit_f, true);
Class_Init_f (OBJECT(Class_class), "Class", sizeof(Class), Object_class, Class_Init_f, Class_Deinit_f, false);
retain(Object_class);
retain(Class_class);
/* Phew... Object and Class are now bootstrapped,
classes can now be created by instantiating
Class
*/
/* Create String class normally */
String_class = new(Class, "String", sizeof(String), Object_class, String_Init_f, String_Deinit_f, false);
/* Etc... */
List_class = new(Class, "List", sizeof(List), Object_class, List_Init_f, List_Deinit_f, true);
ArrayList_class = new(Class, "ArrayList", sizeof(ArrayList), List_class, ArrayList_Init_f, ArrayList_Deinit_f, false);
Number_class = new(Class, "Number", sizeof(Number), Object_class, Number_Init_f, Number_Deinit_f, true);
Integer_class = new(Class, "Integer", sizeof(Integer), Number_class, Integer_Init_f, Integer_Deinit_f, false);
/* Run a test! */
Object_Test();
}

View file

@ -71,6 +71,7 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "QF/dstring.h"
#include "QF/model.h"
#include "QF/msg.h"
#include "QF/object.h"
#include "QF/plugin.h"
#include "QF/qargs.h"
#include "QF/quakefs.h"
@ -2496,6 +2497,9 @@ SV_Init (void)
Cmd_StuffCmds (sv_cbuf);
Cbuf_Execute_Sets (sv_cbuf);
// snax: Init experimental object system and run a test
Object_Init();
// execute the global configuration file if it exists
// would have been nice if Cmd_Exec_f could have been used, but it
// only reads from within the quake file system, and changing that is