CbmRoot
Loading...
Searching...
No Matches
PartitionedSpan.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_SPAN_H
5#define CBM_ALGO_BASE_PARTITIONED_SPAN_H
6
7#include <array>
8#include <cstdint>
9#include <gsl/span>
10#include <stdexcept>
11#include <vector>
12
13namespace cbm
14{
15
16 template<typename T, typename Allocator>
18
19 namespace detail
20 {
21 template<typename U, typename T>
22 using EnableOnConst = std::enable_if_t<std::is_const_v<T> && std::is_same_v<U, std::remove_cv_t<T>>>;
23
24 template<typename U, typename T>
25 using EnableOnNonConst = std::enable_if_t<!std::is_const_v<T> && std::is_same_v<U, std::remove_cv_t<T>>>;
26 } // namespace detail
27
28 template<typename T>
30
31 public:
33
34 // Intellisense and clang workaround, fails on template deduction with stl containers for some reason
35 // #if defined(__INTELLISENSE__) || defined(__clang__)
36 template<typename Allocator>
37 PartitionedSpan(std::vector<T, Allocator>& container, gsl::span<const size_t> offsets,
38 gsl::span<const uint32_t> addresses)
39 : fData(container)
40 , fOffsets(offsets)
41 , fAdresses(addresses)
42 {
44 }
45
46 // FIXME disable if T is non-const via SFINAE, otherwise get misleading compiler errors
47 template<typename Allocator>
48 PartitionedSpan(const std::vector<T, Allocator>& container, gsl::span<const size_t> offsets,
49 gsl::span<const uint32_t> addresses)
50 : fData(container)
51 , fOffsets(offsets)
52 , fAdresses(addresses)
53 {
55 }
56
57 template<size_t N>
58 PartitionedSpan(std::array<T, N>& container, gsl::span<const size_t> offsets, gsl::span<const uint32_t> addresses)
59 : fData(container)
60 , fOffsets(offsets)
61 , fAdresses(addresses)
62 {
64 }
65
66 // FIXME disable if T is non-const via SFINAE
67 template<size_t N>
68 PartitionedSpan(const std::array<T, N>& container, gsl::span<const size_t> offsets,
69 gsl::span<const uint32_t> addresses)
70 : fData(container)
71 , fOffsets(offsets)
72 , fAdresses(addresses)
73 {
75 }
76 // #endif
77
78 PartitionedSpan(gsl::span<T> data, gsl::span<const size_t> offsets, gsl::span<const uint32_t> addresses)
79 : fData(data)
80 , fOffsets(offsets)
81 , fAdresses(addresses)
82 {
84 }
85
86 template<typename U, typename Allocator, typename = detail::EnableOnConst<U, T>>
88 : fData(container.Data())
89 , fOffsets(container.Offsets())
90 , fAdresses(container.Addresses())
91 {
93 }
94
95 template<typename U, typename Allocator, typename = detail::EnableOnNonConst<U, T>>
97 : fData(container.Data())
98 , fOffsets(container.Offsets())
99 , fAdresses(container.Addresses())
100 {
102 }
103
104 template<typename U, typename = detail::EnableOnConst<U, T>>
106 : fData(other.Data())
107 , fOffsets(other.Offsets())
108 , fAdresses(other.Addresses())
109 {
110 }
111
112 gsl::span<T> operator[](size_t i) const
113 {
114 EnsureBounds(i);
115 return UnsafePartitionSpan(i);
116 }
117
118 uint32_t Address(size_t i) const
119 {
120 EnsureBounds(i);
121 return fAdresses[i];
122 }
123
124 std::pair<gsl::span<T>, uint32_t> Partition(size_t i) const
125 {
126 EnsureBounds(i);
127 return std::pair<gsl::span<T>, uint32_t>(UnsafePartitionSpan(i), fAdresses[i]);
128 }
129
130 size_t NPartitions() const { return fAdresses.size(); }
131
132 size_t Size(size_t i) const
133 {
134 EnsureBounds(i);
135 return UnsafeSize(i);
136 }
137
138 size_t NElements() const { return fData.size(); }
139
140 gsl::span<T> Data() const { return fData; }
141
142 gsl::span<const uint32_t> Addresses() const { return fAdresses; }
143
144 gsl::span<const size_t> Offsets() const { return fOffsets; }
145
146 private:
147 // Required for default constructor, don't use std::array to avoid additional dependency
148 static constexpr size_t NullOffset[1] = {0};
149
150 gsl::span<T> fData;
151 gsl::span<const size_t> fOffsets;
152 gsl::span<const uint32_t> fAdresses;
153
154 // FIXME code duplication with PartitionedVector
155
156 void EnsureDimensions() const
157 {
158 if (fOffsets.size() - 1 != fAdresses.size()) {
159 throw std::runtime_error("PartitionedSpan: fOffsets.size() - 1 != fAdresses.size()");
160 }
161 if (fOffsets.front() != 0) throw std::runtime_error("PartitionedSpan: fOffsets.front() != 0");
162 if (fOffsets.back() != fData.size()) {
163 throw std::runtime_error("PartitionedSpan: fOffsets.back() != fData.size()");
164 }
165 }
166
167 void EnsureBounds(size_t i) const
168 {
169 if (i >= fAdresses.size()) throw std::out_of_range("PartitionedSpan: index out of bounds");
170 }
171
172 size_t UnsafeSize(size_t i) const { return fOffsets[i + 1] - fOffsets[i]; }
173
174 gsl::span<T> UnsafePartitionSpan(size_t i) const { return fData.subspan(fOffsets[i], UnsafeSize(i)); }
175 };
176
177 // template auto deduction
178 template<typename T, template<typename> class Container>
179 PartitionedSpan(Container<T>&, gsl::span<const size_t>, gsl::span<const uint32_t>) -> PartitionedSpan<T>;
180
181 template<typename T, template<typename> class Container>
182 PartitionedSpan(const Container<T>&, gsl::span<const size_t>, gsl::span<const uint32_t>) -> PartitionedSpan<const T>;
183
184 template<typename T, typename Allocator>
186
187 template<typename T, typename Allocator>
189
190} // namespace cbm
191
192#endif
std::pair< gsl::span< T >, uint32_t > Partition(size_t i) const
size_t UnsafeSize(size_t i) const
gsl::span< const uint32_t > Addresses() const
PartitionedSpan(const PartitionedVector< U, Allocator > &container)
gsl::span< const size_t > fOffsets
PartitionedSpan(const std::array< T, N > &container, gsl::span< const size_t > offsets, gsl::span< const uint32_t > addresses)
gsl::span< const size_t > Offsets() const
void EnsureBounds(size_t i) const
PartitionedSpan(PartitionedVector< U, Allocator > &container)
gsl::span< T > Data() const
gsl::span< T > UnsafePartitionSpan(size_t i) const
PartitionedSpan(std::array< T, N > &container, gsl::span< const size_t > offsets, gsl::span< const uint32_t > addresses)
PartitionedSpan(PartitionedSpan< U > other)
size_t NPartitions() const
size_t Size(size_t i) const
gsl::span< T > operator[](size_t i) const
size_t NElements() const
void EnsureDimensions() const
PartitionedSpan(gsl::span< T > data, gsl::span< const size_t > offsets, gsl::span< const uint32_t > addresses)
PartitionedSpan(std::vector< T, Allocator > &container, gsl::span< const size_t > offsets, gsl::span< const uint32_t > addresses)
static constexpr size_t NullOffset[1]
uint32_t Address(size_t i) const
gsl::span< const uint32_t > fAdresses
PartitionedSpan(const std::vector< T, Allocator > &container, gsl::span< const size_t > offsets, gsl::span< const uint32_t > addresses)
A vector that is partitioned into multiple subvectors.
std::enable_if_t<!std::is_const_v< T > &&std::is_same_v< U, std::remove_cv_t< T > > > EnableOnNonConst
std::enable_if_t< std::is_const_v< T > &&std::is_same_v< U, std::remove_cv_t< T > > > EnableOnConst
PartitionedSpan(Container< T > &, gsl::span< const size_t >, gsl::span< const uint32_t >) -> PartitionedSpan< T >