Loading [MathJax]/extensions/TeX/newcommand.js
 deal.II version GIT relicensing-3020-gf6ff73b199 2025-04-05 03:00:00+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\}}
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
utilities.h
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 2005 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#ifndef dealii_utilities_h
16#define dealii_utilities_h
17
18#include <deal.II/base/config.h>
19
21#include <deal.II/base/types.h>
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
427 template <class T>
428 std::string
429 type_to_string(const T &t);
430
456 template <int N, typename T>
457 constexpr T
458 fixed_power(const T t);
459
467 template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
468 constexpr DEAL_II_HOST_DEVICE T
469 pow(const T base, const int iexp);
470
492 template <typename Iterator, typename T>
493 Iterator
494 lower_bound(Iterator first, Iterator last, const T &val);
495
501 template <typename Iterator, typename T, typename Comp>
502 Iterator
503 lower_bound(Iterator first, Iterator last, const T &val, const Comp comp);
504
510 template <typename Integer>
511 std::vector<Integer>
512 reverse_permutation(const std::vector<Integer> &permutation);
513
519 template <typename Integer>
520 std::vector<Integer>
521 invert_permutation(const std::vector<Integer> &permutation);
522
577 template <typename T>
578 std::size_t
579 pack(const T &object,
580 std::vector<char> &dest_buffer,
581 const bool allow_compression = true);
582
591 template <typename T>
592 std::vector<char>
593 pack(const T &object, const bool allow_compression = true);
594
626 template <typename T>
627 T
628 unpack(const std::vector<char> &buffer, const bool allow_compression = true);
629
638 template <typename T>
639 T
640 unpack(const std::vector<char>::const_iterator &cbegin,
641 const std::vector<char>::const_iterator &cend,
642 const bool allow_compression = true);
643
676 template <typename T, int N>
677 void
678 unpack(const std::vector<char> &buffer,
679 T (&unpacked_object)[N],
680 const bool allow_compression = true);
681
690 template <typename T, int N>
691 void
692 unpack(const std::vector<char>::const_iterator &cbegin,
693 const std::vector<char>::const_iterator &cend,
694 T (&unpacked_object)[N],
695 const bool allow_compression = true);
696
700 bool
701 get_bit(const unsigned char number, const unsigned int n);
702
703
707 void
708 set_bit(unsigned char &number, const unsigned int n, const bool x);
709
710
768 template <typename To, typename From>
769 std::unique_ptr<To>
770 dynamic_unique_cast(std::unique_ptr<From> &&p);
771
775 template <typename T>
776 T &
778
782 template <typename T>
783 T &
784 get_underlying_value(std::shared_ptr<T> &p);
785
789 template <typename T>
790 T &
791 get_underlying_value(const std::shared_ptr<T> &p);
792
796 template <typename T>
797 T &
798 get_underlying_value(std::unique_ptr<T> &p);
799
803 template <typename T>
804 T &
805 get_underlying_value(const std::unique_ptr<T> &p);
806
812 namespace System
813 {
821 double
822 get_cpu_load();
823
857 std::string
859
865 {
869 unsigned long int VmPeak;
870
874 unsigned long int VmSize;
875
879 unsigned long int VmHWM;
880
885 unsigned long int VmRSS;
886 };
887
888
893 void
895
896
900 std::string
901 get_hostname();
902
903
907 std::string
908 get_time();
909
914 std::string
915 get_date();
916
931 void
932 posix_memalign(void **memptr, std::size_t alignment, std::size_t size);
933 } // namespace System
934} // namespace Utilities
935
936
937// --------------------- inline functions
938
939namespace Utilities
940{
941 template <int N, typename T>
942 inline constexpr T
943 fixed_power(const T x)
944 {
945 Assert(((std::is_integral_v<T> == true) && (N >= 0)) ||
946 (std::is_integral_v<T> == false),
947 ExcMessage("If the type of the argument, T, is an integer type, "
948 "then the exponent N must be a non-negative integer "
949 "because the result would otherwise not be an integer."));
950
951 if (N == 0)
952 return T(1.);
953 else if (N < 0)
954 // For negative exponents, turn things into a positive exponent
955 return T(1.) / fixed_power<-N>(x);
956 else
957 // If we get here, we have a positive exponent. Compute the result
958 // by repeated squaring:
959 return ((N % 2 == 1) ? x * fixed_power<N / 2>(x * x) :
960 fixed_power<N / 2>(x * x));
961 }
962
963
964
965 template <typename T, typename>
966 constexpr DEAL_II_HOST_DEVICE T
967 pow(const T base, const int iexp)
968 {
969#if defined(DEBUG) && !defined(DEAL_II_CXX14_CONSTEXPR_BUG)
970 // Up to __builtin_expect this is the same code as in the 'Assert' macro.
971 // The call to __builtin_expect turns out to be problematic.
972# if DEAL_II_KOKKOS_VERSION_GTE(3, 6, 0)
973 KOKKOS_IF_ON_HOST(({
974 if (!(iexp >= 0))
977 abort_or_throw_on_exception,
978 __FILE__,
979 __LINE__,
980 __PRETTY_FUNCTION__,
981 "iexp>=0",
982 "ExcMessage(\"The exponent must not be negative!\")",
983 ExcMessage("The exponent must not be negative!"));
984 }))
985# else
986# ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST
987 if (!(iexp >= 0))
990 abort_or_throw_on_exception,
991 __FILE__,
992 __LINE__,
993 __PRETTY_FUNCTION__,
994 "iexp>=0",
995 "ExcMessage(\"The exponent must not be negative!\")",
996 ExcMessage("The exponent must not be negative!"));
997# endif
998# endif
999#endif
1000 // The "exponentiation by squaring" algorithm used below has to be expressed
1001 // in an iterative version since SYCL doesn't allow recursive functions used
1002 // in device code.
1003
1004 if (iexp <= 0)
1005 return 1;
1006
1007 int exp = iexp;
1008 T x = base;
1009 T y = 1;
1010 while (exp > 1)
1011 {
1012 if (exp % 2 == 1)
1013 y *= x;
1014 x *= x;
1015 exp /= 2;
1016 }
1017 return x * y;
1018 }
1019
1020
1021
1022 template <class T>
1023 inline std::string
1024 type_to_string(const T &t)
1025 {
1026 return boost::core::demangle(typeid(t).name());
1027 }
1028
1029
1030
1031 template <typename Iterator, typename T>
1032 inline Iterator
1033 lower_bound(Iterator first, Iterator last, const T &val)
1034 {
1035 return Utilities::lower_bound(first, last, val, std::less<T>());
1036 }
1037
1038
1039
1040 template <typename Iterator, typename T, typename Comp>
1041 inline Iterator
1042 lower_bound(Iterator first, Iterator last, const T &val, const Comp comp)
1043 {
1044 // verify that the two iterators are properly ordered. since
1045 // we need operator- for the iterator type anyway, do the
1046 // test as follows, rather than via 'last >= first'
1047 Assert(last - first >= 0,
1048 ExcMessage(
1049 "The given iterators do not satisfy the proper ordering."));
1050
1051 unsigned int len = static_cast<unsigned int>(last - first);
1052
1053 if (len == 0)
1054 return first;
1055
1056 while (true)
1057 {
1058 // if length equals 8 or less,
1059 // then do a rolled out
1060 // search. use a switch without
1061 // breaks for that and roll-out
1062 // the loop somehow
1063 if (len < 8)
1064 {
1065 switch (len)
1066 {
1067 case 7:
1068 if (!comp(*first, val))
1069 return first;
1070 ++first;
1072 case 6:
1073 if (!comp(*first, val))
1074 return first;
1075 ++first;
1077 case 5:
1078 if (!comp(*first, val))
1079 return first;
1080 ++first;
1082 case 4:
1083 if (!comp(*first, val))
1084 return first;
1085 ++first;
1087 case 3:
1088 if (!comp(*first, val))
1089 return first;
1090 ++first;
1092 case 2:
1093 if (!comp(*first, val))
1094 return first;
1095 ++first;
1097 case 1:
1098 if (!comp(*first, val))
1099 return first;
1100 return first + 1;
1101 default:
1102 // indices seem
1103 // to not be
1104 // sorted
1105 // correctly!? or
1106 // did len
1107 // become==0
1108 // somehow? that
1109 // shouldn't have
1110 // happened
1112 }
1113 }
1114
1115
1116
1117 const unsigned int half = len >> 1;
1118 const Iterator middle = first + half;
1119
1120 // if the value is larger than
1121 // that pointed to by the
1122 // middle pointer, then the
1123 // insertion point must be
1124 // right of it
1125 if (comp(*middle, val))
1126 {
1127 first = middle + 1;
1128 len -= half + 1;
1129 }
1130 else
1131 len = half;
1132 }
1133 }
1134
1135
1136 // --------------------- non-inline functions
1137
1138 namespace internal
1139 {
1145 template <typename T>
1147 {
1148 static constexpr bool value = false;
1149 };
1150
1151
1152
1153 template <typename T>
1155 {
1156 static constexpr bool value =
1157 std::is_trivially_copyable_v<T> && !std::is_same_v<T, bool>;
1158 };
1159
1160
1161
1162 template <typename T>
1163 struct IsVectorOfTriviallyCopyable<std::vector<std::vector<T>>>
1164 {
1165 static constexpr bool value =
1166 std::is_trivially_copyable_v<T> && !std::is_same_v<T, bool>;
1167 };
1168
1169
1170
1179 template <typename T>
1180 inline void
1182 std::vector<char> &)
1183 {
1184 // We shouldn't get here:
1186 }
1187
1188
1189
1190 template <typename T,
1191 typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1192 std::is_trivially_copyable_v<T>>>
1193 inline void
1195 const std::vector<T> &object,
1196 std::vector<char> &dest_buffer)
1197 {
1198 const typename std::vector<T>::size_type vector_size = object.size();
1199
1200 // Reserve for the buffer so that it can store the size of 'object' as
1201 // well as all of its elements.
1202 dest_buffer.reserve(dest_buffer.size() + sizeof(vector_size) +
1203 vector_size * sizeof(T));
1204
1205 // Copy the size into the vector
1206 dest_buffer.insert(dest_buffer.end(),
1207 reinterpret_cast<const char *>(&vector_size),
1208 reinterpret_cast<const char *>(&vector_size + 1));
1209
1210 // Insert the elements at the end of the vector:
1211 if (vector_size > 0)
1212 dest_buffer.insert(dest_buffer.end(),
1213 reinterpret_cast<const char *>(object.data()),
1214 reinterpret_cast<const char *>(object.data() +
1215 vector_size));
1216 }
1217
1218
1219
1220 template <typename T,
1221 typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1222 std::is_trivially_copyable_v<T>>>
1223 inline void
1225 const std::vector<std::vector<T>> &object,
1226 std::vector<char> &dest_buffer)
1227 {
1228 using size_type = typename std::vector<T>::size_type;
1229 const size_type vector_size = object.size();
1230
1231 typename std::vector<T>::size_type aggregated_size = 0;
1232 std::vector<size_type> sizes;
1233 sizes.reserve(vector_size);
1234 for (const auto &a : object)
1235 {
1236 aggregated_size += a.size();
1237 sizes.push_back(a.size());
1238 }
1239
1240 // Reserve for the buffer so that it can store the size of 'object' as
1241 // well as all of its elements.
1242 dest_buffer.reserve(dest_buffer.size() +
1243 sizeof(vector_size) * (1 + vector_size) +
1244 aggregated_size * sizeof(T));
1245
1246 // Copy the size into the vector
1247 dest_buffer.insert(dest_buffer.end(),
1248 reinterpret_cast<const char *>(&vector_size),
1249 reinterpret_cast<const char *>(&vector_size + 1));
1250
1251 // Copy the sizes of the individual chunks into the vector
1252 if (vector_size > 0)
1253 dest_buffer.insert(dest_buffer.end(),
1254 reinterpret_cast<const char *>(sizes.data()),
1255 reinterpret_cast<const char *>(sizes.data() +
1256 vector_size));
1257
1258 // Insert the elements at the end of the vector:
1259 for (const auto &a : object)
1260 dest_buffer.insert(dest_buffer.end(),
1261 reinterpret_cast<const char *>(a.data()),
1262 reinterpret_cast<const char *>(a.data() + a.size()));
1263 }
1264
1265
1266
1267 template <typename T>
1268 inline void
1270 const std::vector<char>::const_iterator &,
1271 const std::vector<char>::const_iterator &,
1272 T &)
1273 {
1274 // We shouldn't get here:
1276 }
1277
1278
1279
1280 template <typename T,
1281 typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1282 std::is_trivially_copyable_v<T>>>
1283 inline void
1285 const std::vector<char>::const_iterator &cbegin,
1286 const std::vector<char>::const_iterator &cend,
1287 std::vector<T> &object)
1288 {
1289 // The size of the object vector can be found in cbegin of the buffer.
1290 // The data starts at cbegin + sizeof(vector_size).
1291
1292 // Get the size of the vector
1293 typename std::vector<T>::size_type vector_size;
1294 memcpy(&vector_size, &*cbegin, sizeof(vector_size));
1295
1296 Assert(static_cast<std::ptrdiff_t>(cend - cbegin) ==
1297 static_cast<std::ptrdiff_t>(sizeof(vector_size) +
1298 vector_size * sizeof(T)),
1299 ExcMessage("The given buffer has the wrong size."));
1300 (void)cend;
1301
1302 // Resize the output array and copy the elements into it. We need
1303 // to make sure that we don't access the buffer via a
1304 // reinterpret_cast<T*> because the T objects in the buffer may
1305 // not be aligned properly. Rather, use memcpy, which doesn't care
1306 // about alignment and is correct in this situation because we
1307 // are dealing with trivially copyable objects.
1308 //
1309 // (Strictly speaking, this writes into the output object twice, once
1310 // for the resize() operation and once during memcpy. This could be
1311 // avoided by (i) checking whether the point is aligned, using for
1312 // example boost::alignment::is_aligned(), and (ii) if the data
1313 // is aligned, re-create the output vector using
1314 // object.clear();
1315 // object.insert (object.end(),
1316 // (T*)(&*cbegin + sizeof(vector_size)),
1317 // (T*)(&*cbegin + sizeof(vector_size)) + vector_size);
1318 // In practice, the difference is likely rather small, assuming the
1319 // compiler does not already optimize away the first initialization.
1320 object.resize(vector_size);
1321 if (vector_size > 0)
1322 std::memcpy(object.data(),
1323 &*cbegin + sizeof(vector_size),
1324 vector_size * sizeof(T));
1325 }
1326
1327
1328
1329 template <typename T,
1330 typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1331 std::is_trivially_copyable_v<T>>>
1332 inline void
1334 const std::vector<char>::const_iterator &cbegin,
1335 const std::vector<char>::const_iterator &cend,
1336 std::vector<std::vector<T>> &object)
1337 {
1338 // First get the size of the vector, and resize the output object
1339 using size_type = typename std::vector<T>::size_type;
1340 std::vector<char>::const_iterator iterator = cbegin;
1341 size_type vector_size;
1342 memcpy(&vector_size, &*iterator, sizeof(vector_size));
1343 object.clear();
1344 object.resize(vector_size);
1345 std::vector<size_type> sizes(vector_size);
1346 if (vector_size > 0)
1347 std::memcpy(sizes.data(),
1348 &*iterator + sizeof(vector_size),
1349 vector_size * sizeof(size_type));
1350
1351 iterator += sizeof(vector_size) * (1 + vector_size);
1352 size_type aggregated_size = 0;
1353 for (const auto a : sizes)
1354 aggregated_size += a;
1355
1356 Assert(static_cast<std::ptrdiff_t>(cend - iterator) ==
1357 static_cast<std::ptrdiff_t>(aggregated_size * sizeof(T)),
1358 ExcMessage("The given buffer has the wrong size."));
1359 (void)cend;
1360
1361 // Then copy the elements. As for the previous function, use memcpy
1362 // rather than accessing the data via reinterpret_cast<T*> to
1363 // avoid alignment issues.
1364 for (unsigned int i = 0; i < vector_size; ++i)
1365 if (sizes[i] > 0)
1366 {
1367 object[i].resize(sizes[i]);
1368 std::memcpy(object[i].data(), &*iterator, sizes[i] * sizeof(T));
1369 iterator += sizes[i] * sizeof(T);
1370 }
1371
1372 Assert(iterator == cend,
1373 ExcMessage("The given buffer has the wrong size."));
1374 }
1375
1376 } // namespace internal
1377
1378
1379
1380 template <typename T>
1381 std::size_t
1382 pack(const T &object,
1383 std::vector<char> &dest_buffer,
1384 const bool allow_compression)
1385 {
1386 std::size_t size = 0;
1387
1388
1389 // see if the object is small and copyable via memcpy. if so, use
1390 // this fast path. otherwise, we have to go through the BOOST
1391 // serialization machinery
1392 if constexpr (std::is_trivially_copyable<T>() && sizeof(T) < 256)
1393 {
1394 // Determine the size. There are places where we would like to use a
1395 // truly empty type, for which we use std::tuple<> (i.e., a tuple
1396 // of zero elements). For this class, the compiler reports a nonzero
1397 // sizeof(...) because that is the minimum possible for objects --
1398 // objects need to have distinct addresses, so they need to have a size
1399 // of at least one. But we can special case this situation.
1400 size = (std::is_same_v<T, std::tuple<>> ? 0 : sizeof(T));
1401
1402 (void)allow_compression;
1403 const std::size_t previous_size = dest_buffer.size();
1404 dest_buffer.resize(previous_size + size);
1405
1406 if (size > 0)
1407 std::memcpy(dest_buffer.data() + previous_size, &object, size);
1408 }
1409 // Next try if we have a vector of trivially copyable objects.
1410 // If that is the case, we can shortcut the whole BOOST serialization
1411 // machinery and just copy the content of the vector bit for bit
1412 // into the output buffer, assuming that we are not asked to compress
1413 // the data.
1415 (allow_compression == false))
1416 {
1417 const std::size_t previous_size = dest_buffer.size();
1418
1419 // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1420 // inline the code of the following function here and make the 'if'
1421 // above a 'if constexpr'. Without the 'constexpr', we need to keep
1422 // the general template of the function that throws an exception.
1424 dest_buffer);
1425
1426 size = dest_buffer.size() - previous_size;
1427 }
1428 else
1429 {
1430 // use buffer as the target of a compressing
1431 // stream into which we serialize the current object
1432 const std::size_t previous_size = dest_buffer.size();
1433 {
1434 boost::iostreams::filtering_ostreambuf fosb;
1435#ifdef DEAL_II_WITH_ZLIB
1436 if (allow_compression)
1437 fosb.push(boost::iostreams::gzip_compressor());
1438#else
1439 (void)allow_compression;
1440#endif
1441 fosb.push(boost::iostreams::back_inserter(dest_buffer));
1442
1443 boost::archive::binary_oarchive boa(fosb);
1444 boa << object;
1445 // the stream object has to be destroyed before the return statement
1446 // to ensure that all data has been written in the buffer
1447 }
1448 size = dest_buffer.size() - previous_size;
1449 }
1450
1451 return size;
1452 }
1453
1454
1455 template <typename T>
1456 std::vector<char>
1457 pack(const T &object, const bool allow_compression)
1458 {
1459 std::vector<char> buffer;
1460 pack<T>(object, buffer, allow_compression);
1461 return buffer;
1462 }
1463
1464
1465
1466 template <typename T>
1467 T
1468 unpack(const std::vector<char>::const_iterator &cbegin,
1469 const std::vector<char>::const_iterator &cend,
1470 const bool allow_compression)
1471 {
1472 // see if the object is small and copyable via memcpy. if so, use
1473 // this fast path. otherwise, we have to go through the BOOST
1474 // serialization machinery
1475 if constexpr (std::is_trivially_copyable<T>() && sizeof(T) < 256)
1476 {
1477 // Determine the size. There are places where we would like to use a
1478 // truly empty type, for which we use std::tuple<> (i.e., a tuple
1479 // of zero elements). For this class, the compiler reports a nonzero
1480 // sizeof(...) because that is the minimum possible for objects --
1481 // objects need to have distinct addresses, so they need to have a size
1482 // of at least one. But we can special case this situation.
1483 const std::size_t size =
1484 (std::is_same_v<T, std::tuple<>> ? 0 : sizeof(T));
1485
1486 T object;
1487
1488 (void)allow_compression;
1489 Assert(std::distance(cbegin, cend) == size, ExcInternalError());
1490
1491 if (size > 0)
1492 std::memcpy(&object, &*cbegin, size);
1493
1494 return object;
1495 }
1496 // Next try if we have a vector of trivially copyable objects.
1497 // If that is the case, we can shortcut the whole BOOST serialization
1498 // machinery and just copy the content of the buffer bit for bit
1499 // into an appropriately sized output vector, assuming that we
1500 // are not asked to compress the data.
1502 (allow_compression == false))
1503 {
1504 // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1505 // inline the code of the following function here and make the 'if'
1506 // above a 'if constexpr'. Without the 'constexpr', we need to keep
1507 // the general template of the function that throws an exception.
1508 T object;
1510 cend,
1511 object);
1512 return object;
1513 }
1514 else
1515 {
1516 // decompress the buffer section into the object
1517 boost::iostreams::filtering_istreambuf fisb;
1518#ifdef DEAL_II_WITH_ZLIB
1519 if (allow_compression)
1520 fisb.push(boost::iostreams::gzip_decompressor());
1521#else
1522 (void)allow_compression;
1523#endif
1524 fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1525
1526 boost::archive::binary_iarchive bia(fisb);
1527
1528 T object;
1529 bia >> object;
1530 return object;
1531 }
1532
1533 return T();
1534 }
1535
1536
1537 template <typename T>
1538 T
1539 unpack(const std::vector<char> &buffer, const bool allow_compression)
1540 {
1541 return unpack<T>(buffer.cbegin(), buffer.cend(), allow_compression);
1542 }
1543
1544
1545 template <typename T, int N>
1546 void
1547 unpack(const std::vector<char>::const_iterator &cbegin,
1548 const std::vector<char>::const_iterator &cend,
1549 T (&unpacked_object)[N],
1550 const bool allow_compression)
1551 {
1552 // see if the object is small and copyable via memcpy. if so, use
1553 // this fast path. otherwise, we have to go through the BOOST
1554 // serialization machinery
1555 if constexpr (std::is_trivially_copyable<T>() && sizeof(T) * N < 256)
1556 {
1557 Assert(std::distance(cbegin, cend) == sizeof(T) * N,
1559 std::memcpy(unpacked_object, &*cbegin, sizeof(T) * N);
1560 }
1561 else
1562 {
1563 // decompress the buffer section into the object
1564 boost::iostreams::filtering_istreambuf fisb;
1565#ifdef DEAL_II_WITH_ZLIB
1566 if (allow_compression)
1567 fisb.push(boost::iostreams::gzip_decompressor());
1568#else
1569 (void)allow_compression;
1570#endif
1571 fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1572
1573 boost::archive::binary_iarchive bia(fisb);
1574 bia >> unpacked_object;
1575 }
1576 }
1577
1578
1579 template <typename T, int N>
1580 void
1581 unpack(const std::vector<char> &buffer,
1582 T (&unpacked_object)[N],
1583 const bool allow_compression)
1584 {
1585 unpack<T, N>(buffer.cbegin(),
1586 buffer.cend(),
1587 unpacked_object,
1588 allow_compression);
1589 }
1590
1591
1592
1593 inline bool
1594 get_bit(const unsigned char number, const unsigned int n)
1595 {
1596 AssertIndexRange(n, 8);
1597
1598 // source:
1599 // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1600 // "Checking a bit"
1601 return ((number >> n) & 1U) != 0u;
1602 }
1603
1604
1605
1606 inline void
1607 set_bit(unsigned char &number, const unsigned int n, const bool x)
1608 {
1609 AssertIndexRange(n, 8);
1610
1611 // source:
1612 // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1613 // "Changing the nth bit to x"
1614 number ^= (-static_cast<unsigned char>(x) ^ number) & (1U << n);
1615 }
1616
1617
1618
1619 template <typename To, typename From>
1620 inline std::unique_ptr<To>
1621 dynamic_unique_cast(std::unique_ptr<From> &&p)
1622 {
1623 // Let's see if we can cast from 'From' to 'To'. If so, do the cast,
1624 // and then release the pointer from the old
1625 // owner
1626 if (To *cast = dynamic_cast<To *>(p.get()))
1627 {
1628 std::unique_ptr<To> result(cast);
1629 p.release();
1630 return result;
1631 }
1632 else
1633 throw std::bad_cast();
1634 }
1635
1636
1637
1638 template <typename T>
1639 inline T &
1641 {
1642 return p;
1643 }
1644
1645
1646
1647 template <typename T>
1648 inline T &
1649 get_underlying_value(std::shared_ptr<T> &p)
1650 {
1651 return *p;
1652 }
1653
1654
1655
1656 template <typename T>
1657 inline T &
1658 get_underlying_value(const std::shared_ptr<T> &p)
1659 {
1660 return *p;
1661 }
1662
1663
1664
1665 template <typename T>
1666 inline T &
1667 get_underlying_value(std::unique_ptr<T> &p)
1668 {
1669 return *p;
1670 }
1671
1672
1673
1674 template <typename T>
1675 inline T &
1676 get_underlying_value(const std::unique_ptr<T> &p)
1677 {
1678 return *p;
1679 }
1680
1681
1682
1683 template <typename Integer>
1684 std::vector<Integer>
1685 reverse_permutation(const std::vector<Integer> &permutation)
1686 {
1687 const std::size_t n = permutation.size();
1688
1689 std::vector<Integer> out(n);
1690 for (std::size_t i = 0; i < n; ++i)
1691 out[i] = n - 1 - permutation[i];
1692
1693 return out;
1694 }
1695
1696
1697
1698 template <typename Integer>
1699 std::vector<Integer>
1700 invert_permutation(const std::vector<Integer> &permutation)
1701 {
1702 const std::size_t n = permutation.size();
1703
1704 std::vector<Integer> out(n, numbers::invalid_unsigned_int);
1705
1706 for (std::size_t i = 0; i < n; ++i)
1707 {
1708 AssertIndexRange(permutation[i], n);
1709 out[permutation[i]] = i;
1710 }
1711
1712 // check that we have actually reached
1713 // all indices
1714 for (std::size_t i = 0; i < n; ++i)
1716 ExcMessage("The given input permutation had duplicate entries!"));
1717
1718 return out;
1719 }
1720} // namespace Utilities
1721
1722
1724
1725#ifndef DOXYGEN
1726namespace boost
1727{
1728 namespace serialization
1729 {
1730 // Provides boost and c++11 with a way to serialize tuples and pairs
1731 // automatically.
1732 template <int N>
1733 struct Serialize
1734 {
1735 template <class Archive, typename... Args>
1736 static void
1737 serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1738 {
1739 ar &std::get<N - 1>(t);
1740 Serialize<N - 1>::serialize(ar, t, version);
1741 }
1742 };
1743
1744 template <>
1745 struct Serialize<0>
1746 {
1747 template <class Archive, typename... Args>
1748 static void
1749 serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1750 {
1751 (void)ar;
1752 (void)t;
1753 (void)version;
1754 }
1755 };
1756
1757 template <class Archive, typename... Args>
1758 void
1759 serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1760 {
1761 Serialize<sizeof...(Args)>::serialize(ar, t, version);
1762 }
1763 } // namespace serialization
1764} // namespace boost
1765#endif
1766
1767#endif
Definition point.h:113
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:35
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:242
#define DEAL_II_HOST_DEVICE
Definition config.h:166
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:36
#define DEAL_II_FALLTHROUGH
Definition config.h:267
#define DEAL_II_ASSERT_UNREACHABLE()
Point< 2 > first
Definition grid_out.cc:4632
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
std::vector< index_type > data
Definition mpi.cc:746
std::size_t size
Definition mpi.cc:745
constexpr char N
constexpr char T
void get_memory_stats(MemoryStats &stats)
Definition utilities.cc:962
std::string get_hostname()
Definition utilities.cc:996
std::string get_time()
void posix_memalign(void **memptr, std::size_t alignment, std::size_t size)
double get_cpu_load()
Definition utilities.cc:928
std::string get_current_vectorization_level()
Definition utilities.cc:936
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:1269
void append_vector_of_trivially_copyable_to_buffer(const T &, std::vector< char > &)
Definition utilities.h:1181
std::size_t pack(const T &object, std::vector< char > &dest_buffer, const bool allow_compression=true)
Definition utilities.h:1382
std::vector< std::string > split_string_list(const std::string &s, const std::string &delimiter=",")
Definition utilities.cc:699
T & get_underlying_value(T &p)
Definition utilities.h:1640
Number truncate_to_n_digits(const Number number, const unsigned int n_digits)
Definition utilities.cc:574
std::string type_to_string(const T &t)
Definition utilities.h:1024
std::string dim_string(const int dim, const int spacedim)
Definition utilities.cc:551
std::uint64_t pack_integers(const std::array< std::uint64_t, dim > &index, const int bits_per_dim)
Definition utilities.cc:360
bool get_bit(const unsigned char number, const unsigned int n)
Definition utilities.h:1594
std::pair< int, unsigned int > get_integer_at_position(const std::string &name, const unsigned int position)
Definition utilities.cc:845
std::string encode_base64(const std::vector< unsigned char > &binary_input)
Definition utilities.cc:427
std::unique_ptr< To > dynamic_unique_cast(std::unique_ptr< From > &&p)
Definition utilities.h:1621
constexpr T fixed_power(const T t)
Definition utilities.h:943
std::string replace_in_string(const std::string &input, const std::string &from, const std::string &to)
Definition utilities.cc:505
std::vector< unsigned char > decode_base64(const std::string &base64_input)
Definition utilities.cc:440
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
Definition utilities.cc:753
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:475
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:140
std::string compress(const std::string &input)
Definition utilities.cc:383
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:466
bool match_at_string_start(const std::string &name, const std::string &pattern)
Definition utilities.cc:830
T unpack(const std::vector< char > &buffer, const bool allow_compression=true)
Definition utilities.h:1539
std::string decompress(const std::string &compressed_input)
Definition utilities.cc:405
unsigned int needed_digits(const unsigned int max_number)
Definition utilities.cc:561
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition utilities.h:1033
double string_to_double(const std::string &s)
Definition utilities.cc:650
std::string dealii_version_string()
Definition utilities.cc:89
void set_bit(unsigned char &number, const unsigned int n, const bool x)
Definition utilities.h:1607
constexpr T pow(const T base, const int iexp)
Definition utilities.h:967
std::string trim(const std::string &input)
Definition utilities.cc:524
double generate_normal_random_number(const double a, const double sigma)
Definition utilities.cc:887
std::vector< Integer > reverse_permutation(const std::vector< Integer > &permutation)
Definition utilities.h:1685
std::vector< Integer > invert_permutation(const std::vector< Integer > &permutation)
Definition utilities.h:1700
int string_to_int(const std::string &s)
Definition utilities.cc:601
void issue_error_noreturn(ExceptionHandling handling, const char *file, int line, const char *function, const char *cond, const char *exc_name, ExceptionType e)
constexpr unsigned int invalid_unsigned_int
Definition types.h:232
STL namespace.