X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/dea4d05507e59ab779ed4bb209e05971d87e260c..284f1fa2ace3e276052ff1bd7d66442500e693da:/lib/sod.h diff --git a/lib/sod.h b/lib/sod.h index 12c7817..360afa8 100644 --- a/lib/sod.h +++ b/lib/sod.h @@ -7,21 +7,22 @@ /*----- Licensing notice --------------------------------------------------* * - * This file is part of the Sensble Object Design, an object system for C. + * This file is part of the Sensible Object Design, an object system for C. * - * SOD is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * The SOD Runtime Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. * - * SOD is distributed in the hope that it will be useful, + * The SOD Runtime is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Library General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with SOD; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU Library General Public + * License along with SOD; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. */ #ifndef SOD_H @@ -31,6 +32,63 @@ extern "C" { #endif +/*----- Preliminary utilities ---------------------------------------------*/ + +/* --- @SOD__HAVE_VARARGS_MACROS@ --- * + * + * Use: Defined if the compiler supports C99-style variadic macros. + * + * This is more complicated than just checking the value of + * @__STDC_VERSION__@ because GCC has traditionally claimed C89 + * by default, but provides the functionality anyway unless it's + * been explicitly turned off. + */ + +#if __STDC_VERSION__ >= 199901 + /* The feature exists. All is well with the world. */ + +# define SOD__HAVE_VARARGS_MACROS + +#elif __GNUC__ >= 3 + /* We're using GCC, which is trying to deny it but we don't believe it. + * Unfortunately there's a fly in the ointment: if `-pedantic' -- or, + * worse, `-pedantic-errors' -- is set, then GCC will warn about these + * macros being defined, and there isn't a way to detect pedantry from the + * preprocessor. + * + * We must deploy bodges. There doesn't seem to be a good way to suppress + * particular warnings from the preprocessor: in particular, messing about + * with `pragma GCC diagnostic' doesn't help. So we're left with this + * hack: just declare all Sod-generated header files which try to do + * varargs macro things to be `system headers', which means that GCC's + * preprocessor will let them get away with all manner of nefarious stuff. + */ + +# define SOD__HAVE_VARARGS_MACROS +# define SOD__VARARGS_MACROS_PREAMBLE _Pragma("GCC system_header") + +#endif + +/* Make sure this gratuitous hack is understood, at least vacuously. */ +#ifndef SOD__VARARGS_MACROS_PREAMBLE +# define SOD__VARARGS_MACROS_PREAMBLE +#endif + +/* We're going to want to make use of this ourselves. */ +SOD__VARARGS_MACROS_PREAMBLE + +/* --- @SOD__CAR@ --- * + * + * Arguments: @...@ = a nonempty list of arguments + * + * Returns: The first argument only. + */ + +#ifdef SOD__HAVE_VARARGS_MACROS +# define SOD__CAR(...) SOD__CARx(__VA_LIST__, _) +# define SOD__CARx(a, ...) a +#endif + /*----- Header files ------------------------------------------------------*/ #include @@ -52,7 +110,7 @@ struct sod_vtable { * these. */ struct sod_instance { - struct sod_vtable *_vt; /* Pointer to (chain's) vtable */ + const struct sod_vtable *_vt; /* Pointer to (chain's) vtable */ }; /* Information about a particular chain of superclasses. In each class, @@ -73,16 +131,17 @@ struct sod_chain { /* --- @SOD_XCHAIN@ --- * * * Arguments: @chead@ = nickname of target chain's head - * @p@ = pointer to an instance chain + * @obj@ = pointer to an instance chain * - * Returns: Pointer to target chain, as a @char *@. + * Returns: Pointer to target chain, as a @void *@. * * Use: Utility for implementing cross-chain upcasts. It's probably * not that clever to use this macro directly; it's used to make * the automatically-generated upcast macros more palatable. */ -#define SOD_XCHAIN(chead, p) ((char *)(p) + (p)->_vt->_off_##chead) +#define SOD_XCHAIN(chead, obj) \ + ((void *)((char *)(obj) + (obj)->_vt->_off_##chead)) /* --- @SOD_OFFSETDIFF@ --- * * @@ -101,19 +160,16 @@ struct sod_chain { * * Arguments: @cls@ = name of a class * @chead@ = nickname of chain head of @cls@ - * @p@ = pointer to the @chead@ ichain of an (exact) instance of - * @cls@ + * @obj@ = pointer to the @chead@ ichain of an (exact) instance + * of @cls@ * * Returns: A pointer to the instance's base, cast as a pointer to the * ilayout structure. * * Use: Finds an instance's base address given a pointer to one of * its ichains, if you know precisely the instance's class and - * which chain you're pointing to. If you don't, then (a) - * - * @(char *)(p) - (p)->_vt->_base@ - * - * will do the job just fine, and (b) you'll have the wrong + * which chain you're pointing to. If you don't, then (a) you + * want @SOD_INSTBASE@ below, and (b) you'll have the wrong * ilayout anyway. * * This macro is not intended to be used directly outside of @@ -122,9 +178,9 @@ struct sod_chain { * necessary to use it safely. */ -#define SOD_ILAYOUT(cls, chead, p) \ +#define SOD_ILAYOUT(cls, chead, obj) \ ((struct cls##__ilayout *) \ - ((char *)(p) - offsetof(struct cls##__ilayout, chead))) + ((char *)(obj) - offsetof(struct cls##__ilayout, chead))) /*----- Utility macros ----------------------------------------------------*/ @@ -132,10 +188,56 @@ struct sod_chain { * * Arguments: @p@ = pointer to an instance chain * - * Returns: A pointer to the instance's class, as a const SodClass. + * Returns: A pointer to the instance's class, as a @const SodClass *@. + */ + +#define SOD_CLASSOF(obj) ((const SodClass *)(obj)->_vt->_class) + +/* --- @SOD_INSTBASE@ --- * + * + * Arguments: @obj@ = pointer to an instance (i.e., the address of one of + * its instance chains) + * + * Returns: The base address of @obj@'s instance layout, as a @void *@. + * + * Use: Finds the base address of an instance. If you know the + * dynamic class of the object then @SOD_ILAYOUT@ is faster. If + * you don't, this is the right macro, but your options for + * doing something sensible with the result are limited, mostly + * to simple memory management operations such as freeing or + * zeroizing the instance structure. + */ + +#define SOD_INSTBASE(obj) ((void *)((char *)(obj) - (obj)->_vt->_base)) + +/* --- @SOD_CONVERT@ --- * + * + * Arguments: @cls@ = a class type name + * @const void *obj@ = a pointer to an instance + * + * Returns: Pointer to appropriate instance ichain, or null if the + * instance isn't of the specified class. + * + * Use: This is a simple wrapper around the @sod_convert@, which + * you should see for full details. It accepts a class type + * name rather than a pointer to a class object, and arranges to + * return a pointer of the correct type. + */ + +#define SOD_CONVERT(cls, obj) ((cls *)sod_convert(cls##__class, (obj))) + +/* --- @SOD_DECL@ --- * + * + * Arguments: @cls_@ = a class type name + * @var_@ = a variable name + * + * Use: Declare @var_@ as a pointer to an initialized instance of + * @cls_@ with automatic lifetime. */ -#define SOD_CLASSOF(p) ((const SodClass *)(p)->_vt->_class) +#define SOD_DECL(cls_, var_) \ + struct cls_##__ilayout var_##__layout; \ + cls_ *var_ = cls_##__class->cls.init(&var_##__layout) /*----- Functions provided ------------------------------------------------*/ @@ -174,7 +276,7 @@ extern int sod_subclassp(const SodClass */*sub*/, const SodClass */*super*/); * to know what either C or S actually are. */ -extern void *sod_convert(const SodClass */*cls*/, void */*p*/); +extern void *sod_convert(const SodClass */*cls*/, const void */*obj*/); /*----- That's all, folks -------------------------------------------------*/