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
|