#ifndef _DYNAMIC_ARRAYS_H
#define _DYNAMIC_ARRAYS_H

/*
* C header file for managing dynamically allocated arrays in a 
* convenient way.  
*
* Version 2.6
*
* (c) david smith today 8th of march 2005 and thereafter.  
* 
* Thanks to Bob Carver for idea to use macros and token catenation.
*/

#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <sysexits.h>


#define DECLARE_ARRAY_RANK3(NAME,TYPE) \
	TYPE *NAME##_ptr = NULL; \
	size_t NAME##_nx, NAME##_ny, NAME##_nz; \
	TYPE* NAME##_alloc(size_t nx, size_t ny, size_t nz) { \
		NAME##_nx = nx; NAME##_ny = ny; NAME##_nz = nz; \
		if ((NAME##_ptr = calloc(nx*ny*nz, sizeof(TYPE))) == NULL) \
			err(EX_OSERR, #NAME "_alloc"); \
		return NAME##_ptr; \
	} \
	TYPE* NAME##_realloc(size_t nx, size_t ny, size_t nz) { \
		TYPE *p; \
		if ((p = realloc(NAME##_ptr,nx*ny*nz*sizeof(TYPE))) \
			== NULL) err(EX_OSERR, #NAME "_realloc"); \
		NAME##_ptr = p; \
		NAME##_nx = nx, NAME##_ny = ny, NAME##_nz = nz; \
		return NAME##_ptr; \
	} \
	void NAME##_free() { free(NAME##_ptr); } \
	static inline TYPE *NAME(size_t i, size_t j, size_t k) { \
		return (NAME##_ptr + (i*NAME##_ny + j)*NAME##_nz + k); \
	} \


#define DECLARE_ARRAY_RANK2(NAME,TYPE) \
	TYPE *NAME##_ptr = NULL; \
	size_t NAME##_nx, NAME##_ny; \
	TYPE* NAME##_alloc(size_t nx, size_t ny) { \
		NAME##_nx = nx; NAME##_ny = ny; \
		if ((NAME##_ptr = calloc(nx*ny, sizeof(TYPE))) == NULL) \
			err(EX_OSERR, #NAME "_alloc"); \
		return NAME##_ptr; \
	} \
	TYPE* NAME##_realloc(size_t nx, size_t ny) { \
		TYPE *p; \
		if ((p = realloc(NAME##_ptr,nx*ny*sizeof(TYPE))) == NULL) \
			err(EX_OSERR, #NAME "_realloc"); \
		NAME##_ptr = p; \
		NAME##_nx = nx, NAME##_ny = ny; \
		return NAME##_ptr; \
	} \
	void NAME##_free() { free(NAME##_ptr); } \
	static inline TYPE *NAME(size_t i, size_t j){ \
		return(NAME##_ptr + i*NAME##_ny + j); \
	} \
      
   
#define DECLARE_ARRAY_RANK1(NAME,TYPE) \
	TYPE *NAME##_ptr = NULL; \
	size_t NAME##_nx; \
	void NAME##_alloc(size_t nx) { \
		NAME##_nx = nx; \
		if ((NAME##_ptr = calloc(nx, sizeof(TYPE))) == NULL) \
			err(EX_OSERR, #NAME "_alloc"); \
	} \
	TYPE* NAME##_realloc(size_t nx) { \
		TYPE *p; \
		if ((p = realloc(NAME##_ptr, nx*sizeof(TYPE))) == NULL) \
			err(EX_OSERR, #NAME "_realloc"); \
		NAME##_ptr = p; \
		NAME##_nx = nx; \
		return NAME##_ptr; \
	} \
	void NAME##_free() { free(NAME##_ptr); } \
	static inline TYPE *NAME(size_t i) { return (NAME##_ptr + i); } \


/* EXAMPLE USAGE FOLLOWS */

#ifdef DYNAMIC_ARRAY_TEST

DECLARE_ARRAY_RANK1(v,float)
DECLARE_ARRAY_RANK2(M,float)
DECLARE_ARRAY_RANK3(T,float)

int
main()
{
	int i, j, k, n = 3;

	puts("Allocating storage for arrays.");
	v_alloc(n);
	M_alloc(n,n);
	T_alloc(n,n,n);

	puts("Computing array elements.");
	for (i=0; i<n; ++i) 
	{
		*v(i) = 0.5*i;
		for (j=0; j<n; ++j) 
		{
			*M(i,j) = i*j;
			for (k=0; k<n; ++k) *T(i,j,k) = i*j - k*k;
		}
	}
	printf("Test 1: v(i) = i/2\n");
	for (i=0; i<n; ++i) printf("v(%d) = %g\n", i, *v(i));

	printf("Test 2: M(i,j) = ij\n");
	for (i=0; i<n; ++i) 
		for (j=0; j<n; ++j) 
			printf("M(%d,%d) = %g\n", i, j, *M(i,j));

	printf("Test 3: T(i,j) = ij - k^2\n");
	for (i=0; i<n; ++i) 
		for (j=0; j<n; ++j) 
			for (k=0; k<n; ++k) 
				printf("T(%d,%d,%d) = %g\n", i, j, k, *T(i,j,k));

	puts("Freeing allocated memory.");
	v_free();
	M_free();
	T_free();
	puts("Done.");

	exit(EX_OK);
}

#endif /* EXAMPLE USAGE */


#endif /* _DYNAMIC_ARRAYS_H */

