chiark / gitweb /
New feature: proper object lifecycle protocol; init and teardown fragments.
[sod] / lib / sod.h
1 /* -*-c-*-
2  *
3  * Sensible Object Design header file
4  *
5  * (c) 2009 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the Sensible Object Design, an object system for C.
11  *
12  * The SOD Runtime Library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * The SOD Runtime is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with SOD; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 #ifndef SOD_H
29 #define SOD_H
30
31 #ifdef __cplusplus
32   extern "C" {
33 #endif
34
35 /*----- Preliminary utilities ---------------------------------------------*/
36
37 /* --- @SOD__HAVE_VARARGS_MACROS@ --- *
38  *
39  * Use:         Defined if the compiler supports C99-style variadic macros.
40  *
41  *              This is more complicated than just checking the value of
42  *              @__STDC_VERSION__@ because GCC has traditionally claimed C89
43  *              by default, but provides the functionality anyway unless it's
44  *              been explicitly turned off.
45  */
46
47 #if __STDC_VERSION__ >= 199901
48    /* The feature exists.  All is well with the world. */
49
50 #  define SOD__HAVE_VARARGS_MACROS
51
52 #elif __GNUC__ >= 3
53    /* We're using GCC, which is trying to deny it but we don't believe it.
54     * Unfortunately there's a fly in the ointment: if `-pedantic' -- or,
55     * worse, `-pedantic-errors' -- is set, then GCC will warn about these
56     * macros being defined, and there isn't a way to detect pedantry from the
57     * preprocessor.
58     *
59     * We must deploy bodges.  There doesn't seem to be a good way to suppress
60     * particular warnings from the preprocessor: in particular, messing about
61     * with `pragma GCC diagnostic' doesn't help.  So we're left with this
62     * hack: just declare all Sod-generated header files which try to do
63     * varargs macro things to be `system headers', which means that GCC's
64     * preprocessor will let them get away with all manner of nefarious stuff.
65     */
66
67 #  define SOD__HAVE_VARARGS_MACROS
68 #  define SOD__VARARGS_MACROS_PREAMBLE _Pragma("GCC system_header")
69
70 #endif
71
72 /* Make sure this gratuitous hack is understood, at least vacuously. */
73 #ifndef SOD__VARARGS_MACROS_PREAMBLE
74 #  define SOD__VARARGS_MACROS_PREAMBLE
75 #endif
76
77 /* We're going to want to make use of this ourselves. */
78 SOD__VARARGS_MACROS_PREAMBLE
79
80 /* --- @SOD__IGNORE@ --- *
81  *
82  * Arguments:   @var@ = some variable name
83  *
84  * Use:         Suppress any warning that @var@ isn't used.
85  */
86
87 #define SOD__IGNORE(var) ((void)(var))
88
89 /* --- @SOD__CAR@ --- *
90  *
91  * Arguments:   @...@ = a nonempty list of arguments
92  *
93  * Returns:     The first argument only.
94  */
95
96 #ifdef SOD__HAVE_VARARGS_MACROS
97 #  define SOD__CAR(...) SOD__CARx(__VA_LIST__, _)
98 #  define SOD__CARx(a, ...) a
99 #endif
100
101 /*----- Header files ------------------------------------------------------*/
102
103 #include <stdarg.h>
104 #include <stddef.h>
105
106 #include "keyword.h"
107 #include "sod-base.h"
108
109 /*----- Data structures ---------------------------------------------------*/
110
111 /* A skeletal vtable structure.  At the beginning of every ichain is a
112  * pointer to one of these.
113  */
114 struct sod_vtable {
115   const SodClass *_class;               /* Pointer to class object */
116   size_t _base;                         /* Offset to instance base */
117 };
118
119 /* A skeletal instance structure.  Every instance pointer points to one of
120  * these.
121  */
122 struct sod_instance {
123   const struct sod_vtable *_vt;         /* Pointer to (chain's) vtable */
124 };
125
126 /* Information about a particular chain of superclasses.  In each class,
127  * there's a pointer to an array of these.  If you search hard enough, you'll
128  * be able to find out a fair amount of information about an instance and its
129  * class.
130  */
131 struct sod_chain {
132   size_t n_classes;                     /* Number of classes in chain */
133   const SodClass *const *classes;       /* Vector of classes, head first */
134   size_t off_ichain;                    /* Offset of ichain from base */
135   const struct sod_vtable *vt;          /* Chain's vtable pointer */
136   size_t ichainsz;                      /* Size of the ichain structure */
137 };
138
139 /*----- Infrastructure macros ---------------------------------------------*/
140
141 /* --- @SOD_XCHAIN@ --- *
142  *
143  * Arguments:   @chead@ = nickname of target chain's head
144  *              @obj@ = pointer to an instance chain
145  *
146  * Returns:     Pointer to target chain, as a @void *@.
147  *
148  * Use:         Utility for implementing cross-chain upcasts.  It's probably
149  *              not that clever to use this macro directly; it's used to make
150  *              the automatically-generated upcast macros more palatable.
151  */
152
153 #define SOD_XCHAIN(chead, obj)                                          \
154   ((void *)((char *)(obj) + (obj)->_vt->_off_##chead))
155
156 /* --- @SOD_OFFSETDIFF@ --- *
157  *
158  * Arguments:   @type@ = a simple (i.e., declaratorless) type name
159  *              @mema, memb@ = members of @type@
160  *
161  * Returns:     The relative offset from @mema@ to @memb@, as a @ptrdiff_t@.
162  *
163  * Use:         Computes a signed offset between structure members.
164  */
165
166 #define SOD_OFFSETDIFF(type, mema, memb)                                \
167   ((ptrdiff_t)offsetof(type, memb) - (ptrdiff_t)offsetof(type, mema))
168
169 /* --- @SOD_ILAYOUT@ --- *
170  *
171  * Arguments:   @cls@ = name of a class
172  *              @chead@ = nickname of chain head of @cls@
173  *              @obj@ = pointer to the @chead@ ichain of an (exact) instance
174  *                      of @cls@
175  *
176  * Returns:     A pointer to the instance's base, cast as a pointer to the
177  *              ilayout structure.
178  *
179  * Use:         Finds an instance's base address given a pointer to one of
180  *              its ichains, if you know precisely the instance's class and
181  *              which chain you're pointing to.  If you don't, then (a) you
182  *              want @SOD_INSTBASE@ below, and (b) you'll have the wrong
183  *              ilayout anyway.
184  *
185  *              This macro is not intended to be used directly outside of
186  *              automatically generated effective method and trampoline
187  *              functions, which have the kinds of specific knowledge
188  *              necessary to use it safely.
189  */
190
191 #define SOD_ILAYOUT(cls, chead, obj)                                    \
192   ((struct cls##__ilayout *)                                            \
193    ((char *)(obj) - offsetof(struct cls##__ilayout, chead)))
194
195 /*----- Utility macros ----------------------------------------------------*/
196
197 /* --- @SOD_CLASSOF@ --- *
198  *
199  * Arguments:   @p@ = pointer to an instance chain
200  *
201  * Returns:     A pointer to the instance's class, as a @const SodClass *@.
202  */
203
204 #define SOD_CLASSOF(obj) ((const SodClass *)(obj)->_vt->_class)
205
206 /* --- @SOD_INSTBASE@ --- *
207  *
208  * Arguments:   @obj@ = pointer to an instance (i.e., the address of one of
209  *                      its instance chains)
210  *
211  * Returns:     The base address of @obj@'s instance layout, as a @void *@.
212  *
213  * Use:         Finds the base address of an instance.  If you know the
214  *              dynamic class of the object then @SOD_ILAYOUT@ is faster.  If
215  *              you don't, this is the right macro, but your options for
216  *              doing something sensible with the result are limited, mostly
217  *              to simple memory management operations such as freeing or
218  *              zeroizing the instance structure.
219  */
220
221 #define SOD_INSTBASE(obj) ((void *)((char *)(obj) - (obj)->_vt->_base))
222
223 /* --- @SOD_CONVERT@ --- *
224  *
225  * Arguments:   @cls@ = a class type name
226  *              @const void *obj@ = a pointer to an instance
227  *
228  * Returns:     Pointer to appropriate instance ichain, or null if the
229  *              instance isn't of the specified class.
230  *
231  * Use:         This is a simple wrapper around the @sod_convert@, which
232  *              you should see for full details.  It accepts a class type
233  *              name rather than a pointer to a class object, and arranges to
234  *              return a pointer of the correct type.
235  */
236
237 #define SOD_CONVERT(cls, obj) ((cls *)sod_convert(cls##__class, (obj)))
238
239 /* --- @SOD_INIT@ --- *
240  *
241  * Arguments:   @cls@ = a class type name
242  *              @p@ = pointer to storage to initialize
243  *              @keys@ = a @KWARGS(...)@ keyword argument sequence
244  *
245  * Use:         Initializes raw storage as an instance of @cls@.
246  */
247
248 #define SOD_INIT(cls, p, keys) ((cls *)sod_init(cls##__class, (p), keys))
249
250 /* --- @SOD_MAKE@ --- *
251  *
252  * Arguments:   @cls@ = a class type name
253  *              @keys@ = a @KWARGS(...)@ keyword argument sequence
254  *
255  * Use:         Allocates (using @malloc@) eand initializes storage to be an
256  *              instance of @cls@.  Returns a null pointer if allocation
257  *              fails.  Use @sod_destroy@ to release the instance.
258  */
259
260 #define SOD_MAKE(cls, keys) ((cls *)sod_make(cls##__class, keys))
261
262 /* --- @SOD_DECL@ --- *
263  *
264  * Arguments:   @cls@ = a class type name
265  *              @var@ = a variable name
266  *              @keys@ = a @KWARGS(...)@ keyword argument sequence
267  *
268  * Use:         Declare @var@ as a pointer to an initialized instance of
269  *              @cls@ with automatic lifetime.
270  */
271
272 #define SOD_DECL(cls, var, keys)                                        \
273   struct cls##__ilayout var##__layout;                                  \
274   cls *var = (cls *)sod_init(cls##__class, &var##__layout, keys)
275
276 /*----- Functions provided ------------------------------------------------*/
277
278 /* --- @sod_subclassp@ --- *
279  *
280  * Arguments:   @const SodClass *sub, *super@ = pointers to two classes
281  *
282  * Returns:     Nonzero if @c@ is a subclass of @d@.
283  */
284
285 extern int sod_subclassp(const SodClass */*sub*/, const SodClass */*super*/);
286
287 /* --- @sod_convert@ --- *
288  *
289  * Arguments:   @const SodClass *cls@ = desired class object
290  *              @const void *obj@ = pointer to instance
291  *
292  * Returns:     Pointer to appropriate ichain of object, or null if the
293  *              instance isn't of the specified class.
294  *
295  * Use:         General down/cross-casting function.
296  *
297  *              Upcasts can be performed efficiently using the automatically
298  *              generated macros.  In particular, upcasts within a chain are
299  *              trivial; cross-chain upcasts require information from vtables
300  *              but are fairly fast.  This function is rather slower, but is
301  *              much more general.
302  *
303  *              Suppose we have an instance of a class C, referred to by a
304  *              pointer to an instance of one of C's superclasses S.  If T
305  *              is some other superclass of C then this function will return
306  *              a pointer to C suitable for use as an instance of T.  If T
307  *              is not a superclass of C, then the function returns null.
308  *              (If the pointer doesn't point to an instance of some class
309  *              then the behaviour is undefined.)  Note that you don't need
310  *              to know what either C or S actually are.
311  */
312
313 extern void *sod_convert(const SodClass */*cls*/, const void */*obj*/);
314
315 /* --- @sod_init@, @sod_initv@ --- *
316  *
317  * Arguments:   @const SodClass *cls@ = class object for new instance
318  *              @void *p@ = pointer to storage for new instance
319  *              @va_list ap, ...@ = initialization keyword arguments
320  *
321  * Returns:     Pointer to the initialized instance.
322  *
323  * Use:         Initializes an instance in pre-allocated storage, and returns
324  *              a pointer to it.
325  *
326  *              This function will imprint the storage, and then send an
327  *              `initialize' message to the fresh instance containing the
328  *              provided keyword arguments.
329  *
330  *              It's usually convenient to use the macro @SOD_INIT@ rather
331  *              than calling @sod_init@ directly.
332  */
333
334 extern KWCALL void *sod_init(const SodClass */*cls*/, void */*p*/, ...);
335 extern void *sod_initv(const SodClass */*cls*/, void */*p*/, va_list /*ap*/);
336
337 /* --- @sod_make@, @sod_makev@ --- *
338  *
339  * Arguments:   @const SodClass *cls@ = class object for new instance
340  *              @va_list ap, ...@ = initialization keyword arguments
341  *
342  * Returns:     Pointer to the newly-allocated initialized instance, or null.
343  *
344  * Use:         Allocates storage for a new instance, initializes it, and
345  *              returns a pointer to it.  If allocation fails, a null pointer
346  *              is returned instead.
347  *
348  *              This function will allocate the storage using @malloc@, and
349  *              then initialize it as for @sod_init@.
350  *
351  *              It's usually convenient to use the macro @SOD_MAKE@ rather
352  *              than calling @sod_make@ directly.
353  *
354  *              (This function is not available in freestanding environments
355  *              lacking @malloc@ and @free@.)
356  */
357
358 extern KWCALL void *sod_make(const SodClass */*cls*/, ...);
359 extern void *sod_makev(const SodClass */*cls*/, va_list /*ap*/);
360
361 /* --- @sod_teardown@ --- *
362  *
363  * Arguments:   @void *p@ = pointer to an instance to be torn down
364  *
365  * Returns:     Zero if the object is torn down; nonzero if it refused for
366  *              some reason.
367  *
368  * Use:         Invokes the instance's `teardown' method to release any held
369  *              resources.
370  *
371  *              If this function returns nonzero, then the object is still
372  *              active, and may still hold important resources.  This is not
373  *              intended to be a failure condition: failures in teardown are
374  *              usually unrecoverable (or very hard to recover from) and
375  *              should probably cause the program to abort.  A refusal, on
376  *              the other hand, means that the object is still live and
377  *              shouldn't be deallocated, but that this is a normal situation
378  *              and the caller shouldn't worry about it.
379  */
380
381 extern int sod_teardown(void */*p*/);
382
383 /* --- @sod_destroy@ --- *
384  *
385  * Arguments:   @void *p@ = pointer to an instance to be torn down, or null
386  *
387  * Returns:     Zero if the object was freed; nonzero if it refused for some
388  *              reason.
389  *
390  * Use:         Invokes the instance's `teardown' method to release any held
391  *              resources, and then calls @free@ to release the instance's
392  *              storage.  See @sod_teardown@ for details, especially
393  *              regarding the return value's meaning.
394  *
395  *              If @p@ is null, then this function does nothing except
396  *              returns zero.
397  *
398  *              (This function is not available in freestanding environments
399  *              lacking @malloc@ and @free@.)
400  */
401
402 extern int sod_destroy(void */*p*/);
403
404 /*----- That's all, folks -------------------------------------------------*/
405
406 #ifdef __cplusplus
407   }
408 #endif
409
410 #endif