CbmRoot
Loading...
Searching...
No Matches
PartitionedVector.h
Go to the documentation of this file.
1/* Copyright (C) 2023-2025 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Felix Weiglhofer [committer] */
4#ifndef CBM_ALGO_BASE_PARTITIONED_VECTOR_H
5#define CBM_ALGO_BASE_PARTITIONED_VECTOR_H
6
7#include "PODAllocator.h"
8
9#include <boost/serialization/access.hpp>
10#include <boost/serialization/vector.hpp>
11
12#include <gsl/span>
13#include <vector>
14
15namespace cbm
16{
17 template<typename T>
18 class PartitionedSpan;
19
28 template<typename T, class Allocator = std::allocator<T>>
30
31 public:
32 using Container_t = std::vector<T, Allocator>; //< Underlying container type
33
38
48 PartitionedVector(Container_t&& data, gsl::span<const size_t> sizes, gsl::span<const uint32_t> addresses)
49 : fData(std::move(data))
50 , fOffsets()
51 , fAddresses(addresses.begin(), addresses.end())
52 {
53 ComputeOffsets(sizes);
55 }
56
60 template<typename OtherAllocator>
62 : fData(other.Data().begin(), other.Data().end())
63 , fOffsets(other.Offsets())
64 , fAddresses(other.Addresses())
65 {
66 // TODO: this check is overkill? We already know that the dimensions are correct,
67 // since they were already checked in the other vector
69 }
70
75 : fData(other.Data().begin(), other.Data().end())
76 , fOffsets(other.Offsets())
77 , fAddresses(other.Addresses())
78 {
80 }
81
86 : fData(std::move(other.fData))
87 , fOffsets(std::move(other.fOffsets))
88 , fAddresses(std::move(other.fAddresses))
89 {
91 other.fOffsets = {0};
92 }
93
94 template<typename U>
96 : fData(other.Data().begin(), other.Data().end())
97 , fOffsets(other.Offsets().begin(), other.Offsets().end())
98 , fAddresses(other.Addresses().begin(), other.Addresses().end())
99 {
101 }
102
107 {
108 if (this != &other) {
109 fData = other.fData;
110 fOffsets = other.fOffsets;
111 fAddresses = other.fAddresses;
112 }
113 return *this;
114 }
115
120 {
121 if (this != &other) {
122 fData = std::move(other.fData);
123 fOffsets = std::move(other.fOffsets);
124 fAddresses = std::move(other.fAddresses);
125 other.fOffsets = {0};
126 }
127 return *this;
128 }
129
133 gsl::span<T> operator[](size_t i)
134 {
135 EnsureBounds(i);
136 return UnsafePartitionSpan(i);
137 }
138
142 gsl::span<const T> operator[](size_t i) const
143 {
144 EnsureBounds(i);
145 return UnsafePartitionSpan(i);
146 }
147
151 uint32_t Address(size_t i) const
152 {
153 EnsureBounds(i);
154 return fAddresses[i];
155 }
156
160 void Clear()
161 {
162 fData.clear();
163 fOffsets.clear();
164 fOffsets = {0};
165 fAddresses.clear();
166 }
167
171 std::pair<gsl::span<T>, uint32_t> Partition(size_t i)
172 {
173 EnsureBounds(i);
174 return std::pair<gsl::span<T>, uint32_t>(UnsafePartitionSpan(i), fAddresses[i]);
175 }
176
180 std::pair<gsl::span<const T>, uint32_t> Partition(size_t i) const
181 {
182 EnsureBounds(i);
183 return std::pair<gsl::span<const T>, uint32_t>(UnsafePartitionSpan(i), fAddresses[i]);
184 }
185
189 size_t NPartitions() const { return fAddresses.size(); }
190
194 size_t Size(size_t i) const
195 {
196 EnsureBounds(i);
197 return UnsafeSize(i);
198 }
199
203 size_t NElements() const { return fData.size(); }
204
208 size_t SizeBytes() const { return fData.size() * sizeof(T); }
209
213 gsl::span<T> Data() { return fData; }
214
218 gsl::span<const T> Data() const { return fData; }
219
223 const std::vector<uint32_t>& Addresses() const { return fAddresses; }
224
228 const std::vector<size_t>& Offsets() const { return fOffsets; }
229
230
231 private:
233 std::vector<size_t> fOffsets;
234 std::vector<uint32_t> fAddresses;
235
236 void EnsureDimensions() const
237 {
238 if (fOffsets.size() - 1 != fAddresses.size()) {
239 throw std::runtime_error("PartitionedVector: fOffsets.size() - 1 != fAddresses.size()");
240 }
241 if (fOffsets.front() != 0) {
242 throw std::runtime_error("PartitionedVector: fOffsets.front() != 0");
243 }
244 if (fOffsets.back() != fData.size()) {
245 throw std::runtime_error("PartitionedVector: fOffsets.back() != fData.size()");
246 }
247 }
248
249 void EnsureBounds(size_t i) const
250 {
251 if (i >= fAddresses.size()) throw std::out_of_range("PartitionedVector: index out of bounds");
252 }
253
254 void ComputeOffsets(gsl::span<const size_t> sizes)
255 {
256 fOffsets.reserve(sizes.size() + 1);
257 fOffsets.push_back(0);
258 for (auto n : sizes) {
259 fOffsets.push_back(fOffsets.back() + n);
260 }
261 }
262
263 size_t UnsafeSize(size_t i) const { return fOffsets[i + 1] - fOffsets[i]; }
264
265 gsl::span<T> UnsafePartitionSpan(size_t i) { return gsl::span<T>(fData.data() + fOffsets[i], UnsafeSize(i)); }
266
267 gsl::span<const T> UnsafePartitionSpan(size_t i) const
268 {
269 return gsl::span<const T>(fData.data() + fOffsets[i], UnsafeSize(i));
270 }
271
272 private: // serialization
273 friend class boost::serialization::access;
274
275 template<class Archive>
276 void serialize(Archive& ar, unsigned int /*version*/)
277 {
278 ar& fData;
279 ar& fOffsets;
280 ar& fAddresses;
281 }
282 };
283
284 template<typename T>
286
287} // namespace cbm
288
289#endif
std::vector< T, PODAllocator< T > > Container_t
A vector that is partitioned into multiple subvectors.
std::pair< gsl::span< const T >, uint32_t > Partition(size_t i) const
Get a pair of the data and the hardware address of partition i.
std::vector< T, Allocator > Container_t
PartitionedVector(Container_t &&data, gsl::span< const size_t > sizes, gsl::span< const uint32_t > addresses)
Constructor. Creates a vector with n partitions.
std::vector< uint32_t > fAddresses
Addresses of the partitions.
gsl::span< const T > Data() const
Get the underlying data.
void ComputeOffsets(gsl::span< const size_t > sizes)
void serialize(Archive &ar, unsigned int)
PartitionedVector(const PartitionedVector< T, OtherAllocator > &other)
Copy constructor. Copy the data from other vector.
const std::vector< uint32_t > & Addresses() const
size_t UnsafeSize(size_t i) const
uint32_t Address(size_t i) const
Get the hardware address of partition i.
PartitionedVector(PartitionedVector< T, Allocator > &&other)
Move constructor.
gsl::span< T > operator[](size_t i)
Access data at partition i.
void Clear()
Clears the vector.
PartitionedVector(PartitionedSpan< U > other)
gsl::span< T > UnsafePartitionSpan(size_t i)
size_t Size(size_t i) const
Get the size of partition i.
const std::vector< size_t > & Offsets() const
PartitionedVector(const PartitionedVector< T, Allocator > &other)
Copy constructor for a given type (to satisfy the rule of five)
PartitionedVector()
Default constructor. Creates an empty vector.
PartitionedVector & operator=(const PartitionedVector< T, Allocator > &other)
Copy assignment operator.
gsl::span< const T > operator[](size_t i) const
Access data at partition i.
PartitionedVector & operator=(PartitionedVector< T, Allocator > &&other)
Move assignment operator.
size_t NPartitions() const
Get the number of partitions.
size_t NElements() const
Get the total number of elements in the container across all partitions.
gsl::span< const T > UnsafePartitionSpan(size_t i) const
size_t SizeBytes() const
Return total size in bytes of the underlying data.
std::pair< gsl::span< T >, uint32_t > Partition(size_t i)
Get a pair of the data and the hardware address of partition i.
void EnsureBounds(size_t i) const
PartitionedVector< T, PODAllocator< T > > PartitionedPODVector
Hash for CbmL1LinkKey.