LCOV - code coverage report
Current view: top level - src/utils - MooseUtils.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 464 565 82.1 %
Date: 2026-05-29 20:35:17 Functions: 53 61 86.9 %
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             : // MOOSE includes
      11             : #include "MooseUtils.h"
      12             : #include "MooseError.h"
      13             : #include "MaterialProperty.h"
      14             : #include "MultiMooseEnum.h"
      15             : #include "InputParameters.h"
      16             : #include "ExecFlagEnum.h"
      17             : #include "InfixIterator.h"
      18             : #include "Registry.h"
      19             : #include "MortarConstraintBase.h"
      20             : #include "MortarNodalAuxKernel.h"
      21             : #include "ExecFlagRegistry.h"
      22             : #include "RestartableDataReader.h"
      23             : 
      24             : #include "libmesh/utility.h"
      25             : #include "libmesh/elem.h"
      26             : 
      27             : // External includes
      28             : #include "pcrecpp.h"
      29             : #include "tinydir.h"
      30             : 
      31             : // C++ includes
      32             : #include <iostream>
      33             : #include <fstream>
      34             : #include <istream>
      35             : #include <iterator>
      36             : #include <filesystem>
      37             : #include <ctime>
      38             : #include <cstdlib>
      39             : #include <regex>
      40             : 
      41             : // System includes
      42             : #include <sys/stat.h>
      43             : #include <numeric>
      44             : #include <unistd.h>
      45             : 
      46             : #include "petscsys.h"
      47             : 
      48             : #ifdef __WIN32__
      49             : #include <windows.h>
      50             : #include <winbase.h>
      51             : #include <fileapi.h>
      52             : #else
      53             : #include <sys/ioctl.h>
      54             : #endif
      55             : 
      56             : namespace MooseUtils
      57             : {
      58             : std::filesystem::path
      59      292912 : pathjoin(const std::filesystem::path & p)
      60             : {
      61      292912 :   return p;
      62             : }
      63             : 
      64             : std::string
      65           3 : runTestsExecutable()
      66             : {
      67           3 :   auto build_loc = pathjoin(Moose::getExecutablePath(), "run_tests");
      68           3 :   if (pathExists(build_loc) && checkFileReadable(build_loc))
      69           3 :     return build_loc;
      70             :   // TODO: maybe no path prefix - just moose_test_runner here?
      71           0 :   return pathjoin(Moose::getExecutablePath(), "moose_test_runner");
      72           3 : }
      73             : 
      74             : std::string
      75           3 : findTestRoot()
      76             : {
      77           3 :   std::string path = ".";
      78           3 :   for (int i = 0; i < 5; i++)
      79             :   {
      80           3 :     auto testroot = pathjoin(path, "testroot");
      81           3 :     if (pathExists(testroot) && checkFileReadable(testroot))
      82           3 :       return testroot;
      83           0 :     path += "/..";
      84           3 :   }
      85           0 :   return "";
      86           3 : }
      87             : 
      88             : bool
      89        2804 : parsesToReal(const std::string & input, Real * parsed_real)
      90             : {
      91        2804 :   std::istringstream ss(input);
      92             :   Real real_value;
      93        2804 :   if (ss >> real_value && ss.eof())
      94             :   {
      95        2050 :     if (parsed_real)
      96         273 :       (*parsed_real) = real_value;
      97        2050 :     return true;
      98             :   }
      99         754 :   return false;
     100        2804 : }
     101             : 
     102             : std::string
     103           6 : installedInputsDir(const std::string & app_name,
     104             :                    const std::string & dir_name,
     105             :                    const std::string & extra_error_msg)
     106             : {
     107             :   // See moose.mk for a detailed explanation of the assumed installed application
     108             :   // layout. Installed inputs are expected to be installed in "share/<app_name>/<folder>".
     109             :   // The binary, which has a defined location will be in "bin", a peer directory to "share".
     110             :   std::string installed_path =
     111           6 :       pathjoin(Moose::getExecutablePath(), "..", "share", app_name, dir_name);
     112             : 
     113           6 :   auto test_root = pathjoin(installed_path, "testroot");
     114           6 :   if (!pathExists(installed_path))
     115           0 :     mooseError("Couldn't locate any installed inputs to copy in path: ",
     116             :                installed_path,
     117           0 :                '\n',
     118             :                extra_error_msg);
     119             : 
     120           6 :   checkFileReadable(test_root);
     121          12 :   return installed_path;
     122           6 : }
     123             : 
     124             : std::string
     125           0 : docsDir(const std::string & app_name)
     126             : {
     127             :   // See moose.mk for a detailed explanation of the assumed installed application
     128             :   // layout. Installed docs are expected to be installed in "share/<app_name>/doc".
     129             :   // The binary, which has a defined location will be in "bin", a peer directory to "share".
     130           0 :   std::string installed_path = pathjoin(Moose::getExecutablePath(), "..", "share", app_name, "doc");
     131             : 
     132           0 :   auto docfile = pathjoin(installed_path, "css", "moose.css");
     133           0 :   if (pathExists(docfile) && checkFileReadable(docfile))
     134           0 :     return installed_path;
     135           0 :   return "";
     136           0 : }
     137             : 
     138             : std::string
     139     6374311 : mooseDocsURL(const std::string & path)
     140             : {
     141     6374311 :   return "https://mooseframework.inl.gov/" + path;
     142             : }
     143             : 
     144             : std::string
     145      213653 : replaceAll(std::string str, const std::string & from, const std::string & to)
     146             : {
     147      213653 :   size_t start_pos = 0;
     148      214247 :   while ((start_pos = str.find(from, start_pos)) != std::string::npos)
     149             :   {
     150         594 :     str.replace(start_pos, from.length(), to);
     151         594 :     start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
     152             :   }
     153      213653 :   return str;
     154             : }
     155             : 
     156             : std::string
     157        3787 : convertLatestCheckpoint(std::string orig)
     158             : {
     159        3787 :   auto slash_pos = orig.find_last_of("/");
     160        3787 :   auto path = orig.substr(0, slash_pos);
     161        3787 :   auto file = orig.substr(slash_pos + 1);
     162        3787 :   if (file != "LATEST")
     163        3433 :     return orig;
     164             : 
     165         354 :   auto converted = MooseUtils::getLatestCheckpointFilePrefix(MooseUtils::listDir(path));
     166             : 
     167         354 :   if (converted.empty())
     168           0 :     mooseError("Unable to find suitable recovery file!");
     169             : 
     170         354 :   return converted;
     171        3787 : }
     172             : 
     173             : // this implementation is copied from
     174             : // https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C.2B.2B
     175             : int
     176        3433 : levenshteinDist(const std::string & s1, const std::string & s2)
     177             : {
     178             :   // To change the type this function manipulates and returns, change
     179             :   // the return type and the types of the two variables below.
     180        3433 :   auto s1len = s1.size();
     181        3433 :   auto s2len = s2.size();
     182             : 
     183        3433 :   auto column_start = (decltype(s1len))1;
     184             : 
     185        3433 :   auto column = new decltype(s1len)[s1len + 1];
     186        3433 :   std::iota(column + column_start, column + s1len + 1, column_start);
     187             : 
     188       34528 :   for (auto x = column_start; x <= s2len; x++)
     189             :   {
     190       31095 :     column[0] = x;
     191       31095 :     auto last_diagonal = x - column_start;
     192      397623 :     for (auto y = column_start; y <= s1len; y++)
     193             :     {
     194      366528 :       auto old_diagonal = column[y];
     195      366528 :       auto possibilities = {
     196      366528 :           column[y] + 1, column[y - 1] + 1, last_diagonal + (s1[y - 1] == s2[x - 1] ? 0 : 1)};
     197      366528 :       column[y] = std::min(possibilities);
     198      366528 :       last_diagonal = old_diagonal;
     199             :     }
     200             :   }
     201        3433 :   auto result = column[s1len];
     202        3433 :   delete[] column;
     203        3433 :   return result;
     204             : }
     205             : 
     206             : void
     207     1223059 : escape(std::string & str)
     208             : {
     209     1223059 :   std::map<char, std::string> escapes;
     210     1223059 :   escapes['\a'] = "\\a";
     211     1223059 :   escapes['\b'] = "\\b";
     212     1223059 :   escapes['\f'] = "\\f";
     213     1223059 :   escapes['\n'] = "\\n";
     214     1223059 :   escapes['\t'] = "\\t";
     215     1223059 :   escapes['\v'] = "\\v";
     216     1223059 :   escapes['\r'] = "\\r";
     217             : 
     218     9784472 :   for (const auto & it : escapes)
     219     8561729 :     for (size_t pos = 0; (pos = str.find(it.first, pos)) != std::string::npos;
     220         316 :          pos += it.second.size())
     221         316 :       str.replace(pos, 1, it.second);
     222     1223059 : }
     223             : 
     224             : std::string
     225      491408 : removeExtraWhitespace(const std::string & input)
     226             : {
     227      491408 :   return std::regex_replace(input, std::regex("^\\s+|\\s+$|\\s+(?=\\s)"), "");
     228             : }
     229             : 
     230             : bool
     231           0 : pathContains(const std::string & expression,
     232             :              const std::string & string_to_find,
     233             :              const std::string & delims)
     234             : {
     235           0 :   std::vector<std::string> elements;
     236           0 :   tokenize(expression, elements, 0, delims);
     237             : 
     238             :   std::vector<std::string>::iterator found_it =
     239           0 :       std::find(elements.begin(), elements.end(), string_to_find);
     240           0 :   if (found_it != elements.end())
     241           0 :     return true;
     242             :   else
     243           0 :     return false;
     244           0 : }
     245             : 
     246             : bool
     247       26811 : pathExists(const std::string & path)
     248             : {
     249             :   struct stat buffer;
     250       26811 :   return (stat(path.c_str(), &buffer) == 0);
     251             : }
     252             : 
     253             : bool
     254      503055 : checkFileReadable(const std::string & filename,
     255             :                   bool check_line_endings,
     256             :                   bool throw_on_unreadable,
     257             :                   bool check_for_git_lfs_pointer)
     258             : {
     259      503055 :   std::ifstream in(filename.c_str(), std::ifstream::in);
     260      503055 :   if (in.fail())
     261             :   {
     262      140123 :     if (throw_on_unreadable)
     263          14 :       mooseError(
     264          24 :           (std::string("Unable to open file \"") + filename +
     265          18 :            std::string("\". Check to make sure that it exists and that you have read permission."))
     266          16 :               .c_str());
     267             :     else
     268      140109 :       return false;
     269             :   }
     270             : 
     271      362932 :   if (check_line_endings)
     272             :   {
     273       66395 :     std::istream_iterator<char> iter(in);
     274       66395 :     std::istream_iterator<char> eos;
     275       66395 :     in >> std::noskipws;
     276    81395656 :     while (iter != eos)
     277    81329261 :       if (*iter++ == '\r')
     278           0 :         mooseError(filename + " contains Windows(DOS) line endings which are not supported.");
     279             :   }
     280             : 
     281      362932 :   if (check_for_git_lfs_pointer && checkForGitLFSPointer(in))
     282           6 :     mooseError(filename + " appears to be a Git-LFS pointer. Make sure you have \"git-lfs\" "
     283             :                           "installed so that you may pull this file.");
     284      362926 :   in.close();
     285             : 
     286      362926 :   return true;
     287      503037 : }
     288             : 
     289             : bool
     290      209868 : checkForGitLFSPointer(std::ifstream & file)
     291             : {
     292             :   mooseAssert(file.is_open(), "Passed in file handle is not open");
     293             : 
     294      209868 :   std::string line;
     295             : 
     296             :   // git-lfs pointer files contain several name value pairs. The specification states that the
     297             :   // first name/value pair must be "version {url}". We'll do a simplified check for that.
     298      209868 :   file.seekg(0);
     299      209868 :   std::getline(file, line);
     300      209868 :   if (line.find("version https://") != std::string::npos)
     301           6 :     return true;
     302             :   else
     303      209862 :     return false;
     304      209868 : }
     305             : 
     306             : bool
     307         236 : checkFileWriteable(const std::string & filename, bool throw_on_unwritable)
     308             : {
     309         236 :   std::ofstream out(filename.c_str(), std::ios_base::app);
     310         236 :   if (out.fail())
     311             :   {
     312           0 :     if (throw_on_unwritable)
     313           0 :       mooseError(
     314           0 :           (std::string("Unable to open file \"") + filename +
     315           0 :            std::string("\". Check to make sure that it exists and that you have write permission."))
     316           0 :               .c_str());
     317             :     else
     318           0 :       return false;
     319             :   }
     320             : 
     321         236 :   out.close();
     322             : 
     323         236 :   return true;
     324         236 : }
     325             : 
     326             : void
     327      242440 : parallelBarrierNotify(const Parallel::Communicator & comm, bool messaging)
     328             : {
     329             :   processor_id_type secondary_processor_id;
     330             : 
     331      242440 :   if (messaging)
     332           0 :     Moose::out << "Waiting For Other Processors To Finish" << std::endl;
     333      242440 :   if (comm.rank() == 0)
     334             :   {
     335             :     // The primary process is already through, so report it
     336      175211 :     if (messaging)
     337           0 :       Moose::out << "Jobs complete: 1/" << comm.size() << (1 == comm.size() ? "\n" : "\r")
     338           0 :                  << std::flush;
     339      242440 :     for (unsigned int i = 2; i <= comm.size(); ++i)
     340             :     {
     341       67229 :       comm.receive(MPI_ANY_SOURCE, secondary_processor_id);
     342       67229 :       if (messaging)
     343           0 :         Moose::out << "Jobs complete: " << i << "/" << comm.size()
     344           0 :                    << (i == comm.size() ? "\n" : "\r") << std::flush;
     345             :     }
     346             :   }
     347             :   else
     348             :   {
     349       67229 :     secondary_processor_id = comm.rank();
     350       67229 :     comm.send(0, secondary_processor_id);
     351             :   }
     352             : 
     353      242440 :   comm.barrier();
     354      242440 : }
     355             : 
     356             : void
     357           9 : serialBegin(const libMesh::Parallel::Communicator & comm, bool warn)
     358             : {
     359             :   // unless we are the first processor...
     360           9 :   if (comm.rank() > 0)
     361             :   {
     362             :     // ...wait for the previous processor to finish
     363           3 :     int dummy = 0;
     364           3 :     comm.receive(comm.rank() - 1, dummy);
     365             :   }
     366           6 :   else if (warn)
     367           0 :     mooseWarning("Entering serial execution block (use only for debugging)");
     368           9 : }
     369             : 
     370             : void
     371           9 : serialEnd(const libMesh::Parallel::Communicator & comm, bool warn)
     372             : {
     373             :   // unless we are the last processor...
     374           9 :   if (comm.rank() + 1 < comm.size())
     375             :   {
     376             :     // ...notify the next processor of its turn
     377           3 :     int dummy = 0;
     378           3 :     comm.send(comm.rank() + 1, dummy);
     379             :   }
     380             : 
     381           9 :   comm.barrier();
     382           9 :   if (comm.rank() == 0 && warn)
     383           0 :     mooseWarning("Leaving serial execution block (use only for debugging)");
     384           9 : }
     385             : 
     386             : bool
     387       38801 : hasExtension(const std::string & filename, std::string ext, bool strip_exodus_ext)
     388             : {
     389             :   // Extract the extension, w/o the '.'
     390       38801 :   std::string file_ext;
     391       38801 :   if (strip_exodus_ext)
     392             :   {
     393             :     pcrecpp::RE re(
     394       13195 :         ".*\\.([^\\.]*?)(?:-s\\d+)?\\s*$"); // capture the complete extension, ignoring -s*
     395       13195 :     re.FullMatch(filename, &file_ext);
     396       13195 :   }
     397             :   else
     398             :   {
     399       25606 :     pcrecpp::RE re(".*\\.([^\\.]*?)\\s*$"); // capture the complete extension
     400       25606 :     re.FullMatch(filename, &file_ext);
     401       25606 :   }
     402             : 
     403             :   // Perform the comparision
     404       38801 :   if (file_ext == ext)
     405       13655 :     return true;
     406             :   else
     407       25146 :     return false;
     408       38801 : }
     409             : 
     410             : std::string
     411         598 : getExtension(const std::string & filename, const bool rfind)
     412             : {
     413         598 :   std::string file_ext = "";
     414         598 :   if (filename != "")
     415             :   {
     416             :     // The next line splits filename at the last "/" and gives the file name after "/"
     417         586 :     const std::string stripped_filename = splitFileName<std::string>(filename).second;
     418         586 :     auto pos = rfind ? stripped_filename.rfind(".") : stripped_filename.find(".");
     419         586 :     if (pos != std::string::npos)
     420         185 :       file_ext += stripped_filename.substr(pos + 1, std::string::npos);
     421         586 :   }
     422             : 
     423         598 :   return file_ext;
     424           0 : }
     425             : 
     426             : std::string
     427         239 : stripExtension(const std::string & s, const bool rfind)
     428             : {
     429         239 :   const std::string ext = getExtension(s, rfind);
     430         239 :   const bool offset = (ext.size() != 0);
     431             :   // -1 offset accounts for the extension's leading dot ("."), if there is an extension
     432         478 :   return s.substr(0, s.size() - ext.size() - offset);
     433         239 : }
     434             : 
     435             : std::string
     436           3 : getCurrentWorkingDir()
     437             : {
     438             :   // Note: At the time of creating this method, our minimum compiler still
     439             :   // does not support <filesystem>. Additionally, the inclusion of that header
     440             :   // requires an additional library to be linked so for now, we'll just
     441             :   // use the Unix standard library to get us the cwd().
     442           3 :   constexpr unsigned int BUF_SIZE = 1024;
     443             :   char buffer[BUF_SIZE];
     444             : 
     445           6 :   return getcwd(buffer, BUF_SIZE) != nullptr ? buffer : "";
     446             : }
     447             : 
     448             : void
     449          16 : makedirs(const std::string & dir_name, bool throw_on_failure)
     450             : {
     451             :   // split path into directories with delimiter '/'
     452          16 :   std::vector<std::string> split_dir_names;
     453          16 :   MooseUtils::tokenize(dir_name, split_dir_names);
     454             : 
     455          16 :   auto n = split_dir_names.size();
     456             : 
     457             :   // remove '.' and '..' when possible
     458          16 :   auto i = n;
     459          16 :   i = 0;
     460          72 :   while (i != n)
     461             :   {
     462          56 :     if (split_dir_names[i] == ".")
     463             :     {
     464           6 :       for (auto j = i + 1; j < n; ++j)
     465           4 :         split_dir_names[j - 1] = split_dir_names[j];
     466           2 :       --n;
     467             :     }
     468          54 :     else if (i > 0 && split_dir_names[i] == ".." && split_dir_names[i - 1] != "..")
     469             :     {
     470           8 :       for (auto j = i + 1; j < n; ++j)
     471           6 :         split_dir_names[j - 2] = split_dir_names[j];
     472           2 :       n -= 2;
     473           2 :       --i;
     474             :     }
     475             :     else
     476          52 :       ++i;
     477             :   }
     478          16 :   if (n == 0)
     479           0 :     return;
     480             : 
     481          16 :   split_dir_names.resize(n);
     482             : 
     483             :   // start creating directories recursively
     484          16 :   std::string cur_dir = dir_name[0] == '/' ? "" : ".";
     485          64 :   for (auto & dir : split_dir_names)
     486             :   {
     487          50 :     cur_dir += "/" + dir;
     488             : 
     489          50 :     if (!pathExists(cur_dir))
     490             :     {
     491          34 :       auto code = Utility::mkdir(cur_dir.c_str());
     492          34 :       if (code != 0)
     493             :       {
     494           2 :         std::string msg = "Failed creating directory " + dir_name;
     495           2 :         if (throw_on_failure)
     496           2 :           throw std::invalid_argument(msg);
     497             :         else
     498           0 :           mooseError(msg);
     499           2 :       }
     500             :     }
     501             :   }
     502          18 : }
     503             : 
     504             : void
     505          14 : removedirs(const std::string & dir_name, bool throw_on_failure)
     506             : {
     507             :   // split path into directories with delimiter '/'
     508          14 :   std::vector<std::string> split_dir_names;
     509          14 :   MooseUtils::tokenize(dir_name, split_dir_names);
     510             : 
     511          14 :   auto n = split_dir_names.size();
     512             : 
     513             :   // remove '.' and '..' when possible
     514          14 :   auto i = n;
     515          14 :   i = 0;
     516          68 :   while (i != n)
     517             :   {
     518          54 :     if (split_dir_names[i] == ".")
     519             :     {
     520           6 :       for (auto j = i + 1; j < n; ++j)
     521           4 :         split_dir_names[j - 1] = split_dir_names[j];
     522           2 :       --n;
     523             :     }
     524          52 :     else if (i > 0 && split_dir_names[i] == ".." && split_dir_names[i - 1] != "..")
     525             :     {
     526           8 :       for (auto j = i + 1; j < n; ++j)
     527           6 :         split_dir_names[j - 2] = split_dir_names[j];
     528           2 :       n -= 2;
     529           2 :       --i;
     530             :     }
     531             :     else
     532          50 :       ++i;
     533             :   }
     534          14 :   if (n == 0)
     535           0 :     return;
     536             : 
     537          14 :   split_dir_names.resize(n);
     538             : 
     539             :   // start removing directories recursively
     540          14 :   std::string base_dir = dir_name[0] == '/' ? "" : ".";
     541          46 :   for (i = n; i > 0; --i)
     542             :   {
     543          38 :     std::string cur_dir = base_dir;
     544          38 :     auto j = i;
     545         142 :     for (j = 0; j < i; ++j)
     546         104 :       cur_dir += "/" + split_dir_names[j];
     547             : 
     548             :     // listDir should return at least '.' and '..'
     549          38 :     if (pathExists(cur_dir) && listDir(cur_dir).size() == 2)
     550             :     {
     551          32 :       auto code = rmdir(cur_dir.c_str());
     552          32 :       if (code != 0)
     553             :       {
     554           0 :         std::string msg = "Failed removing directory " + dir_name;
     555           0 :         if (throw_on_failure)
     556           0 :           throw std::invalid_argument(msg);
     557             :         else
     558           0 :           mooseError(msg);
     559           0 :       }
     560             :     }
     561             :     else
     562             :       // stop removing
     563           6 :       break;
     564          38 :   }
     565          14 : }
     566             : 
     567             : std::string
     568          28 : camelCaseToUnderscore(const std::string & camel_case_name)
     569             : {
     570          28 :   std::string replaced = camel_case_name;
     571             :   // Put underscores in front of each contiguous set of capital letters
     572          28 :   pcrecpp::RE("(?!^)(?<![A-Z_])([A-Z]+)").GlobalReplace("_\\1", &replaced);
     573             : 
     574             :   // Convert all capital letters to lower case
     575          28 :   std::transform(replaced.begin(), replaced.end(), replaced.begin(), ::tolower);
     576          28 :   return replaced;
     577           0 : }
     578             : 
     579             : std::string
     580         494 : underscoreToCamelCase(const std::string & underscore_name, bool leading_upper_case)
     581             : {
     582         494 :   pcrecpp::StringPiece input(underscore_name);
     583         494 :   pcrecpp::RE re("([^_]*)(_|$)");
     584             : 
     585         494 :   std::string result;
     586         494 :   std::string us, not_us;
     587         494 :   bool make_upper = leading_upper_case;
     588         518 :   while (re.Consume(&input, &not_us, &us))
     589             :   {
     590         518 :     if (not_us.length() > 0)
     591             :     {
     592         506 :       if (make_upper)
     593             :       {
     594         502 :         result += std::toupper(not_us[0]);
     595         502 :         if (not_us.length() > 1)
     596         502 :           result += not_us.substr(1);
     597             :       }
     598             :       else
     599           4 :         result += not_us;
     600             :     }
     601         518 :     if (us == "")
     602         494 :       break;
     603             : 
     604             :     // Toggle flag so next match is upper cased
     605          24 :     make_upper = true;
     606             :   }
     607             : 
     608         988 :   return result;
     609         494 : }
     610             : 
     611             : std::string
     612     4227041 : shortName(const std::string & name)
     613             : {
     614     4227041 :   return name.substr(name.find_last_of('/') != std::string::npos ? name.find_last_of('/') + 1 : 0);
     615             : }
     616             : 
     617             : std::string
     618     1478321 : baseName(const std::string & name)
     619             : {
     620     1478321 :   return name.substr(0, name.find_last_of('/') != std::string::npos ? name.find_last_of('/') : 0);
     621             : }
     622             : 
     623             : std::string
     624          11 : hostname()
     625             : {
     626             :   char hostname[1024];
     627          11 :   hostname[1023] = '\0';
     628             : #ifndef __WIN32__
     629          11 :   if (gethostname(hostname, 1023))
     630           0 :     mooseError("Failed to retrieve hostname!");
     631             : #else
     632             :   DWORD dwSize = sizeof(hostname);
     633             :   if (!GetComputerNameEx(ComputerNamePhysicalDnsHostname, hostname, &dwSize))
     634             :     mooseError("Failed to retrieve hostname!");
     635             : #endif
     636          22 :   return hostname;
     637             : }
     638             : 
     639             : unsigned short
     640      118988 : getTermWidth(bool use_environment)
     641             : {
     642             : #ifndef __WIN32__
     643             :   struct winsize w;
     644             : #else
     645             :   struct
     646             :   {
     647             :     unsigned short ws_col;
     648             :   } w;
     649             : #endif
     650             :   /**
     651             :    * Initialize the value we intend to populate just in case
     652             :    * the system call fails
     653             :    */
     654      118988 :   w.ws_col = std::numeric_limits<unsigned short>::max();
     655             : 
     656      118988 :   if (use_environment)
     657             :   {
     658      118988 :     char * pps_width = std::getenv("MOOSE_PPS_WIDTH");
     659      118988 :     if (pps_width != NULL)
     660             :     {
     661           0 :       std::stringstream ss(pps_width);
     662           0 :       ss >> w.ws_col;
     663           0 :     }
     664             :   }
     665             :   // Default to AUTO if no environment variable was set
     666      118988 :   if (w.ws_col == std::numeric_limits<unsigned short>::max())
     667             :   {
     668             : #ifndef __WIN32__
     669             :     try
     670             :     {
     671      118988 :       ioctl(0, TIOCGWINSZ, &w);
     672             :     }
     673             :     catch (...)
     674             : #endif
     675             :     {
     676             :     }
     677             :   }
     678             : 
     679             :   // Something bad happened, make sure we have a sane value
     680             :   // 132 seems good for medium sized screens, and is available as a GNOME preset
     681      118988 :   if (w.ws_col == std::numeric_limits<unsigned short>::max())
     682      118988 :     w.ws_col = 132;
     683             : 
     684      118988 :   return w.ws_col;
     685             : }
     686             : 
     687             : void
     688           0 : MaterialPropertyStorageDump(
     689             :     const HashMap<const libMesh::Elem *, HashMap<unsigned int, MaterialProperties>> & props)
     690             : {
     691             :   // Loop through the elements
     692           0 :   for (const auto & elem_it : props)
     693             :   {
     694           0 :     Moose::out << "Element " << elem_it.first->id() << '\n';
     695             : 
     696             :     // Loop through the sides
     697           0 :     for (const auto & side_it : elem_it.second)
     698             :     {
     699           0 :       Moose::out << "  Side " << side_it.first << '\n';
     700             : 
     701             :       // Loop over properties
     702           0 :       unsigned int cnt = 0;
     703           0 :       for (const auto & mat_prop : side_it.second)
     704             :       {
     705           0 :         if (auto mp = dynamic_cast<const MaterialProperty<Real> *>(&mat_prop))
     706             :         {
     707           0 :           Moose::out << "    Property " << cnt << '\n';
     708           0 :           cnt++;
     709             : 
     710             :           // Loop over quadrature points
     711           0 :           for (unsigned int qp = 0; qp < mp->size(); ++qp)
     712           0 :             Moose::out << "      prop[" << qp << "] = " << (*mp)[qp] << '\n';
     713             :         }
     714             :       }
     715             :     }
     716             :   }
     717             : 
     718           0 :   Moose::out << std::flush;
     719           0 : }
     720             : 
     721             : std::string &
     722       19426 : removeColor(std::string & msg)
     723             : {
     724       19426 :   pcrecpp::RE re("(\\33\\[3[0-7]m))", pcrecpp::DOTALL());
     725       19426 :   re.GlobalReplace(std::string(""), &msg);
     726       19426 :   return msg;
     727       19426 : }
     728             : 
     729             : void
     730           0 : addLineBreaks(std::string & message,
     731             :               unsigned int line_width /*= ConsoleUtils::console_line_length*/)
     732             : {
     733           0 :   for (auto i : make_range(int(message.length() / line_width)))
     734           0 :     message.insert((i + 1) * (line_width + 2) - 2, "\n");
     735           0 : }
     736             : 
     737             : void
     738     1232954 : indentMessage(const std::string & prefix,
     739             :               std::string & message,
     740             :               const char * color /*= COLOR_CYAN*/,
     741             :               bool indent_first_line,
     742             :               const std::string & post_prefix)
     743             : {
     744             :   // First we need to see if the message we need to indent (with color) also contains color codes
     745             :   // that span lines.
     746             :   // The code matches all of the XTERM constants (see XTermConstants.h). If it does, then we'll work
     747             :   // on formatting
     748             :   // each colored multiline chunk one at a time with the right codes.
     749     1232954 :   std::string colored_message;
     750     1232954 :   std::string curr_color = COLOR_DEFAULT; // tracks last color code before newline
     751     1232954 :   std::string line, color_code;
     752             : 
     753     1232954 :   bool ends_in_newline = message.empty() ? true : message.back() == '\n';
     754             : 
     755     1232954 :   bool first = true;
     756             : 
     757     1232954 :   std::istringstream iss(message);
     758     3203188 :   for (std::string line; std::getline(iss, line);) // loop over each line
     759             :   {
     760     1970234 :     const static pcrecpp::RE match_color(".*(\\33\\[3\\dm)((?!\\33\\[3\\d)[^\n])*");
     761     1970234 :     pcrecpp::StringPiece line_piece(line);
     762     1970234 :     match_color.FindAndConsume(&line_piece, &color_code);
     763             : 
     764     1970234 :     if (!first || indent_first_line)
     765     1970234 :       colored_message += color + prefix + post_prefix + curr_color;
     766             : 
     767     1970234 :     colored_message += line;
     768             : 
     769             :     // Only add a newline to the last line if it had one to begin with!
     770     1970234 :     if (!iss.eof() || ends_in_newline)
     771     1912573 :       colored_message += "\n";
     772             : 
     773     1970234 :     if (!color_code.empty())
     774      877906 :       curr_color = color_code; // remember last color of this line
     775             : 
     776     1970234 :     first = false;
     777     1232954 :   }
     778     1232954 :   message = colored_message;
     779     1232954 : }
     780             : 
     781             : std::list<std::string>
     782        3669 : listDir(const std::string path, bool files_only)
     783             : {
     784        3669 :   std::list<std::string> files;
     785             : 
     786        3669 :   tinydir_dir dir;
     787        3669 :   dir.has_next = 0; // Avoid a garbage value in has_next (clang StaticAnalysis)
     788        3669 :   tinydir_open(&dir, path.c_str());
     789             : 
     790       23322 :   while (dir.has_next)
     791             :   {
     792             :     tinydir_file file;
     793       19653 :     file.is_dir = 0; // Avoid a garbage value in is_dir (clang StaticAnalysis)
     794       19653 :     tinydir_readfile(&dir, &file);
     795             : 
     796       19653 :     if (!files_only || !file.is_dir)
     797       19653 :       files.push_back(path + "/" + file.name);
     798             : 
     799       19653 :     tinydir_next(&dir);
     800             :   }
     801             : 
     802        3669 :   tinydir_close(&dir);
     803             : 
     804        7338 :   return files;
     805           0 : }
     806             : 
     807             : std::list<std::string>
     808        3256 : getFilesInDirs(const std::list<std::string> & directory_list, const bool files_only /* = true */)
     809             : {
     810        3256 :   std::list<std::string> files;
     811             : 
     812        6535 :   for (const auto & dir_name : directory_list)
     813        3279 :     files.splice(files.end(), listDir(dir_name, files_only));
     814             : 
     815        3256 :   return files;
     816           0 : }
     817             : 
     818             : std::string
     819        3610 : getLatestCheckpointFilePrefix(const std::list<std::string> & checkpoint_files)
     820             : {
     821             :   // Create storage for newest restart files
     822             :   // Note that these might have the same modification time if the simulation was fast.
     823             :   // In that case we're going to save all of the "newest" files and sort it out momentarily
     824        3610 :   std::time_t newest_time = 0;
     825        3610 :   std::list<std::string> newest_restart_files;
     826             : 
     827             :   // Loop through all possible files and store the newest
     828       23066 :   for (const auto & cp_file : checkpoint_files)
     829             :   {
     830       38912 :     if (MooseUtils::hasExtension(cp_file, "rd"))
     831             :     {
     832             :       struct stat stats;
     833        7214 :       stat(cp_file.c_str(), &stats);
     834             : 
     835        7214 :       std::time_t mod_time = stats.st_mtime;
     836        7214 :       if (mod_time > newest_time)
     837             :       {
     838        3857 :         newest_restart_files.clear(); // If the modification time is greater, clear the list
     839        3857 :         newest_time = mod_time;
     840             :       }
     841             : 
     842        7214 :       if (mod_time == newest_time)
     843        6592 :         newest_restart_files.push_back(cp_file);
     844             :     }
     845             :   }
     846             : 
     847             :   // Loop through all of the newest files according the number in the file name
     848        3610 :   int max_file_num = -1;
     849        3610 :   std::string max_file;
     850        3610 :   std::string max_prefix;
     851             : 
     852             :   // Pull out the path including the number and the number itself
     853             :   // This takes something_blah_out_cp/0024-restart-1.rd
     854             :   // and returns "something_blah_out_cp/0024" as the "prefix"
     855             :   // and then "24" as the number itself
     856        3610 :   pcrecpp::RE re_file_num("(.*?(\\d+))-restart-\\d+.rd$");
     857             : 
     858             :   // Now, out of the newest files find the one with the largest number in it
     859        9916 :   for (const auto & res_file : newest_restart_files)
     860             :   {
     861        6306 :     int file_num = 0;
     862             : 
     863             :     // All of the file up to and including the digits
     864        6306 :     std::string file_prefix;
     865             : 
     866        6306 :     re_file_num.FullMatch(res_file, &file_prefix, &file_num);
     867             : 
     868        6306 :     if (file_num > max_file_num)
     869             :     {
     870             :       // Need both the header and the data
     871        4103 :       if (!RestartableDataReader::isAvailable(res_file))
     872           0 :         continue;
     873             : 
     874        4103 :       max_file_num = file_num;
     875        4103 :       max_file = res_file;
     876        4103 :       max_prefix = file_prefix;
     877             :     }
     878        6306 :   }
     879             : 
     880             :   // Error if nothing was located
     881        3610 :   if (max_file_num == -1)
     882           3 :     mooseError("No checkpoint file found!");
     883             : 
     884        7214 :   return max_prefix;
     885        3607 : }
     886             : 
     887             : bool
     888    22020162 : wildCardMatch(std::string name, std::string search_string)
     889             : {
     890             :   // Assume that an empty string matches anything
     891    22020162 :   if (search_string == "")
     892    21076470 :     return true;
     893             : 
     894             :   // transform to lower for case insenstive matching
     895      943692 :   std::transform(name.begin(), name.end(), name.begin(), (int (*)(int))std::toupper);
     896      943692 :   std::transform(search_string.begin(),
     897             :                  search_string.end(),
     898             :                  search_string.begin(),
     899             :                  (int (*)(int))std::toupper);
     900             : 
     901             :   // exact match!
     902      943692 :   if (search_string.find("*") == std::string::npos)
     903      943692 :     return search_string == name;
     904             : 
     905             :   // wildcard
     906           0 :   std::vector<std::string> tokens;
     907           0 :   MooseUtils::tokenize(search_string, tokens, 1, "*");
     908             : 
     909           0 :   size_t pos = 0;
     910           0 :   for (unsigned int i = 0; i < tokens.size() && pos != std::string::npos; ++i)
     911             :   {
     912           0 :     pos = name.find(tokens[i], pos);
     913             :     // See if we have a leading wildcard
     914           0 :     if (search_string[0] != '*' && i == 0 && pos != 0)
     915           0 :       return false;
     916             :   }
     917             : 
     918           0 :   if (pos != std::string::npos && tokens.size() > 0)
     919             :   {
     920             :     // Now see if we have a trailing wildcard
     921           0 :     size_t last_token_length = tokens.back().length();
     922           0 :     if (*search_string.rbegin() == '*' || pos == name.size() - last_token_length)
     923           0 :       return true;
     924             :     else
     925           0 :       return false;
     926             :   }
     927             :   else
     928           0 :     return false;
     929           0 : }
     930             : 
     931             : bool
     932       57601 : globCompare(const std::string & candidate,
     933             :             const std::string & pattern,
     934             :             std::size_t c,
     935             :             std::size_t p)
     936             : {
     937       57601 :   if (p == pattern.size())
     938        1965 :     return c == candidate.size();
     939             : 
     940       55636 :   if (pattern[p] == '*')
     941             :   {
     942       28754 :     for (; c < candidate.size(); ++c)
     943       27656 :       if (globCompare(candidate, pattern, c, p + 1))
     944         184 :         return true;
     945        1098 :     return globCompare(candidate, pattern, c, p + 1);
     946             :   }
     947             : 
     948       54354 :   if (pattern[p] != '?' && pattern[p] != candidate[c])
     949       36263 :     return false;
     950             : 
     951       18091 :   return globCompare(candidate, pattern, c + 1, p + 1);
     952             : }
     953             : 
     954             : bool
     955     1241346 : beginsWith(const std::string & value, const std::string & begin_value)
     956             : {
     957     1241346 :   return value.rfind(begin_value, 0) == 0;
     958             : }
     959             : 
     960             : ExecFlagEnum
     961     5215731 : getDefaultExecFlagEnum()
     962             : {
     963     5215731 :   return moose::internal::ExecFlagRegistry::getExecFlagRegistry().getDefaultFlags();
     964             : }
     965             : 
     966             : int
     967         200 : stringToInteger(const std::string & input, bool throw_on_failure)
     968             : {
     969         200 :   return convert<int>(input, throw_on_failure);
     970             : }
     971             : 
     972             : void
     973         802 : linearPartitionItems(dof_id_type num_items,
     974             :                      dof_id_type num_chunks,
     975             :                      dof_id_type chunk_id,
     976             :                      dof_id_type & num_local_items,
     977             :                      dof_id_type & local_items_begin,
     978             :                      dof_id_type & local_items_end)
     979             : {
     980         802 :   auto global_num_local_items = num_items / num_chunks;
     981             : 
     982         802 :   num_local_items = global_num_local_items;
     983             : 
     984         802 :   auto leftovers = num_items % num_chunks;
     985             : 
     986         802 :   if (chunk_id < leftovers)
     987             :   {
     988          42 :     num_local_items++;
     989          42 :     local_items_begin = num_local_items * chunk_id;
     990             :   }
     991             :   else
     992         760 :     local_items_begin =
     993         760 :         (global_num_local_items + 1) * leftovers + global_num_local_items * (chunk_id - leftovers);
     994             : 
     995         802 :   local_items_end = local_items_begin + num_local_items;
     996         802 : }
     997             : 
     998             : processor_id_type
     999      354887 : linearPartitionChunk(dof_id_type num_items, dof_id_type num_chunks, dof_id_type item_id)
    1000             : {
    1001      354887 :   auto global_num_local_items = num_items / num_chunks;
    1002             : 
    1003      354887 :   auto leftovers = num_items % num_chunks;
    1004             : 
    1005      354887 :   auto first_item_past_first_part = leftovers * (global_num_local_items + 1);
    1006             : 
    1007             :   // Is it in the first section (that gets an extra item)
    1008      354887 :   if (item_id < first_item_past_first_part)
    1009         442 :     return item_id / (global_num_local_items + 1);
    1010             :   else
    1011             :   {
    1012      354445 :     auto new_item_id = item_id - first_item_past_first_part;
    1013             : 
    1014             :     // First chunk after the first section + the number of chunks after that
    1015      354445 :     return leftovers + (new_item_id / global_num_local_items);
    1016             :   }
    1017             : }
    1018             : 
    1019             : std::vector<std::string>
    1020       10398 : split(const std::string & str, const std::string & delimiter, std::size_t max_count)
    1021             : {
    1022       10398 :   std::vector<std::string> output;
    1023       10398 :   std::size_t count = 0;
    1024       10398 :   size_t prev = 0, pos = 0;
    1025             :   do
    1026             :   {
    1027       26836 :     pos = str.find(delimiter, prev);
    1028       26836 :     output.push_back(str.substr(prev, pos - prev));
    1029       26836 :     prev = pos + delimiter.length();
    1030       26836 :     count += 1;
    1031       26836 :   } while (pos != std::string::npos && count < max_count);
    1032             : 
    1033       10398 :   if (pos != std::string::npos)
    1034           2 :     output.push_back(str.substr(prev));
    1035             : 
    1036       10398 :   return output;
    1037           0 : }
    1038             : 
    1039             : std::vector<std::string>
    1040        9634 : rsplit(const std::string & str, const std::string & delimiter, std::size_t max_count)
    1041             : {
    1042        9634 :   std::vector<std::string> output;
    1043        9634 :   std::size_t count = 0;
    1044        9634 :   size_t prev = str.length(), pos = str.length();
    1045             :   do
    1046             :   {
    1047       16314 :     pos = str.rfind(delimiter, prev);
    1048       16314 :     output.insert(output.begin(), str.substr(pos + delimiter.length(), prev - pos));
    1049       16314 :     prev = pos - delimiter.length();
    1050       16314 :     count += 1;
    1051       16314 :   } while (pos != std::string::npos && pos > 0 && count < max_count);
    1052             : 
    1053        9634 :   if (pos != std::string::npos)
    1054           4 :     output.insert(output.begin(), str.substr(0, pos));
    1055             : 
    1056        9634 :   return output;
    1057           0 : }
    1058             : 
    1059             : void
    1060         146 : createSymlink(const std::string & target, const std::string & link)
    1061             : {
    1062         146 :   clearSymlink(link);
    1063             : #ifndef __WIN32__
    1064         146 :   auto err = symlink(target.c_str(), link.c_str());
    1065             : #else
    1066             :   auto err = CreateSymbolicLink(target.c_str(), link.c_str(), 0);
    1067             : #endif
    1068         146 :   if (err)
    1069           0 :     mooseError("Failed to create symbolic link (via 'symlink') from ", target, " to ", link);
    1070         146 : }
    1071             : 
    1072             : void
    1073        5906 : clearSymlink(const std::string & link)
    1074             : {
    1075             : #ifndef __WIN32__
    1076             :   struct stat sbuf;
    1077        5906 :   if (lstat(link.c_str(), &sbuf) == 0)
    1078             :   {
    1079         120 :     auto err = unlink(link.c_str());
    1080         120 :     if (err != 0)
    1081           0 :       mooseError("Failed to remove symbolic link (via 'unlink') to ", link);
    1082             :   }
    1083             : #else
    1084             :   auto attr = GetFileAttributesA(link.c_str());
    1085             :   if (attr != INVALID_FILE_ATTRIBUTES)
    1086             :   {
    1087             :     auto err = _unlink(link.c_str());
    1088             :     if (err != 0)
    1089             :       mooseError("Failed to remove link/file (via '_unlink') to ", link);
    1090             :   }
    1091             : #endif
    1092        5906 : }
    1093             : 
    1094             : std::size_t
    1095      120725 : fileSize(const std::string & filename)
    1096             : {
    1097             : #ifndef __WIN32__
    1098             :   struct stat buffer;
    1099      120725 :   if (!stat(filename.c_str(), &buffer))
    1100      120725 :     return buffer.st_size;
    1101             : #else
    1102             :   HANDLE hFile = CreateFile(filename.c_str(),
    1103             :                             GENERIC_READ,
    1104             :                             FILE_SHARE_READ | FILE_SHARE_WRITE,
    1105             :                             NULL,
    1106             :                             OPEN_EXISTING,
    1107             :                             FILE_ATTRIBUTE_NORMAL,
    1108             :                             NULL);
    1109             :   if (hFile == INVALID_HANDLE_VALUE)
    1110             :     return 0;
    1111             : 
    1112             :   LARGE_INTEGER size;
    1113             :   if (GetFileSizeEx(hFile, &size))
    1114             :   {
    1115             :     CloseHandle(hFile);
    1116             :     return size.QuadPart;
    1117             :   }
    1118             : 
    1119             :   CloseHandle(hFile);
    1120             : #endif
    1121           0 :   return 0;
    1122             : }
    1123             : 
    1124             : std::string
    1125       66447 : realpath(const std::string & path)
    1126             : {
    1127       66447 :   return std::filesystem::absolute(path);
    1128             : }
    1129             : 
    1130             : BoundingBox
    1131        7904 : buildBoundingBox(const Point & p1, const Point & p2)
    1132             : {
    1133        7904 :   BoundingBox bb;
    1134        7904 :   bb.union_with(p1);
    1135        7904 :   bb.union_with(p2);
    1136        7904 :   return bb;
    1137             : }
    1138             : 
    1139             : std::string
    1140      863007 : prettyCppType(const std::string & cpp_type)
    1141             : {
    1142             :   // On mac many of the std:: classes are inline namespaced with __1
    1143             :   // On linux std::string can be inline namespaced with __cxx11
    1144      863007 :   std::string s = cpp_type;
    1145             :   // Remove all spaces surrounding a >
    1146      863007 :   pcrecpp::RE("\\s(?=>)").GlobalReplace("", &s);
    1147      863007 :   pcrecpp::RE("std::__\\w+::").GlobalReplace("std::", &s);
    1148             :   // It would be nice if std::string actually looked normal
    1149      863007 :   pcrecpp::RE("\\s*std::basic_string<char, std::char_traits<char>, std::allocator<char>>\\s*")
    1150      863007 :       .GlobalReplace("std::string", &s);
    1151             :   // It would be nice if std::vector looked normal
    1152      863007 :   pcrecpp::RE r("std::vector<([[:print:]]+),\\s?std::allocator<\\s?\\1\\s?>\\s?>");
    1153      863007 :   r.GlobalReplace("std::vector<\\1>", &s);
    1154             :   // Do it again for nested vectors
    1155      863007 :   r.GlobalReplace("std::vector<\\1>", &s);
    1156             :   // It would be nice if std::map and unordered map looked normal
    1157             :   pcrecpp::RE r_map(
    1158             :       "std::map<\\s*((?:[^,<]|<[^>]*>)+)\\s*,\\s*((?:[^,<]|<[^>]*>)+)\\s*,\\s*"
    1159             :       "std::less<\\s*\\1\\s*>\\s*,\\s*"
    1160      863007 :       "std::allocator<\\s*std::pair<\\s*(?:const\\s*\\1|\\1\\s*const)\\s*,\\s*\\2\\s*>\\s*>\\s*>");
    1161      863007 :   r_map.GlobalReplace("std::map<\\1, \\2>", &s);
    1162             :   pcrecpp::RE r_umap(
    1163             :       "std::unordered_map<\\s*([^,]+)\\s*,\\s*([^,]+)\\s*,\\s*"
    1164             :       "std::hash<\\s*\\1\\s*>\\s*,\\s*"
    1165             :       "std::equal_to<\\s*\\1\\s*>\\s*,\\s*"
    1166      863007 :       "std::allocator<\\s*std::pair<\\s*(?:const\\s*\\1|\\1\\s*const)\\s*,\\s*\\2\\s*>\\s*>\\s*>");
    1167      863007 :   r_umap.GlobalReplace("std::unordered_map<\\1, \\2>", &s);
    1168             : 
    1169     1726014 :   return s;
    1170      863007 : }
    1171             : 
    1172             : std::string
    1173      154796 : canonicalPath(const std::string & path)
    1174             : {
    1175      154796 :   return std::filesystem::weakly_canonical(path).c_str();
    1176             : }
    1177             : 
    1178             : bool
    1179           0 : startsWith(const std::string & string1, const std::string & string2)
    1180             : {
    1181           0 :   if (string2.size() > string1.size())
    1182           0 :     return false;
    1183           0 :   return string1.compare(0, string2.size(), string2) == 0;
    1184             : }
    1185             : 
    1186             : void
    1187           0 : replaceStart(std::string & string1, const std::string & string2, const std::string & string3)
    1188             : {
    1189             :   mooseAssert(startsWith(string1, string2),
    1190             :               "Cannot replace the start because it doesn't match the start string");
    1191           0 :   string1.replace(0, string2.size(), string3);
    1192           0 : }
    1193             : 
    1194             : bool
    1195           0 : isAllLowercase(const std::string & str)
    1196             : {
    1197           0 :   return std::all_of(
    1198           0 :       str.begin(), str.end(), [](unsigned char c) { return !std::isalpha(c) || std::islower(c); });
    1199             : }
    1200             : } // MooseUtils namespace
    1201             : 
    1202             : void
    1203       79292 : removeSubstring(std::string & main, const std::string & sub)
    1204             : {
    1205       79292 :   std::string::size_type n = sub.length();
    1206       79292 :   for (std::string::size_type i = main.find(sub); i != std::string::npos; i = main.find(sub))
    1207           0 :     main.erase(i, n);
    1208       79292 : }
    1209             : 
    1210             : std::string
    1211      297811 : removeSubstring(const std::string & main, const std::string & sub)
    1212             : {
    1213      297811 :   std::string copy_main = main;
    1214      297811 :   std::string::size_type n = sub.length();
    1215      595622 :   for (std::string::size_type i = copy_main.find(sub); i != std::string::npos;
    1216      297811 :        i = copy_main.find(sub))
    1217      297811 :     copy_main.erase(i, n);
    1218      297811 :   return copy_main;
    1219           0 : }

Generated by: LCOV version 1.14