A novel approach to creating templates in C

C

Chris M. Thomasson


Why are you actually putting interface function-pointers within the struct
itself? IMVHO, this can be a huge waste of space. A MUCH more space
efficient approach is to include a single pointer to a constant vtable.
Something like this, modulo bugs because I am quickly typing it directly in
the newsreader:


/* common object private vtable */
struct object_prv_vtable {
int (*fp_destroy) (void* const);
};

/* common object interface */
#define object_destroy(t) ( \
(t)->vtable->object.fp_destroy((t)) \
)




/* common device private vtable */
#include <stddef.h>


struct device_prv_vtable {
int (*fp_read) (void* const, void*, size_t);
int (*fp_write) (void* const, void const*, size_t);
};


/* common device vtable */
struct device_vtable {
struct object_prv_vtable const object;
struct device_prv_vtable const device;
};


/* common device object */
struct device {
struct device_vtable const* vtable;
};


/* common device interface */
#define device_read(t, b, s) ( \
(t)->vtable->device.fp_read((t), (b), (s)) \
)

#define device_write(t, b, s) ( \
(t)->vtable->device.fp_write((t), (b), (s)) \
)






There. That's all the scaffolding we need. Now its time to show a concrete
implementation of a device. Lets call the device a `usb_drive'. Here is the
header file:

/* usb_drive.h */
#if ! defined (USB_DRIVE_H)
#define USB_DRIVE_H

extern int usb_drive_create(struct device**);

#endif





Okay, here is the implementation file:

/* usb_drive.c */
#include "usb_drive.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>


struct usb_drive {
struct device device;
/* whatever */
};


static int object_destroy(void*);
static int device_read(void*, void*, size_t);
static int device_write(void*, void const*, size_t);


static struct device_vtable const g_vtable[
{ /* object interface */
object_destroy
},

{ /* device interface */
device_read,
device_write
}
];


int usb_drive_create(
struct device** pself
) {
struct usb_drive* const self = malloc(sizeof(*self));
if (self) {
*pself = &self->device;
return 0;
}
return ENOMEM;
}


int object_destroy(void* const self_) {
struct usb_drive* const self = self_;
free(self);
printf("destroyed a usb_drive(%p)\n", self_);
return 0;
}


int device_read(void* const self_, void* buf, size_t size) {
struct usb_drive* const self = self_;
printf("read from a usb_drive(%p, %p, %lu)\n",
self_, buf, (unsigned long) size);
return 0;
}


int device_read(void* const self_, void* buf, size_t size) {
struct usb_drive* const self = self_;
printf("wrote to a usb_drive(%p, %p, %lu)\n",
self_, buf, (unsigned long) size);
return 0;
}






Well, now its time to actually use it:


#include <usb_drive.h>


void read_write(
struct device* const self
) {
char buf[100];

device_read(a_device, buf, 50);

device_write(a_device, buf, 5);
}


int main(void) {
struct device* a_device;

if (! usb_drive_create(&a_device)) {
read_write(a_device);

object_destroy(a_device);
}

return 0;
}







There, that is an example of a minimalist abstract interface technique in C.





Any thoughts?
 
C

Chris M. Thomasson

Chris M. Thomasson said:
implementation file:

/* usb_drive.c */
#include "usb_drive.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>


struct usb_drive {
struct device device;
/* whatever */
};


static int object_destroy(void*);
static int device_read(void*, void*, size_t);
static int device_write(void*, void const*, size_t);


static struct device_vtable const g_vtable[
{ /* object interface */
object_destroy
},

{ /* device interface */
device_read,
device_write
}
];


int usb_drive_create(
struct device** pself
) {
struct usb_drive* const self = malloc(sizeof(*self));
if (self) {
*pself = &self->device;


Ummmm, well, I should go ahead and point the device object to the fuc%ing
VTABLE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! OUCH!!!!


self->device.vtable = &g_vtable;

return 0;
}
return ENOMEM;
}


int object_destroy(void* const self_) {
struct usb_drive* const self = self_;
free(self);
printf("destroyed a usb_drive(%p)\n", self_);
return 0;
}


int device_read(void* const self_, void* buf, size_t size) {
struct usb_drive* const self = self_;
printf("read from a usb_drive(%p, %p, %lu)\n",
self_, buf, (unsigned long) size);
return 0;
}


int device_read(void* const self_, void* buf, size_t size) {
struct usb_drive* const self = self_;
printf("wrote to a usb_drive(%p, %p, %lu)\n",
self_, buf, (unsigned long) size);
return 0;
}
[...]
 
C

Chris M. Thomasson

Chris M. Thomasson said:

Why are you actually putting interface function-pointers within the struct
itself? IMVHO, this can be a huge waste of space. A MUCH more space
efficient approach is to include a single pointer to a constant vtable.
Something like this, modulo bugs because I am quickly typing it directly
in the newsreader:
[...]


Here ya go:


http://clc.pastebin.com/f52a443b1


fully compliable code.
 
C

Chris M. Thomasson

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,438
Messages
2,571,699
Members
48,796
Latest member
Greg L.
Top