#pragma once #include #include /* for PetscDefined() error checking */ /* SUBMANSEC = Sys */ #if defined(__cplusplus) #if __cplusplus <= 201103L #define PETSC_CPP_VERSION 11 #elif __cplusplus <= 201402L #define PETSC_CPP_VERSION 14 #elif __cplusplus <= 201703L #define PETSC_CPP_VERSION 17 #elif __cplusplus <= 202002L #define PETSC_CPP_VERSION 20 #else #define PETSC_CPP_VERSION 22 // current year, or date of c++2b ratification #endif #endif // __cplusplus #ifndef PETSC_CPP_VERSION #define PETSC_CPP_VERSION 0 #endif #if defined(__STDC_VERSION__) #if __STDC_VERSION__ <= 199901L // C99 except that 99 is >= 11 or 17 so we shorten it to 9 instead #define PETSC_C_VERSION 9 #elif __STDC_VERSION__ <= 201112L #define PETSC_C_VERSION 11 #elif __STDC_VERSION__ <= 201710L #define PETSC_C_VERSION 17 #else #define PETSC_C_VERSION 22 // current year, or date of c2b ratification #endif #endif // __STDC_VERSION__ #ifndef PETSC_C_VERSION #define PETSC_C_VERSION 0 #endif /* ========================================================================== */ /* This facilitates using the C version of PETSc from C++ and the C++ version from C. */ #if defined(__cplusplus) #define PETSC_FUNCTION_NAME PETSC_FUNCTION_NAME_CXX #else #define PETSC_FUNCTION_NAME PETSC_FUNCTION_NAME_C #endif /* ========================================================================== */ /* Since PETSc manages its own extern "C" handling users should never include PETSc include * files within extern "C". This will generate a compiler error if a user does put the include * file within an extern "C". */ #if defined(__cplusplus) void assert_never_put_petsc_headers_inside_an_extern_c(int); void assert_never_put_petsc_headers_inside_an_extern_c(double); #endif #if defined(__cplusplus) #define PETSC_RESTRICT PETSC_CXX_RESTRICT #else #define PETSC_RESTRICT restrict #endif #define PETSC_INLINE PETSC_DEPRECATED_MACRO(3, 17, 0, "inline", ) inline #define PETSC_STATIC_INLINE PETSC_DEPRECATED_MACRO(3, 17, 0, "static inline", ) static inline #if defined(_WIN32) && defined(PETSC_USE_SHARED_LIBRARIES) /* For Win32 shared libraries */ #define PETSC_DLLEXPORT __declspec(dllexport) #define PETSC_DLLIMPORT __declspec(dllimport) #define PETSC_VISIBILITY_INTERNAL #elif defined(__cplusplus) && defined(PETSC_USE_VISIBILITY_CXX) #define PETSC_DLLEXPORT __attribute__((visibility("default"))) #define PETSC_DLLIMPORT __attribute__((visibility("default"))) #define PETSC_VISIBILITY_INTERNAL __attribute__((visibility("hidden"))) #elif !defined(__cplusplus) && defined(PETSC_USE_VISIBILITY_C) #define PETSC_DLLEXPORT __attribute__((visibility("default"))) #define PETSC_DLLIMPORT __attribute__((visibility("default"))) #define PETSC_VISIBILITY_INTERNAL __attribute__((visibility("hidden"))) #else #define PETSC_DLLEXPORT #define PETSC_DLLIMPORT #define PETSC_VISIBILITY_INTERNAL #endif #if defined(petsc_EXPORTS) /* CMake defines this when building the shared library */ #define PETSC_VISIBILITY_PUBLIC PETSC_DLLEXPORT #else /* Win32 users need this to import symbols from petsc.dll */ #define PETSC_VISIBILITY_PUBLIC PETSC_DLLIMPORT #endif /* Functions tagged with PETSC_EXTERN in the header files are always defined as extern "C" when * compiled with C++ so they may be used from C and are always visible in the shared libraries */ #if defined(__cplusplus) #define PETSC_EXTERN extern "C" PETSC_VISIBILITY_PUBLIC #define PETSC_EXTERN_TYPEDEF extern "C" #define PETSC_INTERN extern "C" PETSC_VISIBILITY_INTERNAL #else #define PETSC_EXTERN extern PETSC_VISIBILITY_PUBLIC #define PETSC_EXTERN_TYPEDEF #define PETSC_INTERN extern PETSC_VISIBILITY_INTERNAL #endif #if defined(PETSC_USE_SINGLE_LIBRARY) #define PETSC_SINGLE_LIBRARY_VISIBILITY_INTERNAL PETSC_VISIBILITY_INTERNAL #define PETSC_SINGLE_LIBRARY_INTERN PETSC_INTERN #else #define PETSC_SINGLE_LIBRARY_VISIBILITY_INTERNAL PETSC_VISIBILITY_PUBLIC #define PETSC_SINGLE_LIBRARY_INTERN PETSC_EXTERN #endif #if !defined(__has_feature) #define __has_feature(x) 0 #endif /*MC PetscHasAttribute - Determine whether a particular __attribute__ is supported by the compiler Synopsis: #include int PetscHasAttribute(name) Input Parameter: . name - The name of the attribute to test Level: intermediate Notes: name should be identical to what you might pass to the __attribute__ declaration itself -- plain, unbroken text. As `PetscHasAttribute()` is wrapper over the function-like macro `__has_attribute()`, the exact type and value returned is implementation defined. In practice however, it usually returns `1` if the attribute is supported and `0` if the attribute is not supported. Example Usage: Typical usage is using the preprocessor .vb #if PetscHasAttribute(always_inline) # define MY_ALWAYS_INLINE __attribute__((always_inline)) #else # define MY_ALWAYS_INLINE #endif void foo(void) MY_ALWAYS_INLINE; .ve but it can also be used in regular code .vb if (PetscHasAttribute(some_attribute)) { foo(); } else { bar(); } .ve .seealso: `PetscHasBuiltin()`, `PetscDefined()`, `PetscLikely()`, `PetscUnlikely()`, `PETSC_ATTRIBUTE_FORMAT`, `PETSC_ATTRIBUTE_MAY_ALIAS` M*/ #if !defined(__has_attribute) #define __has_attribute(x) 0 #endif #define PetscHasAttribute(name) __has_attribute(name) /*MC PetscHasBuiltin - Determine whether a particular builtin method is supported by the compiler Synopsis: #include int PetscHasBuiltin(name) Input Parameter: . name - the name of the builtin routine Level: intermediate Notes: Evaluates to `1` if the builtin is supported and `0` otherwise. Note the term "evaluates" (vs "expands") is deliberate; even though `PetscHasBuiltin()` is a macro the underlying detector is itself is a compiler extension with implementation-defined return type and semantics. Some compilers implement it as a macro, others as a compiler function. In practice however, all supporting compilers return an integer boolean as described. Example Usage: Typical usage is in preprocessor directives .vb #if PetscHasBuiltin(__builtin_trap) __builtin_trap(); #else abort(); #endif .ve But it may also be used in regular code .vb if (PetscHasBuiltin(__builtin_alloca)) { foo(); } else { bar(); } .ve .seealso: `PetscHasAttribute()`, `PetscAssume()` M*/ #if !defined(__has_builtin) #define __has_builtin(x) 0 #endif // clangs __has_builtin prior to clang 10 did not properly handle non-function builtins such as // __builtin_types_compatible_p which take types or other non-functiony things as // arguments. The correct way to detect these then is to use __is_identifier (also a clang // extension). GCC has always worked as expected. see https://stackoverflow.com/a/45043153 #if defined(__clang__) && defined(__clang_major__) && (__clang_major__ < 10) && defined(__is_identifier) #define PetscHasBuiltin(name) __is_identifier(name) #else #define PetscHasBuiltin(name) __has_builtin(name) #endif #if !defined(PETSC_SKIP_ATTRIBUTE_MPI_TYPE_TAG) /* Support for Clang (>=3.2) matching type tag arguments with void* buffer types. This allows the compiler to detect cases where the MPI datatype argument passed to a MPI routine does not match the actual type of the argument being passed in */ #if PetscHasAttribute(pointer_with_type_tag) #define PETSC_ATTRIBUTE_MPI_POINTER_WITH_TYPE(bufno, typeno) __attribute__((pointer_with_type_tag(MPI, bufno, typeno))) #endif #if PetscHasAttribute(type_tag_for_datatype) #define PETSC_ATTRIBUTE_MPI_TYPE_TAG(type) __attribute__((type_tag_for_datatype(MPI, type))) #define PETSC_ATTRIBUTE_MPI_TYPE_TAG_LAYOUT_COMPATIBLE(type) __attribute__((type_tag_for_datatype(MPI, type, layout_compatible))) #endif #endif // PETSC_SKIP_ATTRIBUTE_MPI_TYPE_TAG #ifndef PETSC_ATTRIBUTE_MPI_POINTER_WITH_TYPE #define PETSC_ATTRIBUTE_MPI_POINTER_WITH_TYPE(bufno, typeno) #endif #ifndef PETSC_ATTRIBUTE_MPI_TYPE_TAG #define PETSC_ATTRIBUTE_MPI_TYPE_TAG(type) #endif #ifndef PETSC_ATTRIBUTE_MPI_TYPE_TAG_LAYOUT_COMPATIBLE #define PETSC_ATTRIBUTE_MPI_TYPE_TAG_LAYOUT_COMPATIBLE(type) #endif /*MC PETSC_ATTRIBUTE_FORMAT - Indicate to the compiler that specified arguments should be treated as format specifiers and checked for validity Synopsis: #include PETSC_ATTRIBUTE_FORMAT(int strIdx, int vaArgIdx) Input Parameters: + strIdx - The (1-indexed) location of the format string in the argument list - vaArgIdx - The (1-indexed) location of the first formattable argument in the argument list Level: developer Notes: This function attribute causes the compiler to issue warnings when the format specifier does not match the type of the variable that will be formatted, or when there exists a mismatch between the number of format specifiers and variables to be formatted. It is safe to use this macro if your compiler does not support format specifier checking (though this is exceeedingly rare). Both `strIdx` and `vaArgIdx` must be compile-time constant integer literals and cannot have the same value. The arguments to be formatted (and therefore checked by the compiler) must be "contiguous" in the argument list, that is, there is no way to indicate gaps which should not be checked. Definition is suppressed by defining `PETSC_SKIP_ATTRIBUTE_FORMAT` prior to including PETSc header files. In this case the macro will expand empty. Example Usage: .vb // format string is 2nd argument, variable argument list containing args is 3rd argument void my_printf(void *obj, const char *fmt_string, ...) PETSC_ATTRIBUTE_FORMAT(2,3) int x = 1; double y = 50.0; my_printf(NULL,"%g",x); // WARNING, format specifier does not match for 'int'! my_printf(NULL,"%d",x,y); // WARNING, more arguments than format specifiers! my_printf(NULL,"%d %g",x,y); // OK .ve .seealso: `PETSC_ATTRIBUTE_COLD`, `PetscHasAttribute()` M*/ #if PetscHasAttribute(format) && !defined(PETSC_SKIP_ATTRIBUTE_FORMAT) #define PETSC_ATTRIBUTE_FORMAT(strIdx, vaArgIdx) __attribute__((format(printf, strIdx, vaArgIdx))) #else #define PETSC_ATTRIBUTE_FORMAT(strIdx, vaArgIdx) #endif /*MC PETSC_ATTRIBUTE_COLD - Indicate to the compiler that a function is very unlikely to be executed Level: intermediate Notes: The marked function is often optimized for size rather than speed and may be grouped alongside other equally frigid routines improving code locality of lukewarm or hotter parts of program. The paths leading to cold functions are usually automatically marked as unlikely by the compiler. It may thus be useful to mark functions used to handle unlikely conditions -- such as error handlers -- as cold to improve optimization of the surrounding temperate functions. Example Usage: .vb void my_error_handler(...) PETSC_ATTRIBUTE_COLD; if (temperature < 0) { return my_error_handler(...); // chilly! } .ve .seealso: `PetscUnlikely()`, `PetscUnlikelyDebug()`, `PetscLikely()`, `PetscLikelyDebug()`, `PetscUnreachable()`, `PETSC_ATTRIBUTE_FORMAT` M*/ #if PetscHasAttribute(__cold__) #define PETSC_ATTRIBUTE_COLD __attribute__((__cold__)) #elif PetscHasAttribute(cold) /* some implementations (old gcc) use no underscores */ #define PETSC_ATTRIBUTE_COLD __attribute__((cold)) #else #define PETSC_ATTRIBUTE_COLD #endif /*MC PETSC_ATTRIBUTE_MAY_ALIAS - Indicate to the compiler that a type is not subjected to type-based alias analysis, but is instead assumed to be able to alias any other type of objects Example Usage: .vb typedef PetscScalar PetscScalarAlias PETSC_ATTRIBUTE_MAY_ALIAS; PetscReal *pointer; PetscScalarAlias *other_pointer = reinterpret_cast(pointer); .ve Level: advanced .seealso: `PetscHasAttribute()` M*/ #if PetscHasAttribute(may_alias) && !defined(PETSC_SKIP_ATTRIBUTE_MAY_ALIAS) #define PETSC_ATTRIBUTE_MAY_ALIAS __attribute__((may_alias)) #else #define PETSC_ATTRIBUTE_MAY_ALIAS #endif /*MC PETSC_NULLPTR - Standard way of indicating a null value or pointer No Fortran Support Level: beginner Notes: Equivalent to `NULL` in C source, and `nullptr` in C++ source. Note that for the purposes of interoperability between C and C++, setting a pointer to `PETSC_NULLPTR` in C++ is functonially equivalent to setting the same pointer to `NULL` in C. That is to say that the following expressions are equivalent\: .vb ptr == PETSC_NULLPTR ptr == NULL ptr == 0 !ptr ptr = PETSC_NULLPTR ptr = NULL ptr = 0 .ve and for completeness' sake\: .vb PETSC_NULLPTR == NULL .ve Example Usage: .vb // may be used in place of '\0' or other such terminators in the definition of char arrays const char *const MyEnumTypes[] = { "foo", "bar", PETSC_NULLPTR }; // may be used to nullify objects PetscObject obj = PETSC_NULLPTR; // may be used in any function expecting NULL PetscInfo(PETSC_NULLPTR,"Lorem Ipsum Dolor"); .ve Developer Notes: `PETSC_NULLPTR` must be used in place of `NULL` in all C++ source files. Using `NULL` in source files compiled with a C++ compiler may lead to unexpected side-effects in function overload resolution and/or compiler warnings. .seealso: `PETSC_CONSTEXPR_14`, `PETSC_NODISCARD` M*/ /*MC PETSC_CONSTEXPR_14 - C++14 constexpr No Fortran Support Level: beginner Notes: Equivalent to `constexpr` when using a C++ compiler that supports C++14. Expands to nothing if the C++ compiler does not support C++14 or when not compiling with a C++ compiler. Note that this cannot be used in cases where an empty expansion would result in invalid code. It is safe to use this in C source files. Example Usage: .vb PETSC_CONSTEXPR_14 int factorial(int n) { int r = 1; do { r *= n; } while (--n); return r; } .ve .seealso: `PETSC_NULLPTR`, `PETSC_NODISCARD` M*/ /*MC PETSC_NODISCARD - Mark the return value of a function as non-discardable Not available in Fortran Level: beginner Notes: Hints to the compiler that the return value of a function must be captured. A diagnostic may (but is not required to) be emitted if the value is discarded. It is safe to use this in both C and C++ source files. In this context "captured" means assigning the return value of a function to a named variable or casting it to `void`. Between the two, assigning to a named variable is the most portable way of silencing any warnings, since `PETSC_NODISCARD` may expand to GCC's `__attribute__((warn_unused_result))` which will still emit warnings when casting results to `void`. Example Usage: .vb class Foo { int x; public: PETSC_NODISCARD Foo(int y) : x(y) { } }; PETSC_NODISCARD int factorial(int n) { return n <= 1 ? 1 : (n * factorial(n - 1)); } factorial(10); // Warning: ignoring return value of function declared 'nodiscard' auto x = factorial(10); // OK, capturing return value (void)factorial(10); // Maybe OK, casting to void auto y = factorial(10); // OK, capturing in y (and casting y to void to silence (void)y; // set-but-not-used warnings) Foo(x); // Warning: Ignoring temporary created by a constructor declared 'nodiscard' auto f = Foo(x); // OK, capturing constructed object (void)Foo(x); // Maybe OK, casting to void auto g = Foo(x); // OK, capturing in g (and casting g to void to silence set-but-not-used (void)g; // warnings) .ve .seealso: `PETSC_NULLPTR`, `PETSC_CONSTEXPR_14` M*/ /* C++11 features */ #if defined(__cplusplus) || (PETSC_C_VERSION >= 23) #define PETSC_NULLPTR nullptr #else #define PETSC_NULLPTR NULL #endif /* C++14 features */ #if PETSC_CPP_VERSION >= 14 #define PETSC_CONSTEXPR_14 constexpr #else #define PETSC_CONSTEXPR_14 #endif /* C++17 features */ #if PETSC_CPP_VERSION >= 17 #define PETSC_CONSTEXPR_17 constexpr #else #define PETSC_CONSTEXPR_17 #endif #if (PETSC_CPP_VERSION >= 17) || (PETSC_C_VERSION >= 23) #define PETSC_NODISCARD [[nodiscard]] #elif PetscHasAttribute(warn_unused_result) #define PETSC_NODISCARD __attribute__((warn_unused_result)) #else #define PETSC_NODISCARD #endif #include #define PETSC_AUTHOR_INFO " The PETSc Team\n petsc-maint@mcs.anl.gov\n https://petsc.org/\n" /* designated initializers since C99 and C++20, MSVC never supports them though */ #if defined(_MSC_VER) || (defined(__cplusplus) && (PETSC_CPP_VERSION < 20)) #define PetscDesignatedInitializer(name, ...) __VA_ARGS__ #else #define PetscDesignatedInitializer(name, ...) .name = __VA_ARGS__ #endif /*MC PetscUnlikely - Hints the compiler that the given condition is usually false Synopsis: #include bool PetscUnlikely(bool cond) Not Collective; No Fortran Support Input Parameter: . cond - Boolean expression Level: advanced Note: This returns the same truth value, it is only a hint to compilers that the result of cond is unlikely to be true. Example usage: .vb if (PetscUnlikely(cond)) { foo(); // cold path } else { bar(); // hot path } .ve .seealso: `PetscLikely()`, `PetscUnlikelyDebug()`, `PetscCall()`, `PetscDefined()`, `PetscHasAttribute()`, `PETSC_ATTRIBUTE_COLD` M*/ /*MC PetscLikely - Hints the compiler that the given condition is usually true Synopsis: #include bool PetscLikely(bool cond) Not Collective; No Fortran Support Input Parameter: . cond - Boolean expression Level: advanced Note: This returns the same truth value, it is only a hint to compilers that the result of cond is likely to be true. Example usage: .vb if (PetscLikely(cond)) { foo(); // hot path } else { bar(); // cold path } .ve .seealso: `PetscUnlikely()`, `PetscDefined()`, `PetscHasAttribute()` `PETSC_ATTRIBUTE_COLD` M*/ #if defined(PETSC_HAVE_BUILTIN_EXPECT) #define PetscUnlikely(cond) __builtin_expect(!!(cond), 0) #define PetscLikely(cond) __builtin_expect(!!(cond), 1) #else #define PetscUnlikely(cond) (cond) #define PetscLikely(cond) (cond) #endif /*MC PetscUnreachable - Indicate to the compiler that a code-path is logically unreachable Synopsis: #include void PetscUnreachable(void) Level: advanced Note: Indicates to the compiler (usually via some built-in) that a particular code path is always unreachable. Behavior is undefined if this function is ever executed, the user can expect an unceremonious crash. Example usage: Useful in situations such as switches over enums where not all enumeration values are explicitly covered by the switch .vb int foo(Color c) { // it is known to programmer (or checked previously) that c is either RED or GREEN // but compiler may not be able to deduce this and/or emit spurious warnings switch (c) { case RED: return bar(); case GREEN: return baz(); default: PetscUnreachable(); // program is ill-formed if executed } } .ve .seealso: `SETERRABORT()`, `PETSCABORT()`, `PETSC_ATTRIBUTE_COLD`, `PetscAssume()` M*/ #if PETSC_CPP_VERSION >= 23 #include #define PetscUnreachable() std::unreachable() #elif defined(__GNUC__) /* GCC 4.8+, Clang, Intel and other compilers compatible with GCC (-std=c++0x or above) */ #define PetscUnreachable() __builtin_unreachable() #elif defined(_MSC_VER) /* MSVC */ #define PetscUnreachable() __assume(0) #else /* ??? */ #define PetscUnreachable() SETERRABORT(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Code path explicitly marked as unreachable executed") #endif /*MC PetscAssume - Indicate to the compiler a condition that is defined to be true Synopsis: #include void PetscAssume(bool cond) Input Parameter: . cond - Boolean expression Level: advanced Notes: If supported by the compiler, `cond` is used to inform the optimizer of an invariant truth. The argument itself is never evaluated, so any side effects of the expression will be discarded. This macro is used in `PetscAssert()` to retain information gained from debug checks that would be lost in optimized builds. For example\: .vb PetscErrorCode foo(PetscInt x) { PetscAssert(x >= 0, ...); } .ve The assertion checks that `x` is positive when debugging is enabled (and returns from `foo()` if it is not). This implicitly informs the optimizer that `x` cannot be negative. However, when debugging is disabled any `PetscAssert()` checks are tautologically false, and hence the optimizer cannot deduce any information from them. Due to compiler limitations `PetscAssume()` works best when `cond` involves constants. Certain compilers do not yet propagate symbolic inequalities i.e.\: .vb int a, b, var_five; // BEST, all supporting compilers will understand a cannot be >= 5 PetscAssume(a < 5); // OK, some compilers may understand that a cannot be >= 5 PetscAssume(a <= b && b < 5); // WORST, most compilers will not get the memo PetscAssume(a <= b && b < var_five); .ve If the condition is violated at runtime then behavior is wholly undefined. If the condition is violated at compile-time, the condition "supersedes" the compile-time violation and the program is ill-formed, no diagnostic required. For example consider the following\: .vb PetscInt x = 0; PetscAssume(x != 0); if (x == 0) { x += 10; } else { popen("rm -rf /", "w"); } .ve Even though `x` is demonstrably `0` the compiler may opt to\: - emit an unconditional `popen("rm -rf /", "w")` - ignore `PetscAssume()` altogether and emit the correct path of `x += 10` - reformat the primary disk partition .seealso: `PetscAssert()` M*/ #if PETSC_CPP_VERSION >= 23 #define PetscAssume(...) [[assume(__VA_ARGS__)]] #elif defined(_MSC_VER) // msvc #define PetscAssume(...) __assume(__VA_ARGS__) #elif defined(__clang__) && PetscHasBuiltin(__builtin_assume) // clang #define PetscAssume(...) \ do { \ _Pragma("clang diagnostic push"); \ _Pragma("clang diagnostic ignored \"-Wassume\""); \ __builtin_assume(__VA_ARGS__); \ _Pragma("clang diagnostic pop"); \ } while (0) #else // gcc (and really old clang) // gcc does not have its own __builtin_assume() intrinsic. One could fake it via // // if (PetscUnlikely(!cond)) PetscUnreachable(); // // but this it unsavory because the side effects of cond are not guaranteed to be // discarded. Though in most circumstances gcc will optimize out the if (because any evaluation // for which cond is false would be undefined results in undefined behavior anyway) it cannot // always do so. This is especially the case for opaque or non-inline function calls: // // extern int bar(int); // // int foo(int x) { // PetscAssume(bar(x) == 2); // if (bar(x) == 2) { // return 1; // } else { // return 0; // } // } // // Here gcc would (if just using builtin_expect()) emit 2 calls to bar(). Note we still have // cond "tested" in the condition, but this is done to silence unused-but-set variable warnings #define PetscAssume(...) \ do { \ if (0 && (__VA_ARGS__)) PetscUnreachable(); \ } while (0) #endif /*MC PetscExpand - Expand macro argument Synopsis: #include PetscExpand(x) Input Parameter: . x - The preprocessor token to expand Level: beginner .seealso: `PetscStringize()`, `PetscConcat()` M*/ #define PetscExpand_(...) __VA_ARGS__ #define PetscExpand(...) PetscExpand_(__VA_ARGS__) /*MC PetscStringize - Stringize a token Synopsis: #include const char* PetscStringize(x) No Fortran Support Input Parameter: . x - The token you would like to stringize Output Parameter: . - The string representation of `x` Level: beginner Note: `PetscStringize()` expands `x` before stringizing it, if you do not wish to do so, use `PetscStringize_()` instead. Example Usage: .vb #define MY_OTHER_VAR hello there #define MY_VAR MY_OTHER_VAR PetscStringize(MY_VAR) -> "hello there" PetscStringize_(MY_VAR) -> "MY_VAR" int foo; PetscStringize(foo) -> "foo" PetscStringize_(foo) -> "foo" .ve .seealso: `PetscConcat()`, `PetscExpandToNothing()`, `PetscExpand()` M*/ #define PetscStringize_(...) #__VA_ARGS__ #define PetscStringize(...) PetscStringize_(__VA_ARGS__) /*MC PetscConcat - Concatenate two tokens Synopsis: #include PetscConcat(x, y) No Fortran Support Input Parameters: + x - First token - y - Second token Level: beginner Note: `PetscConcat()` will expand both arguments before pasting them together, use `PetscConcat_()` if you don't want to expand them. Example usage: .vb PetscConcat(hello,there) -> hellothere #define HELLO hello PetscConcat(HELLO,there) -> hellothere PetscConcat_(HELLO,there) -> HELLOthere .ve .seealso: `PetscStringize()`, `PetscExpand()` M*/ #define PetscConcat_(x, y) x##y #define PetscConcat(x, y) PetscConcat_(x, y) #define PETSC_INTERNAL_COMPL_0 1 #define PETSC_INTERNAL_COMPL_1 0 /*MC PetscCompl - Expands to the integer complement of its argument Synopsis: #include int PetscCompl(b) No Fortran Support Input Parameter: . b - Preprocessor variable, must expand to either integer literal 0 or 1 Output Parameter: . - Either integer literal 0 or 1 Level: beginner Notes: Expands to integer literal 0 if b expands to 1, or integer literal 1 if b expands to 0. Behaviour is undefined if b expands to anything else. PetscCompl() will expand its argument before returning the complement. This macro can be useful for negating `PetscDefined()` inside macros e.g. .vb #define PETSC_DONT_HAVE_FOO PetscCompl(PetscDefined(HAVE_FOO)) .ve Example usage: .vb #define MY_VAR 1 PetscCompl(MY_VAR) -> 0 #undef MY_VAR #define MY_VAR 0 PetscCompl(MY_VAR) -> 1 .ve .seealso: `PetscConcat()`, `PetscDefined()` M*/ #define PetscCompl(b) PetscConcat_(PETSC_INTERNAL_COMPL_, PetscExpand(b)) /*MC PetscDefined - Determine whether a boolean macro is defined Synopsis: #include int PetscDefined(def) No Fortran Support Input Parameter: . def - PETSc-style preprocessor variable (without PETSC_ prepended!) Output Parameter: . - Either integer literal 0 or 1 Level: intermediate Notes: `PetscDefined()` returns 1 if and only if "PETSC_ ## def" is defined (but empty) or defined to integer literal 1. In all other cases, `PetscDefined()` returns integer literal 0. Therefore this macro should not be used if its argument may be defined to a non-empty value other than 1. The prefix "PETSC_" is automatically prepended to def. To avoid prepending "PETSC_", say to add custom checks in user code, one should use `PetscDefined_()`. .vb #define FooDefined(d) PetscDefined_(PetscConcat(FOO_, d)) .ve Developer Notes: Getting something that works in C and CPP for an arg that may or may not be defined is tricky. Here, if we have "#define PETSC_HAVE_BOOGER 1" we match on the placeholder define, insert the "0," for arg1 and generate the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one). When PETSC_HAVE_BOOGER is not defined, we generate a (... 1, 0) pair, and when the last step cherry picks the 2nd arg, we get a zero. Our extra expansion via PetscDefined__take_second_expand() is needed with MSVC, which has a nonconforming implementation of variadic macros. Example Usage: Suppose you would like to call either "foo()" or "bar()" depending on whether PETSC_USE_DEBUG is defined then .vb #if PetscDefined(USE_DEBUG) foo(); #else bar(); #endif // or alternatively within normal code if (PetscDefined(USE_DEBUG)) { foo(); } else { bar(); } .ve is equivalent to .vb #if defined(PETSC_USE_DEBUG) # if MY_DETECT_EMPTY_MACRO(PETSC_USE_DEBUG) // assuming you have such a macro foo(); # elif PETSC_USE_DEBUG == 1 foo(); # else bar(); # endif #else bar(); #endif .ve .seealso: `PetscHasAttribute()`, `PetscUnlikely()`, `PetscLikely()`, `PetscConcat()`, `PetscExpandToNothing()`, `PetscCompl()` M*/ #define PetscDefined_arg_1 shift, #define PetscDefined_arg_ shift, #define PetscDefined__take_second_expanded(ignored, val, ...) val #define PetscDefined__take_second_expand(args) PetscDefined__take_second_expanded args #define PetscDefined__take_second(...) PetscDefined__take_second_expand((__VA_ARGS__)) #define PetscDefined__(arg1_or_junk) PetscDefined__take_second(arg1_or_junk 1, 0, at_) #define PetscDefined_(value) PetscDefined__(PetscConcat_(PetscDefined_arg_, value)) #define PetscDefined(def) PetscDefined_(PetscConcat(PETSC_, def)) /*MC PetscUnlikelyDebug - Hints the compiler that the given condition is usually false, eliding the check in optimized mode Synopsis: #include bool PetscUnlikelyDebug(bool cond) Not Collective; No Fortran Support Input Parameter: . cond - Boolean expression Level: advanced Note: This returns the same truth value, it is only a hint to compilers that the result of `cond` is likely to be false. When PETSc is compiled in optimized mode this will always return false. Additionally, `cond` is guaranteed to not be evaluated when PETSc is compiled in optimized mode. Example usage: This routine is shorthand for checking both the condition and whether PetscDefined(USE_DEBUG) is true. So .vb if (PetscUnlikelyDebug(cond)) { foo(); } else { bar(); } .ve is equivalent to .vb if (PetscDefined(USE_DEBUG)) { if (PetscUnlikely(cond)) { foo(); } else { bar(); } } else { bar(); } .ve .seealso: `PetscUnlikely()`, `PetscLikely()`, `PetscCall()`, `SETERRQ` M*/ #define PetscUnlikelyDebug(cond) (PetscDefined(USE_DEBUG) && PetscUnlikely(cond)) #if defined(PETSC_CLANG_STATIC_ANALYZER) // silence compiler warnings when using -pedantic, this is only used by the linter and it cares // not what ISO C allows #define PetscMacroReturns_(retexpr, ...) \ __extension__({ \ __VA_ARGS__; \ retexpr; \ }) #else #define PetscMacroReturns_(retexpr, ...) \ retexpr; \ do { \ __VA_ARGS__; \ } while (0) #endif /*MC PetscExpandToNothing - Expands to absolutely nothing Synopsis: #include void PetscExpandToNothing(...) No Fortran Support Input Parameter: . __VA_ARGS__ - Anything at all Level: beginner Note: Must have at least 1 parameter. Example usage: .vb PetscExpandToNothing(a,b,c) -> *nothing* .ve .seealso: `PetscConcat()`, `PetscDefined()`, `PetscStringize()`, `PetscExpand()` M*/ #define PetscExpandToNothing(...) /*MC PetscMacroReturns - Define a macro body that returns a value Synopsis: #include return_type PetscMacroReturns(return_type retexpr, ...) Input Parameters: + retexpr - The value or expression that the macro should return - __VA_ARGS__ - The body of the macro Level: intermediate Notes: Due to limitations of the C-preprocessor retexpr cannot depend on symbols declared in the body of the macro and should not depend on values produced as a result of the expression. The user should not assume that the result of this macro is equivalent to a single logical source line. It is not portable to use macros defined using this one in conditional or loop bodies without enclosing them in curly braces\: .vb #define FOO(arg1) PetscMacroReturns(0,arg1+=10) // returns 0 int err,x = 10; if (...) err = FOO(x); // ERROR, body of FOO() executed outside the if statement if (...) { err = FOO(x); } // OK for (...) err = FOO(x); // ERROR, body of FOO() executed outside the loop for (...) { err = FOO(x); } // OK .ve It is also not portable to use this macro directly inside function call, conditional, loop, or switch statements\: .vb extern void bar(int); int ret = FOO(x); bar(FOO(x)); // ERROR, may not compile bar(ret); // OK if (FOO(x)) // ERROR, may not compile if (ret) // OK .ve Example usage: .vb #define MY_SIMPLE_RETURNING_MACRO(arg1) PetscMacroReturns(0,arg1+=10) int x = 10; int err = MY_SIMPLE_RETURNING_MACRO(x); // err = 0, x = 20 // multiline macros allowed, but must declare with line continuation as usual #define MY_COMPLEX_RETURNING_MACRO(arg1) PetscMacroReturns(0, \ if (arg1 > 10) { \ puts("big int!"); \ } else { \ return 7355608; \ } \ ) // if retexpr contains commas, must enclose it with braces #define MY_COMPLEX_RETEXPR_MACRO_1() PetscMacroReturns(x+=10,0,body...) #define MY_COMPLEX_RETEXPR_MACRO_2() PetscMacroReturns((x+=10,0),body...) int x = 10; int y = MY_COMPLEX_RETEXPR_MACRO_1(); // ERROR, y = x = 20 not 0 int z = MY_COMPLEX_RETEXPR_MACRO_2(); // OK, y = 0, x = 20 .ve .seealso: `PetscExpand()`, `PetscConcat()`, `PetscStringize()` M*/ #define PetscMacroReturns(retexpr, ...) PetscMacroReturns_(retexpr, __VA_ARGS__) #define PetscMacroReturnStandard(...) PetscMacroReturns(PETSC_SUCCESS, __VA_ARGS__) /*MC PETSC_STATIC_ARRAY_LENGTH - Return the length of a static array Synopsis: #include size_t PETSC_STATIC_ARRAY_LENGTH(a) Input Parameter: . a - a static array of any type Output Parameter: . - the length of the array Example: .vb PetscInt a[22]; size_t sa = PETSC_STATIC_ARRAY_LENGTH(a) .ve `sa` will have a value of 22 Level: intermediate M*/ #if PETSC_CPP_VERSION >= 14 #include #include template static inline constexpr std::size_t PETSC_STATIC_ARRAY_LENGTH(const T &) noexcept { static_assert(std::is_array::value, ""); return std::extent::value - 1>::value; } #else #define PETSC_STATIC_ARRAY_LENGTH(...) (sizeof(__VA_ARGS__) / sizeof(__VA_ARGS__)[0]) #endif /* These macros allow extracting out the first argument or all but the first argument from a macro __VAR_ARGS__ INSIDE another macro. Example usage: #define mymacro(obj,...) { PETSC_FIRST_ARG((__VA_ARGS__,unused)); f(22 PETSC_REST_ARG(__VA_ARGS__)); } Note you add a dummy extra argument to __VA_ARGS__ and enclose them in an extra set of () for PETSC_FIRST_ARG() and PETSC_REST_ARG(__VA_ARGS__) automatically adds a leading comma only if there are additional arguments Reference: https://stackoverflow.com/questions/5588855/standard-alternative-to-gccs-va-args-trick */ #define PETSC_FIRST_ARG_(N, ...) N #define PETSC_FIRST_ARG(args) PETSC_FIRST_ARG_ args #define PETSC_SELECT_16TH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, ...) a16 #define PETSC_NUM(...) PETSC_SELECT_16TH(__VA_ARGS__, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway) #define PETSC_REST_HELPER_TWOORMORE(first, ...) , __VA_ARGS__ #define PETSC_REST_HELPER_ONE(first) #define PETSC_REST_HELPER2(qty, ...) PETSC_REST_HELPER_##qty(__VA_ARGS__) #define PETSC_REST_HELPER(qty, ...) PETSC_REST_HELPER2(qty, __VA_ARGS__) #define PETSC_REST_ARG(...) PETSC_REST_HELPER(PETSC_NUM(__VA_ARGS__), __VA_ARGS__) #define PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN_(name, ...) \ _Pragma(PetscStringize(name diagnostic push)) \ _Pragma(PetscStringize(name diagnostic ignored __VA_ARGS__)) #define PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END_(name) _Pragma(PetscStringize(name diagnostic pop)) #if defined(__clang__) #define PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN(...) PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN_(clang, __VA_ARGS__) #define PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END() PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END_(clang) #elif defined(__GNUC__) || defined(__GNUG__) // gcc >= 4.6.0 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40600 #define PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN(...) PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN_(GCC, __VA_ARGS__) #define PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END() PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END_(GCC) #endif #endif #ifndef PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN #define PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN(...) #define PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END(...) // only undefine these if they are not used #undef PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN_ #undef PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END_ #endif /*MC PetscPragmaOMP - Sets an OpenMP pragma to affect the next block of code Synopsis: #include int PetscPragmaOMP(name) No Fortran Support Input Parameter: . name - the OpenMP pragma, for example, `critical` or `parallel for` Level: intermediate Note: The pragma takes effect when PETSc was configured with `--with-openmp`. See `PetscPragmaUseOMPKernels()` for when PETSc was configured to use OpenMP in some of its numerical kernels. .seealso: `PetscPragmaUseOMPKernels()`, `PetscHasBuiltin()`, `PetscDefined()`, `PetscLikely()`, `PetscUnlikely()`, `PETSC_ATTRIBUTE_FORMAT`, `PETSC_ATTRIBUTE_MAY_ALIAS` M*/ #if defined(_OPENMP) #if defined(_MSC_VER) #define PetscPragmaOMP(...) __pragma(__VA_ARGS__) #else #define PetscPragmaOMP(...) _Pragma(PetscStringize(omp __VA_ARGS__)) #endif #else #define PetscPragmaOMP(...) #endif /*MC PetscPragmaUseOMPKernels - Sets an OpenMP pragma to affect the next block of code Synopsis: #include int PetscPragmaUseOMPKernels(name) No Fortran Support Input Parameter: . name - the OpenMP pragma, for example, `critical` or `parallel for` Level: intermediate Note: The pragma takes effect when PETSc was configured with `--with-openmp-kernels`. See `PetscPragmaOMP()` for when PETSc was configured with OpenMP but not to use it in its numerical kernels .seealso: `PetscPragmaOMP()`, `PetscHasBuiltin()`, `PetscDefined()`, `PetscLikely()`, `PetscUnlikely()`, `PETSC_ATTRIBUTE_FORMAT`, `PETSC_ATTRIBUTE_MAY_ALIAS` M*/ #if defined(PETSC_USE_OPENMP_KERNELS) #if defined(_MSC_VER) #define PetscPragmaUseOMPKernels(...) __pragma(__VA_ARGS__) #else #define PetscPragmaUseOMPKernels(...) _Pragma(PetscStringize(omp __VA_ARGS__)) #endif #else #define PetscPragmaUseOMPKernels(...) #endif /* PetscPragmaSIMD - from CeedPragmaSIMD */ #if defined(__NEC__) #define PetscPragmaSIMD _Pragma("_NEC ivdep") #elif defined(__INTEL_COMPILER) && !defined(_WIN32) #define PetscPragmaSIMD _Pragma("vector") #elif defined(__GNUC__) #if __GNUC__ >= 5 && !defined(__PGI) #define PetscPragmaSIMD _Pragma("GCC ivdep") #endif #elif defined(_OPENMP) && _OPENMP >= 201307 #define PetscPragmaSIMD PetscPragmaOMP(simd) #elif defined(PETSC_HAVE_CRAY_VECTOR) #define PetscPragmaSIMD _Pragma("_CRI ivdep") #endif #ifndef PetscPragmaSIMD #define PetscPragmaSIMD #endif #include #define PetscConcat6_(a, b, c, d, e, f) a##b##c##d##e##f #define PetscConcat6(a, b, c, d, e, f) PetscConcat6_(a, b, c, d, e, f) #define PETSC_DEPRECATED_IDENTIFIER_(__PETSC_DEPRECATION_MACRO__, __SILENCE_MACRO__, major, minor, subminor, replacement, ...) \ PetscIfPetscDefined(__SILENCE_MACRO__, PetscExpandToNothing, \ __PETSC_DEPRECATION_MACRO__)(PetscStringize(Use replacement (since version major.minor.subminor) instead. Silence this warning (as well as all others for this version) by defining PetscConcat_(PETSC_, __SILENCE_MACRO__). __VA_ARGS__)) #define PETSC_DEPRECATED_IDENTIFIER(__PETSC_DEPRECATION_MACRO__, major, minor, subminor, ...) \ PETSC_DEPRECATED_IDENTIFIER_(__PETSC_DEPRECATION_MACRO__, PetscConcat6(SILENCE_DEPRECATION_WARNINGS_, major, _, minor, _, subminor), major, minor, subminor, __VA_ARGS__) #define PETSC_DEPRECATED_OBJECT(major, minor, subminor, replacement, ...) PETSC_DEPRECATED_IDENTIFIER(PETSC_DEPRECATED_OBJECT_BASE, major, minor, subminor, replacement, __VA_ARGS__) #define PETSC_DEPRECATED_FUNCTION(major, minor, subminor, replacement, ...) PETSC_DEPRECATED_IDENTIFIER(PETSC_DEPRECATED_FUNCTION_BASE, major, minor, subminor, replacement, __VA_ARGS__) #define PETSC_DEPRECATED_TYPEDEF(major, minor, subminor, replacement, ...) PETSC_DEPRECATED_IDENTIFIER(PETSC_DEPRECATED_TYPEDEF_BASE, major, minor, subminor, replacement, __VA_ARGS__) #define PETSC_DEPRECATED_ENUM(major, minor, subminor, replacement, ...) PETSC_DEPRECATED_IDENTIFIER(PETSC_DEPRECATED_ENUM_BASE, major, minor, subminor, replacement, __VA_ARGS__) #define PETSC_DEPRECATED_MACRO(major, minor, subminor, replacement, ...) PETSC_DEPRECATED_IDENTIFIER(PETSC_DEPRECATED_MACRO_BASE, major, minor, subminor, replacement, __VA_ARGS__)