summaryrefslogtreecommitdiff
path: root/class.h
diff options
context:
space:
mode:
Diffstat (limited to 'class.h')
-rw-r--r--class.h465
1 files changed, 465 insertions, 0 deletions
diff --git a/class.h b/class.h
new file mode 100644
index 0000000..90e6c19
--- /dev/null
+++ b/class.h
@@ -0,0 +1,465 @@
+/* C class and object types functions.
+ *
+ * Copyright 2013, Michael Cohen <sucdette@gmail.com>.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __CLASS_H__
+#define __CLASS_H__
+
+/*
+ Classes and objects in C
+
+ This file makes it easy to implement classes and objects in C. To
+ define a class we need to perform three steps:
+
+ Define the class prototype. This is suitable to go in a .h file for
+ general use by other code.
+
+ Note all classes extend Object.
+
+ Example::
+
+CLASS(Foo, Object)
+ int x;
+ int y;
+
+ //This declares a method of a class Foo, called Con returning a
+ //Foo object. In other words it is a constructor.
+ Foo METHOD(Foo, Con, int x, int y);
+ int METHOD(Foo, add);
+
+END_CLASS
+
+Now we need to define some functions for the constructor and
+methods. Note that the constuctor is using ALLOCATE_CLASS to allocate
+space for the class structures. Callers may call with self==NULL to
+force allocation of a new class. Note that we do not call the
+constructor of our superclass implicitly here. (Calling the sperclass
+constructor is optional, but ALLOCATE_CLASS is not.).
+
+Foo Foo_Con(Foo self,int x,int y) {
+ self->x = x;
+ self->y = y;
+
+ return self;
+};
+
+int Foo_add(Foo this) {
+ return (this->x + this->y);
+};
+
+Now we need to define the Virtual function table - These are those
+functions and attributes which are defined in this class (over its
+superclass). Basically these are all those things in the class
+definition above, with real function names binding them. (Note that by
+convention we preceed the name of the method with the name of the
+class):
+
+VIRTUAL(Foo,Object)
+ VMETHOD(Con) = Foo_Con;
+ VMETHOD(add) = Foo_add;
+END_VIRTUAL
+
+We can use inheritance too:
+
+CLASS(Bar, Foo)
+ Bar METHOD(Bar, Con, char *something)
+END_CLASS
+
+Here Bar extends Foo and defines a new constructor with a different prototype:
+
+VIRTUAL(Bar,Foo)
+ VMETHOD(Con) = Bar_Con
+END_VIRTUAL
+
+If there is a function which expects a Foo, we will need to over ride
+the Foo constructor in the Bar, so the function will not see the
+difference between the Foo and Bar:
+
+CLASS(Bar,Foo)
+ int bar_attr;
+END_CLASS
+
+Foo Bar_Con(Foo self, int x, int y) {
+...
+}
+
+VIRTUAL(Bar, Foo)
+ VMETHOD(super.Con) = Bar_Con
+END_VIRTUAL
+
+Note that in this case we are over riding the Con method defined in
+Foo while creating derived Bar classes. The notation in the VIRTUAL
+table is to use super.Con, because Foo's Con method (the one we are
+over riding), can be located by using super.Con inside a Bar object.
+
+Imagine now that in Bar_Con we wish to use methods and attributes
+defined in Bar. Since Bar_Con over rides Bar's base class (Foo) it
+must have the prototype described above. Since self is of type Foo its
+impossible to use self->bar_attr (There is no bar_attr in Foo - its in
+Bar).
+
+In this case, we need to make a type cast to convice C that self is
+actually a Bar not a Foo:
+
+Foo Bar_Con(Foo self, int x, int y) {
+ Bar this = (Bar)self;
+
+ this->bar_attr=1
+};
+
+This allows us to access bars attributes.
+
+This is a general oddity with C style classes, which C++ and Java
+hide. In C we must always know which class defines which method and
+attribute and reference the right class's method. So for example if we
+want to call a Bar's add method:
+
+Bar a;
+
+a->super.add()
+
+because add is defined in Bar's super class (Foo). Constract this with
+C++ or Java which hide where methods are defined and simply make all
+methods appear like they were defined inside the derived class. This
+takes a while to get used to but the compiler will ensure that the
+references are correct - otherwise things will generally not compile
+properly.
+
+This difference can be used for good and bad. It is possible in C to
+call the base class's version of the method at any time (despite the
+fact it was over ridden).
+
+For example:
+
+CLASS(Derived, Foo)
+ int METHOD(Derived, add);
+END_CLASS
+
+VIRTUAL(Derived, Foo)
+ VMETHOD(add) = Derived_add
+END_VIRTUAL
+
+If d is a Derived object, we can call Foo's version like this:
+d->super.add()
+
+But Derived's version is accessed by:
+d->add()
+
+Sometimes a derived class may want to over ride the base class's
+methods as well, in this case the VIRTUAL section should over ride
+super.add as well.
+
+*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "misc.h"
+
+#include <talloc.h>
+
+#define CLASS(class,super_class) \
+ typedef struct class ## _t *class; \
+ DLL_PUBLIC class alloc_ ## class(void); /* Allocates object memory */ \
+ DLL_PUBLIC int class ## _init(Object self); /* Class initializer */ \
+ DLL_PUBLIC extern struct class ## _t __ ## class; /* Public class template */ \
+ struct class ## _t { \
+ struct super_class ## _t super; /* Superclass Fields we inherit */ \
+ class __class__; /* Pointer to our own class */ \
+ super_class __super__; /* Pointer to our superclass */
+
+#define METHOD(cls, name, ... ) \
+ (* name)(cls self, ## __VA_ARGS__ )
+
+ // Class methods are attached to the class but are not called with
+ // an instance. This is similar to the python class method or java
+ // static methods.
+#define CLASS_METHOD(name, ... ) \
+ (*name)(__VA_ARGS__)
+
+/* This is a convenience macro which may be used if x if really large */
+#define CALL(x, method, ... ) \
+ (x)->method((x), ## __VA_ARGS__)
+
+#define END_CLASS };
+
+/* This is used to set the classes up for use:
+ *
+ * class_init = checks the class template (__class) to see if it has
+ * been allocated. otherwise allocates it in the global context.
+ *
+ * class_Alloc = Allocates new memory for an instance of the
+ * class. This is a recursive function calling each super class in
+ * turn and setting the currently over ridden defaults. So for eample
+ * suppose this class (foo) derives from bar, we first fill the
+ * template with bars methods, and attributes. Then we over write
+ * those with foos methods and attributes.
+ */
+#define VIRTUAL(class,superclass) \
+ struct class ## _t __ ## class; \
+ \
+ DLL_PUBLIC class alloc_ ## class(void) { \
+ class result = talloc_memdup(NULL, &__## class, sizeof(__## class)); \
+ return result; \
+ }; \
+ \
+ DLL_PUBLIC int class ## _init(Object this) { \
+ class self = (class)this; \
+ if(self->__super__) return 1; \
+ superclass ##_init(this); \
+ this->__class__ = (Object)&__ ## class; \
+ self->__class__ = (class)&__ ## class; \
+ this->__super__ = (Object)&__ ## superclass; \
+ self->__super__ = (superclass)&__ ## superclass; \
+ this->__size = sizeof(struct class ## _t); \
+ this->__name__ = #class;
+
+#define SET_DOCSTRING(string) \
+ ((Object)self)->__doc__ = string
+
+#define END_VIRTUAL return 1; };
+
+#define VMETHOD(method) \
+ (self)->method
+
+#define VMETHOD_BASE(base, method) \
+ (((base)self)->method)
+
+#define CLASS_ATTR(self, base, method) \
+ (((base)self)->method)
+
+#define VATTR(attribute) \
+ (self)->attribute
+
+#define NAMEOF(obj) \
+ ((Object)obj)->__name__
+
+#define SIZEOF(obj) \
+ ((Object)obj)->__size
+
+#define DOCSTRING(obj) \
+ ((Object)obj)->__doc__
+
+#define INIT_CLASS(class) \
+ class ## _init((Object)&__ ## class)
+
+/* This MACRO is used to construct a new Class using a constructor.
+ *
+ * This is done to try and hide the bare (unbound) method names in
+ * order to prevent name space pollution. (Bare methods may be
+ * defined as static within the implementation file). This macro
+ * ensures that class structures are initialised properly before
+ * calling their constructors.
+ *
+ * We require the following args:
+ * class - the type of class to make
+ * virt_class - The class where the method was defined
+ * constructors - The constructor method to use
+ * context - a talloc context to use.
+ *
+ * Note that the class and virt_class do not have to be the same if
+ * the method was not defined in the current class. For example
+ * suppose Foo extends Bar, but method is defined in Bar but
+ * inherited in Foo:
+ *
+ * CONSTRUCT(Foo, Bar, super.method, context)
+ *
+ * virt_class is Bar because thats where method was defined.
+ */
+
+// The following only initialises the class if the __super__ element
+// is NULL. This is fast as it wont call the initaliser unnecessaily
+
+ // This requires the class initializers to have been called
+ // previously. Therefore they are not exported.
+#define CONSTRUCT(class, virt_class, constructor, context, ...) \
+ (class)(((virt_class) (&__ ## class))->constructor( \
+ (virt_class) _talloc_memdup( \
+ context, &__ ## class, \
+ sizeof(struct class ## _t), \
+ __location__ "(" #class ")"), \
+ ## __VA_ARGS__) )
+
+/* _talloc_memdup version
+#define CONSTRUCT_CREATE(class, virt_class, context) \
+ (virt_class) _talloc_memdup(context, &__ ## class, sizeof(struct class ## _t), __location__ "(" #class ")")
+*/
+
+#define CONSTRUCT_CREATE(class, virt_class, context) \
+ (virt_class) talloc_memdup(context, &__ ## class, sizeof(struct class ## _t))
+
+#define CONSTRUCT_INITIALIZE(class, virt_class, constructor, object, ...) \
+ (class)(((virt_class) (&__ ## class))->constructor(object, ## __VA_ARGS__))
+
+/* This variant is useful when all we have is a class reference
+ * (GETCLASS(Foo)) or &__Foo
+ */
+#define CONSTRUCT_FROM_REFERENCE(class, constructor, context, ... ) \
+ ( (class)->constructor( \
+ (void *)_talloc_memdup(context, ((Object)class), ((Object)class)->__size, __location__ "(" #class "." #constructor ")"), \
+ ## __VA_ARGS__) )
+
+/* Finds the size of the class in x */
+#define CLASS_SIZE(class) \
+ ((Object)class)->__size
+
+typedef struct Object_t *Object;
+
+struct Object_t {
+ //A reference to a class instance - this is useful to be able to
+ //tell which class an object really belongs to:
+ Object __class__;
+
+ //And its super class:
+ Object __super__;
+
+ char *__name__;
+
+ /** Objects may have a doc string associated with them. */
+ char *__doc__;
+
+ //How large the class is:
+ int __size;
+
+ /* A pointer to an extension - An extension is some other arbitrary
+ object which may be linked with this one.
+ */
+ void *extension;
+};
+
+#define SUPER(base, imp, method, ...) \
+ ((base)&__ ## imp)->method((base)self, ## __VA_ARGS__)
+
+#define GETCLASS(class) \
+ (Object)&__ ## class
+
+// Returns true if the obj belongs to the class
+#define ISINSTANCE(obj,class) \
+ (((Object)obj)->__class__ == GETCLASS(class))
+
+// This is a string comparison version of ISINSTANCE which works
+// across different shared objects.
+#define ISNAMEINSTANCE(obj, class) \
+ (obj && !strcmp(class, NAMEOF(obj)))
+
+// We need to ensure that class was properly initialised:
+#define ISSUBCLASS(obj,class) \
+ issubclass((Object)obj, (Object)&__ ## class)
+
+#define CLASSOF(obj) \
+ ((Object)obj)->__class__
+
+DLL_PUBLIC void Object_init(Object);
+
+DLL_PUBLIC extern struct Object_t __Object;
+
+/** Find out if obj is an instance of cls or a derived class.
+
+ Use like this:
+
+ if(issubclass(obj, (Object)&__FileLikeObject)) {
+ ...
+ };
+
+
+ You can also do this in a faster way if you already know the class
+ hierarchy (but it could break if the hierarchy changes):
+ {
+ Object cls = ((Object)obj)->__class__;
+
+ if(cls == (Object)&__Image || \
+ cls == (Object)&__FileLikeObject || \
+ cls == (Object)&__AFFObject || ....) {
+ ...
+ };
+ };
+ */
+int issubclass(Object obj, Object class);
+
+DLL_PUBLIC extern void unimplemented(Object self);
+
+#define UNIMPLEMENTED(class, method) \
+ ((class)self)->method = (void *)unimplemented;
+
+#define ZSTRING_NO_NULL(str) str , (strlen(str))
+#define ZSTRING(str) str , (strlen(str)+1)
+
+ // These dont do anything but are useful to indicate when a function
+ // parameter is used purely to return a value. They are now used to
+ // assist the python binding generator in generating the right sort
+ // of code
+#define OUT
+#define IN
+
+ // This modifier before a class means that the class is abstract and
+ // does not have an implementation - we do not generate bindings for
+ // that class then.
+#define ABSTRACT
+
+ // This modifier indicates that the following pointer is pointing to
+ // a borrowed reference - callers must not free the memory after use.
+#define BORROWED
+
+ // This tells the autobinder to generated bindings to this struct
+#define BOUND
+
+ // This tells the autobinder to ignore this class as it should be
+ // private to the implementation - external callers should not
+ // access this.
+#define PRIVATE
+
+ // This attribute of a method means that this method is a
+ // desctructor - the object is no longer valid after this method is
+ // run
+#define DESTRUCTOR
+
+ // including this after an argument definition will cause the
+ // autogenerator to assign default values to that parameter and make
+ // it optional
+#define DEFAULT(x)
+
+ // This explicitely denote that the type is a null terminated char
+ // ptr as opposed to a pointer to char and length.
+typedef char * ZString;
+
+ /* The following is a direction for the autogenerator to proxy the
+ given class. This is done in the following way:
+
+1) a new python type is created called Proxy_class_name() with a
+constructor which takes a surrogate object.
+
+2) The proxy class contains a member "base" of the type of the proxied
+C class.
+
+3) The returned python object may be passed to any C functions which
+expect the proxied class, and internal C calls will be converted to
+python method calls on the proxied object.
+ */
+#define PROXY_CLASS(name)
+
+ /* This signals the autogenerator to bind the named struct */
+#define BIND_STRUCT(name)
+
+ // This means that the memory owned by this pointer is managed
+ // externally (not using talloc). It is dangerous to use this
+ // keyword too much because we are unable to manage its memory
+ // appropriately and it can be free'd from under us.
+#define FOREIGN
+
+#ifdef __cplusplus
+} /* closing brace for extern "C" */
+#endif
+
+#endif /* ifndef __CLASS_H__ */