pastebin.ch - Objects for retards

Subject
Objects for retards
Author
xlq
Description
No description given
Posted on
Sat, 21 Aug 2010 21:03:51 +0200
Content
/********** obj.h **********/
 
#ifndef RTK_OBJ_H
#define RTK_OBJ_H
 
#if 0
 
Simple interface/implementation-based object orientation.
There is no inheritance, and each implementation can provide
only one interface.
 
Memory layout:
 
 
       Instance:                        Interface:
       +-------------+        /-------> +-----------------+
       |  funcs      |-------/          |    implname_    |
       +-------------+                  +-----------------+
       |  magic      |                  |    method1      |
       +-------------+                  +-----------------+
       |  ...        |                  |    method2      |
       +-------------+                  +-----------------+
                                        |    ...          |
                                        +-----------------+
#endif
 
#include "stdbool.h"
#include "eh.h"
 
EH_DECLARE(E_Type_Error);
 
enum { OBJECT_MAGIC = 0xA0B1EC7 };
 
/* All interfaces have this header */
struct intf_header {
    const char *implname;
};
 
/* All instances have this header */
struct inst_header {
    struct intf_header *funcs;
    int magic;
};
 
/* Object* can point to any instance */
typedef struct inst_header Object;
 
#define BEGIN_INTERFACE(INTF) \
    typedef struct intf_##INTF##_s *INTF; \
    struct intf_##INTF##_s { \
        struct intf_header header_;
#define END_INTERFACE(INTF) };
 
#define BEGIN_IMPLEMENTATION(INTF, IMPL) \
    typedef struct { \
        INTF funcs_; \
        int magic_;
#define METHODS(INTF, IMPL) \
    } IMPL; \
    static struct intf_##INTF##_s IMPL##_funcs = { \
        .header_ = { .implname = #IMPL },
 
#define END_IMPLEMENTATION(INTF, IMPL) };
 
static inline bool downcast_check_internal(
    const char *file, int line, const char *func,
    struct intf_header *from_intfh, struct intf_header *to_intfh, void *obj)
{
    struct inst_header *objh = obj;
    if (objh->magic != OBJECT_MAGIC){
        eh_raise(E_Type_Error, "\n%s:%d: in function %s: Not an object (bad magic number)",
            file, line, func);
        return false;
    } else if (from_intfh != to_intfh){
        eh_raise(E_Type_Error, "\n%s:%d: in function %s: Cannot cast `%s *' to `%s *'",
            file, line, func, from_intfh->implname, to_intfh->implname);
        return false;
    } else {
        return true;
    }
}
#define CAST(IMPL, OBJ) \
    (downcast_check_internal(__FILE__, __LINE__, __func__, \
        &(*(OBJ))->header_, &(IMPL##_funcs).header_, (OBJ)) ? (IMPL *) (OBJ) : NULL)
#define INTF(OBJ) (&(OBJ)->funcs_)
 
#define INIT_OBJ(IMPL, OBJ) \
    ((OBJ)->funcs_ = &(IMPL##_funcs), \
    (OBJ)->magic_ = OBJECT_MAGIC)
 
#define CALL(OBJ, METHOD, ...) \
    ((*(OBJ))->METHOD((OBJ), __VA_ARGS__))
 
#define CALL0(OBJ, METHOD) \
    ((*(OBJ))->METHOD((OBJ)))
 
#endif
 
/********** otest.c **********/
 
#include "rtk/obj.h"
#include "stdio.h"
 
EH_DEFINE(E_Type_Error);
 
BEGIN_INTERFACE(Animal)
    void (* sound)(Animal *);
END_INTERFACE(Animal)
 
static void cow_sound(Animal *a)
{
    puts("Moo!");
}
 
BEGIN_IMPLEMENTATION(Animal, Cow)
METHODS(Animal, Cow)
    .sound = cow_sound
END_IMPLEMENTATION(Animal, Cow)
 
static void dog_sound(Animal *a);
 
BEGIN_IMPLEMENTATION(Animal, Dog)
    const char *name_on_collar;
METHODS(Animal, Dog)
    .sound = dog_sound
END_IMPLEMENTATION(Animal, Dog)
 
static void dog_sound(Animal *a)
{
    Dog *dogp;
    puts("Woof!");
    if (!(dogp = CAST(Dog, a))) return;
    printf("Dog appears to be called %s\n", dogp->name_on_collar);
}
 
int main()
{
    Cow cow;
    Dog dog;
    Animal *a, *b;
 
    INIT_OBJ(Cow, &cow);
    INIT_OBJ(Dog, &dog);
    dog.name_on_collar = "Fido";
    a = INTF(&cow);
    b = INTF(&dog);
 
    (*a)->sound(a);
    (*b)->sound(b);
 
    /* This will cause an error */
    (*b)->sound(a);
 
    return 0;
}
 
Don't email to hereI'm now supporting the experiment spamschlucker.org too :)