xref: /petsc/src/sys/dll/reg.c (revision 012c79f403d420e9d0d77bf7bae9feb1b717d6c8)
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> /*I "petscsys.h" I*/
6 #include <petscviewer.h>
7 
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;
13 
14 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
15 
PetscLoadDynamicLibrary(const char * name,PetscBool * found)16 static PetscErrorCode PetscLoadDynamicLibrary(const char *name, PetscBool *found)
17 {
18   char libs[PETSC_MAX_PATH_LEN], dlib[PETSC_MAX_PATH_LEN];
19 
20   PetscFunctionBegin;
21   PetscCall(PetscStrncpy(libs, "${PETSC_LIB_DIR}/libpetsc", sizeof(libs)));
22   PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
23   #if defined(PETSC_LIB_NAME_SUFFIX)
24   PetscCall(PetscStrlcat(libs, PETSC_LIB_NAME_SUFFIX, sizeof(libs)));
25   #endif
26   PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
27   if (*found) {
28     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
29   } else {
30     PetscCall(PetscStrncpy(libs, "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc", sizeof(libs)));
31     PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
32   #if defined(PETSC_LIB_NAME_SUFFIX)
33     PetscCall(PetscStrlcat(libs, PETSC_LIB_NAME_SUFFIX, sizeof(libs)));
34   #endif
35     PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
36     if (*found) PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
37   }
38   PetscFunctionReturn(PETSC_SUCCESS);
39 }
40 #endif
41 
42 #if defined(PETSC_USE_SINGLE_LIBRARY) && !(defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES))
43 PETSC_EXTERN PetscErrorCode AOInitializePackage(void);
44 PETSC_EXTERN PetscErrorCode PetscSFInitializePackage(void);
45   #if !defined(PETSC_USE_COMPLEX)
46 PETSC_EXTERN PetscErrorCode CharacteristicInitializePackage(void);
47   #endif
48 PETSC_EXTERN PetscErrorCode ISInitializePackage(void);
49 PETSC_EXTERN PetscErrorCode VecInitializePackage(void);
50 PETSC_EXTERN PetscErrorCode MatInitializePackage(void);
51 PETSC_EXTERN PetscErrorCode DMInitializePackage(void);
52 PETSC_EXTERN PetscErrorCode PCInitializePackage(void);
53 PETSC_EXTERN PetscErrorCode KSPInitializePackage(void);
54 PETSC_EXTERN PetscErrorCode SNESInitializePackage(void);
55 PETSC_EXTERN PetscErrorCode TSInitializePackage(void);
56 PETSC_EXTERN PetscErrorCode TaoInitializePackage(void);
57 #endif
58 
59 /*
60     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
61     search path.
62 */
PetscInitialize_DynamicLibraries(void)63 PETSC_INTERN PetscErrorCode PetscInitialize_DynamicLibraries(void)
64 {
65   char     *libname[32];
66   PetscInt  nmax, i;
67   PetscBool preload = PETSC_FALSE;
68 #if defined(PETSC_HAVE_ELEMENTAL)
69   PetscBool PetscInitialized = PetscInitializeCalled;
70 #endif
71 
72   PetscFunctionBegin;
73 #if defined(PETSC_HAVE_THREADSAFETY)
74   /* These must be all initialized here because it is not safe for individual threads to call these initialize routines */
75   preload = PETSC_TRUE;
76 #endif
77 
78   nmax = 32;
79   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_prepend", libname, &nmax, NULL));
80   for (i = 0; i < nmax; i++) {
81     PetscCall(PetscDLLibraryPrepend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
82     PetscCall(PetscFree(libname[i]));
83   }
84 
85   PetscCall(PetscOptionsGetBool(NULL, NULL, "-library_preload", &preload, NULL));
86   if (!preload) {
87     PetscCall(PetscSysInitializePackage());
88   } else {
89 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
90     PetscBool found;
91   #if defined(PETSC_USE_SINGLE_LIBRARY)
92     PetscCall(PetscLoadDynamicLibrary("", &found));
93     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library. You cannot move the dynamic libraries!");
94   #else
95     PetscCall(PetscLoadDynamicLibrary("sys", &found));
96     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Sys dynamic library. You cannot move the dynamic libraries!");
97     PetscCall(PetscLoadDynamicLibrary("vec", &found));
98     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Vec dynamic library. You cannot move the dynamic libraries!");
99     PetscCall(PetscLoadDynamicLibrary("mat", &found));
100     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Mat dynamic library. You cannot move the dynamic libraries!");
101     PetscCall(PetscLoadDynamicLibrary("dm", &found));
102     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc DM dynamic library. You cannot move the dynamic libraries!");
103     PetscCall(PetscLoadDynamicLibrary("ksp", &found));
104     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc KSP dynamic library. You cannot move the dynamic libraries!");
105     PetscCall(PetscLoadDynamicLibrary("snes", &found));
106     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc SNES dynamic library. You cannot move the dynamic libraries!");
107     PetscCall(PetscLoadDynamicLibrary("ts", &found));
108     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc TS dynamic library. You cannot move the dynamic libraries!");
109     PetscCall(PetscLoadDynamicLibrary("tao", &found));
110     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate Tao dynamic library. You cannot move the dynamic libraries!");
111   #endif
112 #else /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
113   #if defined(PETSC_USE_SINGLE_LIBRARY)
114     PetscCall(AOInitializePackage());
115     PetscCall(PetscSFInitializePackage());
116     #if !defined(PETSC_USE_COMPLEX)
117     PetscCall(CharacteristicInitializePackage());
118     #endif
119     PetscCall(ISInitializePackage());
120     PetscCall(VecInitializePackage());
121     PetscCall(MatInitializePackage());
122     PetscCall(DMInitializePackage());
123     PetscCall(PCInitializePackage());
124     PetscCall(KSPInitializePackage());
125     PetscCall(SNESInitializePackage());
126     PetscCall(TSInitializePackage());
127     PetscCall(TaoInitializePackage());
128   #else
129     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Cannot use -library_preload with multiple static PETSc libraries");
130   #endif
131 #endif /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
132   }
133 
134 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) && defined(PETSC_HAVE_BAMG)
135   {
136     PetscBool found;
137     PetscCall(PetscLoadDynamicLibrary("bamg", &found));
138     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc BAMG dynamic library. You cannot move the dynamic libraries!");
139   }
140 #endif
141 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) && defined(PETSC_HAVE_PFLARE)
142   {
143     PetscBool found;
144     PetscCall(PetscLoadDynamicLibrary("pflare", &found));
145     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PFLARE dynamic library. You cannot move the dynamic libraries!");
146   }
147 #endif
148 
149   nmax = 32;
150   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_append", libname, &nmax, NULL));
151   for (i = 0; i < nmax; i++) {
152     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
153     PetscCall(PetscFree(libname[i]));
154   }
155 
156 #if defined(PETSC_HAVE_ELEMENTAL)
157   /* in Fortran, PetscInitializeCalled is set to PETSC_TRUE before PetscInitialize_DynamicLibraries() */
158   /* in C, it is not the case, but the value is forced to PETSC_TRUE so that PetscRegisterFinalize() is called */
159   PetscInitializeCalled = PETSC_TRUE;
160   PetscCall(PetscElementalInitializePackage());
161   PetscInitializeCalled = PetscInitialized;
162 #endif
163   PetscFunctionReturn(PETSC_SUCCESS);
164 }
165 
166 /*
167      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
168 */
PetscFinalize_DynamicLibraries(void)169 PETSC_INTERN PetscErrorCode PetscFinalize_DynamicLibraries(void)
170 {
171   PetscBool flg = PETSC_FALSE;
172 
173   PetscFunctionBegin;
174   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dll_view", &flg, NULL));
175   if (flg) PetscCall(PetscDLLibraryPrintPath(PetscDLLibrariesLoaded));
176   PetscCall(PetscDLLibraryClose(PetscDLLibrariesLoaded));
177   PetscDLLibrariesLoaded = NULL;
178   PetscFunctionReturn(PETSC_SUCCESS);
179 }
180 
181 PETSC_HASH_MAP(HMapFunc, const char *, PetscErrorCodeFn *, kh_str_hash_func, kh_str_hash_equal, NULL)
182 
183 struct _n_PetscFunctionList {
184   PetscHMapFunc map;
185 };
186 
187 /* Keep a linked list of PetscFunctionLists so that we can destroy all the left-over ones. */
188 typedef struct n_PetscFunctionListDLAll *PetscFunctionListDLAll;
189 struct n_PetscFunctionListDLAll {
190   PetscFunctionList      data;
191   PetscFunctionListDLAll next;
192 };
193 
194 static PetscFunctionListDLAll dlallhead = NULL;
195 
PetscFunctionListDLAllPush_Private(PetscFunctionList fl)196 static PetscErrorCode PetscFunctionListDLAllPush_Private(PetscFunctionList fl)
197 {
198   PetscFunctionBegin;
199   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
200     PetscFunctionListDLAll head;
201 
202     PetscCall(PetscNew(&head));
203     head->data = fl;
204     head->next = dlallhead;
205     dlallhead  = head;
206   }
207   PetscFunctionReturn(PETSC_SUCCESS);
208 }
209 
PetscFunctionListDLAllPop_Private(PetscFunctionList fl)210 static PetscErrorCode PetscFunctionListDLAllPop_Private(PetscFunctionList fl)
211 {
212   PetscFunctionBegin;
213   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
214     PetscFunctionListDLAll current = dlallhead, prev = NULL;
215 
216     /* Remove this entry from the main DL list (if it is in it) */
217     while (current) {
218       const PetscFunctionListDLAll next = current->next;
219 
220       if (current->data == fl) {
221         if (prev) {
222           // somewhere in the middle (or end) of the list
223           prev->next = next;
224         } else {
225           // prev = NULL implies current = dlallhead, so front of list
226           dlallhead = next;
227         }
228         PetscCall(PetscFree(current));
229         break;
230       }
231       prev    = current;
232       current = next;
233     }
234   }
235   PetscFunctionReturn(PETSC_SUCCESS);
236 }
237 
PetscHMapFuncInsert_Private(PetscHMapFunc map,const char name[],PetscErrorCodeFn * fnc)238 static PetscErrorCode PetscHMapFuncInsert_Private(PetscHMapFunc map, const char name[], PetscErrorCodeFn *fnc)
239 {
240   PetscHashIter it;
241   PetscBool     found;
242 
243   PetscFunctionBegin;
244   PetscAssertPointer(name, 2);
245   if (fnc) PetscValidFunction(fnc, 3);
246   PetscCall(PetscHMapFuncFind(map, name, &it, &found));
247   if (fnc) {
248     if (found) {
249       PetscCall(PetscHMapFuncIterSet(map, it, fnc));
250     } else {
251       char *tmp_name;
252 
253       PetscCall(PetscStrallocpy(name, &tmp_name));
254       PetscCall(PetscHMapFuncSet(map, tmp_name, fnc));
255     }
256   } else if (found) {
257     const char *tmp_name;
258 
259     PetscHashIterGetKey(map, it, tmp_name);
260     PetscCall(PetscFree(tmp_name));
261     PetscCall(PetscHMapFuncIterDel(map, it));
262   }
263   PetscFunctionReturn(PETSC_SUCCESS);
264 }
265 
PetscFunctionListCreate_Private(PetscInt size,PetscFunctionList * fl)266 static PetscErrorCode PetscFunctionListCreate_Private(PetscInt size, PetscFunctionList *fl)
267 {
268   PetscFunctionBegin;
269   if (*fl) PetscFunctionReturn(PETSC_SUCCESS);
270   PetscCall(PetscNew(fl));
271   PetscCall(PetscHMapFuncCreateWithSize(size, &(*fl)->map));
272   PetscCall(PetscFunctionListDLAllPush_Private(*fl));
273   PetscFunctionReturn(PETSC_SUCCESS);
274 }
275 
276 /*MC
277   PetscFunctionListAdd - Given a routine and a string id, saves that routine in the
278   specified registry.
279 
280   Synopsis:
281   #include <petscsys.h>
282   PetscErrorCode PetscFunctionListAdd(PetscFunctionList *flist, const char name[], PetscErrorCodeFn *fptr)
283 
284   Not Collective
285 
286   Input Parameters:
287 + fl   - pointer to function list object
288 . name - string to identify routine
289 - fptr - function pointer
290 
291   Level: developer
292 
293   Notes:
294   To remove a registered routine, pass in a `NULL` `fptr`.
295 
296   Users who wish to register new classes for use by a particular PETSc
297   component (e.g., `SNES`) should generally call the registration routine
298   for that particular component (e.g., `SNESRegister()`) instead of
299   calling `PetscFunctionListAdd()` directly.
300 
301 .seealso: `PetscFunctionListDestroy()`, `SNESRegister()`, `KSPRegister()`,`PetscFunctionListDuplicate()`
302           `PCRegister()`, `TSRegister()`, `PetscFunctionList`, `PetscObjectComposeFunction()`
303 M*/
PetscFunctionListAdd_Private(PetscFunctionList * fl,const char name[],PetscErrorCodeFn * fptr)304 PetscErrorCode PetscFunctionListAdd_Private(PetscFunctionList *fl, const char name[], PetscErrorCodeFn *fptr)
305 {
306   PetscFunctionBegin;
307   PetscAssertPointer(fl, 1);
308   if (name) PetscAssertPointer(name, 2);
309   if (fptr) PetscValidFunction(fptr, 3);
310   if (!fptr && !*fl) PetscFunctionReturn(PETSC_SUCCESS);
311   PetscCall(PetscFunctionListCreate_Private(0, fl));
312   PetscCall(PetscHMapFuncInsert_Private((*fl)->map, name, fptr));
313   PetscFunctionReturn(PETSC_SUCCESS);
314 }
315 
316 /*@C
317   PetscFunctionListDestroy - Destroys a list of registered routines.
318 
319   Input Parameter:
320 . fl - pointer to list
321 
322   Level: developer
323 
324 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscFunctionListClear()`
325 @*/
PetscFunctionListDestroy(PetscFunctionList * fl)326 PetscErrorCode PetscFunctionListDestroy(PetscFunctionList *fl)
327 {
328   PetscFunctionBegin;
329   if (!*fl) PetscFunctionReturn(PETSC_SUCCESS);
330   PetscCall(PetscFunctionListDLAllPop_Private(*fl));
331   /* free this list */
332   PetscCall(PetscFunctionListClear(*fl));
333   PetscCall(PetscHMapFuncDestroy(&(*fl)->map));
334   PetscCall(PetscFree(*fl));
335   PetscFunctionReturn(PETSC_SUCCESS);
336 }
337 
338 #define PetscHMapFuncForEach(__func_list__, __key_name__, __val_name__, ...) \
339   do { \
340     const PetscHMapFunc phmfi_map_ = (__func_list__)->map; \
341     PetscHashIter       phmfi_iter_; \
342 \
343     PetscHashIterBegin(phmfi_map_, phmfi_iter_); \
344     while (!PetscHashIterAtEnd(phmfi_map_, phmfi_iter_)) { \
345       const char *PETSC_UNUSED       __key_name__; \
346       PetscErrorCodeFn *PETSC_UNUSED __val_name__; \
347 \
348       PetscHashIterGetKey(phmfi_map_, phmfi_iter_, __key_name__); \
349       PetscHashIterGetVal(phmfi_map_, phmfi_iter_, __val_name__); \
350       { \
351         __VA_ARGS__; \
352       } \
353       PetscHashIterNext(phmfi_map_, phmfi_iter_); \
354     } /* end while */ \
355   } while (0)
356 
357 /*@C
358   PetscFunctionListClear - Clear a `PetscFunctionList`
359 
360   Not Collective
361 
362   Input Parameter:
363 . fl - The `PetscFunctionList` to clear
364 
365   Level: developer
366 
367   Notes:
368   This clears the contents of `fl` but does not deallocate the entries themselves.
369 
370 .seealso: `PetscFunctionList`, `PetscFunctionListDestroy()`, `PetscFunctionListAdd()`
371 @*/
PetscFunctionListClear(PetscFunctionList fl)372 PetscErrorCode PetscFunctionListClear(PetscFunctionList fl)
373 {
374   PetscFunctionBegin;
375   if (fl) {
376     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscFree(name)));
377     PetscCall(PetscHMapFuncClear(fl->map));
378   }
379   PetscFunctionReturn(PETSC_SUCCESS);
380 }
381 
382 /*
383    Print registered PetscFunctionLists
384 */
PetscFunctionListPrintAll(void)385 PetscErrorCode PetscFunctionListPrintAll(void)
386 {
387   PetscFunctionListDLAll current = dlallhead;
388 
389   PetscFunctionBegin;
390   if (current) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Registered PetscFunctionLists\n", PetscGlobalRank));
391   while (current) {
392     PetscCall(PetscFunctionListPrintNonEmpty(current->data));
393     current = current->next;
394   }
395   PetscFunctionReturn(PETSC_SUCCESS);
396 }
397 
398 /*@C
399   PetscFunctionListPrintNonEmpty - Print composed names for non `NULL` function pointers
400 
401   Logically Collective, No Fortran Support
402 
403   Input Parameter:
404 . fl - the function list
405 
406   Level: developer
407 
408 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
409 @*/
PetscFunctionListPrintNonEmpty(PetscFunctionList fl)410 PetscErrorCode PetscFunctionListPrintNonEmpty(PetscFunctionList fl)
411 {
412   PetscFunctionBegin;
413   if (fl) {
414     // clang-format off
415     PetscHMapFuncForEach(
416       fl,
417       name, func,
418       PetscCall(PetscFPrintf(PETSC_COMM_SELF, PETSC_STDOUT, "[%d] function name: %s\n", PetscGlobalRank, name));
419     );
420     // clang-format on
421   }
422   PetscFunctionReturn(PETSC_SUCCESS);
423 }
424 
425 /*MC
426   PetscFunctionListFind - Find function registered under given name
427 
428   Not Collective, No Fortran Support
429 
430   Synopsis:
431   #include <petscsys.h>
432   PetscErrorCode PetscFunctionListFind(PetscFunctionList flist, const char name[], PetscErrorCodeFn **fptr)
433 
434   Input Parameters:
435 + fl   - the function list
436 - name - name registered for the function
437 
438   Output Parameter:
439 . fptr - the function pointer if name was found, else `NULL`
440 
441   Level: developer
442 
443 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`, `PetscFunctionListDuplicate()`
444 M*/
PetscFunctionListFind_Private(PetscFunctionList fl,const char name[],PetscErrorCodeFn ** fptr)445 PetscErrorCode PetscFunctionListFind_Private(PetscFunctionList fl, const char name[], PetscErrorCodeFn **fptr)
446 {
447   PetscFunctionBegin;
448   PetscAssertPointer(name, 2);
449   PetscAssertPointer(fptr, 3);
450   *fptr = NULL;
451   if (fl) PetscCall(PetscHMapFuncGet(fl->map, name, fptr));
452   PetscFunctionReturn(PETSC_SUCCESS);
453 }
454 
455 /*@C
456   PetscFunctionListView - prints out contents of a `PetscFunctionList`
457 
458   Collective
459 
460   Input Parameters:
461 + list   - the list of functions
462 - viewer - the `PetscViewer` used to view the `PetscFunctionList`
463 
464   Level: developer
465 
466 .seealso: `PetscFunctionListAdd()`, `PetscFunctionListPrintTypes()`, `PetscFunctionList`
467 @*/
PetscFunctionListView(PetscFunctionList list,PetscViewer viewer)468 PetscErrorCode PetscFunctionListView(PetscFunctionList list, PetscViewer viewer)
469 {
470   PetscBool isascii;
471 
472   PetscFunctionBegin;
473   PetscAssertPointer(list, 1);
474   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_SELF, &viewer));
475   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
476 
477   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
478   PetscCheck(isascii, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ASCII viewer supported");
479   {
480     PetscInt size;
481 
482     PetscCall(PetscHMapFuncGetSize(list->map, &size));
483     PetscCall(PetscViewerASCIIPrintf(viewer, "PetscFunctionList Object:\n"));
484     PetscCall(PetscViewerASCIIPushTab(viewer));
485     PetscCall(PetscViewerASCIIPrintf(viewer, "size: %" PetscInt_FMT "\n", size));
486     if (size) {
487       PetscInt count = 0;
488 
489       PetscCall(PetscViewerASCIIPrintf(viewer, "functions:\n"));
490       PetscCall(PetscViewerASCIIPushTab(viewer));
491       PetscHMapFuncForEach(list, name, func, PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT ": %s\n", ++count, name)));
492       PetscCall(PetscViewerASCIIPopTab(viewer));
493     }
494     PetscCall(PetscViewerASCIIPopTab(viewer));
495   }
496   PetscFunctionReturn(PETSC_SUCCESS);
497 }
498 
499 /*@C
500   PetscFunctionListGet - Gets an array the contains the entries in `PetscFunctionList`, this is used
501   by help etc.
502 
503   Not Collective, No Fortran Support
504 
505   Input Parameter:
506 . list - list of types
507 
508   Output Parameters:
509 + array - array of names
510 - n     - length of `array`
511 
512   Level: developer
513 
514   Note:
515   This allocates the array so that must be freed with `PetscFree()`. BUT the individual entries should not be freed.
516 
517 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
518 @*/
PetscFunctionListGet(PetscFunctionList list,const char *** array,int * n)519 PetscErrorCode PetscFunctionListGet(PetscFunctionList list, const char ***array, int *n)
520 {
521   PetscInt size = 0;
522 
523   PetscFunctionBegin;
524   PetscAssertPointer(array, 2);
525   *array = NULL;
526   if (list) {
527     const PetscHMapFunc map = list->map;
528     PetscInt            off = 0;
529 
530     PetscCall(PetscHMapFuncGetSize(map, &size));
531     PetscCall(PetscMalloc1(size, (char ***)array));
532     PetscCall(PetscHMapFuncGetKeys(map, &off, *array));
533   }
534   PetscCall(PetscCIntCast(size, n));
535   PetscFunctionReturn(PETSC_SUCCESS);
536 }
537 
538 /*@C
539   PetscFunctionListPrintTypes - Prints the methods available in a list of functions
540 
541   Collective, No Fortran Support
542 
543   Input Parameters:
544 + comm   - the communicator (usually `MPI_COMM_WORLD`)
545 . fd     - file to print to, usually `stdout`
546 . prefix - prefix to prepend to name (optional)
547 . name   - option string (for example, `-ksp_type`)
548 . text   - short description of the object (for example, "Krylov solvers")
549 . man    - name of manual page that discusses the object (for example, `KSPCreate`)
550 . list   - list of types
551 . def    - default (current) value
552 - newv   - new value
553 
554   Level: developer
555 
556 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
557 @*/
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[])558 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[])
559 {
560   char p[64];
561 
562   PetscFunctionBegin;
563   (void)fd;
564   PetscCall(PetscStrncpy(p, "-", sizeof(p)));
565   if (prefix) PetscCall(PetscStrlcat(p, prefix, sizeof(p)));
566   PetscCall((*PetscHelpPrintf)(comm, "  %s%s <now %s : formerly %s>: %s (one of)", p, name + 1, newv, def, text));
567 
568   if (list) PetscHMapFuncForEach(list, name, func, PetscCall((*PetscHelpPrintf)(comm, " %s", name)));
569   PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", man));
570   PetscFunctionReturn(PETSC_SUCCESS);
571 }
572 
573 /*@C
574   PetscFunctionListDuplicate - Creates a new list from a given function list `PetscFunctionList`.
575 
576   Input Parameter:
577 . fl - pointer to list
578 
579   Output Parameter:
580 . nl - the new list (should point to `NULL` to start, otherwise appends)
581 
582   Level: developer
583 
584 .seealso: `PetscFunctionList`, `PetscFunctionListAdd()`, `PetscFlistDestroy()`
585 @*/
PetscFunctionListDuplicate(PetscFunctionList fl,PetscFunctionList * nl)586 PetscErrorCode PetscFunctionListDuplicate(PetscFunctionList fl, PetscFunctionList *nl)
587 {
588   PetscFunctionBegin;
589   if (fl) {
590     PetscHMapFunc dup_map;
591 
592     if (!*nl) {
593       PetscInt n;
594 
595       PetscCall(PetscHMapFuncGetSize(fl->map, &n));
596       PetscCall(PetscFunctionListCreate_Private(n, nl));
597     }
598     dup_map = (*nl)->map;
599     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscHMapFuncInsert_Private(dup_map, name, func)));
600   }
601   PetscFunctionReturn(PETSC_SUCCESS);
602 }
603