/***** rtk/obj2.h *****/
#ifndef RTK_OBJ2_H
#define RTK_OBJ2_H
#include "stdbool.h"
#include "stddef.h"
#include "stdio.h"
typedef struct Interface Interface;
typedef struct Object Object;
#define STRINGIZE_(x) #x
#define STRINGIZE(x) STRINGIZE_(x)
#define PASTE2_(a,b) a##b
#define PASTE2(a,b) PASTE2_(a,b)
#define PASTE4_(a,b,c,d) a##b##c##d
#define PASTE4(a,b,c,d) PASTE4_(a,b,c,d)
#define PASTE5_(a,b,c,d,e) a##b##c##d##e
#define PASTE5(a,b,c,d,e) PASTE5_(a,b,c,d,e)
static inline bool check_getimpl_internal(
const char *file, int line, const char *func,
const char *clsname, const char *intfname,
void **vtabarray, void *vptr)
{
while (*vtabarray){
if (*vtabarray == vptr) return true;
++vtabarray;
}
fprintf(stderr, "%s:%d: in function %s: Bad cast: %s -> %s"
" (wrong instance type)\n",
file, line, func, intfname, clsname);
return false;
}
/* Get pointer to implementation from an interface pointer */
#define GETIMPL(ClassName, IntfName, iptr) \
(check_getimpl_internal(__FILE__, __LINE__, __func__, \
#ClassName, #IntfName, ClassName##_vtables_list, *(iptr)) \
? ((ClassName*)(((char*)(iptr))-offsetof(ClassName,impl_##IntfName))) \
: NULL)
/* Get interface pointer from implementation pointer */
#define GETINTF(IntfName, optr) (&((optr)->impl_##IntfName))
#endif
#ifdef INTERFACE_DEF
typedef struct PASTE2(INTERFACE_NAME,_vtable) *INTERFACE_NAME;
struct PASTE2(INTERFACE_NAME,_vtable) {
#define METHOD(RetT, Name, ...) \
RetT (* Name)(INTERFACE_NAME *, __VA_ARGS__);
#define METHOD0(RetT, Name) \
RetT (* Name)(INTERFACE_NAME *);
INTERFACE_DEF
#undef METHOD
#undef METHOD0
};
#undef INTERFACE_DEF
#undef INTERFACE_NAME
#endif
#ifdef CLASS_DEF
/***** PHASE A (struct) *****/
typedef struct CLASS_NAME CLASS_NAME; \
struct CLASS_NAME {
#define BEGIN_IMPLEMENTATION(IntfName) \
struct IntfName##_vtable *impl_##IntfName;
#define METHOD(...)
#define METHOD0(...)
#define END_IMPLEMENTATION(IntfName)
#define INITIALISATION(...)
CLASS_DEF
#undef BEGIN_IMPLEMENTATION
#undef METHOD
#undef METHOD0
#undef END_IMPLEMENTATION
FIELDS
};
/***** PHASE B (vtables and prototypes) *****/
static bool PASTE2(CLASS_NAME,_vtables_inited) = false;
#define BEGIN_IMPLEMENTATION(IntfName) \
static struct IntfName##_vtable PASTE4(CLASS_NAME,_,IntfName,_vtable);
#define METHOD(IntfName, RetT, Name, ...) \
static RetT PASTE5(CLASS_NAME,_,IntfName,_,Name)(IntfName *, __VA_ARGS__);
#define METHOD0(IntfName, RetT, Name) \
static RetT PASTE5(CLASS_NAME,_,IntfName,_,Name)(IntfName *);
#define END_IMPLEMENTATION(IntfName)
CLASS_DEF
#undef BEGIN_IMPLEMENTATION
#undef METHOD
#undef METHOD0
#undef END_IMPLEMENTATION
/***** PHASE C2 (create array of pointers to interfaces) *****/
static void *PASTE2(CLASS_NAME,_vtables_list)[] = {
#define BEGIN_IMPLEMENTATION(IntfName) \
(void *) &PASTE4(CLASS_NAME,_,IntfName,_vtable),
#define METHOD(...)
#define METHOD0(...)
#define END_IMPLEMENTATION(...)
CLASS_DEF
NULL};
#undef BEGIN_IMPLEMENTATION
#undef METHOD
#undef METHOD0
#undef END_IMPLEMENTATION
/***** PHASE C (init vtables) *****/
static void PASTE2(CLASS_NAME,_init)(CLASS_NAME *self)
{
if (!PASTE2(CLASS_NAME,_vtables_inited)){
#define BEGIN_IMPLEMENTATION(IntfName) \
{ \
/* Get the vtable for this class and interface */ \
struct IntfName##_vtable *vtab = \
&PASTE4(CLASS_NAME,_,IntfName,_vtable);
#define METHOD(IntfName, RetT, Name, ...) \
vtab->Name = PASTE5(CLASS_NAME,_,IntfName,_,Name);
#define METHOD0(IntfName, RetT, Name) \
vtab->Name = PASTE5(CLASS_NAME,_,IntfName,_,Name);
#define END_IMPLEMENTATION(IntfName) \
}
CLASS_DEF
#undef BEGIN_IMPLEMENTATION
#undef METHOD
#undef METHOD0
#undef END_IMPLEMENTATION
PASTE2(CLASS_NAME,_vtables_inited) = true;
}
/***** PHASE D (init instance) *****/
#define BEGIN_IMPLEMENTATION(IntfName) \
self->impl_##IntfName = &PASTE4(CLASS_NAME,_,IntfName,_vtable);
#define END_IMPLEMENTATION(IntfName)
#define METHOD(...)
#define METHOD0(...)
CLASS_DEF
#undef BEGIN_IMPLEMENTATION
#undef END_IMPLEMENTATION
/***** PHASE E (user-specified initialisation code) *****/
#undef INITIALISATION
#define INITIALISATION(x) x
#define BEGIN_IMPLEMENTATION(...)
#define END_IMPLEMENTATION(...)
CLASS_DEF
}
#undef INITIALISATION
#undef BEGIN_IMPLEMENTATION
#undef METHOD
#undef METHOD0
#undef END_IMPLEMENTATION
#undef CLASS_NAME
#undef FIELDS
#undef CLASS_DEF
#endif
/***** animal.c *****/
#include "rtk/obj2.h"
#include "stdio.h"
#define INTERFACE_NAME Animal
#define INTERFACE_DEF \
METHOD0(void, bark)
#include "rtk/obj2.h"
#define CLASS_NAME Dog
#define FIELDS \
const char *name;
#define CLASS_DEF \
BEGIN_IMPLEMENTATION(Animal) \
METHOD0(Animal, void, bark) \
END_IMPLEMENTATION(Animal) \
INITIALISATION( \
self->name = "Fido"; \
)
#include "rtk/obj2.h"
#define CLASS_NAME Cow
#define FIELDS
#define CLASS_DEF \
BEGIN_IMPLEMENTATION(Animal) \
METHOD0(Animal, void, bark) \
END_IMPLEMENTATION(Animal)
#include "rtk/obj2.h"
void Dog_Animal_bark(Animal *self)
{
printf("Woof! I am %s\n", GETIMPL(Dog, Animal, self)->name);
}
void Cow_Animal_bark(Animal *self)
{
printf("Moo!\n");
GETIMPL(Cow, Animal, self);
}
int main()
{
Dog dog;
Cow cow;
Animal *a, *b;
Dog_init(&dog);
Cow_init(&cow);
a = GETINTF(Animal, &dog);
b = GETINTF(Animal, &cow);
(*a)->bark(a);
(*b)->bark(b);
(*b)->bark(a);
return 0;
}