/* binder.h    v0.1  (C) 1999 adolfo@di-mare.com */

#ifndef   BINDER_H
#define   BINDER_H

#include <stdio.h>   /* FILE */
#include <stdlib.h>  /* malloc() */
#include <stddef.h>  /* offsetof() */

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    void (* init  ) (void *);
    void (* copy  ) (void *, void *);
    int  (* equal ) (void *, void *);
    void (* print ) (void *, FILE *);
    void (* done  ) (void *);
    size_t  size;
    size_t  offset;
} binder;

#define set_binder(B, TYPE, LINK, INIT, COPY, EQUAL, PRINT, DONE) \
  do {                                                    \
      (B)->init  = ( void (*) (void *)         )   INIT;  \
      (B)->copy  = ( void (*) (void *, void *) )   COPY;  \
      (B)->equal = ( int  (*) (void *, void *) )   EQUAL; \
      (B)->print = ( void (*) (void *, FILE *) )   PRINT; \
      (B)->done  = ( void (*) (void *)         )   DONE;  \
      (B)->size    = sizeof(TYPE);          \
      (B)->offset  = offsetof(TYPE, LINK);  \
  } while(0)  /* CAVEAT: no typechecking! */

#define name_binder(TYPE, LINK)   \
                  Binder_ ## TYPE ## _ ## LINK

#define declare_binder(TYPE, LINK)   \
    extern binder name_binder(TYPE, LINK)

#define define_binder(TYPE, LINK, INIT, COPY, EQUAL, PRINT, DONE) \
    binder name_binder(TYPE, LINK)  = {             \
    ( void (*) (void *)         )   INIT,           \
    ( void (*) (void *, void *) )   COPY,           \
    ( int  (*) (void *, void *) )   EQUAL,          \
    ( void (*) (void *, FILE *) )   PRINT,          \
    ( void (*) (void *)         )   DONE,           \
    sizeof(TYPE),                                   \
    offsetof(TYPE, LINK)  }


#define binder_destroy(B,p) \
    do { (B)->done(p); free(p); } while(0)

#define binder_CREATE(B,p)  \
    ( (B)->init( (void*)(p) = malloc( (B)->size) ), (p) )

#define binder_create(B,p)               \
    do {                                 \
        (void*)(p) = malloc((B)->size);  \
        (B)->init( (void*)(p) );         \
    } while(0)

#define ADD_OFFSET(p, offset) (void *)( ((char*)(p)) + (offset) )
#define SUB_OFFSET(p, offset) (void *)( ((char*)(p)) - (offset) )

#define  binder_cast(p, TYPE, LINK) \
    ( (TYPE*) SUB_OFFSET(p, offsetof(TYPE, LINK)) )

#ifdef __cplusplus
}
#endif

#endif /* BINDER_H */
/* EOF:   binder.h */
