chiark / gitweb /
src/method-impl.lisp: Initialize `suppliedp' flags properly.
[sod] / lib / sod.c
CommitLineData
77027cca
MW
1/* -*-c-*-
2 *
3 * Runtime support for the Sensible Object Design
4 *
5 * (c) 2009 Straylight/Edgeware
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
e0808c47 10 * This file is part of the Sensible Object Design, an object system for C.
77027cca 11 *
7d21069e
MW
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.
77027cca 16 *
7d21069e 17 * The SOD Runtime is distributed in the hope that it will be useful,
77027cca
MW
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7d21069e 20 * GNU Library General Public License for more details.
77027cca 21 *
7d21069e
MW
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.
77027cca
MW
26 */
27
28/*----- Header files ------------------------------------------------------*/
29
ddee4bb1 30#include "sod.h"
77027cca
MW
31
32/*----- Main code ---------------------------------------------------------*/
33
34/* --- @find_chain@ --- *
35 *
36 * Arguments: @const SodClass *sub, *super@ = pointers to two classes
37 *
38 * Returns: If @sub@ is a subclass of @super@, then a pointer to @sub@'s
39 * chain entry describing @super@'s chain; otherwise null.
40 */
41
42static const struct sod_chain *find_chain(const SodClass *sub,
43 const SodClass *super)
44{
45 const SodClass *head = super->cls.head;
46 const struct sod_chain *chain, *limit;
47
48 /* Slightly fancy footwork. Each class carries a table describing its
49 * constituent chains, and each chain has a vector of the classes in that
50 * chain, with the head (least specific) first. Chains are always
51 * non-empty.
52 *
53 * Another useful bit of information in the class is its level, i.e., its
54 * index in its own chain vector. This is invariant because the chains are
55 * linear.
56 *
57 * This suggests the following algorithm. Search @sub@'s chains for one
58 * headed by @super@'s chain head. If we find one, check that the chain's
59 * class vector is long enough, and look at the entry corresponding to
60 * @super@'s level. If it matches @super@ then @sub@ is indeed a subclass
61 * and we're done. Otherwise it isn't, and we lose. We also lose if no
62 * matching chain is found.
63 */
ddee4bb1 64 for (chain = sub->cls.chains, limit = chain + sub->cls.n_chains;
77027cca
MW
65 chain < limit; chain++) {
66 if (chain->classes[0] != head)
67 continue;
68 if (super->cls.level < chain->n_classes &&
69 chain->classes[super->cls.level] == super)
70 return (chain);
71 break;
72 }
73 return (0);
74}
75
76/* --- @sod_subclassp@ --- *
77 *
78 * Arguments: @const SodClass *sub, *super@ = pointers to two classes
79 *
80 * Returns: Nonzero if @sub@ is a subclass of @super@.
81 */
82
dea4d055
MW
83int sod_subclassp(const SodClass *sub, const SodClass *super)
84 { return (!!find_chain(sub, super)); }
77027cca
MW
85
86/* --- @sod_convert@ --- *
87 *
88 * Arguments: @const SodClass *cls@ = desired class object
89 * @const void *obj@ = pointer to instance
90 *
91 * Returns: Pointer to appropriate ichain of object, or null if the
92 * instance isn't of the specified class.
93 *
94 * Use: General down/cross-casting function.
95 *
96 * Upcasts can be performed efficiently using the automatically
97 * generated macros. In particular, upcasts with a chain are
98 * trivial; cross-chain upcasts require information from vtables
99 * but are fairly fast. This function is rather slower, but is
100 * much more general.
101 *
102 * Suppose we have an instance of a class C, referred to by a
103 * pointer to an instance of one of C's superclasses S. If S'
104 * is some other superclass of C then this function will return
105 * a pointer to C suitable for use as an instance of S'. If S'
106 * is not a superclass of C, then the function returns null.
107 * (If the pointer doesn't point to an instance of some class
108 * then the behaviour is undefined.) Note that you don't need
109 * to know what C or S actually are.
110 */
111
6a590fd0 112void *sod_convert(const SodClass *cls, const void *obj)
77027cca 113{
6a590fd0 114 const struct sod_instance *inst = obj;
77027cca
MW
115 const struct sod_vtable *vt = inst->_vt;
116 const SodClass *realcls = vt->_class;
117 const struct sod_chain *chain = find_chain(realcls, cls);
118
6a590fd0
MW
119 if (!chain) return (0);
120 return ((char *)obj - vt->_base + chain->off_ichain);
77027cca
MW
121}
122
a142609c
MW
123/* --- @sod_init@, @sod_initv@ --- *
124 *
125 * Arguments: @const SodClass *cls@ = class object for new instance
126 * @void *p@ = pointer to storage for new instance
127 * @va_list ap, ...@ = initialization keyword arguments
128 *
129 * Returns: Pointer to the initialized instance.
130 *
131 * Use: Initializes an instance in pre-allocated storage, and returns
132 * a pointer to it.
133 *
134 * This function will imprint the storage, and then send an
135 * `initialize' message to the fresh instance containing the
136 * provided keyword arguments.
137 *
138 * It's usually convenient to use the macro @SOD_INIT@ rather
139 * than calling @sod_init@ directly.
140 */
141
142void *sod_init(const SodClass *cls, void *p, ...)
143{
144 va_list ap;
145
146 va_start(ap, p);
147 sod_initv(cls, p, ap);
148 va_end(ap);
149 return (p);
150}
151
152void *sod_initv(const SodClass *cls, void *p, va_list ap)
153{
154 SodObject *obj;
155
156 cls->cls.imprint(p);
157 obj = SOD_CONVERT(SodObject, p);
158 SodObject_init__v(obj, ap);
159 return (p);
160}
161
a42893dd
MW
162/* --- @sod_teardown@ --- *
163 *
164 * Arguments: @void *p@ = pointer to an instance to be torn down
165 *
166 * Returns: Zero if the object is torn down; nonzero if it refused for
167 * some reason.
168 *
169 * Use: Invokes the instance's `teardown' method to release any held
170 * resources.
171 *
172 * If this function returns nonzero, then the object is still
173 * active, and may still hold important resources. This is not
174 * intended to be a failure condition: failures in teardown are
175 * usually unrecoverable (or very hard to recover from) and
176 * should probably cause the program to abort. A refusal, on
177 * the other hand, means that the object is still live and
178 * shouldn't be deallocated, but that this is a normal situation
179 * and the caller shouldn't worry about it.
180 */
181
182int sod_teardown(void *p)
183{
184 SodObject *obj;
185
186 obj = SOD_CONVERT(SodObject, p);
187 return (SodObject_teardown(obj));
188}
189
77027cca 190/*----- That's all, folks -------------------------------------------------*/