-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtype.h
208 lines (190 loc) · 7.27 KB
/
type.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#ifndef _TYPE_H
#define _TYPE_H
#include <stddef.h>
#include <inttypes.h>
#include <stdbool.h>
typedef uint64_t Type;
typedef struct _TypeInstance TypeInstance;
typedef void (*TypeInitializer)(void *);
typedef void (*TypeDestructor)(void *);
typedef void (*InstanceInitializer)(void *);
typedef void (*InstanceDestructor)(void *);
/**
* Returns true if the given type is
* a subtype of some type, or false
* if the type is not a subtype.
*/
typedef bool (*TypeVerifier)(Type);
struct _TypeInstance {
/* a value of 0 indicates no parent */
Type base_type;
Type type;
size_t instance_size;
/* if klass_size == 0, then this is a
* non-instantiable type */
size_t klass_size;
const char *name;
/* the following methods are chained */
TypeInitializer type_init;
TypeDestructor type_dispose;
InstanceInitializer instance_init;
InstanceDestructor instance_dispose;
/* not chained */
TypeVerifier type_is;
};
/**
* Registers a new type with the type system and returns
* a unique value identifying that type. Under the hood,
* this creates a new TypeInstance and stores it somewhere.
* This TypeInstance is retrievable with the function
* global_types_get_instance ().
*
* There are certain rules as to what a type instance must
* have defined, according to what kind of type it represents.
* There are two basic kinds of types you can define:
* 1. an instantiable type
* - This is a type whose instance can be created with
* type_instance_instance_new() and destroyed with
* type_instance_instance_dispose(). Therefore the
* parameters @instance_init and @instance_dispose
* must not be NULL.
* - The struct defining the instance must have as its
* first element a pointer to a class (this class must
* "inherit" TypeInstance by containing a (TypeInstance)
* as its first member). Therefore @klass_size must be
* at least sizeof(TypeInstance), and @instance_size must
* be at least sizeof(TypeInstance *). Also, @type_init
* and @type_dispose must not be NULL.
* - The contents of @name must be a _unique_ mnemonic for
* the type. It must not be NULL and it must be non-zero
* in length.
* - @type_is must be a pointer to a function checking
* if a given type is a subtype. Obviously, since the
* function cannot make comparisons before the type
* is created, it is recommended to have the function
* refer to a static variable, which is initialized with
* the return value of this function.
* - Finally, the @base_type must be a type that is
* also an instantiable type. The one exception is
* TYPE_ANY, which can be used to mean that our type
* has no subtype.
* 2. a non-instantiable type
* - This is a type whose instance cannot be created and
* destroyed by the dynamic type system. This is usually
* used for fundamental types (like char, long, etc).
* - @klass_size must be zero
* - @instance_size must be non-zero.
* - @name is subject to the same rules as above
* - @type_init and @type_dispose are ignored for now
* - @instance_init and @instance_dispose are ignored
* - @type_is must be defined
*/
Type global_types_register_new (Type base_type,
size_t instance_size, size_t klass_size,
const char *name,
TypeInitializer type_init,
TypeDestructor type_dispose,
InstanceInitializer instance_init,
InstanceDestructor instance_dispose,
TypeVerifier type_is);
TypeInstance *global_types_get_instance (Type type);
void *type_instance_instance_new (Type type);
/**
* Call an object's destructor
*/
void type_instance_instance_dispose (void *data);
/* basic types */
#define TYPE_ANY ((Type) 0)
#define TYPE_UCHAR (TYPE_ANY + 1)
#define TYPE_CHAR (TYPE_UCHAR + 1)
#define TYPE_USHORT (TYPE_CHAR + 1)
#define TYPE_SHORT (TYPE_USHORT + 1)
#define TYPE_UINT (TYPE_SHORT + 1)
#define TYPE_INT (TYPE_UINT + 1)
#define TYPE_ULONG (TYPE_INT + 1)
#define TYPE_LONG (TYPE_ULONG + 1)
#define TYPE_BOOL (TYPE_LONG + 1)
#define TYPE_FLOAT (TYPE_BOOL + 1)
#define TYPE_DOUBLE (TYPE_FLOAT + 1)
#define TYPE_POINTER (TYPE_DOUBLE + 1)
#define TYPE_TYPE (TYPE_POINTER + 1)
#define N_BASIC_TYPES (TYPE_TYPE + 1)
#define _DECLARE_TYPE(TypeName, prefix) \
Type prefix##_get_type (void); \
bool prefix##_is_type (Type type); \
static inline TypeName##Class *prefix##_get_class (void *self) {\
return ((self != NULL && (*(TypeInstance **)self) != NULL && prefix##_is_type ((*(TypeInstance **)self)->type)) ? (*(TypeName##Class **)self) : NULL); \
} \
static inline TypeName *prefix##_cast (void *self) {\
return (prefix##_get_class (self) != NULL ? (TypeName *) self : NULL);\
}\
static inline TypeName##Class *prefix##_class_cast (void *self) {\
return ((self != NULL && prefix##_is_type (((TypeInstance *)self)->type)) ? ((TypeName##Class *)self) : NULL);\
}
/**
* for creating new objects, this macro should appear
* in the .h file
*/
#define DECLARE_TYPE(TypeName, type_prefix) _DECLARE_TYPE(TypeName, type_prefix)
#define _DEFINE_TYPE(TypeName, prefix, BASE_TYPE) \
static void prefix##_init (TypeName *self);\
static void __##prefix##_init (void *self) { \
TypeName *data; \
data = (*(TypeInstance **)self)->instance_size >= sizeof(*data) ? self : NULL; \
assert (data != NULL); \
prefix##_init (data); \
}\
static void prefix##_dispose (TypeName *self);\
static void __##prefix##_dispose (void *self) { \
TypeName *data; \
data = (*(TypeInstance **)self)->instance_size >= sizeof(*data) ? self : NULL; \
assert (data != NULL); \
prefix##_dispose (data);\
}\
static void prefix##_class_init (TypeName##Class *klass);\
static void __##prefix##_class_init (void *self) { \
TypeName##Class *data; \
data = ((TypeInstance *)self)->klass_size >= sizeof(*data) ? self : NULL; \
assert (data != NULL); \
prefix##_class_init (data); \
}\
static void prefix##_class_dispose (TypeName##Class *klass);\
static void __##prefix##_class_dispose (void *self) { \
TypeName##Class *data; \
data = ((TypeInstance *)self)->klass_size >= sizeof(*data) ? self : NULL; \
assert (data != NULL); \
prefix##_class_dispose (data); \
}\
Type prefix##_get_type (void) {\
static Type type = 0;\
if (type == 0) {\
type = global_types_register_new (BASE_TYPE, \
sizeof(TypeName), sizeof(TypeName##Class), \
"" # TypeName, \
&__##prefix##_class_init,\
&__##prefix##_class_dispose,\
&__##prefix##_init,\
&__##prefix##_dispose,\
&prefix##_is_type);\
assert (type != 0); \
}\
return type; \
}\
bool prefix##_is_type (Type type) {\
const Type self_type = prefix##_get_type ();\
TypeInstance *type_inst; \
while (type > BASE_TYPE) {\
type_inst = global_types_get_instance (type); \
assert (type_inst != NULL); \
if (type_inst->type == self_type) \
return true;\
type = type_inst->base_type;\
}\
return false;\
}
/**
* for creating new objects, this macro should appear
* in the .c file
*/
#define DEFINE_TYPE(TypeName, type_prefix, base_type) _DEFINE_TYPE(TypeName, type_prefix, base_type)
#endif /* _TYPE_H */