- 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;
}