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