#include /*I "petscsys.h" I*/ typedef struct _FortranCallbackLink *FortranCallbackLink; struct _FortranCallbackLink { char *type_name; PetscFortranCallbackId max; FortranCallbackLink next; }; typedef struct { PetscFortranCallbackId basecount; PetscFortranCallbackId maxsubtypecount; FortranCallbackLink subtypes; } FortranCallbackBase; static FortranCallbackBase *_classbase; static PetscClassId _maxclassid = PETSC_SMALLEST_CLASSID; static PetscErrorCode PetscFortranCallbackFinalize(void) { PetscFunctionBegin; for (PetscInt i = PETSC_SMALLEST_CLASSID; i < _maxclassid; i++) { FortranCallbackBase *base = &_classbase[i - PETSC_SMALLEST_CLASSID]; FortranCallbackLink next, link = base->subtypes; for (; link; link = next) { next = link->next; PetscCall(PetscFree(link->type_name)); PetscCall(PetscFree(link)); } } PetscCall(PetscFree(_classbase)); _maxclassid = PETSC_SMALLEST_CLASSID; PetscFunctionReturn(0); } /*@C PetscFortranCallbackRegister - register a type+subtype callback Not Collective Input Parameters: + classid - ID of class on which to register callback - subtype - subtype string, or NULL for class ids Output Parameter: . id - callback id Level: developer .seealso: `PetscFortranCallbackGetSizes()` @*/ PetscErrorCode PetscFortranCallbackRegister(PetscClassId classid, const char *subtype, PetscFortranCallbackId *id) { FortranCallbackBase *base; FortranCallbackLink link; PetscFunctionBegin; if (subtype) PetscValidCharPointer(subtype, 2); PetscValidPointer(id, 3); PetscCheck(classid >= PETSC_SMALLEST_CLASSID && classid <= PETSC_LARGEST_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "ClassId %d corrupt", classid); *id = 0; if (classid >= _maxclassid) { PetscClassId newmax = PETSC_SMALLEST_CLASSID + 2 * (PETSC_LARGEST_CLASSID - PETSC_SMALLEST_CLASSID); FortranCallbackBase *newbase; if (!_classbase) PetscCall(PetscRegisterFinalize(PetscFortranCallbackFinalize)); PetscCall(PetscCalloc1(newmax - PETSC_SMALLEST_CLASSID, &newbase)); PetscCall(PetscArraycpy(newbase, _classbase, _maxclassid - PETSC_SMALLEST_CLASSID)); PetscCall(PetscFree(_classbase)); _classbase = newbase; _maxclassid = newmax; } base = &_classbase[classid - PETSC_SMALLEST_CLASSID]; if (!subtype) *id = PETSC_SMALLEST_FORTRAN_CALLBACK + base->basecount++; else { for (link = base->subtypes; link; link = link->next) { /* look for either both NULL or matching values (implies both non-NULL) */ PetscBool match; PetscCall(PetscStrcmp(subtype, link->type_name, &match)); if (match) { /* base type or matching subtype */ goto found; } } /* Not found. Create node and prepend to class' subtype list */ PetscCall(PetscNew(&link)); PetscCall(PetscStrallocpy(subtype, &link->type_name)); link->max = PETSC_SMALLEST_FORTRAN_CALLBACK; link->next = base->subtypes; base->subtypes = link; found: *id = link->max++; base->maxsubtypecount = PetscMax(base->maxsubtypecount, link->max - PETSC_SMALLEST_FORTRAN_CALLBACK); } PetscFunctionReturn(0); } /*@C PetscFortranCallbackGetSizes - get sizes of class and subtype pointer arrays Collective Input Parameter: . classid - class Id Output Parameters: + numbase - number of registered class callbacks - numsubtype - max number of registered subtype callbacks Level: developer .seealso: `PetscFortranCallbackRegister()` @*/ PetscErrorCode PetscFortranCallbackGetSizes(PetscClassId classid, PetscFortranCallbackId *numbase, PetscFortranCallbackId *numsubtype) { PetscFunctionBegin; PetscValidPointer(numbase, 2); PetscValidPointer(numsubtype, 3); if (classid < _maxclassid) { FortranCallbackBase *base = &_classbase[classid - PETSC_SMALLEST_CLASSID]; *numbase = base->basecount; *numsubtype = base->maxsubtypecount; } else { /* nothing registered */ *numbase = 0; *numsubtype = 0; } PetscFunctionReturn(0); }