chiark / gitweb /
vars.am, lib/: Add some manual pages for the library.
[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 *
dea4d055 10 * This file is part of the Sensble 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
123/*----- That's all, folks -------------------------------------------------*/