Skip to content

Commit 73cba8e

Browse files
Adding utilities for flatten/restore for objects with multiple arrays
1 parent d18253f commit 73cba8e

3 files changed

Lines changed: 186 additions & 0 deletions

File tree

Algorithm/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,9 @@ o2_add_test(RangeTokenizer
5252
SOURCES test/test_RangeTokenizer.cxx
5353
COMPONENT_NAME Algorithm
5454
LABELS algorithm)
55+
56+
57+
o2_add_test(FlattenRestore
58+
SOURCES test/test_FlattenRestore.cxx
59+
COMPONENT_NAME Algorithm
60+
LABELS algorithm)
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright CERN and copyright holders of ALICE O2. This software is
2+
// distributed under the terms of the GNU General Public License v3 (GPL
3+
// Version 3), copied verbatim in the file "COPYING".
4+
//
5+
// See http://alice-o2.web.cern.ch/license for full licensing information.
6+
//
7+
// In applying this license CERN does not waive the privileges and immunities
8+
// granted to it by virtue of its status as an Intergovernmental Organization
9+
// or submit itself to any jurisdiction.
10+
11+
#ifndef FLATTERRESTORE_H
12+
#define FLATTERRESTORE_H
13+
14+
/// @file FlattenRestore.h
15+
/// @author Matthias Richter
16+
/// @since 2020-04-05
17+
/// @brief Utilities to copy complex objects to flat buffer and restore
18+
19+
#include <type_traits>
20+
21+
namespace o2::algorithm
22+
{
23+
namespace flatten
24+
{
25+
26+
/// Calculate cumulative value size of a variable number of arguments
27+
/// The function takes parameters by reference and calculates the memory size of
28+
/// all parameters together. The pointer attribute is removed.
29+
///
30+
/// Example:
31+
/// char* array1;
32+
/// int* array2;
33+
/// float* array3;
34+
/// size = value_size(array1, array2, array3);
35+
/// // size is sizeof(char) + sizeof(int) + sizeof(float)
36+
template <typename ValueType, typename... Args>
37+
constexpr size_t value_size(ValueType const& value, Args&&... args)
38+
{
39+
size_t size = sizeof(typename std::remove_pointer<typename std::remove_reference<ValueType>::type>::type);
40+
if constexpr (sizeof...(Args) > 0) {
41+
size += value_size(std::forward<Args>(args)...);
42+
}
43+
return size;
44+
}
45+
46+
/// Copy the content of variable number of arrays with the same extent to a buffer
47+
/// The target pointer is passed be reference and incremented while copying
48+
/// @param wrtptr write pointer
49+
/// @param count extent of the arrays
50+
/// @param args a variable number of pointers to arrays
51+
/// @return copied size in bytes
52+
template <typename TargetType, typename ValueType, typename... Args>
53+
static size_t copy_to(TargetType& wrtptr, size_t count, ValueType* array, Args&&... args)
54+
{
55+
static_assert(std::is_pointer<TargetType>::value == true, "need reference to pointer");
56+
static_assert(sizeof(typename std::remove_pointer<TargetType>::type) == 1, "need char-like pointer");
57+
58+
size_t copySize = 0;
59+
if (array != nullptr) {
60+
copySize = count * value_size(array);
61+
memcpy(wrtptr, array, copySize);
62+
wrtptr += copySize;
63+
} else if (count > 0) {
64+
throw std::runtime_error("invalid nullptr to array of " + std::to_string(count) + " element(s)");
65+
}
66+
if constexpr (sizeof...(Args) > 0) {
67+
copySize += copy_to(wrtptr, count, std::forward<Args>(args)...);
68+
}
69+
return copySize;
70+
}
71+
72+
/// Set pointers to regions in source buffer
73+
/// A variable number of pointer arguments of consecutive arrays in a buffer are set according
74+
/// to the type size and the extent of arrays
75+
/// The read pointer is passed be reference and incremented while copying
76+
/// @param readptr the source buffer
77+
/// @param count extent of the arrays
78+
/// @param args a variable number of references of pointers to arrays
79+
/// @return handled raw size in bytes
80+
template <typename BufferType, typename ValueType, typename... Args>
81+
static size_t set_from(BufferType& readptr, size_t count, ValueType& array, Args&&... args)
82+
{
83+
static_assert(std::is_pointer<typename std::remove_reference<ValueType>::type>::value == true, "need reference to pointer");
84+
array = reinterpret_cast<typename std::remove_reference<ValueType>::type>(readptr);
85+
size_t readSize = count * value_size(array);
86+
readptr += readSize;
87+
if constexpr (sizeof...(Args) > 0) {
88+
readSize += set_from(readptr, count, std::forward<Args>(args)...);
89+
}
90+
return readSize;
91+
}
92+
93+
/// Calculate the total size of a sequence of arrays with the same extent
94+
/// the first argument is a dummy argument to have the same signature as copy_to
95+
/// and set_from
96+
/// @param dummyptr unused
97+
/// @param count extent of the arrays
98+
/// @param args a variable number of references of pointers to arrays
99+
/// @return total size
100+
template <typename BufferType, typename... Args>
101+
static size_t calc_size(BufferType const& dummyptr, size_t count, Args&&... args)
102+
{
103+
return count * value_size(std::forward<Args>(args)...);
104+
}
105+
106+
} // namespace flatten
107+
} // namespace o2::algorithm
108+
109+
#endif
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright CERN and copyright holders of ALICE O2. This software is
2+
// distributed under the terms of the GNU General Public License v3 (GPL
3+
// Version 3), copied verbatim in the file "COPYING".
4+
//
5+
// See http://alice-o2.web.cern.ch/license for full licensing information.
6+
//
7+
// In applying this license CERN does not waive the privileges and immunities
8+
// granted to it by virtue of its status as an Intergovernmental Organization
9+
// or submit itself to any jurisdiction.
10+
11+
// @file test_FlattenRestore.cxx
12+
// @author Matthias Richter
13+
// @since 2020-04-05
14+
// @brief Test program flatten/restore tools
15+
16+
#define BOOST_TEST_MODULE Algorithm FlattenRestore test
17+
#define BOOST_TEST_MAIN
18+
#define BOOST_TEST_DYN_LINK
19+
#include <boost/test/unit_test.hpp>
20+
#include "../include/Algorithm/FlattenRestore.h"
21+
#include <vector>
22+
#include <algorithm>
23+
24+
namespace flatten = o2::algorithm::flatten;
25+
26+
namespace o2::test
27+
{
28+
struct DataAccess {
29+
size_t count = 0;
30+
char* chars = nullptr;
31+
int* ints = nullptr;
32+
float* floats = nullptr;
33+
};
34+
} // namespace o2::test
35+
BOOST_AUTO_TEST_CASE(test_flattenrestore)
36+
{
37+
o2::test::DataAccess access{static_cast<size_t>(rand() % 32)};
38+
std::vector<char> chars(access.count);
39+
std::generate(chars.begin(), chars.end(), []() { return rand() % 256; });
40+
std::vector<int> ints(access.count);
41+
std::generate(ints.begin(), ints.end(), []() { return rand() % 256; });
42+
std::vector<float> floats(access.count);
43+
std::generate(floats.begin(), floats.end(), []() { return rand() % 256; });
44+
access.chars = chars.data();
45+
access.ints = ints.data();
46+
access.floats = floats.data();
47+
48+
std::vector<char> raw(flatten::value_size(access.chars, access.ints, access.floats) * access.count);
49+
char* wrtptr = raw.data();
50+
auto copied = flatten::copy_to(wrtptr, access.count, access.chars, access.ints, access.floats);
51+
BOOST_CHECK(copied == raw.size());
52+
char* checkptr = raw.data();
53+
BOOST_CHECK(memcmp(checkptr, chars.data(), chars.size() * sizeof(decltype(chars)::value_type)) == 0);
54+
checkptr += flatten::calc_size(nullptr, chars.size(), chars.data());
55+
BOOST_CHECK(memcmp(checkptr, ints.data(), ints.size() * sizeof(decltype(ints)::value_type)) == 0);
56+
checkptr += flatten::calc_size(nullptr, ints.size(), ints.data());
57+
BOOST_CHECK(memcmp(checkptr, floats.data(), floats.size() * sizeof(decltype(floats)::value_type)) == 0);
58+
checkptr += flatten::calc_size(nullptr, floats.size(), floats.data());
59+
60+
o2::test::DataAccess target{access.count, nullptr, nullptr, nullptr};
61+
char* readptr = raw.data();
62+
auto readsize = flatten::set_from(readptr, target.count, target.chars, target.ints, target.floats);
63+
BOOST_CHECK(readsize == copied);
64+
checkptr = raw.data();
65+
BOOST_CHECK(reinterpret_cast<decltype(target.chars)>(checkptr) == target.chars);
66+
checkptr += flatten::calc_size(nullptr, chars.size(), chars.data());
67+
BOOST_CHECK(reinterpret_cast<decltype(target.ints)>(checkptr) == target.ints);
68+
checkptr += flatten::calc_size(nullptr, ints.size(), ints.data());
69+
BOOST_CHECK(reinterpret_cast<decltype(target.floats)>(checkptr) == target.floats);
70+
checkptr += flatten::calc_size(nullptr, floats.size(), floats.data());
71+
}

0 commit comments

Comments
 (0)