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