Reference documentation for deal.II version 9.6.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// 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
22#include <boost/archive/binary_iarchive.hpp>
23#include <boost/archive/binary_oarchive.hpp>
24#include <boost/core/demangle.hpp>
25#include <boost/iostreams/device/array.hpp>
26#include <boost/iostreams/device/back_inserter.hpp>
27#include <boost/iostreams/filtering_streambuf.hpp>
28#include <boost/serialization/array.hpp>
29#include <boost/serialization/complex.hpp>
30#include <boost/serialization/vector.hpp>
31
32#include <cstddef>
33#include <functional>
34#include <string>
35#include <tuple>
36#include <type_traits>
37#include <typeinfo>
38#include <utility>
39#include <vector>
40
41#ifdef DEAL_II_WITH_ZLIB
42# include <boost/iostreams/filter/gzip.hpp>
43#endif
44
46
47// forward declare Point
48#ifndef DOXYGEN
49template <int dim, typename Number>
51class Point;
52#endif
53
61namespace Utilities
62{
69 std::string
71
88 template <int dim, typename Number>
89 std::vector<std::array<std::uint64_t, dim>>
91 const std::vector<Point<dim, Number>> &points,
92 const int bits_per_dim = 64);
93
97 template <int dim>
98 std::vector<std::array<std::uint64_t, dim>>
100 const std::vector<std::array<std::uint64_t, dim>> &points,
101 const int bits_per_dim = 64);
102
118 template <int dim>
119 std::uint64_t
120 pack_integers(const std::array<std::uint64_t, dim> &index,
121 const int bits_per_dim);
122
135 std::string
136 compress(const std::string &input);
137
151 std::string
152 decompress(const std::string &compressed_input);
153
167 std::string
168 encode_base64(const std::vector<unsigned char> &binary_input);
169
178 std::vector<unsigned char>
179 decode_base64(const std::string &base64_input);
180
202 std::string
203 int_to_string(const unsigned int value,
204 const unsigned int digits = numbers::invalid_unsigned_int);
205
217 template <typename number>
218 std::string
219 to_string(const number value,
220 const unsigned int digits = numbers::invalid_unsigned_int);
221
226 unsigned int
227 needed_digits(const unsigned int max_number);
228
237 template <typename Number>
238 Number
239 truncate_to_n_digits(const Number number, const unsigned int n_digits);
240
245 int
246 string_to_int(const std::string &s);
247
259 std::string
260 dim_string(const int dim, const int spacedim);
261
266 std::vector<int>
267 string_to_int(const std::vector<std::string> &s);
268
273 double
274 string_to_double(const std::string &s);
275
276
281 std::vector<double>
282 string_to_double(const std::vector<std::string> &s);
283
284
327 std::vector<std::string>
328 split_string_list(const std::string &s, const std::string &delimiter = ",");
329
330
335 std::vector<std::string>
336 split_string_list(const std::string &s, const char delimiter);
337
338
348 std::vector<std::string>
349 break_text_into_lines(const std::string &original_text,
350 const unsigned int width,
351 const char delimiter = ' ');
352
357 bool
358 match_at_string_start(const std::string &name, const std::string &pattern);
359
368 std::pair<int, unsigned int>
369 get_integer_at_position(const std::string &name, const unsigned int position);
370
375 std::string
376 replace_in_string(const std::string &input,
377 const std::string &from,
378 const std::string &to);
379
385 std::string
386 trim(const std::string &input);
387
413 double
414 generate_normal_random_number(const double a, const double sigma);
415
426 template <class T>
427 std::string
428 type_to_string(const T &t);
429
455 template <int N, typename T>
456 constexpr T
457 fixed_power(const T t);
458
466 template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
467 constexpr DEAL_II_HOST_DEVICE T
468 pow(const T base, const int iexp);
469
491 template <typename Iterator, typename T>
492 Iterator
493 lower_bound(Iterator first, Iterator last, const T &val);
494
500 template <typename Iterator, typename T, typename Comp>
501 Iterator
502 lower_bound(Iterator first, Iterator last, const T &val, const Comp comp);
503
509 template <typename Integer>
510 std::vector<Integer>
511 reverse_permutation(const std::vector<Integer> &permutation);
512
518 template <typename Integer>
519 std::vector<Integer>
520 invert_permutation(const std::vector<Integer> &permutation);
521
576 template <typename T>
577 size_t
578 pack(const T &object,
579 std::vector<char> &dest_buffer,
580 const bool allow_compression = true);
581
590 template <typename T>
591 std::vector<char>
592 pack(const T &object, const bool allow_compression = true);
593
625 template <typename T>
626 T
627 unpack(const std::vector<char> &buffer, const bool allow_compression = true);
628
637 template <typename T>
638 T
639 unpack(const std::vector<char>::const_iterator &cbegin,
640 const std::vector<char>::const_iterator &cend,
641 const bool allow_compression = true);
642
675 template <typename T, int N>
676 void
677 unpack(const std::vector<char> &buffer,
678 T (&unpacked_object)[N],
679 const bool allow_compression = true);
680
689 template <typename T, int N>
690 void
691 unpack(const std::vector<char>::const_iterator &cbegin,
692 const std::vector<char>::const_iterator &cend,
693 T (&unpacked_object)[N],
694 const bool allow_compression = true);
695
699 bool
700 get_bit(const unsigned char number, const unsigned int n);
701
702
706 void
707 set_bit(unsigned char &number, const unsigned int n, const bool x);
708
709
767 template <typename To, typename From>
768 std::unique_ptr<To>
769 dynamic_unique_cast(std::unique_ptr<From> &&p);
770
774 template <typename T>
775 T &
777
781 template <typename T>
782 T &
783 get_underlying_value(std::shared_ptr<T> &p);
784
788 template <typename T>
789 T &
790 get_underlying_value(const std::shared_ptr<T> &p);
791
795 template <typename T>
796 T &
797 get_underlying_value(std::unique_ptr<T> &p);
798
802 template <typename T>
803 T &
804 get_underlying_value(const std::unique_ptr<T> &p);
805
811 namespace System
812 {
820 double
821 get_cpu_load();
822
856 std::string
858
864 {
868 unsigned long int VmPeak;
869
873 unsigned long int VmSize;
874
878 unsigned long int VmHWM;
879
884 unsigned long int VmRSS;
885 };
886
887
892 void
894
895
899 std::string
900 get_hostname();
901
902
906 std::string
907 get_time();
908
913 std::string
914 get_date();
915
930 void
931 posix_memalign(void **memptr, std::size_t alignment, std::size_t size);
932 } // namespace System
933} // namespace Utilities
934
935
936// --------------------- inline functions
937
938namespace Utilities
939{
940 template <int N, typename T>
941 inline constexpr T
942 fixed_power(const T x)
943 {
944 Assert(((std::is_integral_v<T> == true) && (N >= 0)) ||
945 (std::is_integral_v<T> == false),
946 ExcMessage("If the type of the argument, T, is an integer type, "
947 "then the exponent N must be a non-negative integer "
948 "because the result would otherwise not be an integer."));
949
950 if (N == 0)
951 return T(1.);
952 else if (N < 0)
953 // For negative exponents, turn things into a positive exponent
954 return T(1.) / fixed_power<-N>(x);
955 else
956 // If we get here, we have a positive exponent. Compute the result
957 // by repeated squaring:
958 return ((N % 2 == 1) ? x * fixed_power<N / 2>(x * x) :
959 fixed_power<N / 2>(x * x));
960 }
961
962
963
964 template <typename T, typename>
965 constexpr DEAL_II_HOST_DEVICE T
966 pow(const T base, const int iexp)
967 {
968#if defined(DEBUG) && !defined(DEAL_II_CXX14_CONSTEXPR_BUG)
969 // Up to __builtin_expect this is the same code as in the 'Assert' macro.
970 // The call to __builtin_expect turns out to be problematic.
971# if KOKKOS_VERSION >= 30600
972 KOKKOS_IF_ON_HOST(({
973 if (!(iexp >= 0))
976 abort_or_throw_on_exception,
977 __FILE__,
978 __LINE__,
979 __PRETTY_FUNCTION__,
980 "iexp>=0",
981 "ExcMessage(\"The exponent must not be negative!\")",
982 ExcMessage("The exponent must not be negative!"));
983 }))
984# else
985# ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST
986 if (!(iexp >= 0))
989 abort_or_throw_on_exception,
990 __FILE__,
991 __LINE__,
992 __PRETTY_FUNCTION__,
993 "iexp>=0",
994 "ExcMessage(\"The exponent must not be negative!\")",
995 ExcMessage("The exponent must not be negative!"));
996# endif
997# endif
998#endif
999 // The "exponentiation by squaring" algorithm used below has to be expressed
1000 // in an iterative version since SYCL doesn't allow recursive functions used
1001 // in device code.
1002
1003 if (iexp <= 0)
1004 return 1;
1005
1006 int exp = iexp;
1007 T x = base;
1008 T y = 1;
1009 while (exp > 1)
1010 {
1011 if (exp % 2 == 1)
1012 y *= x;
1013 x *= x;
1014 exp /= 2;
1015 }
1016 return x * y;
1017 }
1018
1019
1020
1021 template <class T>
1022 inline std::string
1023 type_to_string(const T &t)
1024 {
1025 return boost::core::demangle(typeid(t).name());
1026 }
1027
1028
1029
1030 template <typename Iterator, typename T>
1031 inline Iterator
1032 lower_bound(Iterator first, Iterator last, const T &val)
1033 {
1034 return Utilities::lower_bound(first, last, val, std::less<T>());
1035 }
1036
1037
1038
1039 template <typename Iterator, typename T, typename Comp>
1040 inline Iterator
1041 lower_bound(Iterator first, Iterator last, const T &val, const Comp comp)
1042 {
1043 // verify that the two iterators are properly ordered. since
1044 // we need operator- for the iterator type anyway, do the
1045 // test as follows, rather than via 'last >= first'
1046 Assert(last - first >= 0,
1047 ExcMessage(
1048 "The given iterators do not satisfy the proper ordering."));
1049
1050 unsigned int len = static_cast<unsigned int>(last - first);
1051
1052 if (len == 0)
1053 return first;
1054
1055 while (true)
1056 {
1057 // if length equals 8 or less,
1058 // then do a rolled out
1059 // search. use a switch without
1060 // breaks for that and roll-out
1061 // the loop somehow
1062 if (len < 8)
1063 {
1064 switch (len)
1065 {
1066 case 7:
1067 if (!comp(*first, val))
1068 return first;
1069 ++first;
1071 case 6:
1072 if (!comp(*first, val))
1073 return first;
1074 ++first;
1076 case 5:
1077 if (!comp(*first, val))
1078 return first;
1079 ++first;
1081 case 4:
1082 if (!comp(*first, val))
1083 return first;
1084 ++first;
1086 case 3:
1087 if (!comp(*first, val))
1088 return first;
1089 ++first;
1091 case 2:
1092 if (!comp(*first, val))
1093 return first;
1094 ++first;
1096 case 1:
1097 if (!comp(*first, val))
1098 return first;
1099 return first + 1;
1100 default:
1101 // indices seem
1102 // to not be
1103 // sorted
1104 // correctly!? or
1105 // did len
1106 // become==0
1107 // somehow? that
1108 // shouldn't have
1109 // happened
1111 }
1112 }
1113
1114
1115
1116 const unsigned int half = len >> 1;
1117 const Iterator middle = first + half;
1118
1119 // if the value is larger than
1120 // that pointed to by the
1121 // middle pointer, then the
1122 // insertion point must be
1123 // right of it
1124 if (comp(*middle, val))
1125 {
1126 first = middle + 1;
1127 len -= half + 1;
1128 }
1129 else
1130 len = half;
1131 }
1132 }
1133
1134
1135 // --------------------- non-inline functions
1136
1137 namespace internal
1138 {
1144 template <typename T>
1146 {
1147 static constexpr bool value = false;
1148 };
1149
1150
1151
1152 template <typename T>
1154 {
1155 static constexpr bool value =
1156 std::is_trivially_copyable_v<T> && !std::is_same_v<T, bool>;
1157 };
1158
1159
1160
1161 template <typename T>
1162 struct IsVectorOfTriviallyCopyable<std::vector<std::vector<T>>>
1163 {
1164 static constexpr bool value =
1165 std::is_trivially_copyable_v<T> && !std::is_same_v<T, bool>;
1166 };
1167
1168
1169
1178 template <typename T>
1179 inline void
1181 std::vector<char> &)
1182 {
1183 // We shouldn't get here:
1185 }
1186
1187
1188
1189 template <typename T,
1190 typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1191 std::is_trivially_copyable_v<T>>>
1192 inline void
1194 const std::vector<T> &object,
1195 std::vector<char> &dest_buffer)
1196 {
1197 const typename std::vector<T>::size_type vector_size = object.size();
1198
1199 // Reserve for the buffer so that it can store the size of 'object' as
1200 // well as all of its elements.
1201 dest_buffer.reserve(dest_buffer.size() + sizeof(vector_size) +
1202 vector_size * sizeof(T));
1203
1204 // Copy the size into the vector
1205 dest_buffer.insert(dest_buffer.end(),
1206 reinterpret_cast<const char *>(&vector_size),
1207 reinterpret_cast<const char *>(&vector_size + 1));
1208
1209 // Insert the elements at the end of the vector:
1210 if (vector_size > 0)
1211 dest_buffer.insert(dest_buffer.end(),
1212 reinterpret_cast<const char *>(object.data()),
1213 reinterpret_cast<const char *>(object.data() +
1214 vector_size));
1215 }
1216
1217
1218
1219 template <typename T,
1220 typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1221 std::is_trivially_copyable_v<T>>>
1222 inline void
1224 const std::vector<std::vector<T>> &object,
1225 std::vector<char> &dest_buffer)
1226 {
1227 using size_type = typename std::vector<T>::size_type;
1228 const size_type vector_size = object.size();
1229
1230 typename std::vector<T>::size_type aggregated_size = 0;
1231 std::vector<size_type> sizes;
1232 sizes.reserve(vector_size);
1233 for (const auto &a : object)
1234 {
1235 aggregated_size += a.size();
1236 sizes.push_back(a.size());
1237 }
1238
1239 // Reserve for the buffer so that it can store the size of 'object' as
1240 // well as all of its elements.
1241 dest_buffer.reserve(dest_buffer.size() +
1242 sizeof(vector_size) * (1 + vector_size) +
1243 aggregated_size * sizeof(T));
1244
1245 // Copy the size into the vector
1246 dest_buffer.insert(dest_buffer.end(),
1247 reinterpret_cast<const char *>(&vector_size),
1248 reinterpret_cast<const char *>(&vector_size + 1));
1249
1250 // Copy the sizes of the individual chunks into the vector
1251 if (vector_size > 0)
1252 dest_buffer.insert(dest_buffer.end(),
1253 reinterpret_cast<const char *>(sizes.data()),
1254 reinterpret_cast<const char *>(sizes.data() +
1255 vector_size));
1256
1257 // Insert the elements at the end of the vector:
1258 for (const auto &a : object)
1259 dest_buffer.insert(dest_buffer.end(),
1260 reinterpret_cast<const char *>(a.data()),
1261 reinterpret_cast<const char *>(a.data() + a.size()));
1262 }
1263
1264
1265
1266 template <typename T>
1267 inline void
1269 const std::vector<char>::const_iterator &,
1270 const std::vector<char>::const_iterator &,
1271 T &)
1272 {
1273 // We shouldn't get here:
1275 }
1276
1277
1278
1279 template <typename T,
1280 typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1281 std::is_trivially_copyable_v<T>>>
1282 inline void
1284 const std::vector<char>::const_iterator &cbegin,
1285 const std::vector<char>::const_iterator &cend,
1286 std::vector<T> &object)
1287 {
1288 // The size of the object vector can be found in cbegin of the buffer.
1289 // The data starts at cbegin + sizeof(vector_size).
1290
1291 // Get the size of the vector
1292 typename std::vector<T>::size_type vector_size;
1293 memcpy(&vector_size, &*cbegin, sizeof(vector_size));
1294
1295 Assert(static_cast<std::ptrdiff_t>(cend - cbegin) ==
1296 static_cast<std::ptrdiff_t>(sizeof(vector_size) +
1297 vector_size * sizeof(T)),
1298 ExcMessage("The given buffer has the wrong size."));
1299 (void)cend;
1300
1301 // Resize the output array and copy the elements into it. We need
1302 // to make sure that we don't access the buffer via a
1303 // reinterpret_cast<T*> because the T objects in the buffer may
1304 // not be aligned properly. Rather, use memcpy, which doesn't care
1305 // about alignment and is correct in this situation because we
1306 // are dealing with trivially copyable objects.
1307 //
1308 // (Strictly speaking, this writes into the output object twice, once
1309 // for the resize() operation and once during memcpy. This could be
1310 // avoided by (i) checking whether the point is aligned, using for
1311 // example boost::alignment::is_aligned(), and (ii) if the data
1312 // is aligned, re-create the output vector using
1313 // object.clear();
1314 // object.insert (object.end(),
1315 // (T*)(&*cbegin + sizeof(vector_size)),
1316 // (T*)(&*cbegin + sizeof(vector_size)) + vector_size);
1317 // In practice, the difference is likely rather small, assuming the
1318 // compiler does not already optimize away the first initialization.
1319 object.resize(vector_size);
1320 if (vector_size > 0)
1321 std::memcpy(object.data(),
1322 &*cbegin + sizeof(vector_size),
1323 vector_size * sizeof(T));
1324 }
1325
1326
1327
1328 template <typename T,
1329 typename = std::enable_if_t<!std::is_same_v<T, bool> &&
1330 std::is_trivially_copyable_v<T>>>
1331 inline void
1333 const std::vector<char>::const_iterator &cbegin,
1334 const std::vector<char>::const_iterator &cend,
1335 std::vector<std::vector<T>> &object)
1336 {
1337 // First get the size of the vector, and resize the output object
1338 using size_type = typename std::vector<T>::size_type;
1339 std::vector<char>::const_iterator iterator = cbegin;
1340 size_type vector_size;
1341 memcpy(&vector_size, &*iterator, sizeof(vector_size));
1342 object.clear();
1343 object.resize(vector_size);
1344 std::vector<size_type> sizes(vector_size);
1345 if (vector_size > 0)
1346 std::memcpy(sizes.data(),
1347 &*iterator + sizeof(vector_size),
1348 vector_size * sizeof(size_type));
1349
1350 iterator += sizeof(vector_size) * (1 + vector_size);
1351 size_type aggregated_size = 0;
1352 for (const auto a : sizes)
1353 aggregated_size += a;
1354
1355 Assert(static_cast<std::ptrdiff_t>(cend - iterator) ==
1356 static_cast<std::ptrdiff_t>(aggregated_size * sizeof(T)),
1357 ExcMessage("The given buffer has the wrong size."));
1358 (void)cend;
1359
1360 // Then copy the elements. As for the previous function, use memcpy
1361 // rather than accessing the data via reinterpret_cast<T*> to
1362 // avoid alignment issues.
1363 for (unsigned int i = 0; i < vector_size; ++i)
1364 if (sizes[i] > 0)
1365 {
1366 object[i].resize(sizes[i]);
1367 std::memcpy(object[i].data(), &*iterator, sizes[i] * sizeof(T));
1368 iterator += sizes[i] * sizeof(T);
1369 }
1370
1371 Assert(iterator == cend,
1372 ExcMessage("The given buffer has the wrong size."));
1373 }
1374
1375 } // namespace internal
1376
1377
1378
1379 template <typename T>
1380 size_t
1381 pack(const T &object,
1382 std::vector<char> &dest_buffer,
1383 const bool allow_compression)
1384 {
1385 std::size_t size = 0;
1386
1387
1388 // see if the object is small and copyable via memcpy. if so, use
1389 // this fast path. otherwise, we have to go through the BOOST
1390 // serialization machinery
1391 if constexpr (std::is_trivially_copyable<T>() && sizeof(T) < 256)
1392 {
1393 // Determine the size. There are places where we would like to use a
1394 // truly empty type, for which we use std::tuple<> (i.e., a tuple
1395 // of zero elements). For this class, the compiler reports a nonzero
1396 // sizeof(...) because that is the minimum possible for objects --
1397 // objects need to have distinct addresses, so they need to have a size
1398 // of at least one. But we can special case this situation.
1399 size = (std::is_same_v<T, std::tuple<>> ? 0 : sizeof(T));
1400
1401 (void)allow_compression;
1402 const std::size_t previous_size = dest_buffer.size();
1403 dest_buffer.resize(previous_size + size);
1404
1405 if (size > 0)
1406 std::memcpy(dest_buffer.data() + previous_size, &object, size);
1407 }
1408 // Next try if we have a vector of trivially copyable objects.
1409 // If that is the case, we can shortcut the whole BOOST serialization
1410 // machinery and just copy the content of the vector bit for bit
1411 // into the output buffer, assuming that we are not asked to compress
1412 // the data.
1414 (allow_compression == false))
1415 {
1416 const std::size_t previous_size = dest_buffer.size();
1417
1418 // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1419 // inline the code of the following function here and make the 'if'
1420 // above a 'if constexpr'. Without the 'constexpr', we need to keep
1421 // the general template of the function that throws an exception.
1423 dest_buffer);
1424
1425 size = dest_buffer.size() - previous_size;
1426 }
1427 else
1428 {
1429 // use buffer as the target of a compressing
1430 // stream into which we serialize the current object
1431 const std::size_t previous_size = dest_buffer.size();
1432 {
1433 boost::iostreams::filtering_ostreambuf fosb;
1434#ifdef DEAL_II_WITH_ZLIB
1435 if (allow_compression)
1436 fosb.push(boost::iostreams::gzip_compressor());
1437#else
1438 (void)allow_compression;
1439#endif
1440 fosb.push(boost::iostreams::back_inserter(dest_buffer));
1441
1442 boost::archive::binary_oarchive boa(fosb);
1443 boa << object;
1444 // the stream object has to be destroyed before the return statement
1445 // to ensure that all data has been written in the buffer
1446 }
1447 size = dest_buffer.size() - previous_size;
1448 }
1449
1450 return size;
1451 }
1452
1453
1454 template <typename T>
1455 std::vector<char>
1456 pack(const T &object, const bool allow_compression)
1457 {
1458 std::vector<char> buffer;
1459 pack<T>(object, buffer, allow_compression);
1460 return buffer;
1461 }
1462
1463
1464
1465 template <typename T>
1466 T
1467 unpack(const std::vector<char>::const_iterator &cbegin,
1468 const std::vector<char>::const_iterator &cend,
1469 const bool allow_compression)
1470 {
1471 // see if the object is small and copyable via memcpy. if so, use
1472 // this fast path. otherwise, we have to go through the BOOST
1473 // serialization machinery
1474 if constexpr (std::is_trivially_copyable<T>() && sizeof(T) < 256)
1475 {
1476 // Determine the size. There are places where we would like to use a
1477 // truly empty type, for which we use std::tuple<> (i.e., a tuple
1478 // of zero elements). For this class, the compiler reports a nonzero
1479 // sizeof(...) because that is the minimum possible for objects --
1480 // objects need to have distinct addresses, so they need to have a size
1481 // of at least one. But we can special case this situation.
1482 const std::size_t size =
1483 (std::is_same_v<T, std::tuple<>> ? 0 : sizeof(T));
1484
1485 T object;
1486
1487 (void)allow_compression;
1488 Assert(std::distance(cbegin, cend) == size, ExcInternalError());
1489
1490 if (size > 0)
1491 std::memcpy(&object, &*cbegin, size);
1492
1493 return object;
1494 }
1495 // Next try if we have a vector of trivially copyable objects.
1496 // If that is the case, we can shortcut the whole BOOST serialization
1497 // machinery and just copy the content of the buffer bit for bit
1498 // into an appropriately sized output vector, assuming that we
1499 // are not asked to compress the data.
1501 (allow_compression == false))
1502 {
1503 // When we have DEAL_II_HAVE_CXX17 set by default, we can just
1504 // inline the code of the following function here and make the 'if'
1505 // above a 'if constexpr'. Without the 'constexpr', we need to keep
1506 // the general template of the function that throws an exception.
1507 T object;
1509 cend,
1510 object);
1511 return object;
1512 }
1513 else
1514 {
1515 // decompress the buffer section into the object
1516 boost::iostreams::filtering_istreambuf fisb;
1517#ifdef DEAL_II_WITH_ZLIB
1518 if (allow_compression)
1519 fisb.push(boost::iostreams::gzip_decompressor());
1520#else
1521 (void)allow_compression;
1522#endif
1523 fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1524
1525 boost::archive::binary_iarchive bia(fisb);
1526
1527 T object;
1528 bia >> object;
1529 return object;
1530 }
1531
1532 return T();
1533 }
1534
1535
1536 template <typename T>
1537 T
1538 unpack(const std::vector<char> &buffer, const bool allow_compression)
1539 {
1540 return unpack<T>(buffer.cbegin(), buffer.cend(), allow_compression);
1541 }
1542
1543
1544 template <typename T, int N>
1545 void
1546 unpack(const std::vector<char>::const_iterator &cbegin,
1547 const std::vector<char>::const_iterator &cend,
1548 T (&unpacked_object)[N],
1549 const bool allow_compression)
1550 {
1551 // see if the object is small and copyable via memcpy. if so, use
1552 // this fast path. otherwise, we have to go through the BOOST
1553 // serialization machinery
1554 if constexpr (std::is_trivially_copyable<T>() && sizeof(T) * N < 256)
1555 {
1556 Assert(std::distance(cbegin, cend) == sizeof(T) * N,
1558 std::memcpy(unpacked_object, &*cbegin, sizeof(T) * N);
1559 }
1560 else
1561 {
1562 // decompress the buffer section into the object
1563 boost::iostreams::filtering_istreambuf fisb;
1564#ifdef DEAL_II_WITH_ZLIB
1565 if (allow_compression)
1566 fisb.push(boost::iostreams::gzip_decompressor());
1567#else
1568 (void)allow_compression;
1569#endif
1570 fisb.push(boost::iostreams::array_source(&*cbegin, cend - cbegin));
1571
1572 boost::archive::binary_iarchive bia(fisb);
1573 bia >> unpacked_object;
1574 }
1575 }
1576
1577
1578 template <typename T, int N>
1579 void
1580 unpack(const std::vector<char> &buffer,
1581 T (&unpacked_object)[N],
1582 const bool allow_compression)
1583 {
1584 unpack<T, N>(buffer.cbegin(),
1585 buffer.cend(),
1586 unpacked_object,
1587 allow_compression);
1588 }
1589
1590
1591
1592 inline bool
1593 get_bit(const unsigned char number, const unsigned int n)
1594 {
1595 AssertIndexRange(n, 8);
1596
1597 // source:
1598 // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1599 // "Checking a bit"
1600 return ((number >> n) & 1U) != 0u;
1601 }
1602
1603
1604
1605 inline void
1606 set_bit(unsigned char &number, const unsigned int n, const bool x)
1607 {
1608 AssertIndexRange(n, 8);
1609
1610 // source:
1611 // https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
1612 // "Changing the nth bit to x"
1613 number ^= (-static_cast<unsigned char>(x) ^ number) & (1U << n);
1614 }
1615
1616
1617
1618 template <typename To, typename From>
1619 inline std::unique_ptr<To>
1620 dynamic_unique_cast(std::unique_ptr<From> &&p)
1621 {
1622 // Let's see if we can cast from 'From' to 'To'. If so, do the cast,
1623 // and then release the pointer from the old
1624 // owner
1625 if (To *cast = dynamic_cast<To *>(p.get()))
1626 {
1627 std::unique_ptr<To> result(cast);
1628 p.release();
1629 return result;
1630 }
1631 else
1632 throw std::bad_cast();
1633 }
1634
1635
1636
1637 template <typename T>
1638 inline T &
1640 {
1641 return p;
1642 }
1643
1644
1645
1646 template <typename T>
1647 inline T &
1648 get_underlying_value(std::shared_ptr<T> &p)
1649 {
1650 return *p;
1651 }
1652
1653
1654
1655 template <typename T>
1656 inline T &
1657 get_underlying_value(const std::shared_ptr<T> &p)
1658 {
1659 return *p;
1660 }
1661
1662
1663
1664 template <typename T>
1665 inline T &
1666 get_underlying_value(std::unique_ptr<T> &p)
1667 {
1668 return *p;
1669 }
1670
1671
1672
1673 template <typename T>
1674 inline T &
1675 get_underlying_value(const std::unique_ptr<T> &p)
1676 {
1677 return *p;
1678 }
1679
1680
1681
1682 template <typename Integer>
1683 std::vector<Integer>
1684 reverse_permutation(const std::vector<Integer> &permutation)
1685 {
1686 const std::size_t n = permutation.size();
1687
1688 std::vector<Integer> out(n);
1689 for (std::size_t i = 0; i < n; ++i)
1690 out[i] = n - 1 - permutation[i];
1691
1692 return out;
1693 }
1694
1695
1696
1697 template <typename Integer>
1698 std::vector<Integer>
1699 invert_permutation(const std::vector<Integer> &permutation)
1700 {
1701 const std::size_t n = permutation.size();
1702
1703 std::vector<Integer> out(n, numbers::invalid_unsigned_int);
1704
1705 for (std::size_t i = 0; i < n; ++i)
1706 {
1707 AssertIndexRange(permutation[i], n);
1708 out[permutation[i]] = i;
1709 }
1710
1711 // check that we have actually reached
1712 // all indices
1713 for (std::size_t i = 0; i < n; ++i)
1715 ExcMessage("The given input permutation had duplicate entries!"));
1716
1717 return out;
1718 }
1719} // namespace Utilities
1720
1721
1723
1724#ifndef DOXYGEN
1725namespace boost
1726{
1727 namespace serialization
1728 {
1729 // Provides boost and c++11 with a way to serialize tuples and pairs
1730 // automatically.
1731 template <int N>
1732 struct Serialize
1733 {
1734 template <class Archive, typename... Args>
1735 static void
1736 serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1737 {
1738 ar &std::get<N - 1>(t);
1739 Serialize<N - 1>::serialize(ar, t, version);
1740 }
1741 };
1742
1743 template <>
1744 struct Serialize<0>
1745 {
1746 template <class Archive, typename... Args>
1747 static void
1748 serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1749 {
1750 (void)ar;
1751 (void)t;
1752 (void)version;
1753 }
1754 };
1755
1756 template <class Archive, typename... Args>
1757 void
1758 serialize(Archive &ar, std::tuple<Args...> &t, const unsigned int version)
1759 {
1760 Serialize<sizeof...(Args)>::serialize(ar, t, version);
1761 }
1762 } // namespace serialization
1763} // namespace boost
1764#endif
1765
1766#endif
Definition point.h:111
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:503
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:177
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:504
#define DEAL_II_FALLTHROUGH
Definition config.h:235
Point< 2 > first
Definition grid_out.cc:4623
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define DEAL_II_ASSERT_UNREACHABLE()
void get_memory_stats(MemoryStats &stats)
Definition utilities.cc:964
std::string get_hostname()
Definition utilities.cc:998
std::string get_time()
void posix_memalign(void **memptr, std::size_t alignment, std::size_t size)
double get_cpu_load()
Definition utilities.cc:930
std::string get_current_vectorization_level()
Definition utilities.cc:938
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:1268
void append_vector_of_trivially_copyable_to_buffer(const T &, std::vector< char > &)
Definition utilities.h:1180
std::vector< std::string > split_string_list(const std::string &s, const std::string &delimiter=",")
Definition utilities.cc:701
T & get_underlying_value(T &p)
Definition utilities.h:1639
Number truncate_to_n_digits(const Number number, const unsigned int n_digits)
Definition utilities.cc:578
std::string type_to_string(const T &t)
Definition utilities.h:1023
size_t pack(const T &object, std::vector< char > &dest_buffer, const bool allow_compression=true)
Definition utilities.h:1381
std::string dim_string(const int dim, const int spacedim)
Definition utilities.cc:555
std::uint64_t pack_integers(const std::array< std::uint64_t, dim > &index, const int bits_per_dim)
Definition utilities.cc:366
bool get_bit(const unsigned char number, const unsigned int n)
Definition utilities.h:1593
std::pair< int, unsigned int > get_integer_at_position(const std::string &name, const unsigned int position)
Definition utilities.cc:847
std::string encode_base64(const std::vector< unsigned char > &binary_input)
Definition utilities.cc:433
std::unique_ptr< To > dynamic_unique_cast(std::unique_ptr< From > &&p)
Definition utilities.h:1620
constexpr T fixed_power(const T t)
Definition utilities.h:942
std::string replace_in_string(const std::string &input, const std::string &from, const std::string &to)
Definition utilities.cc:509
std::vector< unsigned char > decode_base64(const std::string &base64_input)
Definition utilities.cc:446
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
Definition utilities.cc:755
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:479
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:145
std::string compress(const std::string &input)
Definition utilities.cc:389
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:470
bool match_at_string_start(const std::string &name, const std::string &pattern)
Definition utilities.cc:832
T unpack(const std::vector< char > &buffer, const bool allow_compression=true)
Definition utilities.h:1538
std::string decompress(const std::string &compressed_input)
Definition utilities.cc:411
unsigned int needed_digits(const unsigned int max_number)
Definition utilities.cc:565
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition utilities.h:1032
double string_to_double(const std::string &s)
Definition utilities.cc:653
std::string dealii_version_string()
Definition utilities.cc:94
void set_bit(unsigned char &number, const unsigned int n, const bool x)
Definition utilities.h:1606
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
std::string trim(const std::string &input)
Definition utilities.cc:528
double generate_normal_random_number(const double a, const double sigma)
Definition utilities.cc:889
std::vector< Integer > reverse_permutation(const std::vector< Integer > &permutation)
Definition utilities.h:1684
std::vector< Integer > invert_permutation(const std::vector< Integer > &permutation)
Definition utilities.h:1699
int string_to_int(const std::string &s)
Definition utilities.cc:605
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:220
STL namespace.
#define DEAL_II_HOST_DEVICE
Definition numbers.h:34