LCOV - code coverage report
Current view: top level - include/utils - MooseUtils.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 7323e9 Lines: 162 165 98.2 %
Date: 2025-11-05 20:01:15 Functions: 190 854 22.2 %
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      356355 : pathjoin(const std::filesystem::path & p, Args... args)
      66             : {
      67      356355 :   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      104231 : join(Iterator begin, Iterator end, const std::string & delimiter)
     145             : {
     146      104231 :   std::ostringstream oss;
     147      104231 :   std::copy(begin, end, infix_ostream_iterator<std::string>(oss, delimiter.c_str()));
     148      208462 :   return oss.str();
     149      104231 : }
     150             : 
     151             : /**
     152             :  * Python-like join function for strings over a container.
     153             :  */
     154             : template <typename T>
     155             : std::string
     156      104079 : join(const T & strings, const std::string & delimiter)
     157             : {
     158      104079 :   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       71100 : splitFileName(const T & full_file)
     264             : {
     265       71100 :   const auto p = std::filesystem::path(std::string(full_file));
     266             :   // Error if path ends with /
     267       71100 :   if (!p.has_filename())
     268           2 :     mooseError("Invalid full file name: ", p);
     269             : 
     270       71098 :   const auto d = p.parent_path();
     271      142196 :   return {d.empty() ? "." : d, p.filename()};
     272       71100 : }
     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      166289 : prettyCppType(const T * obj = nullptr)
     346             : {
     347      166289 :   if (obj)
     348       12205 :     return prettyCppType(libMesh::demangle(typeid(*obj).name()));
     349             :   else
     350      154084 :     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      120748 : doesMapContainValue(const std::map<T1, T2> & the_map, const T2 & value)
     359             : {
     360      408364 :   for (typename std::map<T1, T2>::const_iterator iter = the_map.begin(); iter != the_map.end();
     361      287616 :        ++iter)
     362      390277 :     if (iter->second == value)
     363      102661 :       return true;
     364       18087 :   return false;
     365             : }
     366             : 
     367             : /**
     368             :  * Function to check whether two variables are equal within an absolute tolerance
     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
     373             :  */
     374             : template <
     375             :     typename T,
     376             :     typename T2,
     377             :     typename T3 = T,
     378             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     379             :                                 libMesh::ScalarTraits<T3>::value,
     380             :                             int>::type = 0>
     381             : bool
     382    50939833 : absoluteFuzzyEqual(const T & var1,
     383             :                    const T2 & var2,
     384    88352748 :                    const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     385             : {
     386    50939833 :   return (std::abs(MetaPhysicL::raw_value(var1) - MetaPhysicL::raw_value(var2)) <=
     387    50939833 :           MetaPhysicL::raw_value(tol));
     388             : }
     389             : 
     390             : /**
     391             :  * Function to check whether a variable is greater than or equal to another variable within an
     392             :  * absolute tolerance
     393             :  * @param var1 The first variable to be checked
     394             :  * @param var2 The second variable to be checked
     395             :  * @param tol The tolerance to be used
     396             :  * @return true if var1 > var2 or var1 == var2 within tol
     397             :  */
     398             : template <
     399             :     typename T,
     400             :     typename T2,
     401             :     typename T3 = T,
     402             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     403             :                                 libMesh::ScalarTraits<T3>::value,
     404             :                             int>::type = 0>
     405             : bool
     406      288700 : absoluteFuzzyGreaterEqual(const T & var1,
     407             :                           const T2 & var2,
     408      389344 :                           const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     409             : {
     410      288700 :   return (MetaPhysicL::raw_value(var1) >=
     411      288700 :           (MetaPhysicL::raw_value(var2) - MetaPhysicL::raw_value(tol)));
     412             : }
     413             : 
     414             : /**
     415             :  * Function to check whether a variable is greater than another variable within an absolute
     416             :  * tolerance
     417             :  * @param var1 The first variable to be checked
     418             :  * @param var2 The second variable to be checked
     419             :  * @param tol The tolerance to be used
     420             :  * @return true if var1 > var2 and var1 != var2 within tol
     421             :  */
     422             : template <
     423             :     typename T,
     424             :     typename T2,
     425             :     typename T3 = T,
     426             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     427             :                                 libMesh::ScalarTraits<T3>::value,
     428             :                             int>::type = 0>
     429             : bool
     430     6235170 : absoluteFuzzyGreaterThan(const T & var1,
     431             :                          const T2 & var2,
     432     8619431 :                          const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     433             : {
     434     6235170 :   return (MetaPhysicL::raw_value(var1) >
     435     6235170 :           (MetaPhysicL::raw_value(var2) + MetaPhysicL::raw_value(tol)));
     436             : }
     437             : 
     438             : /**
     439             :  * Function to check whether a variable is less than or equal to another variable within an absolute
     440             :  * tolerance
     441             :  * @param var1 The first variable to be checked
     442             :  * @param var2 The second variable to be checked
     443             :  * @param tol The tolerance to be used
     444             :  * @return true if var1 < var2 or var1 == var2 within tol
     445             :  */
     446             : template <
     447             :     typename T,
     448             :     typename T2,
     449             :     typename T3 = T,
     450             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     451             :                                 libMesh::ScalarTraits<T3>::value,
     452             :                             int>::type = 0>
     453             : bool
     454         307 : absoluteFuzzyLessEqual(const T & var1,
     455             :                        const T2 & var2,
     456         271 :                        const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     457             : {
     458         307 :   return (MetaPhysicL::raw_value(var1) <=
     459         307 :           (MetaPhysicL::raw_value(var2) + MetaPhysicL::raw_value(tol)));
     460             : }
     461             : 
     462             : /**
     463             :  * Function to check whether a variable is less than another variable within an absolute tolerance
     464             :  * @param var1 The first variable to be checked
     465             :  * @param var2 The second variable to be checked
     466             :  * @param tol The tolerance to be used
     467             :  * @return true if var1 < var2 and var1 != var2 within tol
     468             :  */
     469             : template <
     470             :     typename T,
     471             :     typename T2,
     472             :     typename T3 = T,
     473             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     474             :                                 libMesh::ScalarTraits<T3>::value,
     475             :                             int>::type = 0>
     476             : bool
     477      770993 : absoluteFuzzyLessThan(const T & var1,
     478             :                       const T2 & var2,
     479     1000524 :                       const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     480             : {
     481      770993 :   return (MetaPhysicL::raw_value(var1) <
     482      770993 :           (MetaPhysicL::raw_value(var2) - MetaPhysicL::raw_value(tol)));
     483             : }
     484             : 
     485             : /**
     486             :  * Function to check whether two variables are equal within a relative tolerance
     487             :  * @param var1 The first variable to be checked
     488             :  * @param var2 The second variable to be checked
     489             :  * @param tol The relative tolerance to be used
     490             :  * @return true if var1 and var2 are equal within relative tol
     491             :  */
     492             : template <typename T, typename T2, typename T3 = Real>
     493             : bool
     494     6212320 : relativeFuzzyEqual(const T & var1,
     495             :                    const T2 & var2,
     496         747 :                    const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     497             : {
     498             :   if constexpr (libMesh::ScalarTraits<T>::value ||
     499             :                 libMesh::TensorTools::MathWrapperTraits<T>::value)
     500             :   {
     501             :     static_assert(libMesh::TensorTools::TensorTraits<T>::rank ==
     502             :                       libMesh::TensorTools::TensorTraits<T2>::rank,
     503             :                   "Mathematical types must be same for arguments to relativelyFuzzEqual");
     504             :     if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 0)
     505    12424640 :       return absoluteFuzzyEqual(
     506             :           var1,
     507             :           var2,
     508     6212320 :           tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2))));
     509             :     else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 1)
     510             :     {
     511             :       for (const auto i : make_range(Moose::dim))
     512             :         if (!relativeFuzzyEqual(var1(i), var2(i), tol))
     513             :           return false;
     514             : 
     515             :       return true;
     516             :     }
     517             :     else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 2)
     518             :     {
     519             :       for (const auto i : make_range(Moose::dim))
     520             :         for (const auto j : make_range(Moose::dim))
     521             :           if (!relativeFuzzyEqual(var1(i, j), var2(i, j), tol))
     522             :             return false;
     523             : 
     524             :       return true;
     525             :     }
     526             :   }
     527             :   else
     528             :   {
     529             :     // We dare to dream
     530             :     mooseAssert(var1.size() == var2.size(), "These must be the same size");
     531             :     for (const auto i : index_range(var1))
     532             :       if (!relativeFuzzyEqual(var1(i), var2(i), tol))
     533             :         return false;
     534             : 
     535             :     return true;
     536             :   }
     537             : }
     538             : 
     539             : /**
     540             :  * Function to check whether a variable is greater than or equal to another variable within a
     541             :  * relative tolerance
     542             :  * @param var1 The first variable to be checked
     543             :  * @param var2 The second variable to be checked
     544             :  * @param tol The tolerance to be used
     545             :  * @return true if var1 > var2 or var1 == var2 within relative tol
     546             :  */
     547             : template <
     548             :     typename T,
     549             :     typename T2,
     550             :     typename T3 = T,
     551             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     552             :                                 libMesh::ScalarTraits<T3>::value,
     553             :                             int>::type = 0>
     554             : bool
     555           8 : relativeFuzzyGreaterEqual(const T & var1,
     556             :                           const T2 & var2,
     557          16 :                           const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     558             : {
     559          16 :   return (absoluteFuzzyGreaterEqual(
     560             :       var1,
     561             :       var2,
     562           8 :       tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
     563             : }
     564             : 
     565             : /**
     566             :  * Function to check whether a variable is greater than another variable within a relative tolerance
     567             :  * @param var1 The first variable to be checked
     568             :  * @param var2 The second variable to be checked
     569             :  * @param tol The tolerance to be used
     570             :  * @return true if var1 > var2 and var1 != var2 within relative tol
     571             :  */
     572             : template <
     573             :     typename T,
     574             :     typename T2,
     575             :     typename T3 = T,
     576             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     577             :                                 libMesh::ScalarTraits<T3>::value,
     578             :                             int>::type = 0>
     579             : bool
     580           4 : relativeFuzzyGreaterThan(const T & var1,
     581             :                          const T2 & var2,
     582           8 :                          const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     583             : {
     584           8 :   return (absoluteFuzzyGreaterThan(
     585             :       var1,
     586             :       var2,
     587           4 :       tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
     588             : }
     589             : 
     590             : /**
     591             :  * Function to check whether a variable is less than or equal to another variable within a relative
     592             :  * tolerance
     593             :  * @param var1 The first variable to be checked
     594             :  * @param var2 The second variable to be checked
     595             :  * @param tol The tolerance to be used
     596             :  * @return true if var1 < var2 or var1 == var2 within relative tol
     597             :  */
     598             : template <
     599             :     typename T,
     600             :     typename T2,
     601             :     typename T3 = T,
     602             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     603             :                                 libMesh::ScalarTraits<T3>::value,
     604             :                             int>::type = 0>
     605             : bool
     606           8 : relativeFuzzyLessEqual(const T & var1,
     607             :                        const T2 & var2,
     608          16 :                        const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     609             : {
     610          16 :   return (absoluteFuzzyLessEqual(
     611             :       var1,
     612             :       var2,
     613           8 :       tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
     614             : }
     615             : 
     616             : /**
     617             :  * Function to check whether a variable is less than another variable within a relative tolerance
     618             :  * @param var1 The first variable to be checked
     619             :  * @param var2 The second variable to be checked
     620             :  * @param tol The tolerance to be used
     621             :  * @return true if var1 < var2 and var1 != var2 within relative tol
     622             :  */
     623             : template <
     624             :     typename T,
     625             :     typename T2,
     626             :     typename T3 = T,
     627             :     typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
     628             :                                 libMesh::ScalarTraits<T3>::value,
     629             :                             int>::type = 0>
     630             : bool
     631        5262 : relativeFuzzyLessThan(const T & var1,
     632             :                       const T2 & var2,
     633        7895 :                       const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
     634             : {
     635       10524 :   return (absoluteFuzzyLessThan(
     636             :       var1,
     637             :       var2,
     638        5262 :       tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
     639             : }
     640             : 
     641             : /**
     642             :  * Function which takes the union of \p vector1 and \p vector2 and copies them
     643             :  * to \p common . Depending on the vector size and data type this can be very expensive!
     644             :  */
     645             : template <typename T>
     646             : void
     647       43332 : getUnion(const std::vector<T> & vector1, const std::vector<T> & vector2, std::vector<T> & common)
     648             : {
     649       43332 :   std::unordered_set<T> unique_elements;
     650       43332 :   unique_elements.reserve(vector1.size() + vector2.size());
     651             : 
     652       82647 :   for (const T & entry : vector1)
     653       39315 :     unique_elements.insert(entry);
     654       82647 :   for (const T & entry : vector2)
     655       39315 :     unique_elements.insert(entry);
     656             : 
     657             :   // Now populate the common vector with the union
     658       43332 :   common.clear();
     659       43332 :   common.assign(unique_elements.begin(), unique_elements.end());
     660       43332 : }
     661             : 
     662             : /**
     663             :  * Taken from https://stackoverflow.com/a/257382
     664             :  * Evaluating constexpr (Has_size<T>::value) in a templated method over class T will
     665             :  * return whether T is a standard container or a singleton
     666             :  */
     667             : template <typename T>
     668             : class Has_size
     669             : {
     670             :   using Yes = char;
     671             :   struct No
     672             :   {
     673             :     char x[2];
     674             :   };
     675             : 
     676             :   template <typename C>
     677             :   static Yes test(decltype(&C::size));
     678             :   template <typename C>
     679             :   static No test(...);
     680             : 
     681             : public:
     682             :   static constexpr bool value = sizeof(test<T>(0)) == sizeof(Yes);
     683             : };
     684             : 
     685             : /**
     686             :  * @param value The quantity to test for zero-ness
     687             :  * @param tolerance The tolerance for testing zero-ness. The default is 1e-18 for double precision
     688             :  * configurations of libMesh/MOOSE
     689             :  * @return whether the L_infty norm of the value is (close enough to) zero
     690             :  */
     691             : template <typename T>
     692             : bool
     693         208 : isZero(const T & value, const Real tolerance = TOLERANCE * TOLERANCE * TOLERANCE)
     694             : {
     695             :   if constexpr (Has_size<T>::value)
     696             :   {
     697          12 :     for (const auto & element : value)
     698           8 :       if (!isZero(element, tolerance))
     699           4 :         return false;
     700             : 
     701           4 :     return true;
     702             :   }
     703             :   else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 0)
     704         184 :     return MooseUtils::absoluteFuzzyEqual(MetaPhysicL::raw_value(value), 0, tolerance);
     705             :   else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 1)
     706             :   {
     707          20 :     for (const auto i : make_range(Moose::dim))
     708          16 :       if (!MooseUtils::absoluteFuzzyEqual(MetaPhysicL::raw_value(value(i)), 0, tolerance))
     709           4 :         return false;
     710             : 
     711           4 :     return true;
     712             :   }
     713             :   else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 2)
     714             :   {
     715          20 :     for (const auto i : make_range(Moose::dim))
     716          52 :       for (const auto j : make_range(Moose::dim))
     717          40 :         if (!MooseUtils::absoluteFuzzyEqual(MetaPhysicL::raw_value(value(i, j)), 0, tolerance))
     718           4 :           return false;
     719             : 
     720           4 :     return true;
     721             :   }
     722             : }
     723             : 
     724             : /**
     725             :  * Function to dump the contents of MaterialPropertyStorage for debugging purposes
     726             :  * @param props The storage item to dump, this should be
     727             :  * MaterialPropertyStorage.props(state)
     728             :  *
     729             :  * Currently this only words for scalar material properties. Something to do as needed would be to
     730             :  * create a method in MaterialProperty
     731             :  * that may be overloaded to dump the type using template specialization.
     732             :  */
     733             : void MaterialPropertyStorageDump(
     734             :     const HashMap<const libMesh::Elem *, HashMap<unsigned int, MaterialProperties>> & props);
     735             : 
     736             : /**
     737             :  * Indents the supplied message given the prefix and color
     738             :  * @param prefix The prefix to use for indenting
     739             :  * @param message The message that will be indented
     740             :  * @param color The color to apply to the prefix (default CYAN)
     741             :  * @param indent_first_line If true this will indent the first line too (default)
     742             :  * @param post_prefix A string to append right after the prefix, defaults to a column and a space
     743             :  *
     744             :  * Takes a message like the following and indents it with another color code (see below)
     745             :  *
     746             :  * Input message:
     747             :  * COLOR_YELLOW
     748             :  * *** Warning ***
     749             :  * Something bad has happened and we want to draw attention to it with color
     750             :  * COLOR_DEFAULT
     751             :  *
     752             :  * Output message:
     753             :  * COLOR_CYAN sub_app: COLOR_YELLOW
     754             :  * COLOR_CYAN sub_app: COLOR_YELLOW *** Warning ***
     755             :  * COLOR_CYAN sub_app: COLOR_YELLOW Something bad has happened and we want to draw attention to it
     756             :  * with color
     757             :  * COLOR_DEFAULT
     758             :  *
     759             :  * Also handles single line color codes
     760             :  * COLOR_CYAN sub_app: 0 Nonlinear |R| = COLOR_GREEN 1.0e-10 COLOR_DEFAULT
     761             :  *
     762             :  * Not indenting the first line is useful in the case where the first line is actually finishing
     763             :  * the line before it.
     764             :  */
     765             : void indentMessage(const std::string & prefix,
     766             :                    std::string & message,
     767             :                    const char * color = COLOR_CYAN,
     768             :                    bool dont_indent_first_line = true,
     769             :                    const std::string & post_prefix = ": ");
     770             : 
     771             : /**
     772             :  * remove ANSI escape sequences for terminal color from msg
     773             :  */
     774             : std::string & removeColor(std::string & msg);
     775             : 
     776             : std::list<std::string> listDir(const std::string path, bool files_only = false);
     777             : 
     778             : bool pathExists(const std::string & path);
     779             : 
     780             : /**
     781             :  * Retrieves the names of all of the files contained within the list of directories passed into
     782             :  * the routine. The names returned will be the paths to the files relative to the current
     783             :  * directory.
     784             :  * @param directory_list The list of directories to retrieve files from.
     785             :  * @param file_only Whether or not to list only files
     786             :  */
     787             : std::list<std::string> getFilesInDirs(const std::list<std::string> & directory_list,
     788             :                                       const bool files_only = true);
     789             : 
     790             : /**
     791             :  * Returns the most recent checkpoint prefix (the four numbers at the beginning)
     792             :  * If a suitable file isn't found the empty string is returned
     793             :  * @param checkpoint_files the list of files to analyze
     794             :  */
     795             : std::string getLatestCheckpointFilePrefix(const std::list<std::string> & checkpoint_files);
     796             : 
     797             : /*
     798             :  * Checks to see if a string matches a search string
     799             :  * @param name The name to check
     800             :  * @param search_string The search string to check name against
     801             :  */
     802             : bool wildCardMatch(std::string name, std::string search_string);
     803             : 
     804             : /*
     805             :  * Checks to see if a candidate string matches a pattern string, permitting glob
     806             :  * wildcards (* and ?) anywhere in the pattern.
     807             :  * @param candidate The name to check
     808             :  * @param pattern The search string to check name candidate
     809             :  */
     810             : bool globCompare(const std::string & candidate,
     811             :                  const std::string & pattern,
     812             :                  std::size_t c = 0,
     813             :                  std::size_t p = 0);
     814             : 
     815             : template <typename T>
     816             : void
     817          26 : expandAllMatches(const std::vector<T> & candidates, std::vector<T> & patterns)
     818             : {
     819          26 :   std::set<T> expanded;
     820          78 :   for (const auto & p : patterns)
     821             :   {
     822          52 :     unsigned int found = 0;
     823         260 :     for (const auto & c : candidates)
     824         208 :       if (globCompare(c, p))
     825             :       {
     826          52 :         expanded.insert(c);
     827          52 :         found++;
     828             :       }
     829          52 :     if (!found)
     830           0 :       throw std::invalid_argument(p);
     831             :   }
     832          26 :   patterns.assign(expanded.begin(), expanded.end());
     833          26 : }
     834             : 
     835             : /**
     836             :  * Takes the string representation of a value and converts it to the value.
     837             :  *
     838             :  * See the convert method in MooseStringUtils.h for more information on
     839             :  * handling of each case.
     840             :  *
     841             :  * @param str The string to convert from
     842             :  * @param throw_on_failure If true, throw on a failure to convert, otherwise use mooseError
     843             :  * @return The converted value on success
     844             :  */
     845             : template <typename T>
     846             : T
     847        6773 : convert(const std::string & str, bool throw_on_failure = false)
     848             : {
     849             :   T val;
     850             :   try
     851             :   {
     852        6773 :     convert(str, val, true);
     853             :   }
     854        1094 :   catch (std::exception const & e)
     855             :   {
     856         549 :     if (throw_on_failure)
     857         541 :       throw;
     858           8 :     mooseError(e.what());
     859             :   }
     860        6224 :   return val;
     861             : }
     862             : 
     863             : /**
     864             :  * Create a symbolic link, if the link already exists it is replaced.
     865             :  */
     866             : void createSymlink(const std::string & target, const std::string & link);
     867             : 
     868             : /**
     869             :  * Remove a symbolic link, if the given filename is a link.
     870             :  */
     871             : void clearSymlink(const std::string & link);
     872             : 
     873             : /**
     874             :  * Returns a container that contains the content of second passed in container
     875             :  * inserted into the first passed in container (set or map union).
     876             :  */
     877             : template <typename T>
     878             : T
     879             : concatenate(T c1, const T & c2)
     880             : {
     881             :   c1.insert(c2.begin(), c2.end());
     882             :   return c1;
     883             : }
     884             : 
     885             : /**
     886             :  * Returns a vector that contains is the concatenation of the two passed in vectors.
     887             :  */
     888             : template <typename T>
     889             : std::vector<T>
     890             : concatenate(std::vector<T> c1, const std::vector<T> & c2)
     891             : {
     892             :   c1.insert(c1.end(), c2.begin(), c2.end());
     893             :   return c1;
     894             : }
     895             : 
     896             : /**
     897             :  * Returns the passed in vector with the item appended to it.
     898             :  */
     899             : template <typename T>
     900             : std::vector<T>
     901          33 : concatenate(std::vector<T> c1, const T & item)
     902             : {
     903          33 :   c1.push_back(item);
     904          33 :   return c1;
     905             : }
     906             : 
     907             : /**
     908             :  * Concatenates \p value into a single string separated by \p separator
     909             :  */
     910             : std::string stringJoin(const std::vector<std::string> & values,
     911             :                        const std::string & separator = " ");
     912             : 
     913             : /**
     914             :  * @return Whether or not \p value begins with \p begin_value
     915             :  */
     916             : bool beginsWith(const std::string & value, const std::string & begin_value);
     917             : 
     918             : /**
     919             :  * Return the number of digits for a number.
     920             :  *
     921             :  * This can foster quite a large discussion:
     922             :  * https://stackoverflow.com/questions/1489830/efficient-way-to-determine-number-of-digits-in-an-integer
     923             :  *
     924             :  * For our purposes I like the following algorithm.
     925             :  */
     926             : template <typename T>
     927             : int
     928        1942 : numDigits(const T & num)
     929             : {
     930        1942 :   return num > 9 ? static_cast<int>(std::log10(static_cast<double>(num))) + 1 : 1;
     931             : }
     932             : 
     933             : /**
     934             :  * Return the default ExecFlagEnum for MOOSE.
     935             :  */
     936             : ExecFlagEnum getDefaultExecFlagEnum();
     937             : 
     938             : /**
     939             :  * Robust string to integer conversion that fails for cases such at "1foo".
     940             :  * @param input The string to convert.
     941             :  * @param throw_on_failure Throw an invalid_argument exception instead of mooseError.
     942             :  */
     943             : int stringToInteger(const std::string & input, bool throw_on_failure = false);
     944             : 
     945             : /**
     946             :  * Linearly partition a number of items
     947             :  *
     948             :  * @param num_items The number of items to partition
     949             :  * @param num_chunks The number of chunks to partition into
     950             :  * @param chunk_id The ID of the chunk you are trying to get information about (typically the
     951             :  * current MPI rank)
     952             :  * @param num_local_items Output: The number of items for this chunk_id
     953             :  * @param local_items_begin Output: The first item for this chunk_id
     954             :  * @param local_items_end Output: One past the final item for this chunk_id
     955             :  */
     956             : void linearPartitionItems(dof_id_type num_items,
     957             :                           dof_id_type num_chunks,
     958             :                           dof_id_type chunk_id,
     959             :                           dof_id_type & num_local_items,
     960             :                           dof_id_type & local_items_begin,
     961             :                           dof_id_type & local_items_end);
     962             : 
     963             : /**
     964             :  * Return the chunk_id that is assigned to handle item_id
     965             :  *
     966             :  * @param num_items Global number of items to partition
     967             :  * @param num_chunks Total number of chunks to split into
     968             :  * @param item_id The item to find the chunk_id for
     969             :  * @return The chunk_id of the chunk that contains item_id
     970             :  */
     971             : processor_id_type
     972             : linearPartitionChunk(dof_id_type num_items, dof_id_type num_chunks, dof_id_type item_id);
     973             : 
     974             : /**
     975             :  * Wrapper around PetscGetRealPath, which is a cross-platform replacement for realpath
     976             :  */
     977             : std::string realpath(const std::string & path);
     978             : 
     979             : /**
     980             :  * Custom type trait that has a ::value of true for types that cam be use interchangeably
     981             :  * with Real. Most notably it is false for complex numbers, which do not have a
     982             :  * strict ordering (and therefore no <,>,<=,>= operators).
     983             :  */
     984             : template <typename T>
     985             : struct IsLikeReal
     986             : {
     987             :   static constexpr bool value = false;
     988             : };
     989             : template <>
     990             : struct IsLikeReal<Real>
     991             : {
     992             :   static constexpr bool value = true;
     993             : };
     994             : template <>
     995             : struct IsLikeReal<ADReal>
     996             : {
     997             :   static constexpr bool value = true;
     998             : };
     999             : 
    1000             : /**
    1001             :  * Custom type trait that has a ::value of true for types that can be broadcasted
    1002             :  */
    1003             : template <typename T>
    1004             : struct canBroadcast
    1005             : {
    1006             :   static constexpr bool value = std::is_base_of<TIMPI::DataType, TIMPI::StandardType<T>>::value ||
    1007             :                                 TIMPI::Has_buffer_type<TIMPI::Packing<T>>::value;
    1008             : };
    1009             : 
    1010             : ///@{ Comparison helpers that support the MooseUtils::Any wildcard which will match any value
    1011             : const static struct AnyType
    1012             : {
    1013             : } Any;
    1014             : 
    1015             : template <typename T1, typename T2>
    1016             : bool
    1017       49557 : wildcardEqual(const T1 & a, const T2 & b)
    1018             : {
    1019       49557 :   return a == b;
    1020             : }
    1021             : 
    1022             : template <typename T>
    1023             : bool
    1024             : wildcardEqual(const T &, AnyType)
    1025             : {
    1026             :   return true;
    1027             : }
    1028             : template <typename T>
    1029             : bool
    1030        5448 : wildcardEqual(AnyType, const T &)
    1031             : {
    1032        5448 :   return true;
    1033             : }
    1034             : ///@}
    1035             : 
    1036             : /**
    1037             :  * Find a specific pair in a container matching on first, second or both pair components
    1038             :  */
    1039             : template <typename C, typename It, typename M1, typename M2>
    1040             : auto
    1041       58978 : findPair(C & container, It start_iterator, const M1 & first, const M2 & second)
    1042             : {
    1043       58978 :   return std::find_if(start_iterator,
    1044             :                       container.end(),
    1045       49557 :                       [&](auto & item) {
    1046       55005 :                         return wildcardEqual(first, item.first) &&
    1047       55005 :                                wildcardEqual(second, item.second);
    1048       58978 :                       });
    1049             : }
    1050             : 
    1051             : /**
    1052             :  * Construct a valid bounding box from 2 arbitrary points
    1053             :  *
    1054             :  * If you have 2 points in space and you wish to construct a bounding box, you should use
    1055             :  * this method to avoid unexpected behavior of the underlying BoundingBox class in libMesh.
    1056             :  * BoundingBox class expect 2 points whose coordinates are "sorted" (i.e., x-, y- and -z
    1057             :  * coordinates of the first point are smaller then the corresponding coordinates of the second
    1058             :  * point). If this "sorting" is not present, the BoundingBox class will build an empty box and
    1059             :  * any further testing of points inside the box will fail. This method will allow you to obtain
    1060             :  * the correct bounding box for any valid combination of 2 corner points of a box.
    1061             :  *
    1062             :  * @param p1 First corner of the constructed bounding box
    1063             :  * @param p2 Second corner of the constructed bounding box
    1064             :  * @return Valid bounding box
    1065             :  */
    1066             : libMesh::BoundingBox buildBoundingBox(const Point & p1, const Point & p2);
    1067             : 
    1068             : /**
    1069             :  * Utility class template for a semidynamic vector with a maximum size N
    1070             :  * and a chosen dynamic size. This container avoids heap allocation and
    1071             :  * is meant as a replacement for small local std::vector variables.
    1072             :  * By default this class uses `value initialization`. This can be disabled
    1073             :  * using the third template parameter if uninitialized storage is acceptable,
    1074             :  */
    1075             : template <typename T, std::size_t N, bool value_init = true>
    1076             : #if METAPHYSICL_MAJOR_VERSION < 2
    1077             : class SemidynamicVector : public MetaPhysicL::DynamicStdArrayWrapper<T, MetaPhysicL::NWrapper<N>>
    1078             : {
    1079             :   typedef MetaPhysicL::DynamicStdArrayWrapper<T, MetaPhysicL::NWrapper<N>> Parent;
    1080             : #else
    1081             : class SemidynamicVector : public MetaPhysicL::DynamicStdArrayWrapper<T, N>
    1082             : {
    1083             :   typedef MetaPhysicL::DynamicStdArrayWrapper<T, N> Parent;
    1084             : #endif
    1085             : 
    1086             : public:
    1087    21764038 :   SemidynamicVector(std::size_t size) : Parent()
    1088             :   {
    1089     5441014 :     Parent::resize(size);
    1090             :     if constexpr (value_init)
    1091    21728244 :       for (const auto i : make_range(size))
    1092    16287232 :         _data[i] = T{};
    1093     5441014 :   }
    1094             : 
    1095           2 :   void resize(std::size_t new_size)
    1096             :   {
    1097           2 :     [[maybe_unused]] const auto old_dynamic_n = Parent::size();
    1098             : 
    1099           2 :     Parent::resize(new_size);
    1100             : 
    1101             :     if constexpr (value_init)
    1102             :       for (const auto i : make_range(old_dynamic_n, _dynamic_n))
    1103             :         _data[i] = T{};
    1104           2 :   }
    1105             : 
    1106           2 :   void push_back(const T & v)
    1107             :   {
    1108           2 :     const auto old_dynamic_n = Parent::size();
    1109           2 :     Parent::resize(old_dynamic_n + 1);
    1110           2 :     _data[old_dynamic_n] = v;
    1111           2 :   }
    1112             : 
    1113             :   template <typename... Args>
    1114           2 :   void emplace_back(Args &&... args)
    1115             :   {
    1116           2 :     const auto old_dynamic_n = Parent::size();
    1117           2 :     Parent::resize(old_dynamic_n + 1);
    1118           2 :     (::new (&_data[old_dynamic_n]) T(std::forward<Args>(args)...));
    1119           2 :   }
    1120             : 
    1121           2 :   std::size_t max_size() const { return N; }
    1122             : 
    1123             :   using Parent::_data;
    1124             :   using Parent::_dynamic_n;
    1125             : };
    1126             : 
    1127             : /**
    1128             :  * The MooseUtils::get() specializations are used to support making
    1129             :  * forwards-compatible code changes from dumb pointers to smart pointers.
    1130             :  * The same line of code, e.g.
    1131             :  *
    1132             :  * libMesh::Parameters::Value * value = MooseUtils::get(map_iter->second);
    1133             :  *
    1134             :  * will then work regardless of whether map_iter->second is a dumb pointer
    1135             :  * or a smart pointer. Note that the smart pointer get() functions are const
    1136             :  * so they can be (ab)used to get a non-const pointer to the underlying
    1137             :  * resource. We are simply following this convention here.
    1138             :  */
    1139             : template <typename T>
    1140             : T *
    1141   147669734 : get(const std::unique_ptr<T> & u)
    1142             : {
    1143   147669734 :   return u.get();
    1144             : }
    1145             : 
    1146             : template <typename T>
    1147             : T *
    1148             : get(T * p)
    1149             : {
    1150             :   return p;
    1151             : }
    1152             : 
    1153             : template <typename T>
    1154             : T *
    1155             : get(const std::shared_ptr<T> & s)
    1156             : {
    1157             :   return s.get();
    1158             : }
    1159             : 
    1160             : /**
    1161             :  * This method detects whether two sets intersect without building a result set.
    1162             :  * It exits as soon as any intersection is detected.
    1163             :  */
    1164             : template <class InputIterator>
    1165             : bool
    1166          37 : setsIntersect(InputIterator first1, InputIterator last1, InputIterator first2, InputIterator last2)
    1167             : {
    1168          51 :   while (first1 != last1 && first2 != last2)
    1169             :   {
    1170          18 :     if (*first1 == *first2)
    1171           4 :       return true;
    1172             : 
    1173          14 :     if (*first1 < *first2)
    1174           0 :       ++first1;
    1175          14 :     else if (*first1 > *first2)
    1176          14 :       ++first2;
    1177             :   }
    1178          33 :   return false;
    1179             : }
    1180             : 
    1181             : template <class T>
    1182             : bool
    1183          37 : setsIntersect(const T & s1, const T & s2)
    1184             : {
    1185          37 :   return setsIntersect(s1.begin(), s1.end(), s2.begin(), s2.end());
    1186             : }
    1187             : 
    1188             : /**
    1189             :  * Courtesy https://stackoverflow.com/a/8889045 and
    1190             :  * https://en.cppreference.com/w/cpp/string/byte/isdigit
    1191             :  * @return Whether every character in the string is a digit
    1192             :  */
    1193             : inline bool
    1194     1953848 : isDigits(const std::string & str)
    1195             : {
    1196     4466371 :   return std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isdigit(c); });
    1197             : }
    1198             : 
    1199             : /**
    1200             :  * Courtesy https://stackoverflow.com/a/57163016 and
    1201             :  * https://stackoverflow.com/questions/447206/c-isfloat-function
    1202             :  * @return Whether the string is convertible to a float
    1203             :  */
    1204             : inline bool
    1205          17 : isFloat(const std::string & str)
    1206             : {
    1207          17 :   if (str.empty())
    1208           0 :     return false;
    1209             :   char * ptr;
    1210          17 :   strtof(str.c_str(), &ptr);
    1211          17 :   return (*ptr) == '\0';
    1212             : }
    1213             : 
    1214             : /**
    1215             :  * Gets the canonical path of the given path
    1216             :  */
    1217             : std::string canonicalPath(const std::string & path);
    1218             : 
    1219             : /**
    1220             :  * @returns Whether the \p string1 starts with \p string2
    1221             :  */
    1222             : bool startsWith(const std::string & string1, const std::string & string2);
    1223             : 
    1224             : /**
    1225             :  * Replace the starting string \p string2 of \p string1 with \p string3. A user should have checked
    1226             :  * that \p string1 \p startsWith \p string2
    1227             :  */
    1228             : void replaceStart(std::string & string1, const std::string & string2, const std::string & string3);
    1229             : 
    1230             : /**
    1231             :  * @returns whether every alphabetic character in a string is lower-case
    1232             :  */
    1233             : bool isAllLowercase(const std::string & str);
    1234             : } // MooseUtils namespace
    1235             : 
    1236             : namespace Moose
    1237             : {
    1238             : template <typename T>
    1239             : struct ADType;
    1240             : 
    1241             : template <typename T, std::size_t N, bool value_init>
    1242             : struct ADType<MooseUtils::SemidynamicVector<T, N, value_init>>
    1243             : {
    1244             :   typedef MooseUtils::SemidynamicVector<typename ADType<T>::type, N, value_init> type;
    1245             : };
    1246             : }
    1247             : 
    1248             : /**
    1249             :  * find, erase, length algorithm for removing a substring from a string
    1250             :  */
    1251             : void removeSubstring(std::string & main, const std::string & sub);
    1252             : 
    1253             : /**
    1254             :  * find, erase, length algorithm for removing a substring from a copy of a string
    1255             :  */
    1256             : std::string removeSubstring(const std::string & main, const std::string & sub);

Generated by: LCOV version 1.14