Reference documentation for deal.II version GIT 9c182271f7 2023-03-28 14:30: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 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 (!(iexp >= 0))
455  abort_or_throw_on_exception,
456  __FILE__,
457  __LINE__,
458  __PRETTY_FUNCTION__,
459  "iexp>=0",
460  "ExcMessage(\"The exponent must not be negative!\")",
461  ExcMessage("The exponent must not be negative!"));
462 #endif
463  // The "exponentiation by squaring" algorithm used below has to be
464  // compressed to one statement due to C++11's restrictions on constexpr
465  // functions. A more descriptive version would be:
466  //
467  // <code>
468  // if (iexp <= 0)
469  // return 1;
470  //
471  // // avoid overflow of one additional recursion with pow(base * base, 0)
472  // if (iexp == 1)
473  // return base;
474  //
475  // // if the current exponent is not divisible by two,
476  // // we need to account for that.
477  // const unsigned int prefactor = (iexp % 2 == 1) ? base : 1;
478  //
479  // // a^b = (a*a)^(b/2) for b even
480  // // a^b = a*(a*a)^((b-1)/2 for b odd
481  // return prefactor * ::Utilities::pow(base*base, iexp/2);
482  // </code>
483 
484  static_assert(std::is_integral<T>::value, "Only integral types supported");
485 
486  return iexp <= 0 ?
487  1 :
488  (iexp == 1 ? base :
489  (((iexp % 2 == 1) ? base : 1) *
490  ::Utilities::pow(base * base, iexp / 2)));
491  }
492 
514  template <typename Iterator, typename T>
515  Iterator
516  lower_bound(Iterator first, Iterator last, const T &val);
517 
518 
524  template <typename Iterator, typename T, typename Comp>
525  Iterator
526  lower_bound(Iterator first, Iterator last, const T &val, const Comp comp);
527 
533  template <typename Integer>
534  std::vector<Integer>
535  reverse_permutation(const std::vector<Integer> &permutation);
536 
542  template <typename Integer>
543  std::vector<Integer>
544  invert_permutation(const std::vector<Integer> &permutation);
545 
600  template <typename T>
601  size_t
602  pack(const T & object,
603  std::vector<char> &dest_buffer,
604  const bool allow_compression = true);
605 
614  template <typename T>
615  std::vector<char>
616  pack(const T &object, const bool allow_compression = true);
617 
649  template <typename T>
650  T
651  unpack(const std::vector<char> &buffer, const bool allow_compression = true);
652 
661  template <typename T>
662  T
663  unpack(const std::vector<char>::const_iterator &cbegin,
664  const std::vector<char>::const_iterator &cend,
665  const bool allow_compression = true);
666 
699  template <typename T, int N>
700  void
701  unpack(const std::vector<char> &buffer,
702  T (&unpacked_object)[N],
703  const bool allow_compression = true);
704 
713  template <typename T, int N>
714  void
715  unpack(const std::vector<char>::const_iterator &cbegin,
716  const std::vector<char>::const_iterator &cend,
717  T (&unpacked_object)[N],
718  const bool allow_compression = true);
719 
723  bool
724  get_bit(const unsigned char number, const unsigned int n);
725 
726 
730  void
731  set_bit(unsigned char &number, const unsigned int n, const bool x);
732 
733 
791  template <typename To, typename From>
792  std::unique_ptr<To>
793  dynamic_unique_cast(std::unique_ptr<From> &&p);
794 
798  template <typename T>
799  T &
801 
805  template <typename T>
806  T &
807  get_underlying_value(std::shared_ptr<T> &p);
808 
812  template <typename T>
813  T &
814  get_underlying_value(const std::shared_ptr<T> &p);
815 
819  template <typename T>
820  T &
821  get_underlying_value(std::unique_ptr<T> &p);
822 
826  template <typename T>
827  T &
828  get_underlying_value(const std::unique_ptr<T> &p);
829 
835  namespace System
836  {
844  double
845  get_cpu_load();
846 
880  const std::string
882 
887  struct MemoryStats
888  {
892  unsigned long int VmPeak;
893 
897  unsigned long int VmSize;
898 
902  unsigned long int VmHWM;
903 
908  unsigned long int VmRSS;
909  };
910 
911 
916  void
918 
919 
923  std::string
924  get_hostname();
925 
926 
930  std::string
931  get_time();
932 
937  std::string
938  get_date();
939 
954  void
955  posix_memalign(void **memptr, std::size_t alignment, std::size_t size);
956  } // namespace System
957 } // namespace Utilities
958 
959 
960 // --------------------- inline functions
961 
962 namespace Utilities
963 {
964  template <int N, typename T>
965  inline T
966  fixed_power(const T x)
967  {
968  Assert(((std::is_integral<T>::value == true) && (N >= 0)) ||
969  (std::is_integral<T>::value == false),
970  ExcMessage("If the type of the argument, T, is an integer type, "
971  "then the exponent N must be a non-negative integer "
972  "because the result would otherwise not be an integer."));
973 
974  if (N == 0)
975  return T(1.);
976  else if (N < 0)
977  // For negative exponents, turn things into a positive exponent
978  return T(1.) / fixed_power<-N>(x);
979  else
980  // If we get here, we have a positive exponent. Compute the result
981  // by repeated squaring:
982  return ((N % 2 == 1) ? x * fixed_power<N / 2>(x * x) :
983  fixed_power<N / 2>(x * x));
984  }
985 
986 
987 
988  template <class T>
989  inline std::string
990  type_to_string(const T &t)
991  {
992  return boost::core::demangle(typeid(t).name());
993  }
994 
995 
996 
997  template <typename Iterator, typename T>
998  inline Iterator
999  lower_bound(Iterator first, Iterator last, const T &val)
1000  {
1001  return Utilities::lower_bound(first, last, val, std::less<T>());
1002  }
1003 
1004 
1005 
1006  template <typename Iterator, typename T, typename Comp>
1007  inline Iterator
1008  lower_bound(Iterator first, Iterator last, const T &val, const Comp comp)
1009  {
1010  // verify that the two iterators are properly ordered. since
1011  // we need operator- for the iterator type anyway, do the
1012  // test as follows, rather than via 'last >= first'
1013  Assert(last - first >= 0,
1014  ExcMessage(
1015  "The given iterators do not satisfy the proper ordering."));
1016 
1017  unsigned int len = static_cast<unsigned int>(last - first);
1018 
1019  if (len == 0)
1020  return first;
1021 
1022  while (true)
1023  {
1024  // if length equals 8 or less,
1025  // then do a rolled out
1026  // search. use a switch without
1027  // breaks for that and roll-out
1028  // the loop somehow
1029  if (len < 8)
1030  {
1031  switch (len)
1032  {
1033  case 7:
1034  if (!comp(*first, val))
1035  return first;
1036  ++first;
1038  case 6:
1039  if (!comp(*first, val))
1040  return first;
1041  ++first;
1043  case 5:
1044  if (!comp(*first, val))
1045  return first;
1046  ++first;
1048  case 4:
1049  if (!comp(*first, val))
1050  return first;
1051  ++first;
1053  case 3:
1054  if (!comp(*first, val))
1055  return first;
1056  ++first;
1058  case 2:
1059  if (!comp(*first, val))
1060  return first;
1061  ++first;
1063  case 1:
1064  if (!comp(*first, val))
1065  return first;
1066  return first + 1;
1067  default:
1068  // indices seem
1069  // to not be
1070  // sorted
1071  // correctly!? or
1072  // did len
1073  // become==0
1074  // somehow? that
1075  // shouldn't have
1076  // happened
1077  Assert(false, ExcInternalError());
1078  }
1079  }
1080 
1081 
1082 
1083  const unsigned int half = len >> 1;
1084  const Iterator middle = first + half;
1085 
1086  // if the value is larger than
1087  // that pointed to by the
1088  // middle pointer, then the
1089  // insertion point must be
1090  // right of it
1091  if (comp(*middle, val))
1092  {
1093  first = middle + 1;
1094  len -= half + 1;
1095  }
1096  else
1097  len = half;
1098  }
1099  }
1100 
1101 
1102  // --------------------- non-inline functions
1103 
1104  namespace internal
1105  {
1111  template <typename T>
1113  {
1114  static constexpr bool value = false;
1115  };
1116 
1117 
1118 
1119  template <typename T>
1120  struct IsVectorOfTriviallyCopyable<std::vector<T>>
1121  {
1122  static constexpr bool value =
1123  std::is_trivially_copyable<T>::value && !std::is_same<T, bool>::value;
1124  };
1125 
1126 
1127 
1128  template <typename T>
1129  struct IsVectorOfTriviallyCopyable<std::vector<std::vector<T>>>
1130  {
1131  static constexpr bool value =
1132  std::is_trivially_copyable<T>::value && !std::is_same<T, bool>::value;
1133  };
1134 
1135 
1136 
1145  template <typename T>
1146  inline void
1148  std::vector<char> &)
1149  {
1150  // We shouldn't get here:
1151  Assert(false, ExcInternalError());
1152  }
1153 
1154 
1155 
1156  template <typename T,
1157  typename = std::enable_if_t<!std::is_same<T, bool>::value &&
1158  std::is_trivially_copyable<T>::value>>
1159  inline void
1161  const std::vector<T> &object,
1162  std::vector<char> & dest_buffer)
1163  {
1164  const typename std::vector<T>::size_type vector_size = object.size();
1165 
1166  // Reserve for the buffer so that it can store the size of 'object' as
1167  // well as all of its elements.
1168  dest_buffer.reserve(dest_buffer.size() + sizeof(vector_size) +
1169  vector_size * sizeof(T));
1170 
1171  // Copy the size into the vector
1172  dest_buffer.insert(dest_buffer.end(),
1173  reinterpret_cast<const char *>(&vector_size),
1174  reinterpret_cast<const char *>(&vector_size + 1));
1175 
1176  // Insert the elements at the end of the vector:
1177  if (vector_size > 0)
1178  dest_buffer.insert(dest_buffer.end(),
1179  reinterpret_cast<const char *>(object.data()),
1180  reinterpret_cast<const char *>(object.data() +
1181  vector_size));
1182  }
1183 
1184 
1185 
1186  template <typename T,
1187  typename = std::enable_if_t<!std::is_same<T, bool>::value &&
1188  std::is_trivially_copyable<T>::value>>
1189  inline void
1191  const std::vector<std::vector<T>> &object,
1192  std::vector<char> & dest_buffer)
1193  {
1194  using size_type = typename std::vector<T>::size_type;
1195  const size_type vector_size = object.size();
1196 
1197  typename std::vector<T>::size_type aggregated_size = 0;
1198  std::vector<size_type> sizes;
1199  sizes.reserve(vector_size);
1200  for (const auto &a : object)
1201  {
1202  aggregated_size += a.size();
1203  sizes.push_back(a.size());
1204  }
1205 
1206  // Reserve for the buffer so that it can store the size of 'object' as
1207  // well as all of its elements.
1208  dest_buffer.reserve(dest_buffer.size() +
1209  sizeof(vector_size) * (1 + vector_size) +
1210  aggregated_size * sizeof(T));
1211 
1212  // Copy the size into the vector
1213  dest_buffer.insert(dest_buffer.end(),
1214  reinterpret_cast<const char *>(&vector_size),
1215  reinterpret_cast<const char *>(&vector_size + 1));
1216 
1217  // Copy the sizes of the individual chunks into the vector
1218  if (vector_size > 0)
1219  dest_buffer.insert(dest_buffer.end(),
1220  reinterpret_cast<const char *>(sizes.data()),
1221  reinterpret_cast<const char *>(sizes.data() +
1222  vector_size));
1223 
1224  // Insert the elements at the end of the vector:
1225  for (const auto &a : object)
1226  dest_buffer.insert(dest_buffer.end(),
1227  reinterpret_cast<const char *>(a.data()),
1228  reinterpret_cast<const char *>(a.data() + a.size()));
1229  }
1230 
1231 
1232 
1233  template <typename T>
1234  inline void
1236  const std::vector<char>::const_iterator &,
1237  const std::vector<char>::const_iterator &,
1238  T &)
1239  {
1240  // We shouldn't get here:
1241  Assert(false, ExcInternalError());
1242  }
1243 
1244 
1245 
1246  template <typename T,
1247  typename = std::enable_if_t<!std::is_same<T, bool>::value &&
1248  std::is_trivially_copyable<T>::value>>
1249  inline void
1251  const std::vector<char>::const_iterator &cbegin,
1252  const std::vector<char>::const_iterator &cend,
1253  std::vector<T> & object)
1254  {
1255  // The size of the object vector can be found in cbegin of the buffer.
1256  // The data starts at cbegin + sizeof(vector_size).
1257 
1258  // Get the size of the vector
1259  typename std::vector<T>::size_type vector_size;
1260  memcpy(&vector_size, &*cbegin, sizeof(vector_size));
1261 
1262  Assert(static_cast<std::ptrdiff_t>(cend - cbegin) ==
1263  static_cast<std::ptrdiff_t>(sizeof(vector_size) +
1264  vector_size * sizeof(T)),
1265  ExcMessage("The given buffer has the wrong size."));
1266  (void)cend;
1267 
1268  // Copy the elements:
1269  object.clear();
1270  if (vector_size > 0)
1271  {
1272  const auto buffer_data_begin =
1273  reinterpret_cast<const T *>(&*cbegin + sizeof(vector_size));
1274  const auto buffer_data_end = buffer_data_begin + vector_size;
1275  object.insert(object.end(), buffer_data_begin, buffer_data_end);
1276  }
1277  }
1278 
1279 
1280 
1281  template <typename T,
1282  typename = std::enable_if_t<!std::is_same<T, bool>::value &&
1283  std::is_trivially_copyable<T>::value>>
1284  inline void
1286  const std::vector<char>::const_iterator &cbegin,
1287  const std::vector<char>::const_iterator &cend,
1288  std::vector<std::vector<T>> & object)
1289  {
1290  // First get the size of the vector, and resize the output object
1291  using size_type = typename std::vector<T>::size_type;
1292  std::vector<char>::const_iterator iterator = cbegin;
1293  size_type vector_size;
1294  memcpy(&vector_size, &*iterator, sizeof(vector_size));
1295  object.clear();
1296  object.resize(vector_size);
1297  std::vector<size_type> sizes(vector_size);
1298  if (vector_size > 0)
1299  memcpy(sizes.data(),
1300  &*iterator + sizeof(vector_size),
1301  vector_size * sizeof(size_type));
1302 
1303  iterator += sizeof(vector_size) * (1 + vector_size);
1304  size_type aggregated_size = 0;
1305  for (const auto a : sizes)
1306  aggregated_size += a;
1307 
1308  Assert(static_cast<std::ptrdiff_t>(cend - iterator) ==
1309  static_cast<std::ptrdiff_t>(aggregated_size * sizeof(T)),
1310  ExcMessage("The given buffer has the wrong size."));
1311  (void)cend;
1312 
1313  // Then copy the elements:
1314  for (unsigned int i = 0; i < vector_size; ++i)
1315  if (sizes[i] > 0)
1316  {
1317  object[i].insert(object[i].end(),
1318  reinterpret_cast<const T *>(&*iterator),
1319  reinterpret_cast<const T *>(&*iterator +
1320  sizeof(T) * sizes[i]));
1321  iterator += sizeof(T) * sizes[i];
1322  }
1323 
1324  Assert(iterator == cend,
1325  ExcMessage("The given buffer has the wrong size."));
1326  }
1327 
1328  } // namespace internal
1329 
1330 
1331 
1332  template <typename T>
1333  size_t
1334  pack(const T & object,
1335  std::vector<char> &dest_buffer,
1336  const bool allow_compression)
1337  {
1338  std::size_t size = 0;
1339 
1340 
1341  // see if the object is small and copyable via memcpy. if so, use
1342  // this fast path. otherwise, we have to go through the BOOST
1343  // serialization machinery
1344  if DEAL_II_CONSTEXPR_IN_CONDITIONAL (std::is_trivially_copyable<T>() &&
1345  sizeof(T) < 256)
1346  {
1347  // Determine the size. There are places where we would like to use a
1348  // truly empty type, for which we use std::tuple<> (i.e., a tuple
1349  // of zero elements). For this class, the compiler reports a nonzero
1350  // sizeof(...) because that is the minimum possible for objects --
1351  // objects need to have distinct addresses, so they need to have a size
1352  // of at least one. But we can special case this situation.
1353  size = (std::is_same<T, std::tuple<>>::value ? 0 : sizeof(T));
1354 
1355  (void)allow_compression;
1356  const std::size_t previous_size = dest_buffer.size();
1357  dest_buffer.resize(previous_size + size);
1358 
1359  if (size > 0)
1360  std::memcpy(dest_buffer.data() + previous_size, &object, size);
1361  }
1362  // Next try if we have a vector of trivially copyable objects.
1363  // If that is the case, we can shortcut the whole BOOST serialization
1364  // machinery and just copy the content of the vector bit for bit
1365  // into the output buffer, assuming that we are not asked to compress
1366  // the data.
1368  (allow_compression == false))
1369  {
1370  const std::size_t previous_size = dest_buffer.size();
1371 
1372  // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1373  // inline the code of the following function here and make the 'if'
1374  // above a 'if constexpr'. Without the 'constexpr', we need to keep
1375  // the general template of the function that throws an exception.
1377  dest_buffer);
1378 
1379  size = dest_buffer.size() - previous_size;
1380  }
1381  else
1382  {
1383  // use buffer as the target of a compressing
1384  // stream into which we serialize the current object
1385  const std::size_t previous_size = dest_buffer.size();
1386  {
1387  boost::iostreams::filtering_ostreambuf fosb;
1388 #ifdef DEAL_II_WITH_ZLIB
1389  if (allow_compression)
1390  fosb.push(boost::iostreams::gzip_compressor());
1391 #else
1392  (void)allow_compression;
1393 #endif
1394  fosb.push(boost::iostreams::back_inserter(dest_buffer));
1395 
1396  boost::archive::binary_oarchive boa(fosb);
1397  boa << object;
1398  // the stream object has to be destroyed before the return statement
1399  // to ensure that all data has been written in the buffer
1400  }
1401  size = dest_buffer.size() - previous_size;
1402  }
1403 
1404  return size;
1405  }
1406 
1407 
1408  template <typename T>
1409  std::vector<char>
1410  pack(const T &object, const bool allow_compression)
1411  {
1412  std::vector<char> buffer;
1413  pack<T>(object, buffer, allow_compression);
1414  return buffer;
1415  }
1416 
1417 
1418 
1419  template <typename T>
1420  T
1421  unpack(const std::vector<char>::const_iterator &cbegin,
1422  const std::vector<char>::const_iterator &cend,
1423  const bool allow_compression)
1424  {
1425  // see if the object is small and copyable via memcpy. if so, use
1426  // this fast path. otherwise, we have to go through the BOOST
1427  // serialization machinery
1428  if DEAL_II_CONSTEXPR_IN_CONDITIONAL (std::is_trivially_copyable<T>() &&
1429  sizeof(T) < 256)
1430  {
1431  // Determine the size. There are places where we would like to use a
1432  // truly empty type, for which we use std::tuple<> (i.e., a tuple
1433  // of zero elements). For this class, the compiler reports a nonzero
1434  // sizeof(...) because that is the minimum possible for objects --
1435  // objects need to have distinct addresses, so they need to have a size
1436  // of at least one. But we can special case this situation.
1437  const std::size_t size =
1438  (std::is_same<T, std::tuple<>>::value ? 0 : sizeof(T));
1439 
1440  T object;
1441 
1442  (void)allow_compression;
1443  Assert(std::distance(cbegin, cend) == size, ExcInternalError());
1444 
1445  if (size > 0)
1446  std::memcpy(&object, &*cbegin, size);
1447 
1448  return object;
1449  }
1450  // Next try if we have a vector of trivially copyable objects.
1451  // If that is the case, we can shortcut the whole BOOST serialization
1452  // machinery and just copy the content of the buffer bit for bit
1453  // into an appropriately sized output vector, assuming that we
1454  // are not asked to compress the data.
1456  (allow_compression == false))
1457  {
1458  // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1459  // inline the code of the following function here and make the 'if'
1460  // above a 'if constexpr'. Without the 'constexpr', we need to keep
1461  // the general template of the function that throws an exception.
1462  T object;
1464  cend,
1465  object);
1466  return object;
1467  }
1468  else
1469  {
1470  // decompress the buffer section into the object
1471  boost::iostreams::filtering_istreambuf fisb;
1472 #ifdef DEAL_II_WITH_ZLIB
1473  if (allow_compression)
1474  fisb.push(boost::iostreams::gzip_decompressor());
1475 #else
1476  (void)allow_compression;
1477 #endif
1478  fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1479 
1480  boost::archive::binary_iarchive bia(fisb);
1481 
1482  T object;
1483  bia >> object;
1484  return object;
1485  }
1486 
1487  return T();
1488  }
1489 
1490 
1491  template <typename T>
1492  T
1493  unpack(const std::vector<char> &buffer, const bool allow_compression)
1494  {
1495  return unpack<T>(buffer.cbegin(), buffer.cend(), allow_compression);
1496  }
1497 
1498 
1499  template <typename T, int N>
1500  void
1501  unpack(const std::vector<char>::const_iterator &cbegin,
1502  const std::vector<char>::const_iterator &cend,
1503  T (&unpacked_object)[N],
1504  const bool allow_compression)
1505  {
1506  // see if the object is small and copyable via memcpy. if so, use
1507  // this fast path. otherwise, we have to go through the BOOST
1508  // serialization machinery
1509  if DEAL_II_CONSTEXPR_IN_CONDITIONAL (std::is_trivially_copyable<T>() &&
1510  sizeof(T) * N < 256)
1511  {
1512  Assert(std::distance(cbegin, cend) == sizeof(T) * N,
1513  ExcInternalError());
1514  std::memcpy(unpacked_object, &*cbegin, sizeof(T) * N);
1515  }
1516  else
1517  {
1518  // decompress the buffer section into the object
1519  boost::iostreams::filtering_istreambuf fisb;
1520 #ifdef DEAL_II_WITH_ZLIB
1521  if (allow_compression)
1522  fisb.push(boost::iostreams::gzip_decompressor());
1523 #else
1524  (void)allow_compression;
1525 #endif
1526  fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1527 
1528  boost::archive::binary_iarchive bia(fisb);
1529  bia >> unpacked_object;
1530  }
1531  }
1532 
1533 
1534  template <typename T, int N>
1535  void
1536  unpack(const std::vector<char> &buffer,
1537  T (&unpacked_object)[N],
1538  const bool allow_compression)
1539  {
1540  unpack<T, N>(buffer.cbegin(),
1541  buffer.cend(),
1542  unpacked_object,
1543  allow_compression);
1544  }
1545 
1546 
1547 
1548  inline bool
1549  get_bit(const unsigned char number, const unsigned int n)
1550  {
1551  AssertIndexRange(n, 8);
1552 
1553  // source:
1554  // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1555  // "Checking a bit"
1556  return ((number >> n) & 1U) != 0u;
1557  }
1558 
1559 
1560 
1561  inline void
1562  set_bit(unsigned char &number, const unsigned int n, const bool x)
1563  {
1564  AssertIndexRange(n, 8);
1565 
1566  // source:
1567  // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1568  // "Changing the nth bit to x"
1569  number ^= (-static_cast<unsigned char>(x) ^ number) & (1U << n);
1570  }
1571 
1572 
1573 
1574  template <typename To, typename From>
1575  inline std::unique_ptr<To>
1576  dynamic_unique_cast(std::unique_ptr<From> &&p)
1577  {
1578  // Let's see if we can cast from 'From' to 'To'. If so, do the cast,
1579  // and then release the pointer from the old
1580  // owner
1581  if (To *cast = dynamic_cast<To *>(p.get()))
1582  {
1583  std::unique_ptr<To> result(cast);
1584  p.release();
1585  return result;
1586  }
1587  else
1588  throw std::bad_cast();
1589  }
1590 
1591 
1592 
1593  template <typename T>
1594  inline T &
1596  {
1597  return p;
1598  }
1599 
1600 
1601 
1602  template <typename T>
1603  inline T &
1604  get_underlying_value(std::shared_ptr<T> &p)
1605  {
1606  return *p;
1607  }
1608 
1609 
1610 
1611  template <typename T>
1612  inline T &
1613  get_underlying_value(const std::shared_ptr<T> &p)
1614  {
1615  return *p;
1616  }
1617 
1618 
1619 
1620  template <typename T>
1621  inline T &
1622  get_underlying_value(std::unique_ptr<T> &p)
1623  {
1624  return *p;
1625  }
1626 
1627 
1628 
1629  template <typename T>
1630  inline T &
1631  get_underlying_value(const std::unique_ptr<T> &p)
1632  {
1633  return *p;
1634  }
1635 
1636 
1637 
1638  template <typename Integer>
1639  std::vector<Integer>
1640  reverse_permutation(const std::vector<Integer> &permutation)
1641  {
1642  const std::size_t n = permutation.size();
1643 
1644  std::vector<Integer> out(n);
1645  for (std::size_t i = 0; i < n; ++i)
1646  out[i] = n - 1 - permutation[i];
1647 
1648  return out;
1649  }
1650 
1651 
1652 
1653  template <typename Integer>
1654  std::vector<Integer>
1655  invert_permutation(const std::vector<Integer> &permutation)
1656  {
1657  const std::size_t n = permutation.size();
1658 
1659  std::vector<Integer> out(n, numbers::invalid_unsigned_int);
1660 
1661  for (std::size_t i = 0; i < n; ++i)
1662  {
1663  AssertIndexRange(permutation[i], n);
1664  out[permutation[i]] = i;
1665  }
1666 
1667  // check that we have actually reached
1668  // all indices
1669  for (std::size_t i = 0; i < n; ++i)
1671  ExcMessage("The given input permutation had duplicate entries!"));
1672 
1673  return out;
1674  }
1675 } // namespace Utilities
1676 
1677 
1679 
1680 #ifndef DOXYGEN
1681 namespace boost
1682 {
1683  namespace serialization
1684  {
1685  // Provides boost and c++11 with a way to serialize tuples and pairs
1686  // automatically.
1687  template <int N>
1688  struct Serialize
1689  {
1690  template <class Archive, typename... Args>
1691  static void
1692  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1693  {
1694  ar &std::get<N - 1>(t);
1695  Serialize<N - 1>::serialize(ar, t, version);
1696  }
1697  };
1698 
1699  template <>
1700  struct Serialize<0>
1701  {
1702  template <class Archive, typename... Args>
1703  static void
1704  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1705  {
1706  (void)ar;
1707  (void)t;
1708  (void)version;
1709  }
1710  };
1711 
1712  template <class Archive, typename... Args>
1713  void
1714  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1715  {
1716  Serialize<sizeof...(Args)>::serialize(ar, t, version);
1717  }
1718  } // namespace serialization
1719 } // namespace boost
1720 #endif
1721 
1722 #endif
Definition: point.h:110
#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:1586
#define AssertIndexRange(index, range)
Definition: exceptions.h:1827
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:1235
void append_vector_of_trivially_copyable_to_buffer(const T &, std::vector< char > &)
Definition: utilities.h:1147
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:1595
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:990
size_t pack(const T &object, std::vector< char > &dest_buffer, const bool allow_compression=true)
Definition: utilities.h:1334
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:1549
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:1576
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:1493
T fixed_power(const T t)
Definition: utilities.h:966
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:999
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:1562
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:1640
std::vector< Integer > invert_permutation(const std::vector< Integer > &permutation)
Definition: utilities.h:1655
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:1398
static const unsigned int invalid_unsigned_int
Definition: types.h:213
unsigned long int VmRSS
Definition: utilities.h:908
unsigned long int VmPeak
Definition: utilities.h:892
unsigned long int VmSize
Definition: utilities.h:897
unsigned long int VmHWM
Definition: utilities.h:902