Reference documentation for deal.II version GIT 00e6fe71c9 2023-06-04 19:35:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
utilities.h
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2005 - 2022 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_utilities_h
17 #define dealii_utilities_h
18 
19 #include <deal.II/base/config.h>
20 
22 
23 #include <boost/archive/binary_iarchive.hpp>
24 #include <boost/archive/binary_oarchive.hpp>
25 #include <boost/core/demangle.hpp>
26 #include <boost/iostreams/device/array.hpp>
27 #include <boost/iostreams/device/back_inserter.hpp>
28 #include <boost/iostreams/filtering_streambuf.hpp>
29 #include <boost/serialization/array.hpp>
30 #include <boost/serialization/complex.hpp>
31 #include <boost/serialization/vector.hpp>
32 
33 #include <cstddef>
34 #include <functional>
35 #include <string>
36 #include <tuple>
37 #include <type_traits>
38 #include <typeinfo>
39 #include <utility>
40 #include <vector>
41 
42 #ifdef DEAL_II_WITH_ZLIB
43 # include <boost/iostreams/filter/gzip.hpp>
44 #endif
45 
47 
48 // forward declare Point
49 #ifndef DOXYGEN
50 template <int dim, typename Number>
51 DEAL_II_CXX20_REQUIRES(dim >= 0)
52 class Point;
53 #endif
54 
62 namespace Utilities
63 {
70  std::string
72 
89  template <int dim, typename Number>
90  std::vector<std::array<std::uint64_t, dim>>
92  const std::vector<Point<dim, Number>> &points,
93  const int bits_per_dim = 64);
94 
98  template <int dim>
99  std::vector<std::array<std::uint64_t, dim>>
101  const std::vector<std::array<std::uint64_t, dim>> &points,
102  const int bits_per_dim = 64);
103 
119  template <int dim>
120  std::uint64_t
121  pack_integers(const std::array<std::uint64_t, dim> &index,
122  const int bits_per_dim);
123 
136  std::string
137  compress(const std::string &input);
138 
152  std::string
153  decompress(const std::string &compressed_input);
154 
168  std::string
169  encode_base64(const std::vector<unsigned char> &binary_input);
170 
179  std::vector<unsigned char>
180  decode_base64(const std::string &base64_input);
181 
203  std::string
204  int_to_string(const unsigned int value,
205  const unsigned int digits = numbers::invalid_unsigned_int);
206 
218  template <typename number>
219  std::string
220  to_string(const number value,
221  const unsigned int digits = numbers::invalid_unsigned_int);
222 
227  unsigned int
228  needed_digits(const unsigned int max_number);
229 
238  template <typename Number>
239  Number
240  truncate_to_n_digits(const Number number, const unsigned int n_digits);
241 
246  int
247  string_to_int(const std::string &s);
248 
260  std::string
261  dim_string(const int dim, const int spacedim);
262 
267  std::vector<int>
268  string_to_int(const std::vector<std::string> &s);
269 
274  double
275  string_to_double(const std::string &s);
276 
277 
282  std::vector<double>
283  string_to_double(const std::vector<std::string> &s);
284 
285 
328  std::vector<std::string>
329  split_string_list(const std::string &s, const std::string &delimiter = ",");
330 
331 
336  std::vector<std::string>
337  split_string_list(const std::string &s, const char delimiter);
338 
339 
349  std::vector<std::string>
350  break_text_into_lines(const std::string &original_text,
351  const unsigned int width,
352  const char delimiter = ' ');
353 
358  bool
359  match_at_string_start(const std::string &name, const std::string &pattern);
360 
369  std::pair<int, unsigned int>
370  get_integer_at_position(const std::string &name, const unsigned int position);
371 
376  std::string
377  replace_in_string(const std::string &input,
378  const std::string &from,
379  const std::string &to);
380 
386  std::string
387  trim(const std::string &input);
388 
414  double
415  generate_normal_random_number(const double a, const double sigma);
416 
424  template <class T>
425  std::string
426  type_to_string(const T &t);
427 
436  template <int N, typename T>
437  T
438  fixed_power(const T t);
439 
445  template <typename T>
446  constexpr DEAL_II_HOST_DEVICE T
447  pow(const T base, const int iexp)
448  {
449 #if defined(DEBUG) && !defined(DEAL_II_CXX14_CONSTEXPR_BUG)
450  // Up to __builtin_expect this is the same code as in the 'Assert' macro.
451  // The call to __builtin_expect turns out to be problematic.
452 # if KOKKOS_VERSION >= 30600
453  KOKKOS_IF_ON_HOST(({
454  if (!(iexp >= 0))
457  abort_or_throw_on_exception,
458  __FILE__,
459  __LINE__,
460  __PRETTY_FUNCTION__,
461  "iexp>=0",
462  "ExcMessage(\"The exponent must not be negative!\")",
463  ExcMessage("The exponent must not be negative!"));
464  }))
465 # else
466 # ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST
467  if (!(iexp >= 0))
470  abort_or_throw_on_exception,
471  __FILE__,
472  __LINE__,
473  __PRETTY_FUNCTION__,
474  "iexp>=0",
475  "ExcMessage(\"The exponent must not be negative!\")",
476  ExcMessage("The exponent must not be negative!"));
477 # endif
478 # endif
479 #endif
480  // The "exponentiation by squaring" algorithm used below has to be
481  // compressed to one statement due to C++11's restrictions on constexpr
482  // functions. A more descriptive version would be:
483  //
484  // <code>
485  // if (iexp <= 0)
486  // return 1;
487  //
488  // // avoid overflow of one additional recursion with pow(base * base, 0)
489  // if (iexp == 1)
490  // return base;
491  //
492  // // if the current exponent is not divisible by two,
493  // // we need to account for that.
494  // const unsigned int prefactor = (iexp % 2 == 1) ? base : 1;
495  //
496  // // a^b = (a*a)^(b/2) for b even
497  // // a^b = a*(a*a)^((b-1)/2 for b odd
498  // return prefactor * ::Utilities::pow(base*base, iexp/2);
499  // </code>
500 
501  static_assert(std::is_integral<T>::value, "Only integral types supported");
502 
503  return iexp <= 0 ?
504  1 :
505  (iexp == 1 ? base :
506  (((iexp % 2 == 1) ? base : 1) *
507  ::Utilities::pow(base * base, iexp / 2)));
508  }
509 
531  template <typename Iterator, typename T>
532  Iterator
533  lower_bound(Iterator first, Iterator last, const T &val);
534 
535 
541  template <typename Iterator, typename T, typename Comp>
542  Iterator
543  lower_bound(Iterator first, Iterator last, const T &val, const Comp comp);
544 
550  template <typename Integer>
551  std::vector<Integer>
552  reverse_permutation(const std::vector<Integer> &permutation);
553 
559  template <typename Integer>
560  std::vector<Integer>
561  invert_permutation(const std::vector<Integer> &permutation);
562 
617  template <typename T>
618  size_t
619  pack(const T & object,
620  std::vector<char> &dest_buffer,
621  const bool allow_compression = true);
622 
631  template <typename T>
632  std::vector<char>
633  pack(const T &object, const bool allow_compression = true);
634 
666  template <typename T>
667  T
668  unpack(const std::vector<char> &buffer, const bool allow_compression = true);
669 
678  template <typename T>
679  T
680  unpack(const std::vector<char>::const_iterator &cbegin,
681  const std::vector<char>::const_iterator &cend,
682  const bool allow_compression = true);
683 
716  template <typename T, int N>
717  void
718  unpack(const std::vector<char> &buffer,
719  T (&unpacked_object)[N],
720  const bool allow_compression = true);
721 
730  template <typename T, int N>
731  void
732  unpack(const std::vector<char>::const_iterator &cbegin,
733  const std::vector<char>::const_iterator &cend,
734  T (&unpacked_object)[N],
735  const bool allow_compression = true);
736 
740  bool
741  get_bit(const unsigned char number, const unsigned int n);
742 
743 
747  void
748  set_bit(unsigned char &number, const unsigned int n, const bool x);
749 
750 
808  template <typename To, typename From>
809  std::unique_ptr<To>
810  dynamic_unique_cast(std::unique_ptr<From> &&p);
811 
815  template <typename T>
816  T &
818 
822  template <typename T>
823  T &
824  get_underlying_value(std::shared_ptr<T> &p);
825 
829  template <typename T>
830  T &
831  get_underlying_value(const std::shared_ptr<T> &p);
832 
836  template <typename T>
837  T &
838  get_underlying_value(std::unique_ptr<T> &p);
839 
843  template <typename T>
844  T &
845  get_underlying_value(const std::unique_ptr<T> &p);
846 
852  namespace System
853  {
861  double
862  get_cpu_load();
863 
897  const std::string
899 
904  struct MemoryStats
905  {
909  unsigned long int VmPeak;
910 
914  unsigned long int VmSize;
915 
919  unsigned long int VmHWM;
920 
925  unsigned long int VmRSS;
926  };
927 
928 
933  void
935 
936 
940  std::string
941  get_hostname();
942 
943 
947  std::string
948  get_time();
949 
954  std::string
955  get_date();
956 
971  void
972  posix_memalign(void **memptr, std::size_t alignment, std::size_t size);
973  } // namespace System
974 } // namespace Utilities
975 
976 
977 // --------------------- inline functions
978 
979 namespace Utilities
980 {
981  template <int N, typename T>
982  inline T
983  fixed_power(const T x)
984  {
985  Assert(((std::is_integral<T>::value == true) && (N >= 0)) ||
986  (std::is_integral<T>::value == false),
987  ExcMessage("If the type of the argument, T, is an integer type, "
988  "then the exponent N must be a non-negative integer "
989  "because the result would otherwise not be an integer."));
990 
991  if (N == 0)
992  return T(1.);
993  else if (N < 0)
994  // For negative exponents, turn things into a positive exponent
995  return T(1.) / fixed_power<-N>(x);
996  else
997  // If we get here, we have a positive exponent. Compute the result
998  // by repeated squaring:
999  return ((N % 2 == 1) ? x * fixed_power<N / 2>(x * x) :
1000  fixed_power<N / 2>(x * x));
1001  }
1002 
1003 
1004 
1005  template <class T>
1006  inline std::string
1007  type_to_string(const T &t)
1008  {
1009  return boost::core::demangle(typeid(t).name());
1010  }
1011 
1012 
1013 
1014  template <typename Iterator, typename T>
1015  inline Iterator
1016  lower_bound(Iterator first, Iterator last, const T &val)
1017  {
1018  return Utilities::lower_bound(first, last, val, std::less<T>());
1019  }
1020 
1021 
1022 
1023  template <typename Iterator, typename T, typename Comp>
1024  inline Iterator
1025  lower_bound(Iterator first, Iterator last, const T &val, const Comp comp)
1026  {
1027  // verify that the two iterators are properly ordered. since
1028  // we need operator- for the iterator type anyway, do the
1029  // test as follows, rather than via 'last >= first'
1030  Assert(last - first >= 0,
1031  ExcMessage(
1032  "The given iterators do not satisfy the proper ordering."));
1033 
1034  unsigned int len = static_cast<unsigned int>(last - first);
1035 
1036  if (len == 0)
1037  return first;
1038 
1039  while (true)
1040  {
1041  // if length equals 8 or less,
1042  // then do a rolled out
1043  // search. use a switch without
1044  // breaks for that and roll-out
1045  // the loop somehow
1046  if (len < 8)
1047  {
1048  switch (len)
1049  {
1050  case 7:
1051  if (!comp(*first, val))
1052  return first;
1053  ++first;
1055  case 6:
1056  if (!comp(*first, val))
1057  return first;
1058  ++first;
1060  case 5:
1061  if (!comp(*first, val))
1062  return first;
1063  ++first;
1065  case 4:
1066  if (!comp(*first, val))
1067  return first;
1068  ++first;
1070  case 3:
1071  if (!comp(*first, val))
1072  return first;
1073  ++first;
1075  case 2:
1076  if (!comp(*first, val))
1077  return first;
1078  ++first;
1080  case 1:
1081  if (!comp(*first, val))
1082  return first;
1083  return first + 1;
1084  default:
1085  // indices seem
1086  // to not be
1087  // sorted
1088  // correctly!? or
1089  // did len
1090  // become==0
1091  // somehow? that
1092  // shouldn't have
1093  // happened
1094  Assert(false, ExcInternalError());
1095  }
1096  }
1097 
1098 
1099 
1100  const unsigned int half = len >> 1;
1101  const Iterator middle = first + half;
1102 
1103  // if the value is larger than
1104  // that pointed to by the
1105  // middle pointer, then the
1106  // insertion point must be
1107  // right of it
1108  if (comp(*middle, val))
1109  {
1110  first = middle + 1;
1111  len -= half + 1;
1112  }
1113  else
1114  len = half;
1115  }
1116  }
1117 
1118 
1119  // --------------------- non-inline functions
1120 
1121  namespace internal
1122  {
1128  template <typename T>
1130  {
1131  static constexpr bool value = false;
1132  };
1133 
1134 
1135 
1136  template <typename T>
1137  struct IsVectorOfTriviallyCopyable<std::vector<T>>
1138  {
1139  static constexpr bool value =
1140  std::is_trivially_copyable<T>::value && !std::is_same<T, bool>::value;
1141  };
1142 
1143 
1144 
1145  template <typename T>
1146  struct IsVectorOfTriviallyCopyable<std::vector<std::vector<T>>>
1147  {
1148  static constexpr bool value =
1149  std::is_trivially_copyable<T>::value && !std::is_same<T, bool>::value;
1150  };
1151 
1152 
1153 
1162  template <typename T>
1163  inline void
1165  std::vector<char> &)
1166  {
1167  // We shouldn't get here:
1168  Assert(false, ExcInternalError());
1169  }
1170 
1171 
1172 
1173  template <typename T,
1174  typename = std::enable_if_t<!std::is_same<T, bool>::value &&
1175  std::is_trivially_copyable<T>::value>>
1176  inline void
1178  const std::vector<T> &object,
1179  std::vector<char> & dest_buffer)
1180  {
1181  const typename std::vector<T>::size_type vector_size = object.size();
1182 
1183  // Reserve for the buffer so that it can store the size of 'object' as
1184  // well as all of its elements.
1185  dest_buffer.reserve(dest_buffer.size() + sizeof(vector_size) +
1186  vector_size * sizeof(T));
1187 
1188  // Copy the size into the vector
1189  dest_buffer.insert(dest_buffer.end(),
1190  reinterpret_cast<const char *>(&vector_size),
1191  reinterpret_cast<const char *>(&vector_size + 1));
1192 
1193  // Insert the elements at the end of the vector:
1194  if (vector_size > 0)
1195  dest_buffer.insert(dest_buffer.end(),
1196  reinterpret_cast<const char *>(object.data()),
1197  reinterpret_cast<const char *>(object.data() +
1198  vector_size));
1199  }
1200 
1201 
1202 
1203  template <typename T,
1204  typename = std::enable_if_t<!std::is_same<T, bool>::value &&
1205  std::is_trivially_copyable<T>::value>>
1206  inline void
1208  const std::vector<std::vector<T>> &object,
1209  std::vector<char> & dest_buffer)
1210  {
1211  using size_type = typename std::vector<T>::size_type;
1212  const size_type vector_size = object.size();
1213 
1214  typename std::vector<T>::size_type aggregated_size = 0;
1215  std::vector<size_type> sizes;
1216  sizes.reserve(vector_size);
1217  for (const auto &a : object)
1218  {
1219  aggregated_size += a.size();
1220  sizes.push_back(a.size());
1221  }
1222 
1223  // Reserve for the buffer so that it can store the size of 'object' as
1224  // well as all of its elements.
1225  dest_buffer.reserve(dest_buffer.size() +
1226  sizeof(vector_size) * (1 + vector_size) +
1227  aggregated_size * sizeof(T));
1228 
1229  // Copy the size into the vector
1230  dest_buffer.insert(dest_buffer.end(),
1231  reinterpret_cast<const char *>(&vector_size),
1232  reinterpret_cast<const char *>(&vector_size + 1));
1233 
1234  // Copy the sizes of the individual chunks into the vector
1235  if (vector_size > 0)
1236  dest_buffer.insert(dest_buffer.end(),
1237  reinterpret_cast<const char *>(sizes.data()),
1238  reinterpret_cast<const char *>(sizes.data() +
1239  vector_size));
1240 
1241  // Insert the elements at the end of the vector:
1242  for (const auto &a : object)
1243  dest_buffer.insert(dest_buffer.end(),
1244  reinterpret_cast<const char *>(a.data()),
1245  reinterpret_cast<const char *>(a.data() + a.size()));
1246  }
1247 
1248 
1249 
1250  template <typename T>
1251  inline void
1253  const std::vector<char>::const_iterator &,
1254  const std::vector<char>::const_iterator &,
1255  T &)
1256  {
1257  // We shouldn't get here:
1258  Assert(false, ExcInternalError());
1259  }
1260 
1261 
1262 
1263  template <typename T,
1264  typename = std::enable_if_t<!std::is_same<T, bool>::value &&
1265  std::is_trivially_copyable<T>::value>>
1266  inline void
1268  const std::vector<char>::const_iterator &cbegin,
1269  const std::vector<char>::const_iterator &cend,
1270  std::vector<T> & object)
1271  {
1272  // The size of the object vector can be found in cbegin of the buffer.
1273  // The data starts at cbegin + sizeof(vector_size).
1274 
1275  // Get the size of the vector
1276  typename std::vector<T>::size_type vector_size;
1277  memcpy(&vector_size, &*cbegin, sizeof(vector_size));
1278 
1279  Assert(static_cast<std::ptrdiff_t>(cend - cbegin) ==
1280  static_cast<std::ptrdiff_t>(sizeof(vector_size) +
1281  vector_size * sizeof(T)),
1282  ExcMessage("The given buffer has the wrong size."));
1283  (void)cend;
1284 
1285  // Copy the elements:
1286  object.clear();
1287  if (vector_size > 0)
1288  {
1289  const auto buffer_data_begin =
1290  reinterpret_cast<const T *>(&*cbegin + sizeof(vector_size));
1291  const auto buffer_data_end = buffer_data_begin + vector_size;
1292  object.insert(object.end(), buffer_data_begin, buffer_data_end);
1293  }
1294  }
1295 
1296 
1297 
1298  template <typename T,
1299  typename = std::enable_if_t<!std::is_same<T, bool>::value &&
1300  std::is_trivially_copyable<T>::value>>
1301  inline void
1303  const std::vector<char>::const_iterator &cbegin,
1304  const std::vector<char>::const_iterator &cend,
1305  std::vector<std::vector<T>> & object)
1306  {
1307  // First get the size of the vector, and resize the output object
1308  using size_type = typename std::vector<T>::size_type;
1309  std::vector<char>::const_iterator iterator = cbegin;
1310  size_type vector_size;
1311  memcpy(&vector_size, &*iterator, sizeof(vector_size));
1312  object.clear();
1313  object.resize(vector_size);
1314  std::vector<size_type> sizes(vector_size);
1315  if (vector_size > 0)
1316  memcpy(sizes.data(),
1317  &*iterator + sizeof(vector_size),
1318  vector_size * sizeof(size_type));
1319 
1320  iterator += sizeof(vector_size) * (1 + vector_size);
1321  size_type aggregated_size = 0;
1322  for (const auto a : sizes)
1323  aggregated_size += a;
1324 
1325  Assert(static_cast<std::ptrdiff_t>(cend - iterator) ==
1326  static_cast<std::ptrdiff_t>(aggregated_size * sizeof(T)),
1327  ExcMessage("The given buffer has the wrong size."));
1328  (void)cend;
1329 
1330  // Then copy the elements:
1331  for (unsigned int i = 0; i < vector_size; ++i)
1332  if (sizes[i] > 0)
1333  {
1334  object[i].insert(object[i].end(),
1335  reinterpret_cast<const T *>(&*iterator),
1336  reinterpret_cast<const T *>(&*iterator +
1337  sizeof(T) * sizes[i]));
1338  iterator += sizeof(T) * sizes[i];
1339  }
1340 
1341  Assert(iterator == cend,
1342  ExcMessage("The given buffer has the wrong size."));
1343  }
1344 
1345  } // namespace internal
1346 
1347 
1348 
1349  template <typename T>
1350  size_t
1351  pack(const T & object,
1352  std::vector<char> &dest_buffer,
1353  const bool allow_compression)
1354  {
1355  std::size_t size = 0;
1356 
1357 
1358  // see if the object is small and copyable via memcpy. if so, use
1359  // this fast path. otherwise, we have to go through the BOOST
1360  // serialization machinery
1361  if DEAL_II_CONSTEXPR_IN_CONDITIONAL (std::is_trivially_copyable<T>() &&
1362  sizeof(T) < 256)
1363  {
1364  // Determine the size. There are places where we would like to use a
1365  // truly empty type, for which we use std::tuple<> (i.e., a tuple
1366  // of zero elements). For this class, the compiler reports a nonzero
1367  // sizeof(...) because that is the minimum possible for objects --
1368  // objects need to have distinct addresses, so they need to have a size
1369  // of at least one. But we can special case this situation.
1370  size = (std::is_same<T, std::tuple<>>::value ? 0 : sizeof(T));
1371 
1372  (void)allow_compression;
1373  const std::size_t previous_size = dest_buffer.size();
1374  dest_buffer.resize(previous_size + size);
1375 
1376  if (size > 0)
1377  std::memcpy(dest_buffer.data() + previous_size, &object, size);
1378  }
1379  // Next try if we have a vector of trivially copyable objects.
1380  // If that is the case, we can shortcut the whole BOOST serialization
1381  // machinery and just copy the content of the vector bit for bit
1382  // into the output buffer, assuming that we are not asked to compress
1383  // the data.
1385  (allow_compression == false))
1386  {
1387  const std::size_t previous_size = dest_buffer.size();
1388 
1389  // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1390  // inline the code of the following function here and make the 'if'
1391  // above a 'if constexpr'. Without the 'constexpr', we need to keep
1392  // the general template of the function that throws an exception.
1394  dest_buffer);
1395 
1396  size = dest_buffer.size() - previous_size;
1397  }
1398  else
1399  {
1400  // use buffer as the target of a compressing
1401  // stream into which we serialize the current object
1402  const std::size_t previous_size = dest_buffer.size();
1403  {
1404  boost::iostreams::filtering_ostreambuf fosb;
1405 #ifdef DEAL_II_WITH_ZLIB
1406  if (allow_compression)
1407  fosb.push(boost::iostreams::gzip_compressor());
1408 #else
1409  (void)allow_compression;
1410 #endif
1411  fosb.push(boost::iostreams::back_inserter(dest_buffer));
1412 
1413  boost::archive::binary_oarchive boa(fosb);
1414  boa << object;
1415  // the stream object has to be destroyed before the return statement
1416  // to ensure that all data has been written in the buffer
1417  }
1418  size = dest_buffer.size() - previous_size;
1419  }
1420 
1421  return size;
1422  }
1423 
1424 
1425  template <typename T>
1426  std::vector<char>
1427  pack(const T &object, const bool allow_compression)
1428  {
1429  std::vector<char> buffer;
1430  pack<T>(object, buffer, allow_compression);
1431  return buffer;
1432  }
1433 
1434 
1435 
1436  template <typename T>
1437  T
1438  unpack(const std::vector<char>::const_iterator &cbegin,
1439  const std::vector<char>::const_iterator &cend,
1440  const bool allow_compression)
1441  {
1442  // see if the object is small and copyable via memcpy. if so, use
1443  // this fast path. otherwise, we have to go through the BOOST
1444  // serialization machinery
1445  if DEAL_II_CONSTEXPR_IN_CONDITIONAL (std::is_trivially_copyable<T>() &&
1446  sizeof(T) < 256)
1447  {
1448  // Determine the size. There are places where we would like to use a
1449  // truly empty type, for which we use std::tuple<> (i.e., a tuple
1450  // of zero elements). For this class, the compiler reports a nonzero
1451  // sizeof(...) because that is the minimum possible for objects --
1452  // objects need to have distinct addresses, so they need to have a size
1453  // of at least one. But we can special case this situation.
1454  const std::size_t size =
1455  (std::is_same<T, std::tuple<>>::value ? 0 : sizeof(T));
1456 
1457  T object;
1458 
1459  (void)allow_compression;
1460  Assert(std::distance(cbegin, cend) == size, ExcInternalError());
1461 
1462  if (size > 0)
1463  std::memcpy(&object, &*cbegin, size);
1464 
1465  return object;
1466  }
1467  // Next try if we have a vector of trivially copyable objects.
1468  // If that is the case, we can shortcut the whole BOOST serialization
1469  // machinery and just copy the content of the buffer bit for bit
1470  // into an appropriately sized output vector, assuming that we
1471  // are not asked to compress the data.
1473  (allow_compression == false))
1474  {
1475  // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1476  // inline the code of the following function here and make the 'if'
1477  // above a 'if constexpr'. Without the 'constexpr', we need to keep
1478  // the general template of the function that throws an exception.
1479  T object;
1481  cend,
1482  object);
1483  return object;
1484  }
1485  else
1486  {
1487  // decompress the buffer section into the object
1488  boost::iostreams::filtering_istreambuf fisb;
1489 #ifdef DEAL_II_WITH_ZLIB
1490  if (allow_compression)
1491  fisb.push(boost::iostreams::gzip_decompressor());
1492 #else
1493  (void)allow_compression;
1494 #endif
1495  fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1496 
1497  boost::archive::binary_iarchive bia(fisb);
1498 
1499  T object;
1500  bia >> object;
1501  return object;
1502  }
1503 
1504  return T();
1505  }
1506 
1507 
1508  template <typename T>
1509  T
1510  unpack(const std::vector<char> &buffer, const bool allow_compression)
1511  {
1512  return unpack<T>(buffer.cbegin(), buffer.cend(), allow_compression);
1513  }
1514 
1515 
1516  template <typename T, int N>
1517  void
1518  unpack(const std::vector<char>::const_iterator &cbegin,
1519  const std::vector<char>::const_iterator &cend,
1520  T (&unpacked_object)[N],
1521  const bool allow_compression)
1522  {
1523  // see if the object is small and copyable via memcpy. if so, use
1524  // this fast path. otherwise, we have to go through the BOOST
1525  // serialization machinery
1526  if DEAL_II_CONSTEXPR_IN_CONDITIONAL (std::is_trivially_copyable<T>() &&
1527  sizeof(T) * N < 256)
1528  {
1529  Assert(std::distance(cbegin, cend) == sizeof(T) * N,
1530  ExcInternalError());
1531  std::memcpy(unpacked_object, &*cbegin, sizeof(T) * N);
1532  }
1533  else
1534  {
1535  // decompress the buffer section into the object
1536  boost::iostreams::filtering_istreambuf fisb;
1537 #ifdef DEAL_II_WITH_ZLIB
1538  if (allow_compression)
1539  fisb.push(boost::iostreams::gzip_decompressor());
1540 #else
1541  (void)allow_compression;
1542 #endif
1543  fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1544 
1545  boost::archive::binary_iarchive bia(fisb);
1546  bia >> unpacked_object;
1547  }
1548  }
1549 
1550 
1551  template <typename T, int N>
1552  void
1553  unpack(const std::vector<char> &buffer,
1554  T (&unpacked_object)[N],
1555  const bool allow_compression)
1556  {
1557  unpack<T, N>(buffer.cbegin(),
1558  buffer.cend(),
1559  unpacked_object,
1560  allow_compression);
1561  }
1562 
1563 
1564 
1565  inline bool
1566  get_bit(const unsigned char number, const unsigned int n)
1567  {
1568  AssertIndexRange(n, 8);
1569 
1570  // source:
1571  // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1572  // "Checking a bit"
1573  return ((number >> n) & 1U) != 0u;
1574  }
1575 
1576 
1577 
1578  inline void
1579  set_bit(unsigned char &number, const unsigned int n, const bool x)
1580  {
1581  AssertIndexRange(n, 8);
1582 
1583  // source:
1584  // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1585  // "Changing the nth bit to x"
1586  number ^= (-static_cast<unsigned char>(x) ^ number) & (1U << n);
1587  }
1588 
1589 
1590 
1591  template <typename To, typename From>
1592  inline std::unique_ptr<To>
1593  dynamic_unique_cast(std::unique_ptr<From> &&p)
1594  {
1595  // Let's see if we can cast from 'From' to 'To'. If so, do the cast,
1596  // and then release the pointer from the old
1597  // owner
1598  if (To *cast = dynamic_cast<To *>(p.get()))
1599  {
1600  std::unique_ptr<To> result(cast);
1601  p.release();
1602  return result;
1603  }
1604  else
1605  throw std::bad_cast();
1606  }
1607 
1608 
1609 
1610  template <typename T>
1611  inline T &
1613  {
1614  return p;
1615  }
1616 
1617 
1618 
1619  template <typename T>
1620  inline T &
1621  get_underlying_value(std::shared_ptr<T> &p)
1622  {
1623  return *p;
1624  }
1625 
1626 
1627 
1628  template <typename T>
1629  inline T &
1630  get_underlying_value(const std::shared_ptr<T> &p)
1631  {
1632  return *p;
1633  }
1634 
1635 
1636 
1637  template <typename T>
1638  inline T &
1639  get_underlying_value(std::unique_ptr<T> &p)
1640  {
1641  return *p;
1642  }
1643 
1644 
1645 
1646  template <typename T>
1647  inline T &
1648  get_underlying_value(const std::unique_ptr<T> &p)
1649  {
1650  return *p;
1651  }
1652 
1653 
1654 
1655  template <typename Integer>
1656  std::vector<Integer>
1657  reverse_permutation(const std::vector<Integer> &permutation)
1658  {
1659  const std::size_t n = permutation.size();
1660 
1661  std::vector<Integer> out(n);
1662  for (std::size_t i = 0; i < n; ++i)
1663  out[i] = n - 1 - permutation[i];
1664 
1665  return out;
1666  }
1667 
1668 
1669 
1670  template <typename Integer>
1671  std::vector<Integer>
1672  invert_permutation(const std::vector<Integer> &permutation)
1673  {
1674  const std::size_t n = permutation.size();
1675 
1676  std::vector<Integer> out(n, numbers::invalid_unsigned_int);
1677 
1678  for (std::size_t i = 0; i < n; ++i)
1679  {
1680  AssertIndexRange(permutation[i], n);
1681  out[permutation[i]] = i;
1682  }
1683 
1684  // check that we have actually reached
1685  // all indices
1686  for (std::size_t i = 0; i < n; ++i)
1688  ExcMessage("The given input permutation had duplicate entries!"));
1689 
1690  return out;
1691  }
1692 } // namespace Utilities
1693 
1694 
1696 
1697 #ifndef DOXYGEN
1698 namespace boost
1699 {
1700  namespace serialization
1701  {
1702  // Provides boost and c++11 with a way to serialize tuples and pairs
1703  // automatically.
1704  template <int N>
1705  struct Serialize
1706  {
1707  template <class Archive, typename... Args>
1708  static void
1709  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1710  {
1711  ar &std::get<N - 1>(t);
1712  Serialize<N - 1>::serialize(ar, t, version);
1713  }
1714  };
1715 
1716  template <>
1717  struct Serialize<0>
1718  {
1719  template <class Archive, typename... Args>
1720  static void
1721  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1722  {
1723  (void)ar;
1724  (void)t;
1725  (void)version;
1726  }
1727  };
1728 
1729  template <class Archive, typename... Args>
1730  void
1731  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1732  {
1733  Serialize<sizeof...(Args)>::serialize(ar, t, version);
1734  }
1735  } // namespace serialization
1736 } // namespace boost
1737 #endif
1738 
1739 #endif
Definition: point.h:112
#define DEAL_II_CONSTEXPR_IN_CONDITIONAL
Definition: config.h:576
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:474
#define DEAL_II_CXX20_REQUIRES(condition)
Definition: config.h:162
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:475
#define DEAL_II_FALLTHROUGH
Definition: config.h:186
Point< 2 > first
Definition: grid_out.cc:4615
static ::ExceptionBase & ExcInternalError()
#define Assert(cond, exc)
Definition: exceptions.h:1614
#define AssertIndexRange(index, range)
Definition: exceptions.h:1855
static ::ExceptionBase & ExcMessage(std::string arg1)
static const char T
static const char N
types::global_dof_index size_type
Definition: cuda_kernels.h:45
VectorType::value_type * end(VectorType &V)
void get_memory_stats(MemoryStats &stats)
Definition: utilities.cc:965
std::string get_hostname()
Definition: utilities.cc:999
std::string get_time()
Definition: utilities.cc:1014
void posix_memalign(void **memptr, std::size_t alignment, std::size_t size)
Definition: utilities.cc:1045
double get_cpu_load()
Definition: utilities.cc:931
const std::string get_current_vectorization_level()
Definition: utilities.cc:939
std::string get_date()
Definition: utilities.cc:1030
void create_vector_of_trivially_copyable_from_buffer(const std::vector< char >::const_iterator &, const std::vector< char >::const_iterator &, T &)
Definition: utilities.h:1252
void append_vector_of_trivially_copyable_to_buffer(const T &, std::vector< char > &)
Definition: utilities.h:1164
constexpr T pow(const T base, const int iexp)
Definition: utilities.h:447
std::vector< std::string > split_string_list(const std::string &s, const std::string &delimiter=",")
Definition: utilities.cc:702
T & get_underlying_value(T &p)
Definition: utilities.h:1612
Number truncate_to_n_digits(const Number number, const unsigned int n_digits)
Definition: utilities.cc:579
std::string type_to_string(const T &t)
Definition: utilities.h:1007
size_t pack(const T &object, std::vector< char > &dest_buffer, const bool allow_compression=true)
Definition: utilities.h:1351
std::string dim_string(const int dim, const int spacedim)
Definition: utilities.cc:556
std::uint64_t pack_integers(const std::array< std::uint64_t, dim > &index, const int bits_per_dim)
Definition: utilities.cc:367
bool get_bit(const unsigned char number, const unsigned int n)
Definition: utilities.h:1566
std::pair< int, unsigned int > get_integer_at_position(const std::string &name, const unsigned int position)
Definition: utilities.cc:848
std::string encode_base64(const std::vector< unsigned char > &binary_input)
Definition: utilities.cc:434
std::vector< std::array< std::uint64_t, dim > > inverse_Hilbert_space_filling_curve(const std::vector< Point< dim, Number >> &points, const int bits_per_dim=64)
Definition: utilities.cc:146
std::unique_ptr< To > dynamic_unique_cast(std::unique_ptr< From > &&p)
Definition: utilities.h:1593
std::string replace_in_string(const std::string &input, const std::string &from, const std::string &to)
Definition: utilities.cc:510
std::vector< unsigned char > decode_base64(const std::string &base64_input)
Definition: utilities.cc:447
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
Definition: utilities.cc:756
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:480
std::string compress(const std::string &input)
Definition: utilities.cc:390
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:471
bool match_at_string_start(const std::string &name, const std::string &pattern)
Definition: utilities.cc:833
T unpack(const std::vector< char > &buffer, const bool allow_compression=true)
Definition: utilities.h:1510
T fixed_power(const T t)
Definition: utilities.h:983
std::string decompress(const std::string &compressed_input)
Definition: utilities.cc:412
unsigned int needed_digits(const unsigned int max_number)
Definition: utilities.cc:566
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition: utilities.h:1016
double string_to_double(const std::string &s)
Definition: utilities.cc:654
std::string dealii_version_string()
Definition: utilities.cc:95
void set_bit(unsigned char &number, const unsigned int n, const bool x)
Definition: utilities.h:1579
std::string trim(const std::string &input)
Definition: utilities.cc:529
double generate_normal_random_number(const double a, const double sigma)
Definition: utilities.cc:890
std::vector< Integer > reverse_permutation(const std::vector< Integer > &permutation)
Definition: utilities.h:1657
std::vector< Integer > invert_permutation(const std::vector< Integer > &permutation)
Definition: utilities.h:1672
int string_to_int(const std::string &s)
Definition: utilities.cc:606
void issue_error_noreturn(ExceptionHandling handling, const char *file, int line, const char *function, const char *cond, const char *exc_name, ExceptionType e)
Definition: exceptions.h:1426
static const unsigned int invalid_unsigned_int
Definition: types.h:213
#define DEAL_II_HOST_DEVICE
Definition: numbers.h:35
unsigned long int VmRSS
Definition: utilities.h:925
unsigned long int VmPeak
Definition: utilities.h:909
unsigned long int VmSize
Definition: utilities.h:914
unsigned long int VmHWM
Definition: utilities.h:919