LCOV - code coverage report
Current view: top level - include/utils - utility.h (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4308 (b969c4) with base 7aa2c3 Lines: 46 66 69.7 %
Date: 2025-11-07 13:38:09 Functions: 97 188 51.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : #ifndef LIBMESH_UTILITY_H
      20             : #define LIBMESH_UTILITY_H
      21             : 
      22             : // LibMesh includes
      23             : #include "libmesh/libmesh_common.h" // for Real
      24             : 
      25             : // C++ includes
      26             : #include <string>
      27             : #include <vector>
      28             : #include <algorithm> // is_sorted, lower_bound
      29             : #include <memory> // unique_ptr
      30             : 
      31             : namespace libMesh
      32             : {
      33             : 
      34             : /**
      35             :  * Encapsulates the common "get value from map, otherwise error"
      36             :  * idiom, which is similar to calling map.at(), but gives a more
      37             :  * useful error message with a line number.
      38             :  */
      39             : #define libmesh_map_find(map, key) libMesh::Utility::map_find((map), (key), __FILE__, __LINE__)
      40             : 
      41             : /**
      42             :  * Encapsulates the common "get value from vector, otherwise error"
      43             :  * idiom, which is similar to calling vec.at(), but gives a more
      44             :  * useful error message with a line number.
      45             :  */
      46             : #define libmesh_vector_at(vec, idx) libMesh::Utility::vector_at((vec), (idx), __FILE__, __LINE__)
      47             : 
      48             : // ------------------------------------------------------------
      49             : // The Utility namespace is for functions
      50             : // which are useful but don't necessarily belong anywhere else.
      51             : 
      52             : namespace Utility
      53             : {
      54             : 
      55             : /**
      56             :  * \returns A string containing information about the system you are
      57             :  * running on.
      58             :  */
      59             : std::string system_info();
      60             : 
      61             : /**
      62             :  * Helper struct for enabling template metaprogramming/SFINAE.
      63             :  */
      64             : template <typename T>
      65             : class is_streamable
      66             : {
      67             :   template <typename U> // must be template to get SFINAE fall-through...
      68             :   static auto test(const U* u) -> decltype(std::cout << *u);
      69             : 
      70             :   static auto test(...) -> std::false_type;
      71             : 
      72             : public:
      73             :   enum { value = !std::is_same<decltype(test((T*)0)), std::false_type>::value };
      74             : };
      75             : 
      76             : /**
      77             :  * -Wdangling-reference was nowhere *near* ready to add to -Wall in
      78             :  *  gcc 13.  It's been moved to -Wextra, but we use that too.  :-)
      79             :  *
      80             :  *  See e.g. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109642
      81             :  *
      82             :  *  Our map_find functions trigger it.
      83             :  */
      84             : 
      85             : #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
      86             : #if (__GNUC__ > 12)
      87             : #pragma GCC diagnostic push
      88             : #pragma GCC diagnostic ignored "-Wdangling-reference"
      89             : #endif
      90             : #endif
      91             : 
      92             : /**
      93             :  * This function should not be called directly (although it can be),
      94             :  * instead see the libmesh_map_find() macro.
      95             :  *
      96             :  * Calls find(key), and checks the result against end(). Returns the
      97             :  * corresponding value if found, throws an error otherwise. Templated
      98             :  * on the type of map, so this will work with both std::map and
      99             :  * std::unordered_map.
     100             :  */
     101             : template<typename Map, typename Key,
     102             :          typename std::enable_if<!is_streamable<Key>::value, Key>::type* = nullptr>
     103             : inline
     104             : typename Map::mapped_type &
     105      316664 : map_find(Map & map,
     106             :          const Key & key,
     107             :          const char * filename,
     108             :          int line_number)
     109             : {
     110      205880 :   auto it = map.find(key);
     111      316664 :   libmesh_error_msg_if(it == map.end(),
     112             :                        "map_find() error: key not found in file "
     113             :                        << filename << " on line " << line_number);
     114      316664 :   return it->second;
     115             : }
     116             : 
     117             : /**
     118             :  * A version of the function above that works for const objects.
     119             :  */
     120             : template<typename Map, typename Key,
     121             :          typename std::enable_if<!is_streamable<Key>::value, Key>::type* = nullptr>
     122             : inline
     123             : const typename Map::mapped_type &
     124        8736 : map_find(const Map & map,
     125             :          const Key & key,
     126             :          const char * filename,
     127             :          int line_number)
     128             : {
     129         684 :   auto it = map.find(key);
     130        8736 :   libmesh_error_msg_if(it == map.end(),
     131             :                        "map_find() error: key not found in file "
     132             :                        << filename << " on line " << line_number);
     133        8736 :   return it->second;
     134             : }
     135             : 
     136             : /**
     137             :  * A version of the map_find() utility which can only be used if
     138             :  * the map key is printable via std::stream.
     139             :  */
     140             : template<typename Map, typename Key,
     141             :          typename std::enable_if<is_streamable<Key>::value, Key>::type* = nullptr>
     142             : inline
     143             : typename Map::mapped_type &
     144    29533135 : map_find(Map & map,
     145             :          const Key & key,
     146             :          const char * filename,
     147             :          int line_number)
     148             : {
     149    19681631 :   auto it = map.find(key);
     150    29533135 :   libmesh_error_msg_if(it == map.end(),
     151             :                        "map_find() error: key \"" << key << "\" not found in file "
     152             :                        << filename << " on line " << line_number);
     153    29533135 :   return it->second;
     154             : }
     155             : 
     156             : /**
     157             :  * A version of the function above that works for const objects.
     158             :  */
     159             : template<typename Map, typename Key,
     160             :          typename std::enable_if<is_streamable<Key>::value, Key>::type* = nullptr>
     161             : inline
     162             : const typename Map::mapped_type &
     163    58930011 : map_find(const Map & map,
     164             :          const Key & key,
     165             :          const char * filename,
     166             :          int line_number)
     167             : {
     168     4554132 :   auto it = map.find(key);
     169    58930437 :   libmesh_error_msg_if(it == map.end(),
     170             :                        "map_find() error: key \"" << key << "\" not found in file "
     171             :                        << filename << " on line " << line_number);
     172    58929798 :   return it->second;
     173             : }
     174             : 
     175             : // The map_find functions are our only dangling-reference false positives
     176             : 
     177             : #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
     178             : #if (__GNUC__ > 12)
     179             : #pragma GCC diagnostic pop
     180             : #endif
     181             : #endif
     182             : 
     183             : 
     184             : /**
     185             :  * A replacement for std::vector::at(i) which is meant to be used with
     186             :  * a macro, and, unlike at(), gives a proper line number and useful
     187             :  * error message when the index is past the end.
     188             :  */
     189             : template<typename Vector>
     190             : inline
     191             : typename Vector::reference &
     192     5250151 : vector_at(Vector & vec,
     193             :           typename Vector::size_type i,
     194             :           const char * filename,
     195             :           int line_number)
     196             : {
     197     5685295 :   libmesh_error_msg_if(i >= vec.size(),
     198             :                        "vec_at() error: Index " << i <<
     199             :                        " past end of vector in file " << filename <<
     200             :                        " on line " << line_number);
     201     5250151 :   return vec[i];
     202             : }
     203             : 
     204             : /**
     205             :  * Same as above, but for const inputs.
     206             :  */
     207             : template<typename Vector>
     208             : inline
     209             : typename Vector::const_reference &
     210       33237 : vector_at(const Vector & vec,
     211             :           typename Vector::size_type i,
     212             :           const char * filename,
     213             :           int line_number)
     214             : {
     215       33237 :   libmesh_error_msg_if(i >= vec.size(),
     216             :                        "vec_at() error: Index " << i <<
     217             :                        " past end of vector in file " << filename <<
     218             :                        " on line " << line_number);
     219       33237 :   return vec[i];
     220             : }
     221             : 
     222             : 
     223             : /**
     224             :  * The STL provides \p std::binary_search() which returns \p true or
     225             :  * \p false depending on whether the searched-for value is found.  In
     226             :  * contrast, Utility::binary_find() uses a std::lower_bound() based
     227             :  * search on a sorted range to find the required value.
     228             :  *
     229             :  * \returns An iterator to the searched-for element, or "last" if the
     230             :  * element is not found.
     231             :  */
     232             : template<class ForwardIterator, class T>
     233         572 : ForwardIterator binary_find(ForwardIterator first, ForwardIterator last, const T & value)
     234             : {
     235         572 :   ForwardIterator it = std::lower_bound(first, last, value);
     236         572 :   return (it == last || value < *it) ? last : it;
     237             : }
     238             : 
     239             : /**
     240             :  * As above, but takes a custom comparison object.
     241             :  */
     242             : template<class ForwardIterator, class T, class Compare>
     243             : ForwardIterator binary_find(ForwardIterator first, ForwardIterator last, const T & value, Compare comp)
     244             : {
     245             :   ForwardIterator it = std::lower_bound(first, last, value, comp);
     246             :   return (it == last || comp(value,*it)) ? last : it;
     247             : }
     248             : 
     249             : 
     250             : /**
     251             :  * An efficient template instantiation for raising
     252             :  * to an arbitrary integer power.
     253             :  */
     254             : template <int N, typename T>
     255             : struct do_pow {
     256   147956813 :   static inline T apply (const T & x)
     257             :   {
     258             :     libmesh_assert(N>1);
     259             : 
     260             :     if (N%2) // odd exponent
     261     4768157 :       return x * do_pow<N-1,T>::apply(x);
     262             : 
     263   147881428 :     const T xNover2 = do_pow<N/2,T>::apply(x);
     264             : 
     265  7241691431 :     return xNover2*xNover2;
     266             :   }
     267             : };
     268             : 
     269             : // An efficient compiler would distill N=6 down to 3
     270             : // multiplications, but an inefficient one (or a complicated
     271             : // T::operator*) might do worse, so we'll specialize here.
     272             : template <typename T>
     273             : struct do_pow<6,T> {
     274         289 :   static inline T apply (const T & x)
     275             :   {
     276        3179 :     const T x2 = x*x,
     277        3179 :       x4 = x2*x2;
     278             : 
     279        3179 :     return x4*x2;
     280             :   }
     281             : };
     282             : 
     283             : template <typename T>
     284             : struct do_pow<1,T> {
     285    59112543 :   static inline T apply (const T & x) { return x; }
     286             : };
     287             : 
     288             : template <typename T>
     289             : struct do_pow<0,T> {
     290             :   static inline T apply (const T &) { return 1; }
     291             : };
     292             : 
     293             : 
     294             : template <int N, typename T>
     295             : inline
     296   599351757 : T pow(const T & x)
     297             : {
     298   599351757 :   return do_pow<N,T>::apply(x);
     299             : }
     300             : 
     301             : /**
     302             :  * A simple implementation of the factorial.
     303             :  */
     304             : inline
     305             : unsigned int factorial(unsigned int n)
     306             : {
     307             : 
     308             :   unsigned int factorial_n = 1;
     309             : 
     310             :   if (n==0)
     311             :     return factorial_n;
     312             : 
     313             :   for (unsigned int i=1; i<n; i++)
     314             :     factorial_n *= i+1;
     315             : 
     316             :   return factorial_n;
     317             : }
     318             : 
     319             : 
     320             : // Simple function to compute "n choose k", aka the binomial coefficient.
     321             : template <typename T>
     322           0 : T binomial(T n, T k)
     323             : {
     324           0 :   T ret = 1;
     325             : 
     326             :   // Binomial function is "symmetric" in k, C(n, k) = C(n, n-k).
     327           0 :   if (k > n - k)
     328           0 :     k = n - k;
     329             : 
     330             :   // Compute n * (n-1) * ... * (n-k+1) / (k * (k-1) * ... * 1)
     331           0 :   for (T i = 0; i < k; ++i)
     332             :     {
     333           0 :       ret *= (n - i);
     334           0 :       ret /= (i + 1);
     335             :     }
     336             : 
     337           0 :   return ret;
     338             : }
     339             : 
     340             : 
     341             : /**
     342             :  * A convenient method to truly empty a vector using the "swap trick"
     343             :  */
     344             : template <typename T>
     345        9912 : void deallocate (std::vector<T> & vec)
     346             : {
     347        9960 :   std::vector<T>().swap(vec);
     348        9912 : }
     349             : 
     350             : 
     351             : // When looking for a complicated suffix to a filename, we only want
     352             : // to consider the base name, without any preceding path name.
     353             : // "/tmp/foo.e25ad0/mesh.msh" is not ExodusII.
     354             : std::string_view basename_of(const std::string & fullname);
     355             : 
     356             : 
     357             : /**
     358             :  * Look for a substring within a string.
     359             :  */
     360             : bool contains(std::string_view superstring,
     361             :               std::string_view substring);
     362             : 
     363             : 
     364             : /**
     365             :  * Look for a substring at the very end of a string.
     366             :  */
     367             : bool ends_with(std::string_view superstring,
     368             :                std::string_view suffix);
     369             : 
     370             : 
     371             : // Utility functions useful when dealing with complex numbers.
     372             : 
     373             : #ifdef LIBMESH_USE_COMPLEX_NUMBERS
     374             : 
     375             : /**
     376             :  * \returns For \p r_o_c = 0 the filename for output of the real part
     377             :  * of complex data, and for  \p r_o_c = 1 the filename for the imaginary
     378             :  * part.
     379             :  */
     380             : std::string complex_filename (std::string basename,
     381             :                               unsigned int r_o_c=0);
     382             : 
     383             : /**
     384             :  * Prepare complex data for writing.
     385             :  */
     386             : void prepare_complex_data (const std::vector<Complex> & source,
     387             :                            std::vector<Real> & real_part,
     388             :                            std::vector<Real> & imag_part);
     389             : 
     390             : #endif // #ifdef LIBMESH_USE_COMPLEX_NUMBERS
     391             : 
     392             : 
     393             : /**
     394             :  * Create a directory.
     395             :  */
     396             : int mkdir(const char* pathname);
     397             : 
     398             : 
     399             : /**
     400             :  * Create an unzipped copy of a bz2 or xz file, returning the name of
     401             :  * the now-unzipped file that can be directly opened.
     402             :  *
     403             :  * This is a hack because we don't have a neat bz2/xz equivalent to
     404             :  * gzstreams.
     405             :  */
     406             : std::string unzip_file (std::string_view name);
     407             : 
     408             : 
     409             : /**
     410             :  * This Functor simply takes an object and reverses its byte
     411             :  * representation.  This is useful for changing endian-ness
     412             :  * for file IO.  This class has been tested on x86 architectures
     413             :  * with 4-byte words.
     414             :  *
     415             :  *
     416             :  */
     417             : class ReverseBytes
     418             : {
     419             : public:
     420             : 
     421             :   /**
     422             :    * Constructor.  Takes a bool, determines if we will actually
     423             :    * do byte reversing.
     424             :    */
     425             :   explicit
     426             :   ReverseBytes (const bool dr);
     427             : 
     428             :   /**
     429             :    * Functor.  Takes the data to reverse and performs the
     430             :    * byte-ordering reversal.
     431             :    */
     432             :   template <typename T>
     433             :   T operator () (T & data) const;
     434             : 
     435             : private:
     436             : 
     437             :   /**
     438             :    * \returns The value of the reverse flag.
     439             :    */
     440       42185 :   bool reverse () const { return _do_reverse; }
     441             : 
     442             :   /**
     443             :    * flag
     444             :    */
     445             :   const bool _do_reverse;
     446             : };
     447             : 
     448             : 
     449             : 
     450             : // ReverseBytes inline members
     451             : inline
     452          11 : ReverseBytes::ReverseBytes (const bool rb) :
     453          11 :   _do_reverse (rb)
     454           1 : {}
     455             : 
     456             : 
     457             : template <typename T>
     458             : inline
     459       42185 : T ReverseBytes::operator() (T & data) const
     460             : {
     461             :   // Possibly reverse the byte ordering
     462       42185 :   if (this->reverse())
     463             :     {
     464           0 :       unsigned char * b = (unsigned char *) &data;
     465             : 
     466           0 :       int i=0;
     467           0 :       int j=(sizeof(T) - 1);
     468             : 
     469           0 :       while (i < j)
     470             :         {
     471           0 :           std::swap (b[i], b[j]);
     472           0 :           i++; j--;
     473             :         }
     474             :     }
     475             : 
     476       43464 :   return data;
     477             : }
     478             : 
     479             : 
     480             : 
     481             : /**
     482             :  * Struct which defines a custom comparison object that
     483             :  * can be used with std::sets of std::unique_ptrs
     484             :  */
     485             : struct CompareUnderlying
     486             : {
     487             :   /**
     488             :    * As of C++14, std::set::find() can be a templated overload.
     489             :    * https://en.cppreference.com/w/cpp/container/set/find
     490             :    * We enable this by defining is_transparent as a type.
     491             :    */
     492             :   using is_transparent = void;
     493             : 
     494             :   /**
     495             :    * This is already what the default operator< comparison for std::unique_ptrs does,
     496             :    * we are not adding anything here.
     497             :    */
     498             :   template <class T>
     499           0 :   bool operator()(const std::unique_ptr<T> & a, const std::unique_ptr<T> & b) const
     500             :   {
     501           0 :     return a.get() < b.get();
     502             :   }
     503             : 
     504             :   /**
     505             :    * operator< comparison when rhs is a dumb pointer
     506             :    */
     507             :   template <class T>
     508           0 :   bool operator()(const std::unique_ptr<T> & a, const T * const & b) const
     509             :   {
     510           0 :     return a.get() < b;
     511             :   }
     512             : 
     513             :   /**
     514             :    * operator< comparison when lhs is a dumb pointer
     515             :    */
     516             :   template <class T>
     517           0 :   bool operator()(const T * const & a, const std::unique_ptr<T> & b) const
     518             :   {
     519           0 :     return a < b.get();
     520             :   }
     521             : };
     522             : 
     523             : } // namespace Utility
     524             : 
     525             : } // namespace libMesh
     526             : 
     527             : #endif // LIBMESH_UTILITY_H

Generated by: LCOV version 1.14