CbmRoot
Loading...
Searching...
No Matches
PartitionedSpan.h
Go to the documentation of this file.
1/* Copyright (C) 2023 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 "Definitions.h"
8
9#include <array>
10#include <gsl/span>
11#include <stdexcept>
12#include <vector>
13
14namespace cbm::algo
15{
16
17 template<typename T, typename Allocator>
18 class PartitionedVector;
19
20 namespace detail
21 {
22 template<typename U, typename T>
23 using EnableOnConst = std::enable_if_t<std::is_const_v<T> && std::is_same_v<U, std::remove_cv_t<T>>>;
24
25 template<typename U, typename T>
26 using EnableOnNonConst = std::enable_if_t<!std::is_const_v<T> && std::is_same_v<U, std::remove_cv_t<T>>>;
27 } // namespace detail
28
29 template<typename T>
30 class PartitionedSpan {
31
32 public:
34
35 // Intellisense and clang workaround, fails on template deduction with stl containers for some reason
36 // #if defined(__INTELLISENSE__) || defined(__clang__)
37 template<typename Allocator>
38 PartitionedSpan(std::vector<T, Allocator>& container, gsl::span<const size_t> offsets,
39 gsl::span<const u32> addresses)
40 : fData(container)
41 , fOffsets(offsets)
42 , fAdresses(addresses)
43 {
45 }
46
47 // FIXME disable if T is non-const via SFINAE, otherwise get misleading compiler errors
48 template<typename Allocator>
49 PartitionedSpan(const std::vector<T, Allocator>& container, gsl::span<const size_t> offsets,
50 gsl::span<const u32> addresses)
51 : fData(container)
52 , fOffsets(offsets)
53 , fAdresses(addresses)
54 {
56 }
57
58 template<size_t N>
59 PartitionedSpan(std::array<T, N>& container, gsl::span<const size_t> offsets, gsl::span<const u32> addresses)
60 : fData(container)
61 , fOffsets(offsets)
62 , fAdresses(addresses)
63 {
65 }
66
67 // FIXME disable if T is non-const via SFINAE
68 template<size_t N>
69 PartitionedSpan(const std::array<T, N>& container, gsl::span<const size_t> offsets, gsl::span<const u32> 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 u32> 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 u32 Address(size_t i) const
119 {
120 EnsureBounds(i);
121 return fAdresses[i];
122 }
123
124 std::pair<gsl::span<T>, u32> Partition(size_t i) const
125 {
126 EnsureBounds(i);
127 return std::pair<gsl::span<T>, u32>(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 u32> 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 u32> 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() != 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 u32>) -> PartitionedSpan<T>;
180
181 template<typename T, template<typename> class Container>
182 PartitionedSpan(const Container<T>&, gsl::span<const size_t>, gsl::span<const u32>) -> PartitionedSpan<const T>;
183
184 template<typename T, typename Allocator>
186
187 template<typename T, typename Allocator>
189
190} // namespace cbm::algo
191
192#endif
gsl::span< const size_t > Offsets() const
PartitionedSpan(PartitionedSpan< U > other)
std::pair< gsl::span< T >, u32 > Partition(size_t i) const
PartitionedSpan(PartitionedVector< U, Allocator > &container)
PartitionedSpan(std::vector< T, Allocator > &container, gsl::span< const size_t > offsets, gsl::span< const u32 > addresses)
PartitionedSpan(const PartitionedVector< U, Allocator > &container)
PartitionedSpan(const std::array< T, N > &container, gsl::span< const size_t > offsets, gsl::span< const u32 > addresses)
gsl::span< T > operator[](size_t i) const
PartitionedSpan(std::array< T, N > &container, gsl::span< const size_t > offsets, gsl::span< const u32 > addresses)
u32 Address(size_t i) const
gsl::span< T > Data() const
void EnsureBounds(size_t i) const
gsl::span< T > UnsafePartitionSpan(size_t i) const
gsl::span< const u32 > Addresses() const
gsl::span< const size_t > fOffsets
PartitionedSpan(const std::vector< T, Allocator > &container, gsl::span< const size_t > offsets, gsl::span< const u32 > addresses)
size_t Size(size_t i) const
PartitionedSpan(gsl::span< T > data, gsl::span< const size_t > offsets, gsl::span< const u32 > addresses)
static constexpr size_t NullOffset[1]
gsl::span< const u32 > fAdresses
size_t UnsafeSize(size_t i) const
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 u32 >) -> PartitionedSpan< T >
std::uint32_t u32
Definition Definitions.h:21