taskrambler  0.1.9
Web server and task management solution.
class/class.h
Go to the documentation of this file.
1 /**
2  * \file
3  * My own class implementation for C. It combines a data structure
4  * with a set of dynamically linked methods defined by an interface. A
5  * dynamically linked method will be called via a selector method which in
6  * turn gets the implementation stored in the class.
7  *
8  * \author Georg Hopp
9  *
10  * \copyright
11  * Copyright © 2012 Georg Hopp
12  *
13  * This program is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program. If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 #ifndef __CLASS_CLASS_H__
28 #define __CLASS_CLASS_H__
29 
30 #include <stdarg.h>
31 #include <sys/types.h>
32 #include <string.h>
33 #include <assert.h>
34 
35 #include "class/interface.h"
36 
37 #ifndef _ISOC99_SOURCE
38 #define _ISOC99_SOURCE
39 #endif
40 
41 #define CLASS_MAGIC 0xFEFE
42 
43 #define CLASS(name) \
44  struct c_##name; \
45  typedef struct c_##name * name; \
46  extern struct class * const _##name; \
47  struct c_##name
48 
49 #define EXTENDS(parent) \
50  const char _[sizeof(struct c_##parent)]
51 
52 #define _NULL NULL
53 #define CREATE_CLASS(name,_parent,...) \
54  static struct class c_##name; \
55  static class_ptr _classInit##name##_(void) { \
56  c_##name.parent = _##_parent; \
57  c_##name.init = NULL; \
58  return &c_##name; \
59  } \
60  static struct class c_##name = { \
61  CLASS_MAGIC, \
62  NULL, \
63  sizeof(struct c_##name), \
64  _classInit##name##_, \
65  INIT_IFACE_IMPL(__VA_ARGS__) \
66  }; struct class * const _##name = &c_##name; \
67  struct c_##name##_object { void * class; struct c_##name data; }
68 
69 
70 /**
71  * create a static instance of a class.
72  * \todo
73  * this macro requires to close the initializer
74  * with an extra curly brancket. This is not nice...find a
75  * way to prevent this.
76  */
77 #define INSTANCE(class, name) \
78  struct c_##class##_object _##name; \
79  class name = &(_##name.data); \
80  struct c_##class##_object _##name = { \
81  &c_##class,
82 
83 #define INIT_CLASS(class) ((class)->init? (class)->init() : (class))
84 #define GET_CLASS(object) (INIT_CLASS(*(class_ptr *)((void*)(object) - sizeof(void*))))
85 #define IFACE_GET(class,iface) (interfaceGet(&((class)->impl),(iface)))
86 #define HAS_PARENT(class) (NULL != ((class)->parent) && INIT_CLASS((class)->parent))
87 
88 #define IS_OBJECT(obj) ((GET_CLASS((obj)))->magic == CLASS_MAGIC)
89 #define INSTANCE_OF(class,obj) ((GET_CLASS((obj))) == _##class)
90 
91 /**
92  * \todo actually i use gcc feature ## for variadoc... think about
93  * a way to make this standard.
94  */
95 #define _CALL(_class,_iface,method,...) \
96  do { \
97  class_ptr class = _class; \
98  iface = (struct i_##_iface *)IFACE_GET(class, &i_##_iface); \
99  while ((NULL == iface || NULL == iface->method) && HAS_PARENT(class)) { \
100  class = class->parent; \
101  iface = (struct i_##_iface *)IFACE_GET(class, &i_##_iface); \
102  } \
103  assert(NULL != iface->method); \
104  } while(0)
105 
106 #define CALL(object,_iface,method,...) \
107  do { \
108  struct i_##_iface * iface; \
109  _CALL(GET_CLASS(object), _iface, method, ##__VA_ARGS__); \
110  iface->method(object, ##__VA_ARGS__); \
111  } while(0)
112 
113 #define RETCALL(object,_iface,method,ret,...) \
114  do { \
115  struct i_##_iface * iface; \
116  _CALL(GET_CLASS(object), _iface, method, ##__VA_ARGS__); \
117  ret = iface->method(object, ##__VA_ARGS__); \
118  } while(0)
119 
120 #define PARENTCALL(object,_iface,method,...) \
121  do { \
122  struct i_##_iface * iface; \
123  class_ptr pc_class = GET_CLASS((object)); \
124  assert(HAS_PARENT(pc_class)); \
125  _CALL(pc_class->parent, _iface, method, ##__VA_ARGS__); \
126  iface->method(object, ##__VA_ARGS__); \
127  } while(0)
128 
129 
130 struct class;
131 typedef struct class * class_ptr;
132 typedef class_ptr (* fptr_classInit)(void);
133 struct class {
134  const int magic;
135  class_ptr parent;
136  size_t object_size;
138  struct iface_impl impl;
139 };
140 
141 #endif // __CLASS_CLASS_H__
142 
143 // vim: set ts=4 sw=4:
class_ptr(* fptr_classInit)(void)
Definition: class/class.h:132
const int magic
Definition: class/class.h:134
class_ptr parent
Definition: class/class.h:135
struct iface_impl impl
Definition: class/class.h:138
fptr_classInit init
Definition: class/class.h:137
size_t object_size
Definition: class/class.h:136