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