I'm tired of mistakes matching types when allocating memory.

  PetscMPIInt *array;

  PetscMalloc(n*sizeof(PetscInt),&array);

This is not caught in debug mode due to:

  #if defined(PETSC_USE_DEBUG)
  #define PetscMalloc2(m1,t1,r1,m2,t2,r2) (PetscMalloc((m1)*sizeof(t1),r1) || 
PetscMalloc((m2)*sizeof(t2),r2))
  #else
  #define PetscMalloc2(m1,t1,r1,m2,t2,r2) ((*(r2) = 
0,PetscMalloc((m1)*sizeof(t1)+(m2)*sizeof(t2)+(PETSC_MEMALIGN-1),r1)) || (*(r2) 
= (t2*)PetscAddrAlign(*(r1)+m1),0))
  #endif

At least it generates a warning when compiling optimized mode with
64-bit ints.  A similar problem arises when confusing PetscReal for
PetscScalar.

But this can be much simpler:

  #define PetscMallocA(n,p) (PetscMalloc((n)*sizeof(**(p)),(p)))

Now it is always correct to write

  PetscMallocA(n,&array);

To break up the common sequence of PetscMalloc followed by PetscMemzero,
I would add

  #define PetscCalloc(n,p) (PetscMalloc((n),(p)) || PetscMemzero(*(p),(n)))  /* 
Could use calloc() if we add support */
  #define PetscCallocA(n,p) (PetscCalloc((n)*sizeof(**(p)),(p)))

And we can extend to more cases, e.g.,

  #if defined(PETSC_USE_DEBUG)
  # define PetscMallocA2(n0,p0,n1,p1) (PetscMallocA((n0),(p0)) || 
PetscMallocA((n1),(p1)))
  #else
  # define PetscMallocA2(n0,p0,n1,p1) 
(PetscMalloc((n0)*sizeof(**(p0))+(n1)*sizeof(**(p1))+(PETSC_MEMALIGN-1),(p0)) 
|| (*(void**)(p1) = PetscAddrAlign(*(p0)+(n0)),0))
  #endif

This is used like

  PetscMallocA2(n0,&array0,n1,&array1);


I've used similar macros in non-PETSc projects for years and I find it's
a lot cleaner, less error-prone, and easier to change types.  Is anyone
opposed to me adding PetscMallocA* functions?

Attachment: pgp6LccUe8hOy.pgp
Description: PGP signature

Reply via email to