From e1dba61c2e3aa38e9ab5efe19f18fde9a05e6f36 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Wed, 25 May 2022 12:08:33 +0200 Subject: [PATCH] Optimize Utilities::pack for std::vector> --- include/deal.II/base/utilities.h | 127 ++++++++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 10 deletions(-) diff --git a/include/deal.II/base/utilities.h b/include/deal.II/base/utilities.h index 1c29fcbdad..24b328ff24 100644 --- a/include/deal.II/base/utilities.h +++ b/include/deal.II/base/utilities.h @@ -1218,8 +1218,8 @@ namespace Utilities namespace internal { /** - * A structure that is used to identify whether a template - * argument is a std::vector where T is a type that + * A structure that is used to identify whether a template argument is a + * std::vector or std::vector> where T is a type that * satisfies std::is_trivially_copyable::value == true. */ template @@ -1239,6 +1239,15 @@ namespace Utilities + template + struct IsVectorOfTriviallyCopyable>> + { + static constexpr bool value = + std::is_trivially_copyable::value && !std::is_same::value; + }; + + + /** * A function that is used to append the contents of a std::vector * (where T is a type that satisfies std::is_trivially_copyable::value @@ -1257,6 +1266,7 @@ namespace Utilities } + template ::value && std::is_trivially_copyable::value>> @@ -1270,7 +1280,7 @@ namespace Utilities // Reserve for the buffer so that it can store the size of 'object' as // well as all of its elements. dest_buffer.reserve(dest_buffer.size() + sizeof(vector_size) + - object.size() * sizeof(T)); + vector_size * sizeof(T)); // Copy the size into the vector dest_buffer.insert(dest_buffer.end(), @@ -1278,11 +1288,58 @@ namespace Utilities reinterpret_cast(&vector_size + 1)); // Insert the elements at the end of the vector: - if (object.size() > 0) + if (vector_size > 0) dest_buffer.insert(dest_buffer.end(), reinterpret_cast(object.data()), reinterpret_cast(object.data() + - object.size())); + vector_size)); + } + + + + template ::value && + std::is_trivially_copyable::value>> + inline void + append_vector_of_trivially_copyable_to_buffer( + const std::vector> &object, + std::vector & dest_buffer) + { + using size_type = typename std::vector::size_type; + const size_type vector_size = object.size(); + + typename std::vector::size_type aggregated_size = 0; + std::vector sizes; + sizes.reserve(vector_size); + for (const auto &a : object) + { + aggregated_size += a.size(); + sizes.push_back(a.size()); + } + + // Reserve for the buffer so that it can store the size of 'object' as + // well as all of its elements. + dest_buffer.reserve(dest_buffer.size() + + sizeof(vector_size) * (1 + vector_size) + + aggregated_size * sizeof(T)); + + // Copy the size into the vector + dest_buffer.insert(dest_buffer.end(), + reinterpret_cast(&vector_size), + reinterpret_cast(&vector_size + 1)); + + // Copy the sizes of the individual chunks into the vector + if (vector_size > 0) + dest_buffer.insert(dest_buffer.end(), + reinterpret_cast(sizes.data()), + reinterpret_cast(sizes.data() + + vector_size)); + + // Insert the elements at the end of the vector: + for (const auto &a : object) + dest_buffer.insert(dest_buffer.end(), + reinterpret_cast(a.data()), + reinterpret_cast(a.data() + a.size())); } @@ -1312,7 +1369,6 @@ namespace Utilities // First get the size of the vector, and resize the output object typename std::vector::size_type vector_size; memcpy(&vector_size, &*cbegin, sizeof(vector_size)); - object.resize(vector_size); Assert(static_cast(cend - cbegin) == static_cast(sizeof(vector_size) + @@ -1321,10 +1377,61 @@ namespace Utilities (void)cend; // Then copy the elements: - if (object.size() > 0) - memcpy(object.data(), - &*cbegin + sizeof(vector_size), - vector_size * sizeof(T)); + object.clear(); + if (vector_size > 0) + object.insert(object.end(), + reinterpret_cast(&*cbegin + + sizeof(vector_size)), + reinterpret_cast(&*cend)); + } + + + + template ::value && + std::is_trivially_copyable::value>> + inline void + create_vector_of_trivially_copyable_from_buffer( + const std::vector::const_iterator &cbegin, + const std::vector::const_iterator &cend, + std::vector> & object) + { + // First get the size of the vector, and resize the output object + using size_type = typename std::vector::size_type; + std::vector::const_iterator iterator = cbegin; + size_type vector_size; + memcpy(&vector_size, &*iterator, sizeof(vector_size)); + object.clear(); + object.resize(vector_size); + std::vector sizes(vector_size); + if (vector_size > 0) + memcpy(sizes.data(), + &*iterator + sizeof(vector_size), + vector_size * sizeof(size_type)); + + iterator += sizeof(vector_size) * (1 + vector_size); + size_type aggregated_size = 0; + for (const auto a : sizes) + aggregated_size += a; + + Assert(static_cast(cend - iterator) == + static_cast(aggregated_size * sizeof(T)), + ExcMessage("The given buffer has the wrong size.")); + (void)cend; + + // Then copy the elements: + for (unsigned int i = 0; i < vector_size; ++i) + if (sizes[i] > 0) + { + object[i].insert(object[i].end(), + reinterpret_cast(&*iterator), + reinterpret_cast(&*iterator + + sizeof(T) * sizes[i])); + iterator += sizeof(T) * sizes[i]; + } + + Assert(iterator == cend, + ExcMessage("The given buffer has the wrong size.")); } } // namespace internal -- 2.39.5