Reference documentation for deal.II version GIT 9042b9283b 2023-12-02 14:50:02+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 - 2023 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  static_assert(std::is_integral_v<T>, "Only integral types supported");
481 
482  // The "exponentiation by squaring" algorithm used below has to be expressed
483  // in an iterative version since SYCL doesn't allow recursive functions used
484  // in device code.
485 
486  if (iexp <= 0)
487  return 1;
488 
489  int exp = iexp;
490  T x = base;
491  T y = 1;
492  while (exp > 1)
493  {
494  if (exp % 2 == 1)
495  y *= x;
496  x *= x;
497  exp /= 2;
498  }
499  return x * y;
500  }
501 
523  template <typename Iterator, typename T>
524  Iterator
525  lower_bound(Iterator first, Iterator last, const T &val);
526 
527 
533  template <typename Iterator, typename T, typename Comp>
534  Iterator
535  lower_bound(Iterator first, Iterator last, const T &val, const Comp comp);
536 
542  template <typename Integer>
543  std::vector<Integer>
544  reverse_permutation(const std::vector<Integer> &permutation);
545 
551  template <typename Integer>
552  std::vector<Integer>
553  invert_permutation(const std::vector<Integer> &permutation);
554 
609  template <typename T>
610  size_t
611  pack(const T &object,
612  std::vector<char> &dest_buffer,
613  const bool allow_compression = true);
614 
623  template <typename T>
624  std::vector<char>
625  pack(const T &object, const bool allow_compression = true);
626 
658  template <typename T>
659  T
660  unpack(const std::vector<char> &buffer, const bool allow_compression = true);
661 
670  template <typename T>
671  T
672  unpack(const std::vector<char>::const_iterator &cbegin,
673  const std::vector<char>::const_iterator &cend,
674  const bool allow_compression = true);
675 
708  template <typename T, int N>
709  void
710  unpack(const std::vector<char> &buffer,
711  T (&unpacked_object)[N],
712  const bool allow_compression = true);
713 
722  template <typename T, int N>
723  void
724  unpack(const std::vector<char>::const_iterator &cbegin,
725  const std::vector<char>::const_iterator &cend,
726  T (&unpacked_object)[N],
727  const bool allow_compression = true);
728 
732  bool
733  get_bit(const unsigned char number, const unsigned int n);
734 
735 
739  void
740  set_bit(unsigned char &number, const unsigned int n, const bool x);
741 
742 
800  template <typename To, typename From>
801  std::unique_ptr<To>
802  dynamic_unique_cast(std::unique_ptr<From> &&p);
803 
807  template <typename T>
808  T &
810 
814  template <typename T>
815  T &
816  get_underlying_value(std::shared_ptr<T> &p);
817 
821  template <typename T>
822  T &
823  get_underlying_value(const std::shared_ptr<T> &p);
824 
828  template <typename T>
829  T &
830  get_underlying_value(std::unique_ptr<T> &p);
831 
835  template <typename T>
836  T &
837  get_underlying_value(const std::unique_ptr<T> &p);
838 
844  namespace System
845  {
853  double
854  get_cpu_load();
855 
889  std::string
891 
896  struct MemoryStats
897  {
901  unsigned long int VmPeak;
902 
906  unsigned long int VmSize;
907 
911  unsigned long int VmHWM;
912 
917  unsigned long int VmRSS;
918  };
919 
920 
925  void
927 
928 
932  std::string
933  get_hostname();
934 
935 
939  std::string
940  get_time();
941 
946  std::string
947  get_date();
948 
963  void
964  posix_memalign(void **memptr, std::size_t alignment, std::size_t size);
965  } // namespace System
966 } // namespace Utilities
967 
968 
969 // --------------------- inline functions
970 
971 namespace Utilities
972 {
973  template <int N, typename T>
974  inline T
975  fixed_power(const T x)
976  {
977  Assert(((std::is_integral_v<T> == true) && (N >= 0)) ||
978  (std::is_integral_v<T> == false),
979  ExcMessage("If the type of the argument, T, is an integer type, "
980  "then the exponent N must be a non-negative integer "
981  "because the result would otherwise not be an integer."));
982 
983  if (N == 0)
984  return T(1.);
985  else if (N < 0)
986  // For negative exponents, turn things into a positive exponent
987  return T(1.) / fixed_power<-N>(x);
988  else
989  // If we get here, we have a positive exponent. Compute the result
990  // by repeated squaring:
991  return ((N % 2 == 1) ? x * fixed_power<N / 2>(x * x) :
992  fixed_power<N / 2>(x * x));
993  }
994 
995 
996 
997  template <class T>
998  inline std::string
999  type_to_string(const T &t)
1000  {
1001  return boost::core::demangle(typeid(t).name());
1002  }
1003 
1004 
1005 
1006  template <typename Iterator, typename T>
1007  inline Iterator
1008  lower_bound(Iterator first, Iterator last, const T &val)
1009  {
1010  return Utilities::lower_bound(first, last, val, std::less<T>());
1011  }
1012 
1013 
1014 
1015  template <typename Iterator, typename T, typename Comp>
1016  inline Iterator
1017  lower_bound(Iterator first, Iterator last, const T &val, const Comp comp)
1018  {
1019  // verify that the two iterators are properly ordered. since
1020  // we need operator- for the iterator type anyway, do the
1021  // test as follows, rather than via 'last >= first'
1022  Assert(last - first >= 0,
1023  ExcMessage(
1024  "The given iterators do not satisfy the proper ordering."));
1025 
1026  unsigned int len = static_cast<unsigned int>(last - first);
1027 
1028  if (len == 0)
1029  return first;
1030 
1031  while (true)
1032  {
1033  // if length equals 8 or less,
1034  // then do a rolled out
1035  // search. use a switch without
1036  // breaks for that and roll-out
1037  // the loop somehow
1038  if (len < 8)
1039  {
1040  switch (len)
1041  {
1042  case 7:
1043  if (!comp(*first, val))
1044  return first;
1045  ++first;
1047  case 6:
1048  if (!comp(*first, val))
1049  return first;
1050  ++first;
1052  case 5:
1053  if (!comp(*first, val))
1054  return first;
1055  ++first;
1057  case 4:
1058  if (!comp(*first, val))
1059  return first;
1060  ++first;
1062  case 3:
1063  if (!comp(*first, val))
1064  return first;
1065  ++first;
1067  case 2:
1068  if (!comp(*first, val))
1069  return first;
1070  ++first;
1072  case 1:
1073  if (!comp(*first, val))
1074  return first;
1075  return first + 1;
1076  default:
1077  // indices seem
1078  // to not be
1079  // sorted
1080  // correctly!? or
1081  // did len
1082  // become==0
1083  // somehow? that
1084  // shouldn't have
1085  // happened
1086  Assert(false, ExcInternalError());
1087  }
1088  }
1089 
1090 
1091 
1092  const unsigned int half = len >> 1;
1093  const Iterator middle = first + half;
1094 
1095  // if the value is larger than
1096  // that pointed to by the
1097  // middle pointer, then the
1098  // insertion point must be
1099  // right of it
1100  if (comp(*middle, val))
1101  {
1102  first = middle + 1;
1103  len -= half + 1;
1104  }
1105  else
1106  len = half;
1107  }
1108  }
1109 
1110 
1111  // --------------------- non-inline functions
1112 
1113  namespace internal
1114  {
1120  template <typename T>
1122  {
1123  static constexpr bool value = false;
1124  };
1125 
1126 
1127 
1128  template <typename T>
1129  struct IsVectorOfTriviallyCopyable<std::vector<T>>
1130  {
1131  static constexpr bool value =
1132  std::is_trivially_copyable_v<T> && !std::is_same_v<T, bool>;
1133  };
1134 
1135 
1136 
1137  template <typename T>
1138  struct IsVectorOfTriviallyCopyable<std::vector<std::vector<T>>>
1139  {
1140  static constexpr bool value =
1141  std::is_trivially_copyable_v<T> && !std::is_same_v<T, bool>;
1142  };
1143 
1144 
1145 
1154  template <typename T>
1155  inline void
1157  std::vector<char> &)
1158  {
1159  // We shouldn't get here:
1160  Assert(false, ExcInternalError());
1161  }
1162 
1163 
1164 
1165  template <typename T,
1166  typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1167  std::is_trivially_copyable_v<T>>>
1168  inline void
1170  const std::vector<T> &object,
1171  std::vector<char> &dest_buffer)
1172  {
1173  const typename std::vector<T>::size_type vector_size = object.size();
1174 
1175  // Reserve for the buffer so that it can store the size of 'object' as
1176  // well as all of its elements.
1177  dest_buffer.reserve(dest_buffer.size() + sizeof(vector_size) +
1178  vector_size * sizeof(T));
1179 
1180  // Copy the size into the vector
1181  dest_buffer.insert(dest_buffer.end(),
1182  reinterpret_cast<const char *>(&vector_size),
1183  reinterpret_cast<const char *>(&vector_size + 1));
1184 
1185  // Insert the elements at the end of the vector:
1186  if (vector_size > 0)
1187  dest_buffer.insert(dest_buffer.end(),
1188  reinterpret_cast<const char *>(object.data()),
1189  reinterpret_cast<const char *>(object.data() +
1190  vector_size));
1191  }
1192 
1193 
1194 
1195  template <typename T,
1196  typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1197  std::is_trivially_copyable_v<T>>>
1198  inline void
1200  const std::vector<std::vector<T>> &object,
1201  std::vector<char> &dest_buffer)
1202  {
1203  using size_type = typename std::vector<T>::size_type;
1204  const size_type vector_size = object.size();
1205 
1206  typename std::vector<T>::size_type aggregated_size = 0;
1207  std::vector<size_type> sizes;
1208  sizes.reserve(vector_size);
1209  for (const auto &a : object)
1210  {
1211  aggregated_size += a.size();
1212  sizes.push_back(a.size());
1213  }
1214 
1215  // Reserve for the buffer so that it can store the size of 'object' as
1216  // well as all of its elements.
1217  dest_buffer.reserve(dest_buffer.size() +
1218  sizeof(vector_size) * (1 + vector_size) +
1219  aggregated_size * sizeof(T));
1220 
1221  // Copy the size into the vector
1222  dest_buffer.insert(dest_buffer.end(),
1223  reinterpret_cast<const char *>(&vector_size),
1224  reinterpret_cast<const char *>(&vector_size + 1));
1225 
1226  // Copy the sizes of the individual chunks into the vector
1227  if (vector_size > 0)
1228  dest_buffer.insert(dest_buffer.end(),
1229  reinterpret_cast<const char *>(sizes.data()),
1230  reinterpret_cast<const char *>(sizes.data() +
1231  vector_size));
1232 
1233  // Insert the elements at the end of the vector:
1234  for (const auto &a : object)
1235  dest_buffer.insert(dest_buffer.end(),
1236  reinterpret_cast<const char *>(a.data()),
1237  reinterpret_cast<const char *>(a.data() + a.size()));
1238  }
1239 
1240 
1241 
1242  template <typename T>
1243  inline void
1245  const std::vector<char>::const_iterator &,
1246  const std::vector<char>::const_iterator &,
1247  T &)
1248  {
1249  // We shouldn't get here:
1250  Assert(false, ExcInternalError());
1251  }
1252 
1253 
1254 
1255  template <typename T,
1256  typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1257  std::is_trivially_copyable_v<T>>>
1258  inline void
1260  const std::vector<char>::const_iterator &cbegin,
1261  const std::vector<char>::const_iterator &cend,
1262  std::vector<T> &object)
1263  {
1264  // The size of the object vector can be found in cbegin of the buffer.
1265  // The data starts at cbegin + sizeof(vector_size).
1266 
1267  // Get the size of the vector
1268  typename std::vector<T>::size_type vector_size;
1269  memcpy(&vector_size, &*cbegin, sizeof(vector_size));
1270 
1271  Assert(static_cast<std::ptrdiff_t>(cend - cbegin) ==
1272  static_cast<std::ptrdiff_t>(sizeof(vector_size) +
1273  vector_size * sizeof(T)),
1274  ExcMessage("The given buffer has the wrong size."));
1275  (void)cend;
1276 
1277  // Copy the elements:
1278  object.clear();
1279  if (vector_size > 0)
1280  {
1281  const T *const buffer_data_begin =
1282  reinterpret_cast<const T *>(&*cbegin + sizeof(vector_size));
1283  const T *const buffer_data_end = buffer_data_begin + vector_size;
1284  object.insert(object.end(), buffer_data_begin, buffer_data_end);
1285  }
1286  }
1287 
1288 
1289 
1290  template <typename T,
1291  typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1292  std::is_trivially_copyable_v<T>>>
1293  inline void
1295  const std::vector<char>::const_iterator &cbegin,
1296  const std::vector<char>::const_iterator &cend,
1297  std::vector<std::vector<T>> &object)
1298  {
1299  // First get the size of the vector, and resize the output object
1300  using size_type = typename std::vector<T>::size_type;
1301  std::vector<char>::const_iterator iterator = cbegin;
1302  size_type vector_size;
1303  memcpy(&vector_size, &*iterator, sizeof(vector_size));
1304  object.clear();
1305  object.resize(vector_size);
1306  std::vector<size_type> sizes(vector_size);
1307  if (vector_size > 0)
1308  memcpy(sizes.data(),
1309  &*iterator + sizeof(vector_size),
1310  vector_size * sizeof(size_type));
1311 
1312  iterator += sizeof(vector_size) * (1 + vector_size);
1313  size_type aggregated_size = 0;
1314  for (const auto a : sizes)
1315  aggregated_size += a;
1316 
1317  Assert(static_cast<std::ptrdiff_t>(cend - iterator) ==
1318  static_cast<std::ptrdiff_t>(aggregated_size * sizeof(T)),
1319  ExcMessage("The given buffer has the wrong size."));
1320  (void)cend;
1321 
1322  // Then copy the elements:
1323  for (unsigned int i = 0; i < vector_size; ++i)
1324  if (sizes[i] > 0)
1325  {
1326  object[i].insert(object[i].end(),
1327  reinterpret_cast<const T *>(&*iterator),
1328  reinterpret_cast<const T *>(&*iterator +
1329  sizeof(T) * sizes[i]));
1330  iterator += sizeof(T) * sizes[i];
1331  }
1332 
1333  Assert(iterator == cend,
1334  ExcMessage("The given buffer has the wrong size."));
1335  }
1336 
1337  } // namespace internal
1338 
1339 
1340 
1341  template <typename T>
1342  size_t
1343  pack(const T &object,
1344  std::vector<char> &dest_buffer,
1345  const bool allow_compression)
1346  {
1347  std::size_t size = 0;
1348 
1349 
1350  // see if the object is small and copyable via memcpy. if so, use
1351  // this fast path. otherwise, we have to go through the BOOST
1352  // serialization machinery
1353  if constexpr (std::is_trivially_copyable<T>() && sizeof(T) < 256)
1354  {
1355  // Determine the size. There are places where we would like to use a
1356  // truly empty type, for which we use std::tuple<> (i.e., a tuple
1357  // of zero elements). For this class, the compiler reports a nonzero
1358  // sizeof(...) because that is the minimum possible for objects --
1359  // objects need to have distinct addresses, so they need to have a size
1360  // of at least one. But we can special case this situation.
1361  size = (std::is_same_v<T, std::tuple<>> ? 0 : sizeof(T));
1362 
1363  (void)allow_compression;
1364  const std::size_t previous_size = dest_buffer.size();
1365  dest_buffer.resize(previous_size + size);
1366 
1367  if (size > 0)
1368  std::memcpy(dest_buffer.data() + previous_size, &object, size);
1369  }
1370  // Next try if we have a vector of trivially copyable objects.
1371  // If that is the case, we can shortcut the whole BOOST serialization
1372  // machinery and just copy the content of the vector bit for bit
1373  // into the output buffer, assuming that we are not asked to compress
1374  // the data.
1376  (allow_compression == false))
1377  {
1378  const std::size_t previous_size = dest_buffer.size();
1379 
1380  // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1381  // inline the code of the following function here and make the 'if'
1382  // above a 'if constexpr'. Without the 'constexpr', we need to keep
1383  // the general template of the function that throws an exception.
1385  dest_buffer);
1386 
1387  size = dest_buffer.size() - previous_size;
1388  }
1389  else
1390  {
1391  // use buffer as the target of a compressing
1392  // stream into which we serialize the current object
1393  const std::size_t previous_size = dest_buffer.size();
1394  {
1395  boost::iostreams::filtering_ostreambuf fosb;
1396 #ifdef DEAL_II_WITH_ZLIB
1397  if (allow_compression)
1398  fosb.push(boost::iostreams::gzip_compressor());
1399 #else
1400  (void)allow_compression;
1401 #endif
1402  fosb.push(boost::iostreams::back_inserter(dest_buffer));
1403 
1404  boost::archive::binary_oarchive boa(fosb);
1405  boa << object;
1406  // the stream object has to be destroyed before the return statement
1407  // to ensure that all data has been written in the buffer
1408  }
1409  size = dest_buffer.size() - previous_size;
1410  }
1411 
1412  return size;
1413  }
1414 
1415 
1416  template <typename T>
1417  std::vector<char>
1418  pack(const T &object, const bool allow_compression)
1419  {
1420  std::vector<char> buffer;
1421  pack<T>(object, buffer, allow_compression);
1422  return buffer;
1423  }
1424 
1425 
1426 
1427  template <typename T>
1428  T
1429  unpack(const std::vector<char>::const_iterator &cbegin,
1430  const std::vector<char>::const_iterator &cend,
1431  const bool allow_compression)
1432  {
1433  // see if the object is small and copyable via memcpy. if so, use
1434  // this fast path. otherwise, we have to go through the BOOST
1435  // serialization machinery
1436  if constexpr (std::is_trivially_copyable<T>() && sizeof(T) < 256)
1437  {
1438  // Determine the size. There are places where we would like to use a
1439  // truly empty type, for which we use std::tuple<> (i.e., a tuple
1440  // of zero elements). For this class, the compiler reports a nonzero
1441  // sizeof(...) because that is the minimum possible for objects --
1442  // objects need to have distinct addresses, so they need to have a size
1443  // of at least one. But we can special case this situation.
1444  const std::size_t size =
1445  (std::is_same_v<T, std::tuple<>> ? 0 : sizeof(T));
1446 
1447  T object;
1448 
1449  (void)allow_compression;
1450  Assert(std::distance(cbegin, cend) == size, ExcInternalError());
1451 
1452  if (size > 0)
1453  std::memcpy(&object, &*cbegin, size);
1454 
1455  return object;
1456  }
1457  // Next try if we have a vector of trivially copyable objects.
1458  // If that is the case, we can shortcut the whole BOOST serialization
1459  // machinery and just copy the content of the buffer bit for bit
1460  // into an appropriately sized output vector, assuming that we
1461  // are not asked to compress the data.
1463  (allow_compression == false))
1464  {
1465  // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1466  // inline the code of the following function here and make the 'if'
1467  // above a 'if constexpr'. Without the 'constexpr', we need to keep
1468  // the general template of the function that throws an exception.
1469  T object;
1471  cend,
1472  object);
1473  return object;
1474  }
1475  else
1476  {
1477  // decompress the buffer section into the object
1478  boost::iostreams::filtering_istreambuf fisb;
1479 #ifdef DEAL_II_WITH_ZLIB
1480  if (allow_compression)
1481  fisb.push(boost::iostreams::gzip_decompressor());
1482 #else
1483  (void)allow_compression;
1484 #endif
1485  fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1486 
1487  boost::archive::binary_iarchive bia(fisb);
1488 
1489  T object;
1490  bia >> object;
1491  return object;
1492  }
1493 
1494  return T();
1495  }
1496 
1497 
1498  template <typename T>
1499  T
1500  unpack(const std::vector<char> &buffer, const bool allow_compression)
1501  {
1502  return unpack<T>(buffer.cbegin(), buffer.cend(), allow_compression);
1503  }
1504 
1505 
1506  template <typename T, int N>
1507  void
1508  unpack(const std::vector<char>::const_iterator &cbegin,
1509  const std::vector<char>::const_iterator &cend,
1510  T (&unpacked_object)[N],
1511  const bool allow_compression)
1512  {
1513  // see if the object is small and copyable via memcpy. if so, use
1514  // this fast path. otherwise, we have to go through the BOOST
1515  // serialization machinery
1516  if constexpr (std::is_trivially_copyable<T>() && sizeof(T) * N < 256)
1517  {
1518  Assert(std::distance(cbegin, cend) == sizeof(T) * N,
1519  ExcInternalError());
1520  std::memcpy(unpacked_object, &*cbegin, sizeof(T) * N);
1521  }
1522  else
1523  {
1524  // decompress the buffer section into the object
1525  boost::iostreams::filtering_istreambuf fisb;
1526 #ifdef DEAL_II_WITH_ZLIB
1527  if (allow_compression)
1528  fisb.push(boost::iostreams::gzip_decompressor());
1529 #else
1530  (void)allow_compression;
1531 #endif
1532  fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1533 
1534  boost::archive::binary_iarchive bia(fisb);
1535  bia >> unpacked_object;
1536  }
1537  }
1538 
1539 
1540  template <typename T, int N>
1541  void
1542  unpack(const std::vector<char> &buffer,
1543  T (&unpacked_object)[N],
1544  const bool allow_compression)
1545  {
1546  unpack<T, N>(buffer.cbegin(),
1547  buffer.cend(),
1548  unpacked_object,
1549  allow_compression);
1550  }
1551 
1552 
1553 
1554  inline bool
1555  get_bit(const unsigned char number, const unsigned int n)
1556  {
1557  AssertIndexRange(n, 8);
1558 
1559  // source:
1560  // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1561  // "Checking a bit"
1562  return ((number >> n) & 1U) != 0u;
1563  }
1564 
1565 
1566 
1567  inline void
1568  set_bit(unsigned char &number, const unsigned int n, const bool x)
1569  {
1570  AssertIndexRange(n, 8);
1571 
1572  // source:
1573  // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1574  // "Changing the nth bit to x"
1575  number ^= (-static_cast<unsigned char>(x) ^ number) & (1U << n);
1576  }
1577 
1578 
1579 
1580  template <typename To, typename From>
1581  inline std::unique_ptr<To>
1582  dynamic_unique_cast(std::unique_ptr<From> &&p)
1583  {
1584  // Let's see if we can cast from 'From' to 'To'. If so, do the cast,
1585  // and then release the pointer from the old
1586  // owner
1587  if (To *cast = dynamic_cast<To *>(p.get()))
1588  {
1589  std::unique_ptr<To> result(cast);
1590  p.release();
1591  return result;
1592  }
1593  else
1594  throw std::bad_cast();
1595  }
1596 
1597 
1598 
1599  template <typename T>
1600  inline T &
1602  {
1603  return p;
1604  }
1605 
1606 
1607 
1608  template <typename T>
1609  inline T &
1610  get_underlying_value(std::shared_ptr<T> &p)
1611  {
1612  return *p;
1613  }
1614 
1615 
1616 
1617  template <typename T>
1618  inline T &
1619  get_underlying_value(const std::shared_ptr<T> &p)
1620  {
1621  return *p;
1622  }
1623 
1624 
1625 
1626  template <typename T>
1627  inline T &
1628  get_underlying_value(std::unique_ptr<T> &p)
1629  {
1630  return *p;
1631  }
1632 
1633 
1634 
1635  template <typename T>
1636  inline T &
1637  get_underlying_value(const std::unique_ptr<T> &p)
1638  {
1639  return *p;
1640  }
1641 
1642 
1643 
1644  template <typename Integer>
1645  std::vector<Integer>
1646  reverse_permutation(const std::vector<Integer> &permutation)
1647  {
1648  const std::size_t n = permutation.size();
1649 
1650  std::vector<Integer> out(n);
1651  for (std::size_t i = 0; i < n; ++i)
1652  out[i] = n - 1 - permutation[i];
1653 
1654  return out;
1655  }
1656 
1657 
1658 
1659  template <typename Integer>
1660  std::vector<Integer>
1661  invert_permutation(const std::vector<Integer> &permutation)
1662  {
1663  const std::size_t n = permutation.size();
1664 
1665  std::vector<Integer> out(n, numbers::invalid_unsigned_int);
1666 
1667  for (std::size_t i = 0; i < n; ++i)
1668  {
1669  AssertIndexRange(permutation[i], n);
1670  out[permutation[i]] = i;
1671  }
1672 
1673  // check that we have actually reached
1674  // all indices
1675  for (std::size_t i = 0; i < n; ++i)
1677  ExcMessage("The given input permutation had duplicate entries!"));
1678 
1679  return out;
1680  }
1681 } // namespace Utilities
1682 
1683 
1685 
1686 #ifndef DOXYGEN
1687 namespace boost
1688 {
1689  namespace serialization
1690  {
1691  // Provides boost and c++11 with a way to serialize tuples and pairs
1692  // automatically.
1693  template <int N>
1694  struct Serialize
1695  {
1696  template <class Archive, typename... Args>
1697  static void
1698  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1699  {
1700  ar &std::get<N - 1>(t);
1701  Serialize<N - 1>::serialize(ar, t, version);
1702  }
1703  };
1704 
1705  template <>
1706  struct Serialize<0>
1707  {
1708  template <class Archive, typename... Args>
1709  static void
1710  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1711  {
1712  (void)ar;
1713  (void)t;
1714  (void)version;
1715  }
1716  };
1717 
1718  template <class Archive, typename... Args>
1719  void
1720  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1721  {
1722  Serialize<sizeof...(Args)>::serialize(ar, t, version);
1723  }
1724  } // namespace serialization
1725 } // namespace boost
1726 #endif
1727 
1728 #endif
Definition: point.h:112
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:477
#define DEAL_II_CXX20_REQUIRES(condition)
Definition: config.h:166
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:478
#define DEAL_II_FALLTHROUGH
Definition: config.h:206
Point< 2 > first
Definition: grid_out.cc:4614
static ::ExceptionBase & ExcInternalError()
#define Assert(cond, exc)
Definition: exceptions.h:1631
#define AssertIndexRange(index, range)
Definition: exceptions.h:1888
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
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:1244
void append_vector_of_trivially_copyable_to_buffer(const T &, std::vector< char > &)
Definition: utilities.h:1156
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:1601
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:999
size_t pack(const T &object, std::vector< char > &dest_buffer, const bool allow_compression=true)
Definition: utilities.h:1343
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:1555
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:1582
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:1500
T fixed_power(const T t)
Definition: utilities.h:975
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:1008
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:1568
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:1646
std::vector< Integer > invert_permutation(const std::vector< Integer > &permutation)
Definition: utilities.h:1661
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:1433
static const unsigned int invalid_unsigned_int
Definition: types.h:221
#define DEAL_II_HOST_DEVICE
Definition: numbers.h:35
unsigned long int VmRSS
Definition: utilities.h:917
unsigned long int VmPeak
Definition: utilities.h:901
unsigned long int VmSize
Definition: utilities.h:906
unsigned long int VmHWM
Definition: utilities.h:911