-
Notifications
You must be signed in to change notification settings - Fork 496
Expand file tree
/
Copy pathStaticSequenceAllocator.h
More file actions
157 lines (138 loc) · 4.98 KB
/
StaticSequenceAllocator.h
File metadata and controls
157 lines (138 loc) · 4.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
/// @file StaticSequenceAllocator.h
/// @author Matthias Richter, based on work by Mikolaj Krzewicki
/// @since 2017-09-21
/// @brief An allocator for static sequences of object types
namespace o2
{
namespace algorithm
{
/**
* Helper struct to define a composite element from a header, some payload
* and a trailer
*/
template <typename HeaderT, typename TrailerT = void>
struct Composite {
using HeaderType = HeaderT;
using TrailerType = TrailerT;
size_t compositeLength = 0;
size_t trailerLength = 0;
size_t dataLength = 0;
template <size_t N,
typename U = TrailerType>
constexpr Composite(const HeaderType h, const char (&d)[N],
typename std::conditional<!std::is_void<U>::value, const TrailerType, int>::type t,
typename std::enable_if<!std::is_void<U>::value>::type* = nullptr)
: header(h), data(d), trailer(t)
{
dataLength = N;
trailerLength = sizeof(TrailerType);
compositeLength = sizeof(HeaderType) + dataLength + trailerLength;
}
template <size_t N,
typename U = TrailerType>
constexpr Composite(const HeaderType& h, const char (&d)[N],
typename std::enable_if<std::is_void<U>::value>::type* = nullptr)
: header(h), data(d)
{
dataLength = N;
trailerLength = 0;
compositeLength = sizeof(HeaderType) + dataLength + trailerLength;
}
constexpr size_t getLength() const noexcept
{
return compositeLength;
}
constexpr size_t getDataLength() const noexcept
{
return dataLength;
}
template <typename BufferT>
constexpr size_t insert(BufferT* buffer) const noexcept
{
static_assert(sizeof(BufferT) == 1, "buffer required to be of byte-type");
size_t length = 0;
memcpy(buffer + length, &header, sizeof(HeaderType));
length += sizeof(HeaderType);
memcpy(buffer + length, data, dataLength);
length += dataLength;
if (trailerLength > 0) {
memcpy(buffer + length, &trailer, trailerLength);
length += trailerLength;
}
return length;
}
const HeaderType header;
const char* data = nullptr;
typename std::conditional<!std::is_void<TrailerType>::value, const TrailerType, int>::type trailer;
};
/// recursively calculate the length of the sequence
/// object types are fixed at compile time and so is the total length of the
/// sequence. The function is recursively invoked for all arguments of the
// variable list
template <typename T, typename... TArgs>
constexpr size_t sequenceLength(const T& first, const TArgs... args) noexcept
{
return sequenceLength(first) + sequenceLength(args...);
}
/// template secialization of sequence length calculation for one argument,
/// this is also the terminating instance for the last argument of the recursive
/// invocation of the function template.
template <typename T>
constexpr size_t sequenceLength(const T& first) noexcept
{
return first.getLength();
}
/// recursive insert of variable number of objects
template <typename BufferT, typename T, typename... TArgs>
constexpr size_t sequenceInsert(BufferT* buffer, const T& first, const TArgs... args) noexcept
{
static_assert(sizeof(BufferT) == 1, "buffer required to be of byte-type");
auto length = sequenceInsert(buffer, first);
length += sequenceInsert(buffer + length, args...);
return length;
}
/// terminating template specialization, i.e. for the last element
template <typename BufferT, typename T>
constexpr size_t sequenceInsert(BufferT* buffer, const T& element) noexcept
{
// TODO: make a general algorithm, at the moment this serves the
// Composite class as a special case
return element.insert(buffer);
}
/**
* Allocator for a buffer of a static sequence of multiple objects.
*
* The sequence of object types is fixed at compile time and given as
* a variable list of arguments to the constructor. The data of the objects
* is runtime dependent.
*
* TODO: probably the Composite struct needs to be reworked to allow this
* allocator to be more general
*/
struct StaticSequenceAllocator {
using value_type = unsigned char;
using BufferType = std::unique_ptr<value_type[]>;
BufferType buffer;
size_t bufferSize;
size_t size() const { return bufferSize; }
StaticSequenceAllocator() = delete;
template <typename... Targs>
StaticSequenceAllocator(Targs... args)
{
bufferSize = sequenceLength(args...);
buffer = std::make_unique<value_type[]>(bufferSize);
sequenceInsert(buffer.get(), args...);
}
};
} // namespace algorithm
} // namespace o2