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