pastebin.ch - Interfaces for masochists

Subject
Interfaces for masochists
Author
Unnamed
Description
No description given
Posted on
Sun, 22 Aug 2010 00:43:43 +0200
Content
/***** 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;
}
 
Don't email to hereI'm now supporting the experiment spamschlucker.org too :)