Actual source code: reg.c

      1: /*
      2:     Provides a general mechanism to allow one to register new routines in
      3:     dynamic libraries for many of the PETSc objects (including, e.g., KSP and PC).
      4: */
      5: #include <petsc/private/petscimpl.h>
      6: #include <petscviewer.h>

      8: #include <petsc/private/hashmap.h>
      9: /*
     10:     This is the default list used by PETSc with the PetscDLLibrary register routines
     11: */
     12: PetscDLLibrary PetscDLLibrariesLoaded = NULL;

     14: #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)

     16: static PetscErrorCode PetscLoadDynamicLibrary(const char *name, PetscBool *found)
     17: {
     18:   char libs[PETSC_MAX_PATH_LEN], dlib[PETSC_MAX_PATH_LEN];

     20:   PetscFunctionBegin;
     21:   PetscCall(PetscStrncpy(libs, "${PETSC_LIB_DIR}/libpetsc", sizeof(libs)));
     22:   PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
     23:   PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
     24:   if (*found) {
     25:     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
     26:   } else {
     27:     PetscCall(PetscStrncpy(libs, "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc", sizeof(libs)));
     28:     PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
     29:     PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
     30:     if (*found) PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
     31:   }
     32:   PetscFunctionReturn(PETSC_SUCCESS);
     33: }
     34: #endif

     36: #if defined(PETSC_USE_SINGLE_LIBRARY) && !(defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES))
     37: PETSC_EXTERN PetscErrorCode AOInitializePackage(void);
     38: PETSC_EXTERN PetscErrorCode PetscSFInitializePackage(void);
     39:   #if !defined(PETSC_USE_COMPLEX)
     40: PETSC_EXTERN PetscErrorCode CharacteristicInitializePackage(void);
     41:   #endif
     42: PETSC_EXTERN PetscErrorCode ISInitializePackage(void);
     43: PETSC_EXTERN PetscErrorCode VecInitializePackage(void);
     44: PETSC_EXTERN PetscErrorCode MatInitializePackage(void);
     45: PETSC_EXTERN PetscErrorCode DMInitializePackage(void);
     46: PETSC_EXTERN PetscErrorCode PCInitializePackage(void);
     47: PETSC_EXTERN PetscErrorCode KSPInitializePackage(void);
     48: PETSC_EXTERN PetscErrorCode SNESInitializePackage(void);
     49: PETSC_EXTERN PetscErrorCode TSInitializePackage(void);
     50: PETSC_EXTERN PetscErrorCode TaoInitializePackage(void);
     51: #endif

     53: /*
     54:     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
     55:     search path.
     56: */
     57: PETSC_INTERN PetscErrorCode PetscInitialize_DynamicLibraries(void)
     58: {
     59:   char     *libname[32];
     60:   PetscInt  nmax, i;
     61:   PetscBool preload = PETSC_FALSE;
     62: #if defined(PETSC_HAVE_ELEMENTAL)
     63:   PetscBool PetscInitialized = PetscInitializeCalled;
     64: #endif

     66:   PetscFunctionBegin;
     67: #if defined(PETSC_HAVE_THREADSAFETY)
     68:   /* These must be all initialized here because it is not safe for individual threads to call these initialize routines */
     69:   preload = PETSC_TRUE;
     70: #endif

     72:   nmax = 32;
     73:   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_prepend", libname, &nmax, NULL));
     74:   for (i = 0; i < nmax; i++) {
     75:     PetscCall(PetscDLLibraryPrepend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
     76:     PetscCall(PetscFree(libname[i]));
     77:   }

     79:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-library_preload", &preload, NULL));
     80:   if (!preload) {
     81:     PetscCall(PetscSysInitializePackage());
     82:   } else {
     83: #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
     84:     PetscBool found;
     85:   #if defined(PETSC_USE_SINGLE_LIBRARY)
     86:     PetscCall(PetscLoadDynamicLibrary("", &found));
     87:     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library. You cannot move the dynamic libraries!");
     88:   #else
     89:     PetscCall(PetscLoadDynamicLibrary("sys", &found));
     90:     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Sys dynamic library. You cannot move the dynamic libraries!");
     91:     PetscCall(PetscLoadDynamicLibrary("vec", &found));
     92:     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Vec dynamic library. You cannot move the dynamic libraries!");
     93:     PetscCall(PetscLoadDynamicLibrary("mat", &found));
     94:     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Mat dynamic library. You cannot move the dynamic libraries!");
     95:     PetscCall(PetscLoadDynamicLibrary("dm", &found));
     96:     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc DM dynamic library. You cannot move the dynamic libraries!");
     97:     PetscCall(PetscLoadDynamicLibrary("ksp", &found));
     98:     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc KSP dynamic library. You cannot move the dynamic libraries!");
     99:     PetscCall(PetscLoadDynamicLibrary("snes", &found));
    100:     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc SNES dynamic library. You cannot move the dynamic libraries!");
    101:     PetscCall(PetscLoadDynamicLibrary("ts", &found));
    102:     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc TS dynamic library. You cannot move the dynamic libraries!");
    103:     PetscCall(PetscLoadDynamicLibrary("tao", &found));
    104:     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate Tao dynamic library. You cannot move the dynamic libraries!");
    105:   #endif
    106: #else /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
    107:   #if defined(PETSC_USE_SINGLE_LIBRARY)
    108:     PetscCall(AOInitializePackage());
    109:     PetscCall(PetscSFInitializePackage());
    110:     #if !defined(PETSC_USE_COMPLEX)
    111:     PetscCall(CharacteristicInitializePackage());
    112:     #endif
    113:     PetscCall(ISInitializePackage());
    114:     PetscCall(VecInitializePackage());
    115:     PetscCall(MatInitializePackage());
    116:     PetscCall(DMInitializePackage());
    117:     PetscCall(PCInitializePackage());
    118:     PetscCall(KSPInitializePackage());
    119:     PetscCall(SNESInitializePackage());
    120:     PetscCall(TSInitializePackage());
    121:     PetscCall(TaoInitializePackage());
    122:   #else
    123:     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Cannot use -library_preload with multiple static PETSc libraries");
    124:   #endif
    125: #endif /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
    126:   }

    128: #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) && defined(PETSC_HAVE_BAMG)
    129:   {
    130:     PetscBool found;
    131:     PetscCall(PetscLoadDynamicLibrary("bamg", &found));
    132:     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc BAMG dynamic library. You cannot move the dynamic libraries!");
    133:   }
    134: #endif

    136:   nmax = 32;
    137:   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_append", libname, &nmax, NULL));
    138:   for (i = 0; i < nmax; i++) {
    139:     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
    140:     PetscCall(PetscFree(libname[i]));
    141:   }

    143: #if defined(PETSC_HAVE_ELEMENTAL)
    144:   /* in Fortran, PetscInitializeCalled is set to PETSC_TRUE before PetscInitialize_DynamicLibraries() */
    145:   /* in C, it is not the case, but the value is forced to PETSC_TRUE so that PetscRegisterFinalize() is called */
    146:   PetscInitializeCalled = PETSC_TRUE;
    147:   PetscCall(PetscElementalInitializePackage());
    148:   PetscInitializeCalled = PetscInitialized;
    149: #endif
    150:   PetscFunctionReturn(PETSC_SUCCESS);
    151: }

    153: /*
    154:      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
    155: */
    156: PETSC_INTERN PetscErrorCode PetscFinalize_DynamicLibraries(void)
    157: {
    158:   PetscBool flg = PETSC_FALSE;

    160:   PetscFunctionBegin;
    161:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dll_view", &flg, NULL));
    162:   if (flg) PetscCall(PetscDLLibraryPrintPath(PetscDLLibrariesLoaded));
    163:   PetscCall(PetscDLLibraryClose(PetscDLLibrariesLoaded));
    164:   PetscDLLibrariesLoaded = NULL;
    165:   PetscFunctionReturn(PETSC_SUCCESS);
    166: }

    168: PETSC_HASH_MAP(HMapFunc, const char *, PetscVoidFn *, kh_str_hash_func, kh_str_hash_equal, NULL)

    170: struct _n_PetscFunctionList {
    171:   PetscHMapFunc map;
    172: };

    174: /* Keep a linked list of PetscFunctionLists so that we can destroy all the left-over ones. */
    175: typedef struct n_PetscFunctionListDLAll *PetscFunctionListDLAll;
    176: struct n_PetscFunctionListDLAll {
    177:   PetscFunctionList      data;
    178:   PetscFunctionListDLAll next;
    179: };

    181: static PetscFunctionListDLAll dlallhead = NULL;

    183: static PetscErrorCode PetscFunctionListDLAllPush_Private(PetscFunctionList fl)
    184: {
    185:   PetscFunctionBegin;
    186:   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
    187:     PetscFunctionListDLAll head;

    189:     PetscCall(PetscNew(&head));
    190:     head->data = fl;
    191:     head->next = dlallhead;
    192:     dlallhead  = head;
    193:   }
    194:   PetscFunctionReturn(PETSC_SUCCESS);
    195: }

    197: static PetscErrorCode PetscFunctionListDLAllPop_Private(PetscFunctionList fl)
    198: {
    199:   PetscFunctionBegin;
    200:   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
    201:     PetscFunctionListDLAll current = dlallhead, prev = NULL;

    203:     /* Remove this entry from the main DL list (if it is in it) */
    204:     while (current) {
    205:       const PetscFunctionListDLAll next = current->next;

    207:       if (current->data == fl) {
    208:         if (prev) {
    209:           // somewhere in the middle (or end) of the list
    210:           prev->next = next;
    211:         } else {
    212:           // prev = NULL implies current = dlallhead, so front of list
    213:           dlallhead = next;
    214:         }
    215:         PetscCall(PetscFree(current));
    216:         break;
    217:       }
    218:       prev    = current;
    219:       current = next;
    220:     }
    221:   }
    222:   PetscFunctionReturn(PETSC_SUCCESS);
    223: }

    225: static PetscErrorCode PetscHMapFuncInsert_Private(PetscHMapFunc map, const char name[], PetscVoidFn *fnc)
    226: {
    227:   PetscHashIter it;
    228:   PetscBool     found;

    230:   PetscFunctionBegin;
    231:   PetscAssertPointer(name, 2);
    233:   PetscCall(PetscHMapFuncFind(map, name, &it, &found));
    234:   if (fnc) {
    235:     if (found) {
    236:       PetscCall(PetscHMapFuncIterSet(map, it, fnc));
    237:     } else {
    238:       char *tmp_name;

    240:       PetscCall(PetscStrallocpy(name, &tmp_name));
    241:       PetscCall(PetscHMapFuncSet(map, tmp_name, fnc));
    242:     }
    243:   } else if (found) {
    244:     const char *tmp_name;

    246:     PetscHashIterGetKey(map, it, tmp_name);
    247:     PetscCall(PetscFree(tmp_name));
    248:     PetscCall(PetscHMapFuncIterDel(map, it));
    249:   }
    250:   PetscFunctionReturn(PETSC_SUCCESS);
    251: }

    253: static PetscErrorCode PetscFunctionListCreate_Private(PetscInt size, PetscFunctionList *fl)
    254: {
    255:   PetscFunctionBegin;
    256:   if (*fl) PetscFunctionReturn(PETSC_SUCCESS);
    257:   PetscCall(PetscNew(fl));
    258:   PetscCall(PetscHMapFuncCreateWithSize(size, &(*fl)->map));
    259:   PetscCall(PetscFunctionListDLAllPush_Private(*fl));
    260:   PetscFunctionReturn(PETSC_SUCCESS);
    261: }

    263: /*MC
    264:   PetscFunctionListAdd - Given a routine and a string id, saves that routine in the
    265:   specified registry.

    267:   Synopsis:
    268: #include <petscsys.h>
    269:   PetscErrorCode PetscFunctionListAdd(PetscFunctionList *flist,const char name[],void (*fptr)(void))

    271:   Not Collective

    273:   Input Parameters:
    274: + fl   - pointer to function list object
    275: . name - string to identify routine
    276: - fptr - function pointer

    278:   Level: developer

    280:   Notes:
    281:   To remove a registered routine, pass in a `NULL` `fptr`.

    283:   Users who wish to register new classes for use by a particular PETSc
    284:   component (e.g., `SNES`) should generally call the registration routine
    285:   for that particular component (e.g., `SNESRegister()`) instead of
    286:   calling `PetscFunctionListAdd()` directly.

    288: .seealso: `PetscFunctionListDestroy()`, `SNESRegister()`, `KSPRegister()`,`PetscFunctionListDuplicate()`
    289:           `PCRegister()`, `TSRegister()`, `PetscFunctionList`, `PetscObjectComposeFunction()`
    290: M*/
    291: PetscErrorCode PetscFunctionListAdd_Private(PetscFunctionList *fl, const char name[], PetscVoidFn *fptr)
    292: {
    293:   PetscFunctionBegin;
    294:   PetscAssertPointer(fl, 1);
    295:   if (name) PetscAssertPointer(name, 2);
    297:   if (!fptr && !*fl) PetscFunctionReturn(PETSC_SUCCESS);
    298:   PetscCall(PetscFunctionListCreate_Private(0, fl));
    299:   PetscCall(PetscHMapFuncInsert_Private((*fl)->map, name, fptr));
    300:   PetscFunctionReturn(PETSC_SUCCESS);
    301: }

    303: /*@C
    304:   PetscFunctionListDestroy - Destroys a list of registered routines.

    306:   Input Parameter:
    307: . fl - pointer to list

    309:   Level: developer

    311: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscFunctionListClear()`
    312: @*/
    313: PetscErrorCode PetscFunctionListDestroy(PetscFunctionList *fl)
    314: {
    315:   PetscFunctionBegin;
    316:   if (!*fl) PetscFunctionReturn(PETSC_SUCCESS);
    317:   PetscCall(PetscFunctionListDLAllPop_Private(*fl));
    318:   /* free this list */
    319:   PetscCall(PetscFunctionListClear(*fl));
    320:   PetscCall(PetscHMapFuncDestroy(&(*fl)->map));
    321:   PetscCall(PetscFree(*fl));
    322:   PetscFunctionReturn(PETSC_SUCCESS);
    323: }

    325: #define PetscHMapFuncForEach(__func_list__, __key_name__, __val_name__, ...) \
    326:   do { \
    327:     const PetscHMapFunc phmfi_map_ = (__func_list__)->map; \
    328:     PetscHashIter       phmfi_iter_; \
    329: \
    330:     PetscHashIterBegin(phmfi_map_, phmfi_iter_); \
    331:     while (!PetscHashIterAtEnd(phmfi_map_, phmfi_iter_)) { \
    332:       const char *PETSC_UNUSED  __key_name__; \
    333:       PetscVoidFn *PETSC_UNUSED __val_name__; \
    334: \
    335:       PetscHashIterGetKey(phmfi_map_, phmfi_iter_, __key_name__); \
    336:       PetscHashIterGetVal(phmfi_map_, phmfi_iter_, __val_name__); \
    337:       { \
    338:         __VA_ARGS__; \
    339:       } \
    340:       PetscHashIterNext(phmfi_map_, phmfi_iter_); \
    341:     } /* end while */ \
    342:   } while (0)

    344: /*@C
    345:   PetscFunctionListClear - Clear a `PetscFunctionList`

    347:   Not Collective

    349:   Input Parameter:
    350: . fl - The `PetscFunctionList` to clear

    352:   Level: developer

    354:   Notes:
    355:   This clears the contents of `fl` but does not deallocate the entries themselves.

    357: .seealso: `PetscFunctionList`, `PetscFunctionListDestroy()`, `PetscFunctionListAdd()`
    358: @*/
    359: PetscErrorCode PetscFunctionListClear(PetscFunctionList fl)
    360: {
    361:   PetscFunctionBegin;
    362:   if (fl) {
    363:     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscFree(name)));
    364:     PetscCall(PetscHMapFuncClear(fl->map));
    365:   }
    366:   PetscFunctionReturn(PETSC_SUCCESS);
    367: }

    369: /*
    370:    Print registered PetscFunctionLists
    371: */
    372: PetscErrorCode PetscFunctionListPrintAll(void)
    373: {
    374:   PetscFunctionListDLAll current = dlallhead;

    376:   PetscFunctionBegin;
    377:   if (current) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Registered PetscFunctionLists\n", PetscGlobalRank));
    378:   while (current) {
    379:     PetscCall(PetscFunctionListPrintNonEmpty(current->data));
    380:     current = current->next;
    381:   }
    382:   PetscFunctionReturn(PETSC_SUCCESS);
    383: }

    385: /*@C
    386:   PetscFunctionListPrintNonEmpty - Print composed names for non `NULL` function pointers

    388:   Logically Collective, No Fortran Support

    390:   Input Parameter:
    391: . fl - the function list

    393:   Level: developer

    395: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
    396: @*/
    397: PetscErrorCode PetscFunctionListPrintNonEmpty(PetscFunctionList fl)
    398: {
    399:   PetscFunctionBegin;
    400:   if (fl) {
    401:     // clang-format off
    402:     PetscHMapFuncForEach(
    403:       fl,
    404:       name, func,
    405:       PetscCall(PetscFPrintf(PETSC_COMM_SELF, PETSC_STDOUT, "[%d] function name: %s\n", PetscGlobalRank, name));
    406:     );
    407:     // clang-format on
    408:   }
    409:   PetscFunctionReturn(PETSC_SUCCESS);
    410: }

    412: /*MC
    413:   PetscFunctionListFind - Find function registered under given name

    415:   Not Collective, No Fortran Support

    417:   Synopsis:
    418: #include <petscsys.h>
    419:   PetscErrorCode PetscFunctionListFind(PetscFunctionList flist,const char name[],void (**fptr)(void))

    421:   Input Parameters:
    422: + fl   - the function list
    423: - name - name registered for the function

    425:   Output Parameter:
    426: . fptr - the function pointer if name was found, else `NULL`

    428:   Level: developer

    430: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`, `PetscFunctionListDuplicate()`
    431: M*/
    432: PetscErrorCode PetscFunctionListFind_Private(PetscFunctionList fl, const char name[], PetscVoidFn **fptr)
    433: {
    434:   PetscFunctionBegin;
    435:   PetscAssertPointer(name, 2);
    436:   PetscAssertPointer(fptr, 3);
    437:   *fptr = NULL;
    438:   if (fl) PetscCall(PetscHMapFuncGet(fl->map, name, fptr));
    439:   PetscFunctionReturn(PETSC_SUCCESS);
    440: }

    442: /*@C
    443:   PetscFunctionListView - prints out contents of a `PetscFunctionList`

    445:   Collective

    447:   Input Parameters:
    448: + list   - the list of functions
    449: - viewer - the `PetscViewer` used to view the `PetscFunctionList`

    451:   Level: developer

    453: .seealso: `PetscFunctionListAdd()`, `PetscFunctionListPrintTypes()`, `PetscFunctionList`
    454: @*/
    455: PetscErrorCode PetscFunctionListView(PetscFunctionList list, PetscViewer viewer)
    456: {
    457:   PetscBool iascii;

    459:   PetscFunctionBegin;
    460:   PetscAssertPointer(list, 1);
    461:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_SELF, &viewer));

    464:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    465:   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ASCII viewer supported");
    466:   {
    467:     PetscInt size;

    469:     PetscCall(PetscHMapFuncGetSize(list->map, &size));
    470:     PetscCall(PetscViewerASCIIPrintf(viewer, "PetscFunctionList Object:\n"));
    471:     PetscCall(PetscViewerASCIIPushTab(viewer));
    472:     PetscCall(PetscViewerASCIIPrintf(viewer, "size: %" PetscInt_FMT "\n", size));
    473:     if (size) {
    474:       PetscInt count = 0;

    476:       PetscCall(PetscViewerASCIIPrintf(viewer, "functions:\n"));
    477:       PetscCall(PetscViewerASCIIPushTab(viewer));
    478:       PetscHMapFuncForEach(list, name, func, PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT ": %s\n", ++count, name)));
    479:       PetscCall(PetscViewerASCIIPopTab(viewer));
    480:     }
    481:     PetscCall(PetscViewerASCIIPopTab(viewer));
    482:   }
    483:   PetscFunctionReturn(PETSC_SUCCESS);
    484: }

    486: /*@C
    487:   PetscFunctionListGet - Gets an array the contains the entries in `PetscFunctionList`, this is used
    488:   by help etc.

    490:   Not Collective, No Fortran Support

    492:   Input Parameter:
    493: . list - list of types

    495:   Output Parameters:
    496: + array - array of names
    497: - n     - length of `array`

    499:   Level: developer

    501:   Note:
    502:   This allocates the array so that must be freed with `PetscFree()`. BUT the individual entries should not be freed.

    504: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
    505: @*/
    506: PetscErrorCode PetscFunctionListGet(PetscFunctionList list, const char ***array, int *n)
    507: {
    508:   PetscInt size = 0;

    510:   PetscFunctionBegin;
    511:   PetscAssertPointer(array, 2);
    512:   *array = NULL;
    513:   if (list) {
    514:     const PetscHMapFunc map = list->map;
    515:     PetscInt            off = 0;

    517:     PetscCall(PetscHMapFuncGetSize(map, &size));
    518:     PetscCall(PetscMalloc1(size, (char ***)array));
    519:     PetscCall(PetscHMapFuncGetKeys(map, &off, *array));
    520:   }
    521:   *n = (int)size;
    522:   PetscFunctionReturn(PETSC_SUCCESS);
    523: }

    525: /*@C
    526:   PetscFunctionListPrintTypes - Prints the methods available in a list of functions

    528:   Collective, No Fortran Support

    530:   Input Parameters:
    531: + comm   - the communicator (usually `MPI_COMM_WORLD`)
    532: . fd     - file to print to, usually `stdout`
    533: . prefix - prefix to prepend to name (optional)
    534: . name   - option string (for example, `-ksp_type`)
    535: . text   - short description of the object (for example, "Krylov solvers")
    536: . man    - name of manual page that discusses the object (for example, `KSPCreate`)
    537: . list   - list of types
    538: . def    - default (current) value
    539: - newv   - new value

    541:   Level: developer

    543: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
    544: @*/
    545: PetscErrorCode PetscFunctionListPrintTypes(MPI_Comm comm, FILE *fd, const char prefix[], const char name[], const char text[], const char man[], PetscFunctionList list, const char def[], const char newv[])
    546: {
    547:   char p[64];

    549:   PetscFunctionBegin;
    550:   (void)fd;
    551:   PetscCall(PetscStrncpy(p, "-", sizeof(p)));
    552:   if (prefix) PetscCall(PetscStrlcat(p, prefix, sizeof(p)));
    553:   PetscCall((*PetscHelpPrintf)(comm, "  %s%s <now %s : formerly %s>: %s (one of)", p, name + 1, newv, def, text));

    555:   if (list) PetscHMapFuncForEach(list, name, func, PetscCall((*PetscHelpPrintf)(comm, " %s", name)));
    556:   PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", man));
    557:   PetscFunctionReturn(PETSC_SUCCESS);
    558: }

    560: /*@C
    561:   PetscFunctionListDuplicate - Creates a new list from a given function list `PetscFunctionList`.

    563:   Input Parameter:
    564: . fl - pointer to list

    566:   Output Parameter:
    567: . nl - the new list (should point to `NULL` to start, otherwise appends)

    569:   Level: developer

    571: .seealso: `PetscFunctionList`, `PetscFunctionListAdd()`, `PetscFlistDestroy()`
    572: @*/
    573: PetscErrorCode PetscFunctionListDuplicate(PetscFunctionList fl, PetscFunctionList *nl)
    574: {
    575:   PetscFunctionBegin;
    576:   if (fl) {
    577:     PetscHMapFunc dup_map;

    579:     if (!*nl) {
    580:       PetscInt n;

    582:       PetscCall(PetscHMapFuncGetSize(fl->map, &n));
    583:       PetscCall(PetscFunctionListCreate_Private(n, nl));
    584:     }
    585:     dup_map = (*nl)->map;
    586:     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscHMapFuncInsert_Private(dup_map, name, func)));
    587:   }
    588:   PetscFunctionReturn(PETSC_SUCCESS);
    589: }