/*
 * This example shows how to create a dataset with the variable-length datatype
 * using user-defined functions for memory management.
 */

#include <hdf5.h>

#define FILE   "vltypes.h5"
#define MAX(X,Y)        ((X)>(Y)?(X):(Y))

/* 1-D dataset with fixed dimensions */
#define SPACE_NAME  "Space"
#define SPACE_RANK	1
#define SPACE_DIM	4

void *vltypes_alloc_custom(size_t size, void *info);
void vltypes_free_custom(void *mem, void *info);

/****************************************************************
**
**  vltypes_alloc_custom():  VL datatype custom memory
**      allocation routine.  This routine just uses malloc to
**      allocate the memory and increments the amount of memory
**      allocated.
** 
****************************************************************/
void *vltypes_alloc_custom(size_t size, void *info)
{

    void *ret_value=NULL;       /* Pointer to return */
    int *mem_used=(int *)info;  /* Get the pointer to the memory used */
    size_t extra;               /* Extra space needed */

    /*
     *  This weird contortion is required on the DEC Alpha to keep the
     *  alignment correct.
     */
    extra=MAX(sizeof(void *),sizeof(int));

    if((ret_value=(void *)malloc(extra+size))!=NULL) {
        *(int *)ret_value=size;
        *mem_used+=size;
    } /* end if */
    ret_value=((unsigned char *)ret_value)+extra;
    return(ret_value);
}
/******************************************************************
**  vltypes_free_custom(): VL datatype custom memory
**      allocation routine.  This routine just uses free to
**      release the memory and decrements the amount of memory**      allocated.
** ****************************************************************/
void vltypes_free_custom(void *_mem, void *info)

{  
    unsigned char *mem;
    int *mem_used=(int *)info;  /* Get the pointer to the memory used */
    size_t extra;               /* Extra space needed */    
    /*
     *  This weird contortion is required on the DEC Alpha to keep the
     *  alignment correct.      
     */ 
    extra=MAX(sizeof(void *),sizeof(int));
    if(_mem!=NULL) {        
        mem=((unsigned char *)_mem)-extra;
       *mem_used-=*(int *)mem; 
       free(mem); 
    } /* end if */
}

int main(void)

{   
    hvl_t wdata[SPACE_DIM];   /* Information to write */
    hvl_t rdata[SPACE_DIM];   /* Information read in */
    hid_t		fid;	   /* HDF5 File IDs */  
    hid_t		dataset;   /* Dataset ID */
    hid_t		sid;       /* Dataspace ID */
    hid_t		tid;       /* Datatype ID			*/
    hid_t       xfer_pid;   /* Dataset transfer property list ID */
    hsize_t		dims[] = {SPACE_DIM};
    uint       i,j;        /* counting variables */
    int         mem_used=0; /* Memory used during allocation */
    herr_t		ret;		/* Generic return value		*/

    /*
     * Allocate and initialize VL data to write 
     */
    for(i=0; i<SPACE_DIM; i++) {

        wdata[i].p= (unsigned int *)malloc((i+1)*sizeof(unsigned int));
        wdata[i].len=i+1;
        for(j=0; j<(i+1); j++)
            ((unsigned int *)wdata[i].p)[j]=i*10+j;
    } /* end for */

    /* 
     * Create file. 
     */
    fid = H5Fcreate(FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);

    /* 
     * Create dataspace for datasets. 
     */
    sid = H5Screate_simple(SPACE_RANK, dims, NULL);

    /* 
     * Create a datatype to refer to. 
     */
    tid = H5Tvlen_create (H5T_NATIVE_UINT);

    /* 
     * Create a dataset. 
     */
    dataset=H5Dcreate(fid, "Dataset", tid, sid, H5P_DEFAULT);

    /* 
     * Write dataset to disk. 
     */
    ret=H5Dwrite(dataset, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata);

    /* 
     * Change to the custom memory allocation routines for reading VL data 
     */
    xfer_pid=H5Pcreate(H5P_DATASET_XFER);

    ret=H5Pset_vlen_mem_manager(xfer_pid, vltypes_alloc_custom,
                                &mem_used, vltypes_free_custom, &mem_used);

    /* 
     * Read dataset from disk. vltypes_alloc_custom and
     * will be used to manage memory.
     */
    ret=H5Dread(dataset, tid, H5S_ALL, H5S_ALL, xfer_pid, rdata);   

    /* 
     * Display data read in 
     */
    for(i=0; i<SPACE_DIM; i++) {
        printf("%d-th element length is %d \n", i, (unsigned) rdata[i].len);
        for(j=0; j<rdata[i].len; j++) {
            printf(" %d ",((unsigned int *)rdata[i].p)[j] );   
        } 
        printf("\n"); 
    } /* end for */

    /* 
     * Reclaim the read VL data. vltypes_free_custom will be used 
     * to reclaim the space. 
     */
    ret=H5Dvlen_reclaim(tid, sid, xfer_pid, rdata);

    /* 
     * Reclaim the write VL data.  C language free function will be used 
     * to reclaim space. 
     */
    ret=H5Dvlen_reclaim(tid, sid, H5P_DEFAULT, wdata);

    /* 
     * Close Dataset 
     */
    ret = H5Dclose(dataset);

    /* 
     * Close datatype 
     */
    ret = H5Tclose(tid);

    /* 
     * Close disk dataspace 
     */
    ret = H5Sclose(sid);
    
    /* 
     * Close dataset transfer property list 
     */
    ret = H5Pclose(xfer_pid);
    
    /* 
     * Close file 
     */
    ret = H5Fclose(fid);

} 
      
