Reference documentation for deal.II version GIT 69313620a0 2022-11-28 13:00: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 - 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 <cstddef>
24 #include <functional>
25 #include <string>
26 #include <tuple>
27 #include <type_traits>
28 #include <typeinfo>
29 #include <utility>
30 #include <vector>
31 
33 
34 #include <boost/archive/binary_iarchive.hpp>
35 #include <boost/archive/binary_oarchive.hpp>
36 #include <boost/core/demangle.hpp>
37 #include <boost/iostreams/device/array.hpp>
38 #include <boost/iostreams/device/back_inserter.hpp>
39 #include <boost/iostreams/filtering_streambuf.hpp>
40 #include <boost/serialization/array.hpp>
41 #include <boost/serialization/complex.hpp>
42 #include <boost/serialization/vector.hpp>
43 
44 #ifdef DEAL_II_WITH_ZLIB
45 # include <boost/iostreams/filter/gzip.hpp>
46 #endif
47 
49 
51 
52 // forward declare Point
53 #ifndef DOXYGEN
54 template <int dim, typename Number>
55 class Point;
56 #endif
57 
65 namespace Utilities
66 {
73  std::string
75 
92  template <int dim, typename Number>
93  std::vector<std::array<std::uint64_t, dim>>
95  const std::vector<Point<dim, Number>> &points,
96  const int bits_per_dim = 64);
97 
101  template <int dim>
102  std::vector<std::array<std::uint64_t, dim>>
104  const std::vector<std::array<std::uint64_t, dim>> &points,
105  const int bits_per_dim = 64);
106 
122  template <int dim>
123  std::uint64_t
124  pack_integers(const std::array<std::uint64_t, dim> &index,
125  const int bits_per_dim);
126 
139  std::string
140  compress(const std::string &input);
141 
155  std::string
156  decompress(const std::string &compressed_input);
157 
171  std::string
172  encode_base64(const std::vector<unsigned char> &binary_input);
173 
182  std::vector<unsigned char>
183  decode_base64(const std::string &base64_input);
184 
206  std::string
207  int_to_string(const unsigned int value,
208  const unsigned int digits = numbers::invalid_unsigned_int);
209 
221  template <typename number>
222  std::string
223  to_string(const number value,
224  const unsigned int digits = numbers::invalid_unsigned_int);
225 
230  unsigned int
231  needed_digits(const unsigned int max_number);
232 
241  template <typename Number>
242  Number
243  truncate_to_n_digits(const Number number, const unsigned int n_digits);
244 
249  int
250  string_to_int(const std::string &s);
251 
263  std::string
264  dim_string(const int dim, const int spacedim);
265 
270  std::vector<int>
271  string_to_int(const std::vector<std::string> &s);
272 
277  double
278  string_to_double(const std::string &s);
279 
280 
285  std::vector<double>
286  string_to_double(const std::vector<std::string> &s);
287 
288 
331  std::vector<std::string>
332  split_string_list(const std::string &s, const std::string &delimiter = ",");
333 
334 
339  std::vector<std::string>
340  split_string_list(const std::string &s, const char delimiter);
341 
342 
352  std::vector<std::string>
353  break_text_into_lines(const std::string &original_text,
354  const unsigned int width,
355  const char delimiter = ' ');
356 
361  bool
362  match_at_string_start(const std::string &name, const std::string &pattern);
363 
372  std::pair<int, unsigned int>
373  get_integer_at_position(const std::string &name, const unsigned int position);
374 
379  std::string
380  replace_in_string(const std::string &input,
381  const std::string &from,
382  const std::string &to);
383 
389  std::string
390  trim(const std::string &input);
391 
417  double
418  generate_normal_random_number(const double a, const double sigma);
419 
427  template <class T>
428  std::string
429  type_to_string(const T &t);
430 
439  template <int N, typename T>
440  T
441  fixed_power(const T t);
442 
448  template <typename T>
449  constexpr T
450  pow(const T base, const int iexp)
451  {
452 #if defined(DEBUG) && !defined(DEAL_II_CXX14_CONSTEXPR_BUG)
453  // Up to __builtin_expect this is the same code as in the 'Assert' macro.
454  // The call to __builtin_expect turns out to be problematic.
455  if (!(iexp >= 0))
458  abort_or_throw_on_exception,
459  __FILE__,
460  __LINE__,
461  __PRETTY_FUNCTION__,
462  "iexp>=0",
463  "ExcMessage(\"The exponent must not be negative!\")",
464  ExcMessage("The exponent must not be negative!"));
465 #endif
466  // The "exponentiation by squaring" algorithm used below has to be
467  // compressed to one statement due to C++11's restrictions on constexpr
468  // functions. A more descriptive version would be:
469  //
470  // <code>
471  // if (iexp <= 0)
472  // return 1;
473  //
474  // // avoid overflow of one additional recursion with pow(base * base, 0)
475  // if (iexp == 1)
476  // return base;
477  //
478  // // if the current exponent is not divisible by two,
479  // // we need to account for that.
480  // const unsigned int prefactor = (iexp % 2 == 1) ? base : 1;
481  //
482  // // a^b = (a*a)^(b/2) for b even
483  // // a^b = a*(a*a)^((b-1)/2 for b odd
484  // return prefactor * ::Utilities::pow(base*base, iexp/2);
485  // </code>
486 
487  static_assert(std::is_integral<T>::value, "Only integral types supported");
488 
489  return iexp <= 0 ?
490  1 :
491  (iexp == 1 ? base :
492  (((iexp % 2 == 1) ? base : 1) *
493  ::Utilities::pow(base * base, iexp / 2)));
494  }
495 
517  template <typename Iterator, typename T>
518  Iterator
519  lower_bound(Iterator first, Iterator last, const T &val);
520 
521 
527  template <typename Iterator, typename T, typename Comp>
528  Iterator
529  lower_bound(Iterator first, Iterator last, const T &val, const Comp comp);
530 
536  template <typename Integer>
537  std::vector<Integer>
538  reverse_permutation(const std::vector<Integer> &permutation);
539 
545  template <typename Integer>
546  std::vector<Integer>
547  invert_permutation(const std::vector<Integer> &permutation);
548 
603  template <typename T>
604  size_t
605  pack(const T & object,
606  std::vector<char> &dest_buffer,
607  const bool allow_compression = true);
608 
617  template <typename T>
618  std::vector<char>
619  pack(const T &object, const bool allow_compression = true);
620 
652  template <typename T>
653  T
654  unpack(const std::vector<char> &buffer, const bool allow_compression = true);
655 
664  template <typename T>
665  T
666  unpack(const std::vector<char>::const_iterator &cbegin,
667  const std::vector<char>::const_iterator &cend,
668  const bool allow_compression = true);
669 
702  template <typename T, int N>
703  void
704  unpack(const std::vector<char> &buffer,
705  T (&unpacked_object)[N],
706  const bool allow_compression = true);
707 
716  template <typename T, int N>
717  void
718  unpack(const std::vector<char>::const_iterator &cbegin,
719  const std::vector<char>::const_iterator &cend,
720  T (&unpacked_object)[N],
721  const bool allow_compression = true);
722 
726  bool
727  get_bit(const unsigned char number, const unsigned int n);
728 
729 
733  void
734  set_bit(unsigned char &number, const unsigned int n, const bool x);
735 
736 
794  template <typename To, typename From>
795  std::unique_ptr<To>
796  dynamic_unique_cast(std::unique_ptr<From> &&p);
797 
801  template <typename T>
802  T &
804 
808  template <typename T>
809  T &
810  get_underlying_value(std::shared_ptr<T> &p);
811 
815  template <typename T>
816  T &
817  get_underlying_value(const std::shared_ptr<T> &p);
818 
822  template <typename T>
823  T &
824  get_underlying_value(std::unique_ptr<T> &p);
825 
829  template <typename T>
830  T &
831  get_underlying_value(const std::unique_ptr<T> &p);
832 
838  namespace System
839  {
847  double
848  get_cpu_load();
849 
883  const std::string
885 
890  struct MemoryStats
891  {
895  unsigned long int VmPeak;
896 
900  unsigned long int VmSize;
901 
905  unsigned long int VmHWM;
906 
911  unsigned long int VmRSS;
912  };
913 
914 
919  void
921 
922 
926  std::string
927  get_hostname();
928 
929 
933  std::string
934  get_time();
935 
940  std::string
941  get_date();
942 
957  void
958  posix_memalign(void **memptr, std::size_t alignment, std::size_t size);
959  } // namespace System
960 } // namespace Utilities
961 
962 
963 // --------------------- inline functions
964 
965 namespace Utilities
966 {
967  template <int N, typename T>
968  inline T
969  fixed_power(const T x)
970  {
971  Assert(
972  !std::is_integral<T>::value || (N >= 0),
973  ExcMessage(
974  "The non-type template parameter N must be a non-negative integer for integral type T"));
975 
976  if (N == 0)
977  return T(1.);
978  else if (N < 0)
979  return T(1.) / fixed_power<-N>(x);
980  else
981  // Use exponentiation by 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 #ifdef DEAL_II_HAVE_CXX17
1345  if constexpr (std::is_trivially_copyable<T>() && sizeof(T) < 256)
1346 #else
1347  if (std::is_trivially_copyable<T>() && sizeof(T) < 256)
1348 #endif
1349  {
1350  // Determine the size. There are places where we would like to use a
1351  // truly empty type, for which we use std::tuple<> (i.e., a tuple
1352  // of zero elements). For this class, the compiler reports a nonzero
1353  // sizeof(...) because that is the minimum possible for objects --
1354  // objects need to have distinct addresses, so they need to have a size
1355  // of at least one. But we can special case this situation.
1356  size = (std::is_same<T, std::tuple<>>::value ? 0 : sizeof(T));
1357 
1358  (void)allow_compression;
1359  const std::size_t previous_size = dest_buffer.size();
1360  dest_buffer.resize(previous_size + size);
1361 
1362  if (size > 0)
1363  std::memcpy(dest_buffer.data() + previous_size, &object, size);
1364  }
1365  // Next try if we have a vector of trivially copyable objects.
1366  // If that is the case, we can shortcut the whole BOOST serialization
1367  // machinery and just copy the content of the vector bit for bit
1368  // into the output buffer, assuming that we are not asked to compress
1369  // the data.
1371  (allow_compression == false))
1372  {
1373  const std::size_t previous_size = dest_buffer.size();
1374 
1375  // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1376  // inline the code of the following function here and make the 'if'
1377  // above a 'if constexpr'. Without the 'constexpr', we need to keep
1378  // the general template of the function that throws an exception.
1380  dest_buffer);
1381 
1382  size = dest_buffer.size() - previous_size;
1383  }
1384  else
1385  {
1386  // use buffer as the target of a compressing
1387  // stream into which we serialize the current object
1388  const std::size_t previous_size = dest_buffer.size();
1389  {
1390  boost::iostreams::filtering_ostreambuf fosb;
1391 #ifdef DEAL_II_WITH_ZLIB
1392  if (allow_compression)
1393  fosb.push(boost::iostreams::gzip_compressor());
1394 #else
1395  (void)allow_compression;
1396 #endif
1397  fosb.push(boost::iostreams::back_inserter(dest_buffer));
1398 
1399  boost::archive::binary_oarchive boa(fosb);
1400  boa << object;
1401  // the stream object has to be destroyed before the return statement
1402  // to ensure that all data has been written in the buffer
1403  }
1404  size = dest_buffer.size() - previous_size;
1405  }
1406 
1407  return size;
1408  }
1409 
1410 
1411  template <typename T>
1412  std::vector<char>
1413  pack(const T &object, const bool allow_compression)
1414  {
1415  std::vector<char> buffer;
1416  pack<T>(object, buffer, allow_compression);
1417  return buffer;
1418  }
1419 
1420 
1421 
1422  template <typename T>
1423  T
1424  unpack(const std::vector<char>::const_iterator &cbegin,
1425  const std::vector<char>::const_iterator &cend,
1426  const bool allow_compression)
1427  {
1428  // see if the object is small and copyable via memcpy. if so, use
1429  // this fast path. otherwise, we have to go through the BOOST
1430  // serialization machinery
1431 #ifdef DEAL_II_HAVE_CXX17
1432  if constexpr (std::is_trivially_copyable<T>() && sizeof(T) < 256)
1433 #else
1434  if (std::is_trivially_copyable<T>() && sizeof(T) < 256)
1435 #endif
1436  {
1437  // Determine the size. There are places where we would like to use a
1438  // truly empty type, for which we use std::tuple<> (i.e., a tuple
1439  // of zero elements). For this class, the compiler reports a nonzero
1440  // sizeof(...) because that is the minimum possible for objects --
1441  // objects need to have distinct addresses, so they need to have a size
1442  // of at least one. But we can special case this situation.
1443  const std::size_t size =
1444  (std::is_same<T, std::tuple<>>::value ? 0 : sizeof(T));
1445 
1446  T object;
1447 
1448  (void)allow_compression;
1449  Assert(std::distance(cbegin, cend) == size, ExcInternalError());
1450 
1451  if (size > 0)
1452  std::memcpy(&object, &*cbegin, size);
1453 
1454  return object;
1455  }
1456  // Next try if we have a vector of trivially copyable objects.
1457  // If that is the case, we can shortcut the whole BOOST serialization
1458  // machinery and just copy the content of the buffer bit for bit
1459  // into an appropriately sized output vector, assuming that we
1460  // are not asked to compress the data.
1462  (allow_compression == false))
1463  {
1464  // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1465  // inline the code of the following function here and make the 'if'
1466  // above a 'if constexpr'. Without the 'constexpr', we need to keep
1467  // the general template of the function that throws an exception.
1468  T object;
1470  cend,
1471  object);
1472  return object;
1473  }
1474  else
1475  {
1476  // decompress the buffer section into the object
1477  boost::iostreams::filtering_istreambuf fisb;
1478 #ifdef DEAL_II_WITH_ZLIB
1479  if (allow_compression)
1480  fisb.push(boost::iostreams::gzip_decompressor());
1481 #else
1482  (void)allow_compression;
1483 #endif
1484  fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1485 
1486  boost::archive::binary_iarchive bia(fisb);
1487 
1488  T object;
1489  bia >> object;
1490  return object;
1491  }
1492 
1493  return T();
1494  }
1495 
1496 
1497  template <typename T>
1498  T
1499  unpack(const std::vector<char> &buffer, const bool allow_compression)
1500  {
1501  return unpack<T>(buffer.cbegin(), buffer.cend(), allow_compression);
1502  }
1503 
1504 
1505  template <typename T, int N>
1506  void
1507  unpack(const std::vector<char>::const_iterator &cbegin,
1508  const std::vector<char>::const_iterator &cend,
1509  T (&unpacked_object)[N],
1510  const bool allow_compression)
1511  {
1512  // see if the object is small and copyable via memcpy. if so, use
1513  // this fast path. otherwise, we have to go through the BOOST
1514  // serialization machinery
1515 #ifdef DEAL_II_HAVE_CXX17
1516  if constexpr (std::is_trivially_copyable<T>() && sizeof(T) * N < 256)
1517 #else
1518  if (std::is_trivially_copyable<T>() && sizeof(T) * N < 256)
1519 #endif
1520  {
1521  Assert(std::distance(cbegin, cend) == sizeof(T) * N,
1522  ExcInternalError());
1523  std::memcpy(unpacked_object, &*cbegin, sizeof(T) * N);
1524  }
1525  else
1526  {
1527  // decompress the buffer section into the object
1528  boost::iostreams::filtering_istreambuf fisb;
1529 #ifdef DEAL_II_WITH_ZLIB
1530  if (allow_compression)
1531  fisb.push(boost::iostreams::gzip_decompressor());
1532 #else
1533  (void)allow_compression;
1534 #endif
1535  fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1536 
1537  boost::archive::binary_iarchive bia(fisb);
1538  bia >> unpacked_object;
1539  }
1540  }
1541 
1542 
1543  template <typename T, int N>
1544  void
1545  unpack(const std::vector<char> &buffer,
1546  T (&unpacked_object)[N],
1547  const bool allow_compression)
1548  {
1549  unpack<T, N>(buffer.cbegin(),
1550  buffer.cend(),
1551  unpacked_object,
1552  allow_compression);
1553  }
1554 
1555 
1556 
1557  inline bool
1558  get_bit(const unsigned char number, const unsigned int n)
1559  {
1560  AssertIndexRange(n, 8);
1561 
1562  // source:
1563  // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1564  // "Checking a bit"
1565  return ((number >> n) & 1U) != 0u;
1566  }
1567 
1568 
1569 
1570  inline void
1571  set_bit(unsigned char &number, const unsigned int n, const bool x)
1572  {
1573  AssertIndexRange(n, 8);
1574 
1575  // source:
1576  // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1577  // "Changing the nth bit to x"
1578  number ^= (-static_cast<unsigned char>(x) ^ number) & (1U << n);
1579  }
1580 
1581 
1582 
1583  template <typename To, typename From>
1584  inline std::unique_ptr<To>
1585  dynamic_unique_cast(std::unique_ptr<From> &&p)
1586  {
1587  // Let's see if we can cast from 'From' to 'To'. If so, do the cast,
1588  // and then release the pointer from the old
1589  // owner
1590  if (To *cast = dynamic_cast<To *>(p.get()))
1591  {
1592  std::unique_ptr<To> result(cast);
1593  p.release();
1594  return result;
1595  }
1596  else
1597  throw std::bad_cast();
1598  }
1599 
1600 
1601 
1602  template <typename T>
1603  inline T &
1605  {
1606  return p;
1607  }
1608 
1609 
1610 
1611  template <typename T>
1612  inline T &
1613  get_underlying_value(std::shared_ptr<T> &p)
1614  {
1615  return *p;
1616  }
1617 
1618 
1619 
1620  template <typename T>
1621  inline T &
1622  get_underlying_value(const std::shared_ptr<T> &p)
1623  {
1624  return *p;
1625  }
1626 
1627 
1628 
1629  template <typename T>
1630  inline T &
1631  get_underlying_value(std::unique_ptr<T> &p)
1632  {
1633  return *p;
1634  }
1635 
1636 
1637 
1638  template <typename T>
1639  inline T &
1640  get_underlying_value(const std::unique_ptr<T> &p)
1641  {
1642  return *p;
1643  }
1644 
1645 
1646 
1647  template <typename Integer>
1648  std::vector<Integer>
1649  reverse_permutation(const std::vector<Integer> &permutation)
1650  {
1651  const std::size_t n = permutation.size();
1652 
1653  std::vector<Integer> out(n);
1654  for (std::size_t i = 0; i < n; ++i)
1655  out[i] = n - 1 - permutation[i];
1656 
1657  return out;
1658  }
1659 
1660 
1661 
1662  template <typename Integer>
1663  std::vector<Integer>
1664  invert_permutation(const std::vector<Integer> &permutation)
1665  {
1666  const std::size_t n = permutation.size();
1667 
1668  std::vector<Integer> out(n, numbers::invalid_unsigned_int);
1669 
1670  for (std::size_t i = 0; i < n; ++i)
1671  {
1672  AssertIndexRange(permutation[i], n);
1673  out[permutation[i]] = i;
1674  }
1675 
1676  // check that we have actually reached
1677  // all indices
1678  for (std::size_t i = 0; i < n; ++i)
1680  ExcMessage("The given input permutation had duplicate entries!"));
1681 
1682  return out;
1683  }
1684 } // namespace Utilities
1685 
1686 
1688 
1689 #ifndef DOXYGEN
1690 namespace boost
1691 {
1692  namespace serialization
1693  {
1694  // Provides boost and c++11 with a way to serialize tuples and pairs
1695  // automatically.
1696  template <int N>
1697  struct Serialize
1698  {
1699  template <class Archive, typename... Args>
1700  static void
1701  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1702  {
1703  ar &std::get<N - 1>(t);
1704  Serialize<N - 1>::serialize(ar, t, version);
1705  }
1706  };
1707 
1708  template <>
1709  struct Serialize<0>
1710  {
1711  template <class Archive, typename... Args>
1712  static void
1713  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1714  {
1715  (void)ar;
1716  (void)t;
1717  (void)version;
1718  }
1719  };
1720 
1721  template <class Archive, typename... Args>
1722  void
1723  serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1724  {
1725  Serialize<sizeof...(Args)>::serialize(ar, t, version);
1726  }
1727  } // namespace serialization
1728 } // namespace boost
1729 #endif
1730 
1731 #endif
Definition: point.h:111
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:458
#define DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
Definition: config.h:472
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:459
#define DEAL_II_FALLTHROUGH
Definition: config.h:176
#define DEAL_II_ENABLE_EXTRA_DIAGNOSTICS
Definition: config.h:512
Point< 2 > first
Definition: grid_out.cc:4605
static ::ExceptionBase & ExcInternalError()
#define Assert(cond, exc)
Definition: exceptions.h:1501
#define AssertIndexRange(index, range)
Definition: exceptions.h:1760
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:967
std::string get_hostname()
Definition: utilities.cc:1001
std::string get_time()
Definition: utilities.cc:1016
void posix_memalign(void **memptr, std::size_t alignment, std::size_t size)
Definition: utilities.cc:1047
double get_cpu_load()
Definition: utilities.cc:933
const std::string get_current_vectorization_level()
Definition: utilities.cc:941
std::string get_date()
Definition: utilities.cc:1032
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:450
std::vector< std::string > split_string_list(const std::string &s, const std::string &delimiter=",")
Definition: utilities.cc:704
T & get_underlying_value(T &p)
Definition: utilities.h:1604
Number truncate_to_n_digits(const Number number, const unsigned int n_digits)
Definition: utilities.cc:581
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:558
std::uint64_t pack_integers(const std::array< std::uint64_t, dim > &index, const int bits_per_dim)
Definition: utilities.cc:369
bool get_bit(const unsigned char number, const unsigned int n)
Definition: utilities.h:1558
std::pair< int, unsigned int > get_integer_at_position(const std::string &name, const unsigned int position)
Definition: utilities.cc:850
std::string encode_base64(const std::vector< unsigned char > &binary_input)
Definition: utilities.cc:436
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:148
std::unique_ptr< To > dynamic_unique_cast(std::unique_ptr< From > &&p)
Definition: utilities.h:1585
std::string replace_in_string(const std::string &input, const std::string &from, const std::string &to)
Definition: utilities.cc:512
std::vector< unsigned char > decode_base64(const std::string &base64_input)
Definition: utilities.cc:449
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
Definition: utilities.cc:758
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:482
std::string compress(const std::string &input)
Definition: utilities.cc:392
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:473
bool match_at_string_start(const std::string &name, const std::string &pattern)
Definition: utilities.cc:835
T unpack(const std::vector< char > &buffer, const bool allow_compression=true)
Definition: utilities.h:1499
T fixed_power(const T t)
Definition: utilities.h:969
std::string decompress(const std::string &compressed_input)
Definition: utilities.cc:414
unsigned int needed_digits(const unsigned int max_number)
Definition: utilities.cc:568
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:656
std::string dealii_version_string()
Definition: utilities.cc:97
void set_bit(unsigned char &number, const unsigned int n, const bool x)
Definition: utilities.h:1571
std::string trim(const std::string &input)
Definition: utilities.cc:531
double generate_normal_random_number(const double a, const double sigma)
Definition: utilities.cc:892
std::vector< Integer > reverse_permutation(const std::vector< Integer > &permutation)
Definition: utilities.h:1649
std::vector< Integer > invert_permutation(const std::vector< Integer > &permutation)
Definition: utilities.h:1664
int string_to_int(const std::string &s)
Definition: utilities.cc:608
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:1386
static const unsigned int invalid_unsigned_int
Definition: types.h:206
unsigned long int VmRSS
Definition: utilities.h:911
unsigned long int VmPeak
Definition: utilities.h:895
unsigned long int VmSize
Definition: utilities.h:900
unsigned long int VmHWM
Definition: utilities.h:905