xref: /petsc/include/petscstring.h (revision 0b4b7b1c20c2ed4ade67e3d50a7710fe0ffbfca5)
1 #pragma once
2 
3 #include <petscsystypes.h>
4 #include <petscerror.h>
5 #include <petscmacros.h>
6 #include <petscsys.h>
7 
8 /* SUBMANSEC = Sys */
9 
10 #include <stddef.h> /* size_t */
11 #include <string.h> /* for memcpy, memset */
12 
13 PETSC_EXTERN PetscErrorCode PetscMemcmp(const void *, const void *, size_t, PetscBool *);
14 PETSC_EXTERN PetscErrorCode PetscStrToArray(const char[], char, int *, char ***);
15 PETSC_EXTERN PetscErrorCode PetscStrToArrayDestroy(int, char **);
16 PETSC_EXTERN PetscErrorCode PetscStrcasecmp(const char[], const char[], PetscBool *);
17 PETSC_EXTERN PetscErrorCode PetscStrendswithwhich(const char[], const char *const *, PetscInt *);
18 PETSC_EXTERN PetscErrorCode PetscStrArrayallocpy(const char *const *, char ***);
19 PETSC_EXTERN PetscErrorCode PetscStrArrayDestroy(char ***);
20 PETSC_EXTERN PetscErrorCode PetscStrNArrayallocpy(PetscInt, const char *const *, char ***);
21 PETSC_EXTERN PetscErrorCode PetscStrNArrayDestroy(PetscInt, char ***);
22 PETSC_EXTERN PetscErrorCode PetscStrreplace(MPI_Comm, const char[], char[], size_t);
23 PETSC_EXTERN PetscErrorCode PetscStrcmpAny(const char[], PetscBool *, const char[], ...);
24 
25 PETSC_EXTERN PetscErrorCode PetscTokenCreate(const char[], char, PetscToken *);
26 PETSC_EXTERN PetscErrorCode PetscTokenFind(PetscToken, char *[]);
27 PETSC_EXTERN PetscErrorCode PetscTokenDestroy(PetscToken *);
28 
29 PETSC_EXTERN PetscErrorCode PetscStrInList(const char[], const char[], char, PetscBool *);
30 PETSC_EXTERN const char    *PetscBasename(const char[]);
31 PETSC_EXTERN PetscErrorCode PetscEListFind(PetscInt, const char *const *, const char *, PetscInt *, PetscBool *);
32 PETSC_EXTERN PetscErrorCode PetscEnumFind(const char *const *, const char *, PetscEnum *, PetscBool *);
33 
34 PETSC_EXTERN PetscErrorCode PetscStrcat(char[], const char[]);
35 PETSC_EXTERN PetscErrorCode PetscStrcpy(char[], const char[]);
36 
37 #define PetscAssertPointer_Private(ptr, arg) PetscAssert((ptr), PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null Pointer: Parameter '" PetscStringize(ptr) "' # " PetscStringize(arg))
38 
39 /*@C
40   PetscStrtolower - Converts a string to lower case
41 
42   Not Collective, No Fortran Support
43 
44   Input Parameter:
45 . a - pointer to string
46 
47   Level: intermediate
48 
49 .seealso: `PetscStrtoupper()`
50 @*/
51 static inline PetscErrorCode PetscStrtolower(char a[])
52 {
53   PetscFunctionBegin;
54   PetscAssertPointer_Private(a, 1);
55   while (*a) {
56     if (*a >= 'A' && *a <= 'Z') *a += 'a' - 'A';
57     a++;
58   }
59   PetscFunctionReturn(PETSC_SUCCESS);
60 }
61 
62 /*@C
63   PetscStrtoupper - Converts a string to upper case
64 
65   Not Collective, No Fortran Support
66 
67   Input Parameter:
68 . a - pointer to string
69 
70   Level: intermediate
71 
72 .seealso: `PetscStrtolower()`
73 @*/
74 static inline PetscErrorCode PetscStrtoupper(char a[])
75 {
76   PetscFunctionBegin;
77   PetscAssertPointer_Private(a, 1);
78   while (*a) {
79     if (*a >= 'a' && *a <= 'z') *a += 'A' - 'a';
80     a++;
81   }
82   PetscFunctionReturn(PETSC_SUCCESS);
83 }
84 
85 /*@C
86   PetscStrlen - Gets the length of a string
87 
88   Not Collective, No Fortran Support
89 
90   Input Parameter:
91 . s - pointer to string
92 
93   Output Parameter:
94 . len - length in bytes
95 
96   Level: intermediate
97 
98   Note:
99   This routine is analogous to `strlen()`. `NULL` string returns a length of zero.
100 
101 .seealso: `PetscStrallocpy()`
102 @*/
103 static inline PetscErrorCode PetscStrlen(const char s[], size_t *len)
104 {
105   PetscFunctionBegin;
106   PetscAssertPointer_Private(len, 2);
107   if (s) {
108 #if PetscHasBuiltin(__builtin_strlen)
109     *len = __builtin_strlen(s);
110 #else
111     *len = strlen(s);
112 #endif
113   } else {
114     *len = 0;
115   }
116   PetscFunctionReturn(PETSC_SUCCESS);
117 }
118 
119 /*@C
120   PetscStrallocpy - Allocates space to hold a copy of a string then copies the string into the new space
121 
122   Not Collective, No Fortran Support
123 
124   Input Parameter:
125 . s - pointer to string
126 
127   Output Parameter:
128 . t - the copied string
129 
130   Level: intermediate
131 
132   Notes:
133   `NULL` string returns a new `NULL` string.
134 
135   Use `PetscFree()` to release the data when it is no longer needed.
136 
137   If `t` has previously been allocated then that memory is lost, you may need to `PetscFree()`
138   the array before calling this routine.
139 
140 .seealso: `PetscStrArrayallocpy()`, `PetscStrNArrayallocpy()`
141 @*/
142 static inline PetscErrorCode PetscStrallocpy(const char s[], char *t[])
143 {
144   PetscFunctionBegin;
145   PetscAssertPointer_Private(t, 2);
146   *t = PETSC_NULLPTR;
147   if (s) {
148     size_t len;
149     char  *tmp;
150 
151     PetscAssertPointer_Private(s, 1);
152     PetscCall(PetscStrlen(s, &len));
153     PetscCall(PetscMalloc1(len + 1, &tmp));
154 #if PetscHasBuiltin(__builtin_memcpy)
155     __builtin_memcpy(tmp, s, len);
156 #else
157     memcpy(tmp, s, len);
158 #endif
159     tmp[len] = '\0';
160     *t       = tmp;
161   }
162   PetscFunctionReturn(PETSC_SUCCESS);
163 }
164 
165 static inline void PetscStrcmpNoError(const char a[], const char b[], PetscBool *flg)
166 {
167   if (!a && !b) {
168     *flg = PETSC_TRUE;
169   } else if (!a || !b) {
170     *flg = PETSC_FALSE;
171   } else {
172 #if PetscHasBuiltin(__builtin_strcmp)
173     *flg = __builtin_strcmp(a, b) ? PETSC_FALSE : PETSC_TRUE;
174 #else
175     *flg = strcmp(a, b) ? PETSC_FALSE : PETSC_TRUE;
176 #endif
177   }
178 }
179 
180 /*@C
181   PetscStrcmp - Compares two strings
182 
183   Not Collective, No Fortran Support
184 
185   Input Parameters:
186 + a - pointer to string first string
187 - b - pointer to second string
188 
189   Output Parameter:
190 . flg - `PETSC_TRUE` if the two strings are equal
191 
192   Level: intermediate
193 
194 .seealso: `PetscStrcmpAny()`, `PetscStrgrt()`, `PetscStrncmp()`, `PetscStrcasecmp()`
195 @*/
196 static inline PetscErrorCode PetscStrcmp(const char a[], const char b[], PetscBool *flg)
197 {
198   PetscFunctionBegin;
199   PetscAssertPointer_Private(flg, 3);
200   PetscStrcmpNoError(a, b, flg);
201   PetscFunctionReturn(PETSC_SUCCESS);
202 }
203 
204 #if defined(__GNUC__) && !defined(__clang__)
205   #if __GNUC__ >= 8
206     #define PETSC_SILENCE_WSTRINGOP_TRUNCATION_BEGIN \
207       do { \
208         _Pragma("GCC diagnostic push"); \
209         _Pragma("GCC diagnostic ignored \"-Wstringop-truncation\""); \
210       } while (0)
211     #define PETSC_SILENCE_WSTRINGOP_TRUNCATION_END _Pragma("GCC diagnostic pop")
212   #endif
213 #endif
214 
215 #ifndef PETSC_SILENCE_WSTRINGOP_TRUNCATION_BEGIN
216   #define PETSC_SILENCE_WSTRINGOP_TRUNCATION_BEGIN (void)0
217   #define PETSC_SILENCE_WSTRINGOP_TRUNCATION_END   (void)0
218 #endif
219 
220 /*@C
221   PetscStrncpy - Copies a string up to a certain length
222 
223   Not Collective
224 
225   Input Parameters:
226 + t - pointer to string
227 - n - the length to copy
228 
229   Output Parameter:
230 . s - the copied string
231 
232   Level: intermediate
233 
234   Notes:
235   `NULL` string returns a string starting with zero.
236 
237   If the string that is being copied is of length `n` or larger, then the entire string is not
238   copied and the final location of `s` is set to `NULL`. This is different then the behavior of
239   `strncpy()` which leaves `s` non-terminated if there is not room for the entire string.
240 
241   Developer Note:
242   Should this be `PetscStrlcpy()` to reflect its behavior which is like `strlcpy()` not
243   `strncpy()`?
244 
245 .seealso: `PetscStrlcat()`, `PetscStrallocpy()`
246 @*/
247 static inline PetscErrorCode PetscStrncpy(char s[], const char t[], size_t n)
248 {
249   PetscFunctionBegin;
250   if (s) PetscAssert(n, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Requires an output string of length at least 1 to hold the termination character");
251   if (t) {
252     PetscAssertPointer_Private(s, 1);
253     PETSC_SILENCE_WSTRINGOP_TRUNCATION_BEGIN;
254 #if PetscHasBuiltin(__builtin_strncpy)
255     __builtin_strncpy(s, t, n);
256 #else
257     strncpy(s, t, n);
258 #endif
259     PETSC_SILENCE_WSTRINGOP_TRUNCATION_END;
260     s[n - 1] = '\0';
261   } else if (s) {
262     s[0] = '\0';
263   }
264   PetscFunctionReturn(PETSC_SUCCESS);
265 }
266 
267 /*@C
268   PetscStrlcat - Concatenates a string onto a given string, up to a given length
269 
270   Not Collective, No Fortran Support
271 
272   Input Parameters:
273 + s - pointer to string to be added to at end
274 . t - string to be added
275 - n - length of the original allocated string
276 
277   Level: intermediate
278 
279   Note:
280   Unlike the system call `strncat()`, the length passed in is the length of the
281   original allocated space, not the length of the left-over space. This is
282   similar to the BSD system call `strlcat()`.
283 
284 .seealso: `PetscStrncpy()`
285 @*/
286 static inline PetscErrorCode PetscStrlcat(char s[], const char t[], size_t n)
287 {
288   size_t len;
289 
290   PetscFunctionBegin;
291   if (!t) PetscFunctionReturn(PETSC_SUCCESS);
292   PetscAssert(n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "String buffer length must be positive");
293   PetscCall(PetscStrlen(s, &len));
294   PETSC_SILENCE_WSTRINGOP_TRUNCATION_BEGIN;
295 #if PetscHasBuiltin(__builtin_strncat)
296   __builtin_strncat(s, t, n - len);
297 #else
298   strncat(s, t, n - len);
299 #endif
300   PETSC_SILENCE_WSTRINGOP_TRUNCATION_END;
301   s[n - 1] = '\0';
302   PetscFunctionReturn(PETSC_SUCCESS);
303 }
304 
305 #undef PETSC_SILENCE_WSTRINGOP_TRUNCATION_BEGIN
306 #undef PETSC_SILENCE_WSTRINGOP_TRUNCATION_END
307 
308 /*@C
309   PetscStrncmp - Compares two strings, up to a certain length
310 
311   Not Collective, No Fortran Support
312 
313   Input Parameters:
314 + a - pointer to first string
315 . b - pointer to second string
316 - n - length to compare up to
317 
318   Output Parameter:
319 . t - `PETSC_TRUE` if the two strings are equal, `PETSC_FALSE` otherwise
320 
321   Level: intermediate
322 
323   Note:
324   If `n` is `0`, `t` is set to `PETSC_FALSE`. `a` and/or `b` may be `NULL` in this case.
325 
326 .seealso: `PetscStrgrt()`, `PetscStrcmp()`, `PetscStrcasecmp()`
327 @*/
328 static inline PetscErrorCode PetscStrncmp(const char a[], const char b[], size_t n, PetscBool *t)
329 {
330   PetscFunctionBegin;
331   PetscAssertPointer_Private(t, 4);
332   *t = PETSC_FALSE;
333   if (n) {
334     PetscAssertPointer_Private(a, 1);
335     PetscAssertPointer_Private(b, 2);
336   }
337 #if PetscHasBuiltin(__builtin_strncmp)
338   *t = __builtin_strncmp(a, b, n) ? PETSC_FALSE : PETSC_TRUE;
339 #else
340   *t = strncmp(a, b, n) ? PETSC_FALSE : PETSC_TRUE;
341 #endif
342   PetscFunctionReturn(PETSC_SUCCESS);
343 }
344 
345 /*@C
346   PetscStrrstr - Locates last occurrence of string in another string
347 
348   Not Collective, No Fortran Support
349 
350   Input Parameters:
351 + a - pointer to string
352 - b - string to find
353 
354   Output Parameter:
355 . tmp - location of occurrence
356 
357   Level: intermediate
358 
359 .seealso: `PetscStrbeginswithwhich()`, `PetscStrendswith()`, `PetscStrtoupper`,
360           `PetscStrtolower()`, `PetscStrrchr()`, `PetscStrchr()`, `PetscStrncmp()`, `PetscStrlen()`,
361           `PetscStrcmp()`
362 @*/
363 static inline PetscErrorCode PetscStrrstr(const char a[], const char b[], char *tmp[])
364 {
365   const char *ltmp = PETSC_NULLPTR;
366 
367   PetscFunctionBegin;
368   PetscAssertPointer_Private(a, 1);
369   PetscAssertPointer_Private(b, 2);
370   PetscAssertPointer_Private(tmp, 3);
371   while (a) {
372 #if PetscHasBuiltin(__builtin_strstr)
373     a = (char *)__builtin_strstr(a, b);
374 #else
375     a = (char *)strstr(a, b);
376 #endif
377     if (a) ltmp = a++;
378   }
379   *tmp = (char *)ltmp;
380   PetscFunctionReturn(PETSC_SUCCESS);
381 }
382 
383 /*@C
384   PetscStrstr - Locates first occurrence of string in another string
385 
386   Not Collective, No Fortran Support
387 
388   Input Parameters:
389 + haystack - string to search
390 - needle   - string to find
391 
392   Output Parameter:
393 . tmp - location of `needle` within `haystack`, `NULL` if `needle` is not found
394 
395   Level: intermediate
396 
397 .seealso: `PetscStrbeginswithwhich()`, `PetscStrendswith()`, `PetscStrtoupper`,
398           `PetscStrtolower()`, `PetscStrrchr()`, `PetscStrchr()`, `PetscStrncmp()`, `PetscStrlen()`,
399           `PetscStrcmp()`
400 @*/
401 static inline PetscErrorCode PetscStrstr(const char haystack[], const char needle[], char *tmp[])
402 {
403   PetscFunctionBegin;
404   PetscAssertPointer_Private(haystack, 1);
405   PetscAssertPointer_Private(needle, 2);
406   PetscAssertPointer_Private(tmp, 3);
407 #if PetscHasBuiltin(__builtin_strstr)
408   *tmp = (char *)__builtin_strstr(haystack, needle);
409 #else
410   *tmp = (char *)strstr(haystack, needle);
411 #endif
412   PetscFunctionReturn(PETSC_SUCCESS);
413 }
414 
415 /*@C
416   PetscStrgrt - If first string is greater than the second
417 
418   Not Collective, No Fortran Support
419 
420   Input Parameters:
421 + a - pointer to first string
422 - b - pointer to second string
423 
424   Output Parameter:
425 . flg - `PETSC_TRUE` if `a` is strictly greater than `b`, `PETSC_FALSE` otherwise
426 
427   Level: intermediate
428 
429   Note:
430   `NULL` arguments are OK, a `NULL` string is considered smaller than all others. If both `a`
431   and `b` are `NULL` then `t` is set to `PETSC_FALSE`.
432 
433 .seealso: `PetscStrcmp()`, `PetscStrncmp()`, `PetscStrcasecmp()`
434 @*/
435 static inline PetscErrorCode PetscStrgrt(const char a[], const char b[], PetscBool *t)
436 {
437   PetscFunctionBegin;
438   PetscAssertPointer_Private(t, 3);
439   if (!a && !b) {
440     *t = PETSC_FALSE;
441   } else if (a && !b) {
442     *t = PETSC_TRUE;
443   } else if (!a && b) {
444     *t = PETSC_FALSE;
445   } else {
446 #if PetscHasBuiltin(__builtin_strcmp)
447     *t = __builtin_strcmp(a, b) > 0 ? PETSC_TRUE : PETSC_FALSE;
448 #else
449     *t = strcmp(a, b) > 0 ? PETSC_TRUE : PETSC_FALSE;
450 #endif
451   }
452   PetscFunctionReturn(PETSC_SUCCESS);
453 }
454 
455 /*@C
456   PetscStrchr - Locates first occurrence of a character in a string
457 
458   Not Collective, No Fortran Support
459 
460   Input Parameters:
461 + a - pointer to string
462 - b - character
463 
464   Output Parameter:
465 . c - location of occurrence, `NULL` if not found
466 
467   Level: intermediate
468 
469 .seealso: `PetscStrrchr()`, `PetscTokenCreate()`, `PetscStrendswith()`, `PetscStrbeginsswith()`
470 @*/
471 static inline PetscErrorCode PetscStrchr(const char a[], char b, char *c[])
472 {
473   PetscFunctionBegin;
474   PetscAssertPointer_Private(a, 1);
475   PetscAssertPointer_Private(c, 3);
476 #if PetscHasBuiltin(__builtin_strchr)
477   *c = (char *)__builtin_strchr(a, b);
478 #else
479   *c = (char *)strchr(a, b);
480 #endif
481   PetscFunctionReturn(PETSC_SUCCESS);
482 }
483 
484 /*@C
485   PetscStrrchr - Locates one location past the last occurrence of a character in a string, if
486   the character is not found then returns entire string
487 
488   Not Collective, No Fortran Support
489 
490   Input Parameters:
491 + a - pointer to string
492 - b - character
493 
494   Output Parameter:
495 . c - one past location of `b` in `a`, or `a` if `b` was not found
496 
497   Level: intermediate
498 
499 .seealso: `PetscStrchr()`, `PetscTokenCreate()`, `PetscStrendswith()`, `PetscStrbeginsswith()`
500 @*/
501 static inline PetscErrorCode PetscStrrchr(const char a[], char b, char *c[])
502 {
503   PetscFunctionBegin;
504   PetscAssertPointer_Private(a, 1);
505   PetscAssertPointer_Private(c, 3);
506 #if PetscHasBuiltin(__builtin_strrchr)
507   *c = (char *)__builtin_strrchr(a, b);
508 #else
509   *c = (char *)strrchr(a, b);
510 #endif
511   if (!*c) *c = (char *)a;
512   else *c = *c + 1;
513   PetscFunctionReturn(PETSC_SUCCESS);
514 }
515 
516 /*@C
517   PetscStrendswith - Determines if a string ends with a certain string
518 
519   Not Collective, No Fortran Support
520 
521   Input Parameters:
522 + a - string to search
523 - b - string to end with
524 
525   Output Parameter:
526 . flg - `PETSC_TRUE` if `a` ends with `b`, `PETSC_FALSE` otherwise
527 
528   Level: intermediate
529 
530   Note:
531   Both `a` and `b` may be `NULL` (in which case `flg` is set to `PETSC_FALSE`) bot not either.
532 
533 .seealso: `PetscStrendswithwhich()`, `PetscStrbeginswith()`, `PetscStrtoupper`,
534           `PetscStrtolower()`, `PetscStrrchr()`, `PetscStrchr()`, `PetscStrncmp()`, `PetscStrlen()`,
535           `PetscStrcmp()`
536 @*/
537 static inline PetscErrorCode PetscStrendswith(const char a[], const char b[], PetscBool *flg)
538 {
539   size_t na = 0, nb = 0;
540 
541   PetscFunctionBegin;
542   PetscAssertPointer_Private(flg, 3);
543   // do this here to silence stupid "may be used uninitialized"" warnings
544   *flg = PETSC_FALSE;
545   PetscCall(PetscStrlen(a, &na));
546   PetscCall(PetscStrlen(b, &nb));
547   if (na >= nb) {
548 #if PetscHasBuiltin(__builtin_memcmp)
549     *flg = __builtin_memcmp(b, a + (na - nb), nb) == 0 ? PETSC_TRUE : PETSC_FALSE;
550 #else
551     *flg = memcmp(b, a + (na - nb), nb) == 0 ? PETSC_TRUE : PETSC_FALSE;
552 #endif
553   }
554   PetscFunctionReturn(PETSC_SUCCESS);
555 }
556 
557 /*@C
558   PetscStrbeginswith - Determines if a string begins with a certain string
559 
560   Not Collective, No Fortran Support
561 
562   Input Parameters:
563 + a - string to search
564 - b - string to begin with
565 
566   Output Parameter:
567 . flg - `PETSC_TRUE` if `a` begins with `b`, `PETSC_FALSE` otherwise
568 
569   Level: intermediate
570 
571   Notes:
572   Both `a` and `b` may be `NULL` (in which case `flg` is set to `PETSC_FALSE`) but not
573   either.
574 
575   `a` and `b` may point to the same string.
576 
577 .seealso: `PetscStrendswithwhich()`, `PetscStrendswith()`, `PetscStrtoupper`,
578           `PetscStrtolower()`, `PetscStrrchr()`, `PetscStrchr()`, `PetscStrncmp()`, `PetscStrlen()`,
579           `PetscStrcmp()`
580 @*/
581 static inline PetscErrorCode PetscStrbeginswith(const char a[], const char b[], PetscBool *flg)
582 {
583   size_t len = 0;
584 
585   PetscFunctionBegin;
586   PetscAssertPointer_Private(flg, 3);
587   // do this here to silence stupid "may be used uninitialized"" warnings
588   *flg = PETSC_FALSE;
589   PetscCall(PetscStrlen(b, &len));
590   PetscCall(PetscStrncmp(a, b, len, flg));
591   PetscFunctionReturn(PETSC_SUCCESS);
592 }
593 
594 #undef PetscAssertPointer_Private
595 
596 /*@C
597    PetscMemmove - Copies `n` bytes, beginning at location `b`, to the space
598    beginning at location `a`. Copying  between regions that overlap will
599    take place correctly. Use `PetscMemcpy()` if the locations do not overlap
600 
601    Not Collective, No Fortran Support
602 
603    Input Parameters:
604 +  b - pointer to initial memory space
605 .  a - pointer to copy space
606 -  n - length (in bytes) of space to copy
607 
608    Level: intermediate
609 
610    Notes:
611    `PetscArraymove()` is preferred
612 
613    This routine is analogous to `memmove()`.
614 
615 .seealso: `PetscMemcpy()`, `PetscMemcmp()`, `PetscArrayzero()`, `PetscMemzero()`, `PetscArraycmp()`, `PetscArraycpy()`, `PetscStrallocpy()`,
616           `PetscArraymove()`
617 @*/
618 static inline PetscErrorCode PetscMemmove(void *a, const void *b, size_t n)
619 {
620   PetscFunctionBegin;
621   if (PetscUnlikely((n == 0) || (a == b))) PetscFunctionReturn(PETSC_SUCCESS);
622   PetscAssert(a, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Trying to copy %zu bytes to null pointer (Argument #1)", n);
623   PetscAssert(b, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Trying to copy %zu bytes from a null pointer (Argument #2)", n);
624 #if PetscDefined(HAVE_MEMMOVE)
625   memmove((char *)a, (const char *)b, n);
626 #else
627   if (a < b) {
628     if ((char *)a <= (char *)b - n) {
629       memcpy(a, b, n);
630     } else {
631       const size_t ptr_diff = (size_t)((char *)b - (char *)a);
632 
633       memcpy(a, b, ptr_diff);
634       PetscCall(PetscMemmove((void *)b, (char *)b + ptr_diff, n - ptr_diff));
635     }
636   } else {
637     if ((char *)b <= (char *)a - n) {
638       memcpy(a, b, n);
639     } else {
640       const size_t ptr_diff = (size_t)((char *)a - (char *)b);
641 
642       memcpy((void *)((char *)b + n), (char *)b + (n - ptr_diff), ptr_diff);
643       PetscCall(PetscMemmove(a, b, n - ptr_diff));
644     }
645   }
646 #endif
647   PetscFunctionReturn(PETSC_SUCCESS);
648 }
649 
650 /*@C
651    PetscMemcpy - Copies `n` bytes, beginning at location `b`, to the space
652    beginning at location `a`. The two memory regions CANNOT overlap, use
653    `PetscMemmove()` in that case.
654 
655    Not Collective, No Fortran Support
656 
657    Input Parameters:
658 +  b - pointer to initial memory space
659 -  n - length (in bytes) of space to copy
660 
661    Output Parameter:
662 .  a - pointer to copy space
663 
664    Level: intermediate
665 
666    Compile Options\:
667 +  `PETSC_PREFER_DCOPY_FOR_MEMCPY` - cause the BLAS `dcopy()` routine to be used for memory copies on double precision values.
668 .  `PETSC_PREFER_COPY_FOR_MEMCPY` - cause C code to be used for memory copies on double precision values.
669 -  `PETSC_PREFER_FORTRAN_FORMEMCPY` - cause Fortran code to be used for memory copies on double precision values.
670 
671    Notes:
672    Prefer `PetscArraycpy()`
673 
674    This routine is analogous to `memcpy()`.
675 
676 .seealso: `PetscMemzero()`, `PetscMemcmp()`, `PetscArrayzero()`, `PetscArraycmp()`, `PetscArraycpy()`, `PetscMemmove()`, `PetscStrallocpy()`
677 @*/
678 static inline PetscErrorCode PetscMemcpy(void *a, const void *b, size_t n)
679 {
680   const PETSC_UINTPTR_T al = (PETSC_UINTPTR_T)a;
681   const PETSC_UINTPTR_T bl = (PETSC_UINTPTR_T)b;
682 
683   PetscFunctionBegin;
684   if (PetscUnlikely((n == 0) || (a == b))) PetscFunctionReturn(PETSC_SUCCESS);
685   PetscAssert(a, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Trying to copy %zu bytes to a null pointer (Argument #1)", n);
686   PetscAssert(b, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Trying to copy %zu bytes from a null pointer (Argument #2)", n);
687   PetscAssert(!(((al > bl) && (al - bl) < n) || (bl - al) < n), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Memory regions overlap: either use PetscMemmove(), or make sure your copy regions and lengths are correct. Length (bytes) %zu first address %" PRIxPTR " second address %" PRIxPTR, n, al, bl);
688   if (PetscDefined(PREFER_DCOPY_FOR_MEMCPY) || PetscDefined(PREFER_COPY_FOR_MEMCPY) || PetscDefined(PREFER_FORTRAN_FORMEMCPY)) {
689     if (!(al % sizeof(PetscScalar)) && !(n % sizeof(PetscScalar))) {
690       const size_t       scalar_len = n / sizeof(PetscScalar);
691       const PetscScalar *x          = (PetscScalar *)b;
692       PetscScalar       *y          = (PetscScalar *)a;
693 
694 #if PetscDefined(PREFER_DCOPY_FOR_MEMCPY)
695       {
696         const PetscBLASInt one = 1;
697         PetscBLASInt       blen;
698 
699         PetscCall(PetscBLASIntCast(scalar_len, &blen));
700         PetscCallBLAS("BLAScopy", BLAScopy_(&blen, x, &one, y, &one));
701       }
702 #elif PetscDefined(PREFER_FORTRAN_FORMEMCPY)
703       fortrancopy_(&scalar_len, x, y);
704 #else
705       for (size_t i = 0; i < scalar_len; i++) y[i] = x[i];
706 #endif
707       PetscFunctionReturn(PETSC_SUCCESS);
708     }
709   }
710   memcpy(a, b, n);
711   PetscFunctionReturn(PETSC_SUCCESS);
712 }
713 
714 /*@C
715    PetscMemzero - Zeros the specified memory.
716 
717    Not Collective, No Fortran Support
718 
719    Input Parameters:
720 +  a - pointer to beginning memory location
721 -  n - length (in bytes) of memory to initialize
722 
723    Level: intermediate
724 
725    Compile Option:
726    `PETSC_PREFER_BZERO` - on certain machines (the IBM RS6000) the bzero() routine happens
727    to be faster than the memset() routine. This flag causes the bzero() routine to be used.
728 
729    Note:
730    Prefer `PetscArrayzero()`
731 
732 .seealso: `PetscMemcpy()`, `PetscMemcmp()`, `PetscArrayzero()`, `PetscArraycmp()`, `PetscArraycpy()`, `PetscMemmove()`, `PetscStrallocpy()`
733 @*/
734 static inline PetscErrorCode PetscMemzero(void *a, size_t n)
735 {
736   PetscFunctionBegin;
737   if (PetscUnlikely(n == 0)) PetscFunctionReturn(PETSC_SUCCESS);
738   PetscAssert(a, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Trying to zero %zu bytes at a null pointer", n);
739   if (PetscDefined(PREFER_ZERO_FOR_MEMZERO) || PetscDefined(PREFER_FORTRAN_FOR_MEMZERO)) {
740     if (!(((PETSC_UINTPTR_T)a) % sizeof(PetscScalar)) && !(n % sizeof(PetscScalar))) {
741       const size_t scalar_len = n / sizeof(PetscScalar);
742       PetscScalar *x          = (PetscScalar *)a;
743 
744       if (PetscDefined(PREFER_ZERO_FOR_MEMZERO)) {
745         for (size_t i = 0; i < scalar_len; ++i) x[i] = 0;
746       } else {
747 #if PetscDefined(PREFER_FORTRAN_FOR_MEMZERO)
748         fortranzero_(&scalar_len, x);
749 #else
750         (void)scalar_len;
751         (void)x;
752 #endif
753       }
754       PetscFunctionReturn(PETSC_SUCCESS);
755     }
756   }
757 #if PetscDefined(PREFER_BZERO)
758   bzero(a, n);
759 #else
760   memset(a, 0, n);
761 #endif
762   PetscFunctionReturn(PETSC_SUCCESS);
763 }
764 
765 /*MC
766    PetscArraycmp - Compares two arrays in memory.
767 
768    Synopsis:
769     #include <petscstring.h>
770     PetscErrorCode PetscArraycmp(const anytype *str1, const anytype *str2, size_t cnt, PetscBool *e)
771 
772    Not Collective
773 
774    Input Parameters:
775 +  str1 - First array
776 .  str2 - Second array
777 -  cnt  - Count of the array, not in bytes, but number of entries in the arrays
778 
779    Output Parameter:
780 .   e - `PETSC_TRUE` if equal else `PETSC_FALSE`.
781 
782    Level: intermediate
783 
784    Notes:
785    This routine is a preferred replacement to `PetscMemcmp()`
786 
787    The arrays must be of the same type
788 
789 .seealso: `PetscMemcpy()`, `PetscMemcmp()`, `PetscArrayzero()`, `PetscMemzero()`, `PetscArraycpy()`, `PetscMemmove()`, `PetscStrallocpy()`,
790           `PetscArraymove()`
791 M*/
792 #define PetscArraycmp(str1, str2, cnt, e) ((sizeof(*(str1)) == sizeof(*(str2))) ? PetscMemcmp((str1), (str2), (size_t)(cnt) * sizeof(*(str1)), (e)) : PETSC_ERR_ARG_SIZ)
793 
794 /*MC
795    PetscArraymove - Copies from one array in memory to another, the arrays may overlap. Use `PetscArraycpy()` when the arrays
796                     do not overlap
797 
798    Synopsis:
799     #include <petscstring.h>
800     PetscErrorCode PetscArraymove(anytype *str1, const anytype *str2, size_t cnt)
801 
802    Not Collective
803 
804    Input Parameters:
805 +  str1 - First array
806 .  str2 - Second array
807 -  cnt  - Count of the array, not in bytes, but number of entries in the arrays
808 
809    Level: intermediate
810 
811    Notes:
812    This routine is a preferred replacement to `PetscMemmove()`
813 
814    The arrays must be of the same type
815 
816 .seealso: `PetscMemcpy()`, `PetscMemcmp()`, `PetscArrayzero()`, `PetscMemzero()`, `PetscArraycpy()`, `PetscMemmove()`, `PetscArraycmp()`, `PetscStrallocpy()`
817 M*/
818 #define PetscArraymove(str1, str2, cnt) ((sizeof(*(str1)) == sizeof(*(str2))) ? PetscMemmove((str1), (str2), (size_t)(cnt) * sizeof(*(str1))) : PETSC_ERR_ARG_SIZ)
819 
820 /*MC
821    PetscArraycpy - Copies from one array in memory to another
822 
823    Synopsis:
824     #include <petscstring.h>
825     PetscErrorCode PetscArraycpy(anytype *str1, const anytype *str2, size_t cnt)
826 
827    Not Collective
828 
829    Input Parameters:
830 +  str1 - First array (destination)
831 .  str2 - Second array (source)
832 -  cnt  - Count of the array, not in bytes, but number of entries in the arrays
833 
834    Level: intermediate
835 
836    Notes:
837    This routine is a preferred replacement to `PetscMemcpy()`
838 
839    The arrays must be of the same type
840 
841 .seealso: `PetscMemcpy()`, `PetscMemcmp()`, `PetscArrayzero()`, `PetscMemzero()`, `PetscArraymove()`, `PetscMemmove()`, `PetscArraycmp()`, `PetscStrallocpy()`
842 M*/
843 #define PetscArraycpy(str1, str2, cnt) ((sizeof(*(str1)) == sizeof(*(str2))) ? PetscMemcpy((str1), (str2), (size_t)(cnt) * sizeof(*(str1))) : PETSC_ERR_ARG_SIZ)
844 
845 /*MC
846    PetscArrayzero - Zeros an array in memory.
847 
848    Synopsis:
849     #include <petscstring.h>
850     PetscErrorCode PetscArrayzero(anytype *str1, size_t cnt)
851 
852    Not Collective
853 
854    Input Parameters:
855 +  str1 - array
856 -  cnt  - Count of the array, not in bytes, but number of entries in the array
857 
858    Level: intermediate
859 
860    Note:
861    This routine is a preferred replacement to `PetscMemzero()`
862 
863 .seealso: `PetscMemcpy()`, `PetscMemcmp()`, `PetscMemzero()`, `PetscArraycmp()`, `PetscArraycpy()`, `PetscMemmove()`, `PetscStrallocpy()`, `PetscArraymove()`
864 M*/
865 #define PetscArrayzero(str1, cnt) PetscMemzero((str1), ((size_t)(cnt)) * sizeof(*(str1)))
866