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

Generated by: LCOV version 1.14