LCOV - code coverage report
Current view: top level - include/utils - MooseUtils.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 164 167 98.2 %
Date: 2026-05-29 20:35:17 Functions: 232 915 25.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #pragma once
      11             : 
      12             : // MOOSE includes
      13             : #include "MooseTypes.h"
      14             : #include "HashMap.h"
      15             : #include "InfixIterator.h"
      16             : #include "MooseEnumItem.h"
      17             : #include "MooseError.h"
      18             : #include "Moose.h"
      19             : #include "ExecutablePath.h"
      20             : #include "ConsoleUtils.h"
      21             : #include "MooseStringUtils.h"
      22             : 
      23             : #include "libmesh/compare_types.h"
      24             : #include "libmesh/bounding_box.h"
      25             : #include "libmesh/int_range.h"
      26             : #include "libmesh/tensor_tools.h"
      27             : #include "metaphysicl/raw_type.h"
      28             : #include "metaphysicl/metaphysicl_version.h"
      29             : #include "metaphysicl/dualnumber_decl.h"
      30             : #include "metaphysicl/dynamic_std_array_wrapper.h"
      31             : #include "timpi/standard_type.h"
      32             : 
      33             : // C++ includes
      34             : #include <string>
      35             : #include <vector>
      36             : #include <map>
      37             : #include <list>
      38             : #include <filesystem>
      39             : #include <deque>
      40             : #include <regex>
      41             : 
      42             : // Forward Declarations
      43             : class InputParameters;
      44             : class ExecFlagEnum;
      45             : class MaterialProperties;
      46             : class MaterialBase;
      47             : 
      48             : namespace libMesh
      49             : {
      50             : class Elem;
      51             : namespace Parallel
      52             : {
      53             : class Communicator;
      54             : }
      55             : }
      56             : class MultiMooseEnum;
      57             : 
      58             : namespace MooseUtils
      59             : {
      60             : 
      61             : std::filesystem::path pathjoin(const std::filesystem::path & p);
      62             : 
      63             : template <typename... Args>
      64             : std::filesystem::path
      65      693412 : pathjoin(const std::filesystem::path & p, Args... args)
      66             : {
      67      693412 :   return p / pathjoin(args...);
      68             : }
      69             : 
      70             : /// Check if the input string can be parsed into a Real
      71             : /// @param input input to check / parse
      72             : /// @param parsed_real pointer to a Real that gets set to the parsed real if it does parse to Real
      73             : bool parsesToReal(const std::string & input, Real * parsed_real = nullptr);
      74             : 
      75             : /// Returns the location of either a local repo run_tests script - or an
      76             : /// installed test executor script if run_tests isn't found.
      77             : std::string runTestsExecutable();
      78             : 
      79             : /// Searches in the current working directory and then recursively up in each
      80             : /// parent directory looking for a "testroot" file.  Returns the full path to
      81             : /// the first testroot file found.
      82             : std::string findTestRoot();
      83             : 
      84             : /// Returns the directory of any installed inputs or the empty string if none are found.
      85             : std::string installedInputsDir(const std::string & app_name,
      86             :                                const std::string & dir_name,
      87             :                                const std::string & extra_error_msg = "");
      88             : 
      89             : /// Returns the directory of any installed docs/site.
      90             : std::string docsDir(const std::string & app_name);
      91             : 
      92             : /**
      93             :  * Returns the URL of a page located on the MOOSE documentation site.
      94             :  *
      95             :  * @param[in] path   URL path following the domain name. For example, in the
      96             :  *                   URL "www.example.com/folder1/folder2/file.html", this
      97             :  *                   would be "folder1/folder2/file.html".
      98             :  */
      99             : std::string mooseDocsURL(const std::string & path);
     100             : 
     101             : /// Replaces all occurrences of from in str with to and returns the result.
     102             : std::string replaceAll(std::string str, const std::string & from, const std::string & to);
     103             : 
     104             : /**
     105             :  * Replaces "LATEST" placeholders with the latest checkpoint file name.
     106             :  */
     107             : std::string convertLatestCheckpoint(std::string orig);
     108             : 
     109             : /// Computes and returns the Levenshtein distance between strings s1 and s2.
     110             : int levenshteinDist(const std::string & s1, const std::string & s2);
     111             : 
     112             : /**
     113             :  * This function will escape all of the standard C++ escape characters so that they can be printed.
     114             :  * The
     115             :  * passed in parameter is modified in place
     116             :  */
     117             : void escape(std::string & str);
     118             : 
     119             : /**
     120             :  * Removes additional whitespace from a string
     121             :  *
     122             :  * Removes beginning whitespace, end whitespace, and repeated whitespace into a single space
     123             :  */
     124             : std::string removeExtraWhitespace(const std::string & str);
     125             : 
     126             : /**
     127             :  * Python like split functions for strings.
     128             :  *
     129             :  * NOTE: This is similar to the tokenize function, but it maintains empty items, which tokenize does
     130             :  *       not. For example, "foo;bar;;" becomes {"foo", "bar", "", ""}.
     131             :  */
     132             : std::vector<std::string> split(const std::string & str,
     133             :                                const std::string & delimiter,
     134             :                                std::size_t max_count = std::numeric_limits<std::size_t>::max());
     135             : std::vector<std::string> rsplit(const std::string & str,
     136             :                                 const std::string & delimiter,
     137             :                                 std::size_t max_count = std::numeric_limits<std::size_t>::max());
     138             : 
     139             : /**
     140             :  * Python-like join function for strings over an iterator range.
     141             :  */
     142             : template <typename Iterator>
     143             : std::string
     144      665761 : join(Iterator begin, Iterator end, const std::string & delimiter)
     145             : {
     146      665761 :   std::ostringstream oss;
     147      665761 :   std::copy(begin, end, infix_ostream_iterator<std::string>(oss, delimiter.c_str()));
     148     1331522 :   return oss.str();
     149      665761 : }
     150             : 
     151             : /**
     152             :  * Python-like join function for strings over a container.
     153             :  */
     154             : template <typename T>
     155             : std::string
     156      665654 : join(const T & strings, const std::string & delimiter)
     157             : {
     158      665654 :   return join(strings.begin(), strings.end(), delimiter);
     159             : }
     160             : 
     161             : /**
     162             :  * Check the file size.
     163             :  */
     164             : std::size_t fileSize(const std::string & filename);
     165             : 
     166             : /**
     167             :  * This function tokenizes a path and checks to see if it contains the string to look for
     168             :  */
     169             : bool pathContains(const std::string & expression,
     170             :                   const std::string & string_to_find,
     171             :                   const std::string & delims = "/");
     172             : 
     173             : /**
     174             :  * Checks to see if a file is readable (exists and permissions)
     175             :  * @param filename The filename to check
     176             :  * @param check_line_endings Whether or not to see if the file contains DOS line endings.
     177             :  * @param throw_on_unreadable Whether or not to throw a MOOSE error if the file doesn't exist
     178             :  * @param check_for_git_lfs_pointer Whether or not to call a subroutine utility to make sure that
     179             :  *   the file in question is not actually a git-lfs pointer.
     180             :  * @return a Boolean indicating whether the file exists and is readable
     181             :  */
     182             : bool checkFileReadable(const std::string & filename,
     183             :                        bool check_line_endings = false,
     184             :                        bool throw_on_unreadable = true,
     185             :                        bool check_for_git_lfs_pointer = true);
     186             : 
     187             : /**
     188             :  * Check if the file is writable (path exists and permissions)
     189             :  * @param filename The filename you want to see if you can write to.
     190             :  * @param throw_on_unwritable Whether or not to throw a MOOSE error if the file is not writable
     191             :  * return a Boolean indicating whether the file exists and is writable
     192             :  */
     193             : bool checkFileWriteable(const std::string & filename, bool throw_on_unwritable = true);
     194             : 
     195             : /**
     196             :  * Check if the file is a Git-LFS pointer. When using a repository that utilizes Git-LFS,
     197             :  * it's possible that the client may not have the right packages installed in which case
     198             :  * the clone will contain plain-text files with key information for retrieving the actual
     199             :  * (large) files. This can cause odd errors since the file technically exists, is readable,
     200             :  * and even has the right name/extension. However, the content of the file will not match
     201             :  * the expected content.
     202             :  * @param file A pointer to the open filestream.
     203             :  */
     204             : bool checkForGitLFSPointer(std::ifstream & file);
     205             : 
     206             : /**
     207             :  * This function implements a parallel barrier function but writes progress
     208             :  * to stdout.
     209             :  */
     210             : void parallelBarrierNotify(const libMesh::Parallel::Communicator & comm, bool messaging = true);
     211             : 
     212             : /**
     213             :  * This function marks the begin of a section of code that is executed in serial
     214             :  * rank by rank. The section must be closed with a call to serialEnd.
     215             :  * These functions are intended for debugging use to obtain clean terminal output
     216             :  * from multiple ranks (use --keep-cout).
     217             :  * @param comm The communicator to use
     218             :  * @param warn Whether or not to warn that something is being serialized
     219             :  */
     220             : void serialBegin(const libMesh::Parallel::Communicator & comm, bool warn = true);
     221             : 
     222             : /**
     223             :  * Closes a section of code that is executed in serial rank by rank, and that was
     224             :  * opened with a call to serialBegin. No MPI communication can happen in this block.
     225             :  * @param comm The communicator to use
     226             :  * @param warn Whether or not to warn that something is being serialized
     227             :  */
     228             : void serialEnd(const libMesh::Parallel::Communicator & comm, bool warn = true);
     229             : 
     230             : /**
     231             :  * Function tests if the supplied filename as the desired extension
     232             :  * @param filename The filename to test the extension
     233             :  * @param ext The extension to test for (do not include the .)
     234             :  * @param strip_exodus_ext When true, this function ignores -s* from the end of the extension
     235             :  * @return True if the filename has the supplied extension
     236             :  */
     237             : bool hasExtension(const std::string & filename, std::string ext, bool strip_exodus_ext = false);
     238             : 
     239             : /**
     240             :  * Gets the extension of the passed file name.
     241             :  * @param filename The filename of which to get the extension
     242             :  * @param rfind When true, searches for last "." in filename. Otherwise, searches for first "."
     243             :  * @return file_ext The extension of filename (does not include the leading "."). If filename has no
     244             :  * extension, returns "".
     245             :  */
     246             : std::string getExtension(const std::string & filename, const bool rfind = false);
     247             : 
     248             : /**
     249             :  * Removes any file extension from the given string s (i.e. any ".[extension]" suffix of s) and
     250             :  * returns the result.
     251             :  */
     252             : std::string stripExtension(const std::string & s, const bool rfind = false);
     253             : 
     254             : /**
     255             :  * Function for splitting path and filename
     256             :  * @param full_file A complete filename and path
     257             :  * @return A std::pair<std::string, std::string> containing the path and filename
     258             :  *
     259             :  * If the supplied filename does not contain a path, it returns "." as the path
     260             :  */
     261             : template <typename T>
     262             : std::pair<std::filesystem::path, std::filesystem::path>
     263      134323 : splitFileName(const T & full_file)
     264             : {
     265      134323 :   const auto p = std::filesystem::path(std::string(full_file));
     266             :   // Error if path ends with /
     267      134323 :   if (!p.has_filename())
     268           2 :     mooseError("Invalid full file name: ", p);
     269             : 
     270      134321 :   const auto d = p.parent_path();
     271      268642 :   return {d.empty() ? "." : d, p.filename()};
     272      134323 : }
     273             : 
     274             : /**
     275             :  * Returns the current working directory as a string. If there's a problem
     276             :  * obtaining the current working directory, this function just returns an
     277             :  * empty string. It doesn't not throw.
     278             :  */
     279             : std::string getCurrentWorkingDir();
     280             : 
     281             : /**
     282             :  * Recursively make directories
     283             :  * @param dir_name A complete path
     284             :  * @param throw_on_failure True to throw instead of error out when creating a directory is failed.
     285             :  *
     286             :  * The path can be relative like 'a/b/c' or absolute like '/a/b/c'.
     287             :  * The path is allowed to contain '.' or '..'.
     288             :  */
     289             : void makedirs(const std::string & dir_name, bool throw_on_failure = false);
     290             : 
     291             : /**
     292             :  * Recursively remove directories from inner-most when the directories are empty
     293             :  * @param dir_name A complete path
     294             :  * @param throw_on_failure True to throw instead of error out when deleting a directory is failed.
     295             :  *
     296             :  * The path can be relative like 'a/b/c' or absolute like '/a/b/c'.
     297             :  * The path is allowed to contain '.' or '..'.
     298             :  */
     299             : void removedirs(const std::string & dir_name, bool throw_on_failure = false);
     300             : 
     301             : /**
     302             :  * Function for converting a camel case name to a name containing underscores.
     303             :  * @param camel_case_name A string containing camel casing
     304             :  * @return a string containing no capital letters with underscores as appropriate
     305             :  */
     306             : std::string camelCaseToUnderscore(const std::string & camel_case_name);
     307             : 
     308             : /**
     309             :  * Function for converting an underscore name to a camel case name.
     310             :  * @param underscore_name A string containing underscores
     311             :  * @return a string containing camel casing
     312             :  */
     313             : std::string underscoreToCamelCase(const std::string & underscore_name, bool leading_upper_case);
     314             : 
     315             : /**
     316             :  * Function for stripping name after the file / in parser block
     317             :  */
     318             : std::string shortName(const std::string & name);
     319             : 
     320             : /**
     321             :  * Function for string the information before the final / in a parser block
     322             :  */
     323             : std::string baseName(const std::string & name);
     324             : 
     325             : /**
     326             :  * Get the hostname the current process is running on
     327             :  */
     328             : std::string hostname();
     329             : 
     330             : /**
     331             :  * Returns the width of the terminal using sys/ioctl
     332             :  */
     333             : unsigned short getTermWidth(bool use_environment);
     334             : 
     335             : /**
     336             :  * @returns A cleaner representation of the c++ type \p cpp_type.
     337             :  */
     338             : std::string prettyCppType(const std::string & cpp_type);
     339             : 
     340             : /**
     341             :  * @returns A cleaner representation of the type for the given object
     342             :  */
     343             : template <typename T>
     344             : std::string
     345      141443 : prettyCppType(const T * obj = nullptr)
     346             : {
     347      141443 :   if (obj)
     348       10684 :     return prettyCppType(libMesh::demangle(typeid(*obj).name()));
     349             :   else
     350      130759 :     return prettyCppType(libMesh::demangle(typeid(T).name()));
     351             : }
     352             : 
     353             : /**
     354             :  * This routine is a simple helper function for searching a map by values instead of keys
     355             :  */
     356             : template <typename T1, typename T2>
     357             : bool
     358      108129 : doesMapContainValue(const std::map<T1, T2> & the_map, const T2 & value)
     359             : {
     360      365359 :   for (typename std::map<T1, T2>::const_iterator iter = the_map.begin(); iter != the_map.end();
     361      257230 :        ++iter)
     362      348909 :     if (iter->second == value)
     363       91679 :       return true;
     364       16450 :   return false;
     365             : }
     366             : 
     367             : /**
     368             :  * Function to check whether two points are the same for each component
     369             :  * @param var1 The first variable to be checked
     370             :  * @param var2 The second variable to be checked
     371             :  * @param tol The tolerance to be used
     372             :  * @return true if var1 and var2 are equal within tol for each component
     373             :  * TODO: make this a template to make it work for all vector types
     374             :  * Notably figure out the component access differences
     375             :  */
     376             : inline bool
     377         608 : absoluteFuzzyEqual(const Point & v1,
     378             :                    const Point & v2,
     379             :                    const Real tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     380             : {
     381        1005 :   for (const auto i : make_range(LIBMESH_DIM))
     382         917 :     if (std::abs(v1(i) - v2(i)) > tol)
     383         520 :       return false;
     384          88 :   return true;
     385             : }
     386             : 
     387             : /**
     388             :  * Function to check whether two variables are equal within an absolute tolerance
     389             :  * @param var1 The first variable to be checked
     390             :  * @param var2 The second variable to be checked
     391             :  * @param tol The tolerance to be used
     392             :  * @return true if var1 and var2 are equal within tol
     393             :  */
     394             : template <
     395             :     typename T,
     396             :     typename T2,
     397             :     typename T3 = T,
     398             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     399             :                                 libMesh::ScalarTraits<T3>::value,
     400             :                             int>::type = 0>
     401             : bool
     402    44869982 : absoluteFuzzyEqual(const T & var1,
     403             :                    const T2 & var2,
     404    78750658 :                    const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     405             : {
     406    44869982 :   return (std::abs(MetaPhysicL::raw_value(var1) - MetaPhysicL::raw_value(var2)) <=
     407    44869982 :           MetaPhysicL::raw_value(tol));
     408             : }
     409             : 
     410             : /**
     411             :  * Function to check whether a variable is greater than or equal to another variable within an
     412             :  * absolute tolerance
     413             :  * @param var1 The first variable to be checked
     414             :  * @param var2 The second variable to be checked
     415             :  * @param tol The tolerance to be used
     416             :  * @return true if var1 > var2 or var1 == var2 within tol
     417             :  */
     418             : template <
     419             :     typename T,
     420             :     typename T2,
     421             :     typename T3 = T,
     422             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     423             :                                 libMesh::ScalarTraits<T3>::value,
     424             :                             int>::type = 0>
     425             : bool
     426      260431 : absoluteFuzzyGreaterEqual(const T & var1,
     427             :                           const T2 & var2,
     428      351013 :                           const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     429             : {
     430      260431 :   return (MetaPhysicL::raw_value(var1) >=
     431      260431 :           (MetaPhysicL::raw_value(var2) - MetaPhysicL::raw_value(tol)));
     432             : }
     433             : 
     434             : /**
     435             :  * Function to check whether a variable is greater than another variable within an absolute
     436             :  * tolerance
     437             :  * @param var1 The first variable to be checked
     438             :  * @param var2 The second variable to be checked
     439             :  * @param tol The tolerance to be used
     440             :  * @return true if var1 > var2 and var1 != var2 within tol
     441             :  */
     442             : template <
     443             :     typename T,
     444             :     typename T2,
     445             :     typename T3 = T,
     446             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     447             :                                 libMesh::ScalarTraits<T3>::value,
     448             :                             int>::type = 0>
     449             : bool
     450     5786709 : absoluteFuzzyGreaterThan(const T & var1,
     451             :                          const T2 & var2,
     452     8219286 :                          const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     453             : {
     454     5786709 :   return (MetaPhysicL::raw_value(var1) >
     455     5786709 :           (MetaPhysicL::raw_value(var2) + MetaPhysicL::raw_value(tol)));
     456             : }
     457             : 
     458             : /**
     459             :  * Function to check whether a variable is less than or equal to another variable within an absolute
     460             :  * tolerance
     461             :  * @param var1 The first variable to be checked
     462             :  * @param var2 The second variable to be checked
     463             :  * @param tol The tolerance to be used
     464             :  * @return true if var1 < var2 or var1 == var2 within tol
     465             :  */
     466             : template <
     467             :     typename T,
     468             :     typename T2,
     469             :     typename T3 = T,
     470             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     471             :                                 libMesh::ScalarTraits<T3>::value,
     472             :                             int>::type = 0>
     473             : bool
     474         283 : absoluteFuzzyLessEqual(const T & var1,
     475             :                        const T2 & var2,
     476         250 :                        const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     477             : {
     478         283 :   return (MetaPhysicL::raw_value(var1) <=
     479         283 :           (MetaPhysicL::raw_value(var2) + MetaPhysicL::raw_value(tol)));
     480             : }
     481             : 
     482             : /**
     483             :  * Function to check whether a variable is less than another variable within an absolute tolerance
     484             :  * @param var1 The first variable to be checked
     485             :  * @param var2 The second variable to be checked
     486             :  * @param tol The tolerance to be used
     487             :  * @return true if var1 < var2 and var1 != var2 within tol
     488             :  */
     489             : template <
     490             :     typename T,
     491             :     typename T2,
     492             :     typename T3 = T,
     493             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     494             :                                 libMesh::ScalarTraits<T3>::value,
     495             :                             int>::type = 0>
     496             : bool
     497      688218 : absoluteFuzzyLessThan(const T & var1,
     498             :                       const T2 & var2,
     499      893443 :                       const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     500             : {
     501      688218 :   return (MetaPhysicL::raw_value(var1) <
     502      688218 :           (MetaPhysicL::raw_value(var2) - MetaPhysicL::raw_value(tol)));
     503             : }
     504             : 
     505             : /**
     506             :  * Function to check whether two variables are equal within a relative tolerance
     507             :  * @param var1 The first variable to be checked
     508             :  * @param var2 The second variable to be checked
     509             :  * @param tol The relative tolerance to be used
     510             :  * @return true if var1 and var2 are equal within relative tol
     511             :  */
     512             : template <typename T, typename T2, typename T3 = Real>
     513             : bool
     514     5103865 : relativeFuzzyEqual(const T & var1,
     515             :                    const T2 & var2,
     516         665 :                    const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     517             : {
     518             :   if constexpr (libMesh::ScalarTraits<T>::value ||
     519             :                 libMesh::TensorTools::MathWrapperTraits<T>::value)
     520             :   {
     521             :     static_assert(libMesh::TensorTools::TensorTraits<T>::rank ==
     522             :                       libMesh::TensorTools::TensorTraits<T2>::rank,
     523             :                   "Mathematical types must be same for arguments to relativelyFuzzEqual");
     524             :     if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 0)
     525    10207730 :       return absoluteFuzzyEqual(
     526             :           var1,
     527             :           var2,
     528     5103865 :           tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2))));
     529             :     else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 1)
     530             :     {
     531             :       for (const auto i : make_range(Moose::dim))
     532             :         if (!relativeFuzzyEqual(var1(i), var2(i), tol))
     533             :           return false;
     534             : 
     535             :       return true;
     536             :     }
     537             :     else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 2)
     538             :     {
     539             :       for (const auto i : make_range(Moose::dim))
     540             :         for (const auto j : make_range(Moose::dim))
     541             :           if (!relativeFuzzyEqual(var1(i, j), var2(i, j), tol))
     542             :             return false;
     543             : 
     544             :       return true;
     545             :     }
     546             :   }
     547             :   else
     548             :   {
     549             :     // We dare to dream
     550             :     mooseAssert(var1.size() == var2.size(), "These must be the same size");
     551             :     for (const auto i : index_range(var1))
     552             :       if (!relativeFuzzyEqual(var1(i), var2(i), tol))
     553             :         return false;
     554             : 
     555             :     return true;
     556             :   }
     557             : }
     558             : 
     559             : /**
     560             :  * Function to check whether a variable is greater than or equal to another variable within a
     561             :  * relative tolerance
     562             :  * @param var1 The first variable to be checked
     563             :  * @param var2 The second variable to be checked
     564             :  * @param tol The tolerance to be used
     565             :  * @return true if var1 > var2 or var1 == var2 within relative tol
     566             :  */
     567             : template <
     568             :     typename T,
     569             :     typename T2,
     570             :     typename T3 = T,
     571             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     572             :                                 libMesh::ScalarTraits<T3>::value,
     573             :                             int>::type = 0>
     574             : bool
     575           8 : relativeFuzzyGreaterEqual(const T & var1,
     576             :                           const T2 & var2,
     577          16 :                           const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     578             : {
     579          16 :   return (absoluteFuzzyGreaterEqual(
     580             :       var1,
     581             :       var2,
     582           8 :       tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
     583             : }
     584             : 
     585             : /**
     586             :  * Function to check whether a variable is greater than another variable within a relative tolerance
     587             :  * @param var1 The first variable to be checked
     588             :  * @param var2 The second variable to be checked
     589             :  * @param tol The tolerance to be used
     590             :  * @return true if var1 > var2 and var1 != var2 within relative tol
     591             :  */
     592             : template <
     593             :     typename T,
     594             :     typename T2,
     595             :     typename T3 = T,
     596             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     597             :                                 libMesh::ScalarTraits<T3>::value,
     598             :                             int>::type = 0>
     599             : bool
     600           4 : relativeFuzzyGreaterThan(const T & var1,
     601             :                          const T2 & var2,
     602           8 :                          const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     603             : {
     604           8 :   return (absoluteFuzzyGreaterThan(
     605             :       var1,
     606             :       var2,
     607           4 :       tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
     608             : }
     609             : 
     610             : /**
     611             :  * Function to check whether a variable is less than or equal to another variable within a relative
     612             :  * tolerance
     613             :  * @param var1 The first variable to be checked
     614             :  * @param var2 The second variable to be checked
     615             :  * @param tol The tolerance to be used
     616             :  * @return true if var1 < var2 or var1 == var2 within relative tol
     617             :  */
     618             : template <
     619             :     typename T,
     620             :     typename T2,
     621             :     typename T3 = T,
     622             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     623             :                                 libMesh::ScalarTraits<T3>::value,
     624             :                             int>::type = 0>
     625             : bool
     626           8 : relativeFuzzyLessEqual(const T & var1,
     627             :                        const T2 & var2,
     628          16 :                        const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     629             : {
     630          16 :   return (absoluteFuzzyLessEqual(
     631             :       var1,
     632             :       var2,
     633           8 :       tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
     634             : }
     635             : 
     636             : /**
     637             :  * Function to check whether a variable is less than another variable within a relative tolerance
     638             :  * @param var1 The first variable to be checked
     639             :  * @param var2 The second variable to be checked
     640             :  * @param tol The tolerance to be used
     641             :  * @return true if var1 < var2 and var1 != var2 within relative tol
     642             :  */
     643             : template <
     644             :     typename T,
     645             :     typename T2,
     646             :     typename T3 = T,
     647             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     648             :                                 libMesh::ScalarTraits<T3>::value,
     649             :                             int>::type = 0>
     650             : bool
     651        4806 : relativeFuzzyLessThan(const T & var1,
     652             :                       const T2 & var2,
     653        7211 :                       const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     654             : {
     655        9612 :   return (absoluteFuzzyLessThan(
     656             :       var1,
     657             :       var2,
     658        4806 :       tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
     659             : }
     660             : 
     661             : /**
     662             :  * Function which takes the union of \p vector1 and \p vector2 and copies them
     663             :  * to \p common . Depending on the vector size and data type this can be very expensive!
     664             :  */
     665             : template <typename T>
     666             : void
     667      137043 : getUnion(const std::vector<T> & vector1, const std::vector<T> & vector2, std::vector<T> & common)
     668             : {
     669      137043 :   std::unordered_set<T> unique_elements;
     670      137043 :   unique_elements.reserve(vector1.size() + vector2.size());
     671      137043 :   unique_elements.insert(vector1.begin(), vector1.end());
     672      137043 :   unique_elements.insert(vector2.begin(), vector2.end());
     673             : 
     674             :   // Now populate the common vector with the union
     675      137043 :   common.assign(unique_elements.begin(), unique_elements.end());
     676      137043 : }
     677             : 
     678             : /**
     679             :  * Taken from https://stackoverflow.com/a/257382
     680             :  * Evaluating constexpr (Has_size<T>::value) in a templated method over class T will
     681             :  * return whether T is a standard container or a singleton
     682             :  */
     683             : template <typename T>
     684             : class Has_size
     685             : {
     686             :   using Yes = char;
     687             :   struct No
     688             :   {
     689             :     char x[2];
     690             :   };
     691             : 
     692             :   template <typename C>
     693             :   static Yes test(decltype(&C::size));
     694             :   template <typename C>
     695             :   static No test(...);
     696             : 
     697             : public:
     698             :   static constexpr bool value = sizeof(test<T>(0)) == sizeof(Yes);
     699             : };
     700             : 
     701             : /**
     702             :  * @param value The quantity to test for zero-ness
     703             :  * @param tolerance The tolerance for testing zero-ness. The default is 1e-18 for double precision
     704             :  * configurations of libMesh/MOOSE
     705             :  * @return whether the L_infty norm of the value is (close enough to) zero
     706             :  */
     707             : template <typename T>
     708             : bool
     709         112 : isZero(const T & value, const Real tolerance = TOLERANCE * TOLERANCE * TOLERANCE)
     710             : {
     711             :   if constexpr (Has_size<T>::value)
     712             :   {
     713          12 :     for (const auto & element : value)
     714           8 :       if (!isZero(element, tolerance))
     715           4 :         return false;
     716             : 
     717           4 :     return true;
     718             :   }
     719             :   else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 0)
     720          88 :     return MooseUtils::absoluteFuzzyEqual(MetaPhysicL::raw_value(value), 0, tolerance);
     721             :   else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 1)
     722             :   {
     723          20 :     for (const auto i : make_range(Moose::dim))
     724          16 :       if (!MooseUtils::absoluteFuzzyEqual(MetaPhysicL::raw_value(value(i)), 0, tolerance))
     725           4 :         return false;
     726             : 
     727           4 :     return true;
     728             :   }
     729             :   else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 2)
     730             :   {
     731          20 :     for (const auto i : make_range(Moose::dim))
     732          52 :       for (const auto j : make_range(Moose::dim))
     733          40 :         if (!MooseUtils::absoluteFuzzyEqual(MetaPhysicL::raw_value(value(i, j)), 0, tolerance))
     734           4 :           return false;
     735             : 
     736           4 :     return true;
     737             :   }
     738             : }
     739             : 
     740             : /**
     741             :  * Function to dump the contents of MaterialPropertyStorage for debugging purposes
     742             :  * @param props The storage item to dump, this should be
     743             :  * MaterialPropertyStorage.props(state)
     744             :  *
     745             :  * Currently this only words for scalar material properties. Something to do as needed would be to
     746             :  * create a method in MaterialProperty
     747             :  * that may be overloaded to dump the type using template specialization.
     748             :  */
     749             : void MaterialPropertyStorageDump(
     750             :     const HashMap<const libMesh::Elem *, HashMap<unsigned int, MaterialProperties>> & props);
     751             : 
     752             : /**
     753             :  * Indents the supplied message given the prefix and color
     754             :  * @param prefix The prefix to use for indenting
     755             :  * @param message The message that will be indented
     756             :  * @param color The color to apply to the prefix (default CYAN)
     757             :  * @param indent_first_line If true this will indent the first line too (default)
     758             :  * @param post_prefix A string to append right after the prefix, defaults to a column and a space
     759             :  *
     760             :  * Takes a message like the following and indents it with another color code (see below)
     761             :  *
     762             :  * Input message:
     763             :  * COLOR_YELLOW
     764             :  * *** Warning ***
     765             :  * Something bad has happened and we want to draw attention to it with color
     766             :  * COLOR_DEFAULT
     767             :  *
     768             :  * Output message:
     769             :  * COLOR_CYAN sub_app: COLOR_YELLOW
     770             :  * COLOR_CYAN sub_app: COLOR_YELLOW *** Warning ***
     771             :  * COLOR_CYAN sub_app: COLOR_YELLOW Something bad has happened and we want to draw attention to it
     772             :  * with color
     773             :  * COLOR_DEFAULT
     774             :  *
     775             :  * Also handles single line color codes
     776             :  * COLOR_CYAN sub_app: 0 Nonlinear |R| = COLOR_GREEN 1.0e-10 COLOR_DEFAULT
     777             :  *
     778             :  * Not indenting the first line is useful in the case where the first line is actually finishing
     779             :  * the line before it.
     780             :  */
     781             : void indentMessage(const std::string & prefix,
     782             :                    std::string & message,
     783             :                    const char * color = COLOR_CYAN,
     784             :                    bool dont_indent_first_line = true,
     785             :                    const std::string & post_prefix = ": ");
     786             : 
     787             : /**
     788             :  * remove ANSI escape sequences for terminal color from msg
     789             :  */
     790             : std::string & removeColor(std::string & msg);
     791             : 
     792             : std::list<std::string> listDir(const std::string path, bool files_only = false);
     793             : 
     794             : bool pathExists(const std::string & path);
     795             : 
     796             : /**
     797             :  * Retrieves the names of all of the files contained within the list of directories passed into
     798             :  * the routine. The names returned will be the paths to the files relative to the current
     799             :  * directory.
     800             :  * @param directory_list The list of directories to retrieve files from.
     801             :  * @param file_only Whether or not to list only files
     802             :  */
     803             : std::list<std::string> getFilesInDirs(const std::list<std::string> & directory_list,
     804             :                                       const bool files_only = true);
     805             : 
     806             : /**
     807             :  * Returns the most recent checkpoint prefix (the four numbers at the beginning)
     808             :  * If a suitable file isn't found the empty string is returned
     809             :  * @param checkpoint_files the list of files to analyze
     810             :  */
     811             : std::string getLatestCheckpointFilePrefix(const std::list<std::string> & checkpoint_files);
     812             : 
     813             : /*
     814             :  * Checks to see if a string matches a search string
     815             :  * @param name The name to check
     816             :  * @param search_string The search string to check name against
     817             :  */
     818             : bool wildCardMatch(std::string name, std::string search_string);
     819             : 
     820             : /*
     821             :  * Checks to see if a candidate string matches a pattern string, permitting glob
     822             :  * wildcards (* and ?) anywhere in the pattern.
     823             :  * @param candidate The name to check
     824             :  * @param pattern The search string to check name candidate
     825             :  */
     826             : bool globCompare(const std::string & candidate,
     827             :                  const std::string & pattern,
     828             :                  std::size_t c = 0,
     829             :                  std::size_t p = 0);
     830             : 
     831             : template <typename T>
     832             : void
     833          24 : expandAllMatches(const std::vector<T> & candidates, std::vector<T> & patterns)
     834             : {
     835          24 :   std::set<T> expanded;
     836          72 :   for (const auto & p : patterns)
     837             :   {
     838          48 :     unsigned int found = 0;
     839         240 :     for (const auto & c : candidates)
     840         192 :       if (globCompare(c, p))
     841             :       {
     842          48 :         expanded.insert(c);
     843          48 :         found++;
     844             :       }
     845          48 :     if (!found)
     846           0 :       throw std::invalid_argument(p);
     847             :   }
     848          24 :   patterns.assign(expanded.begin(), expanded.end());
     849          24 : }
     850             : 
     851             : /**
     852             :  * Takes the string representation of a value and converts it to the value.
     853             :  *
     854             :  * See the convert method in MooseStringUtils.h for more information on
     855             :  * handling of each case.
     856             :  *
     857             :  * @param str The string to convert from
     858             :  * @param throw_on_failure If true, throw on a failure to convert, otherwise use mooseError
     859             :  * @return The converted value on success
     860             :  */
     861             : template <typename T>
     862             : T
     863        5990 : convert(const std::string & str, bool throw_on_failure = false)
     864             : {
     865             :   T val;
     866             :   try
     867             :   {
     868        5990 :     convert(str, val, true);
     869             :   }
     870        1801 :   catch (std::exception const & e)
     871             :   {
     872         902 :     if (throw_on_failure)
     873         895 :       throw;
     874           7 :     mooseError(e.what());
     875             :   }
     876        5088 :   return val;
     877             : }
     878             : 
     879             : /**
     880             :  * Create a symbolic link, if the link already exists it is replaced.
     881             :  */
     882             : void createSymlink(const std::string & target, const std::string & link);
     883             : 
     884             : /**
     885             :  * Remove a symbolic link, if the given filename is a link.
     886             :  */
     887             : void clearSymlink(const std::string & link);
     888             : 
     889             : /**
     890             :  * Returns a container that contains the content of second passed in container
     891             :  * inserted into the first passed in container (set or map union).
     892             :  */
     893             : template <typename T>
     894             : T
     895             : concatenate(T c1, const T & c2)
     896             : {
     897             :   c1.insert(c2.begin(), c2.end());
     898             :   return c1;
     899             : }
     900             : 
     901             : /**
     902             :  * Returns a vector that contains is the concatenation of the two passed in vectors.
     903             :  */
     904             : template <typename T>
     905             : std::vector<T>
     906             : concatenate(std::vector<T> c1, const std::vector<T> & c2)
     907             : {
     908             :   c1.insert(c1.end(), c2.begin(), c2.end());
     909             :   return c1;
     910             : }
     911             : 
     912             : /**
     913             :  * Returns the passed in vector with the item appended to it.
     914             :  */
     915             : template <typename T>
     916             : std::vector<T>
     917          30 : concatenate(std::vector<T> c1, const T & item)
     918             : {
     919          30 :   c1.push_back(item);
     920          30 :   return c1;
     921             : }
     922             : 
     923             : /**
     924             :  * @return Whether or not \p value begins with \p begin_value
     925             :  */
     926             : bool beginsWith(const std::string & value, const std::string & begin_value);
     927             : 
     928             : /**
     929             :  * Return the number of digits for a number.
     930             :  *
     931             :  * This can foster quite a large discussion:
     932             :  * https://stackoverflow.com/questions/1489830/efficient-way-to-determine-number-of-digits-in-an-integer
     933             :  *
     934             :  * For our purposes I like the following algorithm.
     935             :  */
     936             : template <typename T>
     937             : int
     938        1826 : numDigits(const T & num)
     939             : {
     940        1826 :   return num > 9 ? static_cast<int>(std::log10(static_cast<double>(num))) + 1 : 1;
     941             : }
     942             : 
     943             : /**
     944             :  * Return the default ExecFlagEnum for MOOSE.
     945             :  */
     946             : ExecFlagEnum getDefaultExecFlagEnum();
     947             : 
     948             : /**
     949             :  * Robust string to integer conversion that fails for cases such at "1foo".
     950             :  * @param input The string to convert.
     951             :  * @param throw_on_failure Throw an invalid_argument exception instead of mooseError.
     952             :  */
     953             : int stringToInteger(const std::string & input, bool throw_on_failure = false);
     954             : 
     955             : /**
     956             :  * Linearly partition a number of items
     957             :  *
     958             :  * @param num_items The number of items to partition
     959             :  * @param num_chunks The number of chunks to partition into
     960             :  * @param chunk_id The ID of the chunk you are trying to get information about (typically the
     961             :  * current MPI rank)
     962             :  * @param num_local_items Output: The number of items for this chunk_id
     963             :  * @param local_items_begin Output: The first item for this chunk_id
     964             :  * @param local_items_end Output: One past the final item for this chunk_id
     965             :  */
     966             : void linearPartitionItems(dof_id_type num_items,
     967             :                           dof_id_type num_chunks,
     968             :                           dof_id_type chunk_id,
     969             :                           dof_id_type & num_local_items,
     970             :                           dof_id_type & local_items_begin,
     971             :                           dof_id_type & local_items_end);
     972             : 
     973             : /**
     974             :  * Return the chunk_id that is assigned to handle item_id
     975             :  *
     976             :  * @param num_items Global number of items to partition
     977             :  * @param num_chunks Total number of chunks to split into
     978             :  * @param item_id The item to find the chunk_id for
     979             :  * @return The chunk_id of the chunk that contains item_id
     980             :  */
     981             : processor_id_type
     982             : linearPartitionChunk(dof_id_type num_items, dof_id_type num_chunks, dof_id_type item_id);
     983             : 
     984             : /**
     985             :  * Wrapper around PetscGetRealPath, which is a cross-platform replacement for realpath
     986             :  */
     987             : std::string realpath(const std::string & path);
     988             : 
     989             : /**
     990             :  * Custom type trait that has a ::value of true for types that cam be use interchangeably
     991             :  * with Real. Most notably it is false for complex numbers, which do not have a
     992             :  * strict ordering (and therefore no <,>,<=,>= operators).
     993             :  */
     994             : template <typename T>
     995             : struct IsLikeReal
     996             : {
     997             :   static constexpr bool value = false;
     998             : };
     999             : template <>
    1000             : struct IsLikeReal<Real>
    1001             : {
    1002             :   static constexpr bool value = true;
    1003             : };
    1004             : template <>
    1005             : struct IsLikeReal<ADReal>
    1006             : {
    1007             :   static constexpr bool value = true;
    1008             : };
    1009             : 
    1010             : /**
    1011             :  * Custom type trait that has a ::value of true for types that can be broadcasted
    1012             :  */
    1013             : template <typename T>
    1014             : struct canBroadcast
    1015             : {
    1016             :   static constexpr bool value = std::is_base_of<TIMPI::DataType, TIMPI::StandardType<T>>::value ||
    1017             :                                 TIMPI::Has_buffer_type<TIMPI::Packing<T>>::value;
    1018             : };
    1019             : 
    1020             : ///@{ Comparison helpers that support the MooseUtils::Any wildcard which will match any value
    1021             : const static struct AnyType
    1022             : {
    1023             : } Any;
    1024             : 
    1025             : template <typename T1, typename T2>
    1026             : bool
    1027       47767 : wildcardEqual(const T1 & a, const T2 & b)
    1028             : {
    1029       47767 :   return a == b;
    1030             : }
    1031             : 
    1032             : template <typename T>
    1033             : bool
    1034             : wildcardEqual(const T &, AnyType)
    1035             : {
    1036             :   return true;
    1037             : }
    1038             : template <typename T>
    1039             : bool
    1040        5052 : wildcardEqual(AnyType, const T &)
    1041             : {
    1042        5052 :   return true;
    1043             : }
    1044             : ///@}
    1045             : 
    1046             : /**
    1047             :  * Find a specific pair in a container matching on first, second or both pair components
    1048             :  */
    1049             : template <typename C, typename It, typename M1, typename M2>
    1050             : auto
    1051       53566 : findPair(C & container, It start_iterator, const M1 & first, const M2 & second)
    1052             : {
    1053       53566 :   return std::find_if(start_iterator,
    1054             :                       container.end(),
    1055       47767 :                       [&](auto & item) {
    1056       52819 :                         return wildcardEqual(first, item.first) &&
    1057       52819 :                                wildcardEqual(second, item.second);
    1058       53566 :                       });
    1059             : }
    1060             : 
    1061             : /**
    1062             :  * Construct a valid bounding box from 2 arbitrary points
    1063             :  *
    1064             :  * If you have 2 points in space and you wish to construct a bounding box, you should use
    1065             :  * this method to avoid unexpected behavior of the underlying BoundingBox class in libMesh.
    1066             :  * BoundingBox class expect 2 points whose coordinates are "sorted" (i.e., x-, y- and -z
    1067             :  * coordinates of the first point are smaller then the corresponding coordinates of the second
    1068             :  * point). If this "sorting" is not present, the BoundingBox class will build an empty box and
    1069             :  * any further testing of points inside the box will fail. This method will allow you to obtain
    1070             :  * the correct bounding box for any valid combination of 2 corner points of a box.
    1071             :  *
    1072             :  * @param p1 First corner of the constructed bounding box
    1073             :  * @param p2 Second corner of the constructed bounding box
    1074             :  * @return Valid bounding box
    1075             :  */
    1076             : libMesh::BoundingBox buildBoundingBox(const Point & p1, const Point & p2);
    1077             : 
    1078             : /**
    1079             :  * Utility class template for a semidynamic vector with a maximum size N
    1080             :  * and a chosen dynamic size. This container avoids heap allocation and
    1081             :  * is meant as a replacement for small local std::vector variables.
    1082             :  * By default this class uses `value initialization`. This can be disabled
    1083             :  * using the third template parameter if uninitialized storage is acceptable,
    1084             :  */
    1085             : template <typename T, std::size_t N, bool value_init = true>
    1086             : #if METAPHYSICL_MAJOR_VERSION < 2
    1087             : class SemidynamicVector : public MetaPhysicL::DynamicStdArrayWrapper<T, MetaPhysicL::NWrapper<N>>
    1088             : {
    1089             :   typedef MetaPhysicL::DynamicStdArrayWrapper<T, MetaPhysicL::NWrapper<N>> Parent;
    1090             : #else
    1091             : class SemidynamicVector : public MetaPhysicL::DynamicStdArrayWrapper<T, N>
    1092             : {
    1093             :   typedef MetaPhysicL::DynamicStdArrayWrapper<T, N> Parent;
    1094             : #endif
    1095             : 
    1096             : public:
    1097    19360038 :   SemidynamicVector(std::size_t size) : Parent()
    1098             :   {
    1099     4840014 :     Parent::resize(size);
    1100             :     if constexpr (value_init)
    1101    19328140 :       for (const auto i : make_range(size))
    1102    14488128 :         _data[i] = T{};
    1103     4840014 :   }
    1104             : 
    1105           2 :   void resize(std::size_t new_size)
    1106             :   {
    1107           2 :     [[maybe_unused]] const auto old_dynamic_n = Parent::size();
    1108             : 
    1109           2 :     Parent::resize(new_size);
    1110             : 
    1111             :     if constexpr (value_init)
    1112             :       for (const auto i : make_range(old_dynamic_n, _dynamic_n))
    1113             :         _data[i] = T{};
    1114           2 :   }
    1115             : 
    1116           2 :   void push_back(const T & v)
    1117             :   {
    1118           2 :     const auto old_dynamic_n = Parent::size();
    1119           2 :     Parent::resize(old_dynamic_n + 1);
    1120           2 :     _data[old_dynamic_n] = v;
    1121           2 :   }
    1122             : 
    1123             :   template <typename... Args>
    1124           2 :   void emplace_back(Args &&... args)
    1125             :   {
    1126           2 :     const auto old_dynamic_n = Parent::size();
    1127           2 :     Parent::resize(old_dynamic_n + 1);
    1128           2 :     (::new (&_data[old_dynamic_n]) T(std::forward<Args>(args)...));
    1129           2 :   }
    1130             : 
    1131           2 :   std::size_t max_size() const { return N; }
    1132             : 
    1133             :   using Parent::_data;
    1134             :   using Parent::_dynamic_n;
    1135             : };
    1136             : 
    1137             : /**
    1138             :  * The MooseUtils::get() specializations are used to support making
    1139             :  * forwards-compatible code changes from dumb pointers to smart pointers.
    1140             :  * The same line of code, e.g.
    1141             :  *
    1142             :  * libMesh::Parameters::Value * value = MooseUtils::get(map_iter->second);
    1143             :  *
    1144             :  * will then work regardless of whether map_iter->second is a dumb pointer
    1145             :  * or a smart pointer. Note that the smart pointer get() functions are const
    1146             :  * so they can be (ab)used to get a non-const pointer to the underlying
    1147             :  * resource. We are simply following this convention here.
    1148             :  */
    1149             : template <typename T>
    1150             : T *
    1151   128351611 : get(const std::unique_ptr<T> & u)
    1152             : {
    1153   128351611 :   return u.get();
    1154             : }
    1155             : 
    1156             : template <typename T>
    1157             : T *
    1158             : get(T * p)
    1159             : {
    1160             :   return p;
    1161             : }
    1162             : 
    1163             : template <typename T>
    1164             : T *
    1165             : get(const std::shared_ptr<T> & s)
    1166             : {
    1167             :   return s.get();
    1168             : }
    1169             : 
    1170             : /**
    1171             :  * This method detects whether two sets intersect without building a result set.
    1172             :  * It exits as soon as any intersection is detected.
    1173             :  */
    1174             : template <class InputIterator>
    1175             : bool
    1176          33 : setsIntersect(InputIterator first1, InputIterator last1, InputIterator first2, InputIterator last2)
    1177             : {
    1178          46 :   while (first1 != last1 && first2 != last2)
    1179             :   {
    1180          16 :     if (*first1 == *first2)
    1181           3 :       return true;
    1182             : 
    1183          13 :     if (*first1 < *first2)
    1184           0 :       ++first1;
    1185          13 :     else if (*first1 > *first2)
    1186          13 :       ++first2;
    1187             :   }
    1188          30 :   return false;
    1189             : }
    1190             : 
    1191             : template <class T>
    1192             : bool
    1193          33 : setsIntersect(const T & s1, const T & s2)
    1194             : {
    1195          33 :   return setsIntersect(s1.begin(), s1.end(), s2.begin(), s2.end());
    1196             : }
    1197             : 
    1198             : /**
    1199             :  * Courtesy https://stackoverflow.com/a/8889045 and
    1200             :  * https://en.cppreference.com/w/cpp/string/byte/isdigit
    1201             :  * @return Whether every character in the string is a digit
    1202             :  */
    1203             : inline bool
    1204     1526063 : isDigits(const std::string & str)
    1205             : {
    1206     3585883 :   return std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isdigit(c); });
    1207             : }
    1208             : 
    1209             : /**
    1210             :  * Courtesy https://stackoverflow.com/a/57163016 and
    1211             :  * https://stackoverflow.com/questions/447206/c-isfloat-function
    1212             :  * @return Whether the string is convertible to a float
    1213             :  */
    1214             : inline bool
    1215          15 : isFloat(const std::string & str)
    1216             : {
    1217          15 :   if (str.empty())
    1218           0 :     return false;
    1219             :   char * ptr;
    1220          15 :   strtof(str.c_str(), &ptr);
    1221          15 :   return (*ptr) == '\0';
    1222             : }
    1223             : 
    1224             : /**
    1225             :  * Gets the canonical path of the given path
    1226             :  */
    1227             : std::string canonicalPath(const std::string & path);
    1228             : 
    1229             : /**
    1230             :  * @returns Whether the \p string1 starts with \p string2
    1231             :  */
    1232             : bool startsWith(const std::string & string1, const std::string & string2);
    1233             : 
    1234             : /**
    1235             :  * Replace the starting string \p string2 of \p string1 with \p string3. A user should have checked
    1236             :  * that \p string1 \p startsWith \p string2
    1237             :  */
    1238             : void replaceStart(std::string & string1, const std::string & string2, const std::string & string3);
    1239             : 
    1240             : /**
    1241             :  * @returns whether every alphabetic character in a string is lower-case
    1242             :  */
    1243             : bool isAllLowercase(const std::string & str);
    1244             : } // MooseUtils namespace
    1245             : 
    1246             : namespace Moose
    1247             : {
    1248             : template <typename T>
    1249             : struct ADType;
    1250             : 
    1251             : template <typename T, std::size_t N, bool value_init>
    1252             : struct ADType<MooseUtils::SemidynamicVector<T, N, value_init>>
    1253             : {
    1254             :   typedef MooseUtils::SemidynamicVector<typename ADType<T>::type, N, value_init> type;
    1255             : };
    1256             : }
    1257             : 
    1258             : /**
    1259             :  * find, erase, length algorithm for removing a substring from a string
    1260             :  */
    1261             : void removeSubstring(std::string & main, const std::string & sub);
    1262             : 
    1263             : /**
    1264             :  * find, erase, length algorithm for removing a substring from a copy of a string
    1265             :  */
    1266             : std::string removeSubstring(const std::string & main, const std::string & sub);

Generated by: LCOV version 1.14