]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Optimize Utilities::pack/unpack for empty objects.
authorWolfgang Bangerth <bangerth@colostate.edu>
Thu, 26 May 2022 19:39:05 +0000 (13:39 -0600)
committerWolfgang Bangerth <bangerth@colostate.edu>
Mon, 30 May 2022 15:34:40 +0000 (09:34 -0600)
include/deal.II/base/utilities.h
tests/base/utilities_pack_unpack_08.cc [new file with mode: 0644]
tests/base/utilities_pack_unpack_08.output [new file with mode: 0644]

index 3deb58189e2c078937ff9b6db3d13ba14bdb7fd3..87f676f64b9bed6e2a08a8246ad136d47d4d931c 100644 (file)
@@ -1456,13 +1456,20 @@ namespace Utilities
     if (std::is_trivially_copyable<T>() && sizeof(T) < 256)
 #endif
       {
+        // Determine the size. There are places where we would like to use a
+        // truly empty type, for which we use std::tuple<> (i.e., a tuple
+        // of zero elements). For this class, the compiler reports a nonzero
+        // sizeof(...) because that is the minimum possible for objects --
+        // objects need to have distinct addresses, so they need to have a size
+        // of at least one. But we can special case this situation.
+        size = (std::is_same<T, std::tuple<>>::value ? 0 : sizeof(T));
+
         (void)allow_compression;
         const std::size_t previous_size = dest_buffer.size();
-        dest_buffer.resize(previous_size + sizeof(T));
-
-        std::memcpy(dest_buffer.data() + previous_size, &object, sizeof(T));
+        dest_buffer.resize(previous_size + size);
 
-        size = sizeof(T);
+        if (size > 0)
+          std::memcpy(dest_buffer.data() + previous_size, &object, size);
       }
     // Next try if we have a vector of trivially copyable objects.
     // If that is the case, we can shortcut the whole BOOST serialization
@@ -1536,11 +1543,22 @@ namespace Utilities
     if (std::is_trivially_copyable<T>() && sizeof(T) < 256)
 #endif
       {
+        // Determine the size. There are places where we would like to use a
+        // truly empty type, for which we use std::tuple<> (i.e., a tuple
+        // of zero elements). For this class, the compiler reports a nonzero
+        // sizeof(...) because that is the minimum possible for objects --
+        // objects need to have distinct addresses, so they need to have a size
+        // of at least one. But we can special case this situation.
+        const std::size_t size =
+          (std::is_same<T, std::tuple<>>::value ? 0 : sizeof(T));
+
         T object;
 
         (void)allow_compression;
-        Assert(std::distance(cbegin, cend) == sizeof(T), ExcInternalError());
-        std::memcpy(&object, &*cbegin, sizeof(T));
+        Assert(std::distance(cbegin, cend) == size, ExcInternalError());
+
+        if (size > 0)
+          std::memcpy(&object, &*cbegin, size);
 
         return object;
       }
diff --git a/tests/base/utilities_pack_unpack_08.cc b/tests/base/utilities_pack_unpack_08.cc
new file mode 100644 (file)
index 0000000..6cf3a3e
--- /dev/null
@@ -0,0 +1,60 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2017 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Make sure that Utilities::pack/unpack can be used on objects that
+// are empty, and that the resulting packed string has length zero.
+
+
+#include <deal.II/base/point.h>
+#include <deal.II/base/timer.h>
+#include <deal.II/base/utilities.h>
+
+#include <tuple>
+
+#include "../tests.h"
+
+
+
+void
+test()
+{
+  using Empty = std::tuple<>;
+
+  Empty e;
+  deallog << "Size = " << sizeof(e) << std::endl;
+
+  // Pack the object and make sure the packed length is zero
+  const std::vector<char> packed = Utilities::pack(e, false);
+  deallog << "Packed size = " << packed.size() << std::endl;
+
+  // Then unpack again. The two should be the same -- though one may
+  // question what equality of objects of size zero might mean -- and
+  // we should check so:
+  Empty e2 = Utilities::unpack<Empty>(packed, false);
+  Assert(e2 == e, ExcInternalError());
+
+  deallog << "OK" << std::endl;
+}
+
+
+
+int
+main()
+{
+  initlog();
+
+  test();
+}
diff --git a/tests/base/utilities_pack_unpack_08.output b/tests/base/utilities_pack_unpack_08.output
new file mode 100644 (file)
index 0000000..e4ada52
--- /dev/null
@@ -0,0 +1,4 @@
+
+DEAL::Size = 1
+DEAL::Packed size = 0
+DEAL::OK

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.