17#ifndef GUDHI_SIMPLE_MDSPAN_H_
18#define GUDHI_SIMPLE_MDSPAN_H_
24#include <initializer_list>
28#include <gudhi/Debug_utils.h>
32inline constexpr std::size_t dynamic_extent = std::numeric_limits<std::size_t>::max();
34template <
class IndexType, std::size_t... Extents>
39 template <std::
size_t v>
40 struct is_dynamic : std::integral_constant<std::size_t, 0> {};
43 struct is_dynamic<dynamic_extent> : std::integral_constant<std::size_t, 1> {};
45 template <std::
size_t I,
class T>
48 template <std::size_t I, std::size_t first, std::size_t... Tail>
49 struct dynamic_count<I, std::integer_sequence<std::size_t, first, Tail...> >
50 : std::integral_constant<std::size_t,
51 (is_dynamic<first>::value +
52 dynamic_count<I - 1, std::integer_sequence<std::size_t, Tail...>>::value)> {
55 template <std::size_t first, std::size_t... Tail>
56 struct dynamic_count<0, std::integer_sequence<std::size_t, first, Tail...> >
57 : std::integral_constant<std::size_t, is_dynamic<first>::value> {
60 template <std::
size_t first>
61 struct dynamic_count<0, std::integer_sequence<std::size_t, first> >
62 : std::integral_constant<std::size_t, is_dynamic<first>::value> {};
64 template <std::
size_t I,
class T>
67 template <std::size_t I, std::size_t first, std::size_t... Tail>
68 struct extent_value<I, std::integer_sequence<std::size_t, first, Tail...>>
69 : extent_value<I - 1, std::integer_sequence<std::size_t, Tail...>> {};
71 template <std::size_t first, std::size_t... Tail>
72 struct extent_value<0, std::integer_sequence<std::size_t, first, Tail...>>
73 : std::integral_constant<std::size_t, first> {};
75 template <
class T, T I, T N, T... integers>
76 struct dynamic_value_sequence {
77 using type =
typename dynamic_value_sequence<T, I + 1, N, integers..., dynamic_extent>::type;
80 template <
class T, T N, T... integers>
81 struct dynamic_value_sequence<T, N, N, integers...> {
82 using type = std::integer_sequence<T, integers...>;
85 template <
class IndexType, std::size_t... Pack>
86 constexpr auto dynamic_value_extents(std::integer_sequence<std::size_t, Pack...>)
88 return extents<IndexType, Pack...>();
91 template <
class IndexType, std::
size_t Rank>
92 constexpr auto dynamic_value_extents_value =
93 dynamic_value_extents<IndexType>((
typename Gudhi::detail::dynamic_value_sequence<std::size_t, 0, Rank>::type{}));
97template <
class IndexType, std::
size_t Rank>
98using dextents =
decltype(detail::dynamic_value_extents_value<IndexType, Rank>);
104template <
class IndexType, std::size_t... Extents>
108 using index_type = IndexType;
109 using size_type = std::make_unsigned_t<index_type>;
110 using rank_type = std::size_t;
113 static constexpr rank_type rank()
noexcept {
return sizeof...(Extents); }
115 static constexpr rank_type rank_dynamic()
noexcept
117 return detail::dynamic_count<rank() - 1, std::integer_sequence<std::size_t, Extents...> >::value;
120 static constexpr std::size_t static_extent(rank_type r)
noexcept
122 std::array<std::size_t,
sizeof...(Extents)> exts{Extents...};
126 constexpr index_type extent(rank_type r)
const noexcept
128 if (dynamic_extent_shifts_[r] < 0)
return static_extent(r);
129 return dynamic_extents_[dynamic_extent_shifts_[r]];
132 void update_dynamic_extent(rank_type r, index_type i){
133 if (dynamic_extent_shifts_[r] < 0)
throw std::invalid_argument(
"Given rank is not dynamic.");
134 dynamic_extents_[dynamic_extent_shifts_[r]] = i;
138 constexpr extents() noexcept : dynamic_extents_(), dynamic_extent_shifts_(_init_shifts()) {}
140 template <
class OtherIndexType, std::size_t... OtherExtents>
141 constexpr explicit extents(
const extents<OtherIndexType, OtherExtents...>& other) noexcept
142 : dynamic_extents_(), dynamic_extent_shifts_(_init_shifts())
144 for (rank_type r = 0; r < rank(); ++r) {
145 if (dynamic_extent_shifts_[r] >= 0) dynamic_extents_[dynamic_extent_shifts_[r]] = other.extent(r);
149 template <
class... OtherIndexTypes>
150 constexpr explicit extents(OtherIndexTypes... extents) noexcept
151 : dynamic_extents_{
static_cast<IndexType
>(extents)...}, dynamic_extent_shifts_(_init_shifts())
154 template <
class OtherIndexType, std::
size_t N>
155 constexpr explicit extents(
const std::array<OtherIndexType, N>& other) noexcept
156 : dynamic_extents_{other}, dynamic_extent_shifts_(_init_shifts())
160 template <
class OtherIndexType, std::size_t... OtherExtents>
161 friend constexpr bool operator==(
const extents& e1,
const extents<OtherIndexType, OtherExtents...>& e2)
noexcept
163 if (e1.rank() != e2.rank())
return false;
164 for (rank_type r = 0; r < rank(); ++r) {
165 if (e1.extent(r) != e2.extent(r))
return false;
170 friend void swap(extents& e1, extents& e2)
noexcept
172 e1.dynamic_extents_.swap(e2.dynamic_extents_);
173 e1.dynamic_extent_shifts_.swap(e2.dynamic_extent_shifts_);
176 friend std::ostream &operator<<(std::ostream &stream,
const extents &e)
178 stream <<
"[ " <<
sizeof...(Extents) <<
" ] ";
179 ((stream << Extents <<
' '), ...);
181 for (rank_type r = 0; r < e.rank(); ++r) stream << e.extent(r) <<
" ";
188 std::array<index_type, rank_dynamic()> dynamic_extents_;
189 std::array<int, rank()> dynamic_extent_shifts_;
191 static constexpr std::array<int, rank()> _init_shifts()
193 std::array<std::size_t,
sizeof...(Extents)> exts{Extents...};
194 std::array<int, rank()> res = {};
195 std::size_t index = 0;
196 for (rank_type i = 0; i < rank(); ++i) {
197 if (exts[i] == dynamic_extent) {
222 template<
class Extents>
226 using extents_type = Extents;
227 using index_type =
typename extents_type::index_type;
228 using size_type =
typename extents_type::size_type;
229 using rank_type =
typename extents_type::rank_type;
230 using layout_type = layout_right;
233 mapping() noexcept = default;
234 mapping(const mapping&) noexcept = default;
236 mapping(const extents_type& exts) noexcept : exts_(exts)
238 if constexpr (extents_type::rank() != 0) _initialize_strides();
241 mapping& operator=(
const mapping&)
noexcept =
default;
244 constexpr const extents_type& extents() const noexcept {
return exts_; }
246 index_type required_span_size() const noexcept
248 if constexpr (extents_type::rank() == 0)
return 0;
249 else return ext_shifts_[0] * exts_.extent(0);
252 template <
class... Indices>
253 constexpr index_type operator()(Indices... indices)
const
255 return operator()({
static_cast<index_type
>(indices)...});
258 template <
class IndexRange = std::initializer_list<index_type> >
259 constexpr index_type operator()(
const IndexRange& indices)
const
261 GUDHI_CHECK(indices.size() == extents_type::rank(),
"Wrong number of parameters.");
263 index_type newIndex = 0;
264 auto it = indices.begin();
265 GUDHI_CHECK_code(
unsigned int i = 0);
266 for (
auto stride : ext_shifts_) {
267 GUDHI_CHECK_code(GUDHI_CHECK(*it < exts_.extent(i),
"Out of bound index."));
268 newIndex += (stride * (*it));
270 GUDHI_CHECK_code(++i);
276 static constexpr bool is_always_unique() noexcept {
return true; }
278 static constexpr bool is_always_exhaustive() noexcept {
return true; }
280 static constexpr bool is_always_strided() noexcept {
return true; }
282 static constexpr bool is_unique() noexcept {
return true; }
284 static constexpr bool is_exhaustive() noexcept {
return true; }
286 static constexpr bool is_strided() noexcept {
return true; }
288 index_type stride(rank_type r)
const
290 GUDHI_CHECK(r < ext_shifts_.size(),
"Stride out of bound.");
291 return ext_shifts_[r];
294 friend bool operator==(
const mapping& m1,
const mapping& m2)
noexcept {
return m1.exts_ == m2.exts_; }
296 friend void swap(mapping& m1, mapping& m2)
noexcept
298 swap(m1.exts_, m2.exts_);
299 m1.ext_shifts_.swap(m2.ext_shifts_);
303 void update_extent(rank_type r, index_type new_value)
305 GUDHI_CHECK(r < extents_type::rank(),
"Index out of bound.");
306 exts_.update_dynamic_extent(r, new_value);
312 std::array<index_type,extents_type::rank()> ext_shifts_;
314 constexpr void _initialize_strides()
316 ext_shifts_[extents_type::rank() - 1] = 1;
317 for (
auto i = extents_type::rank() - 1; i > 0; --i) {
318 ext_shifts_[i - 1] = ext_shifts_[i] * exts_.extent(i);
322 constexpr void _update_strides(rank_type start)
324 for (
auto i = start; i > 0; --i) {
325 ext_shifts_[i - 1] = ext_shifts_[i] * exts_.extent(i);
345template <
typename T,
class Extents,
class LayoutPolicy = layout_right>
349 using layout_type = LayoutPolicy;
350 using mapping_type =
typename LayoutPolicy::template mapping<Extents>;
351 using extents_type = Extents;
352 using element_type = T;
353 using value_type = std::remove_cv_t<T>;
354 using index_type =
typename mapping_type::index_type;
355 using size_type =
typename mapping_type::size_type;
356 using rank_type =
typename mapping_type::rank_type;
357 using data_handle_type = T*;
358 using reference = T&;
360 Simple_mdspan() : ptr_(nullptr) {}
362 Simple_mdspan(
const Simple_mdspan& rhs) =
default;
363 Simple_mdspan(Simple_mdspan&& rhs) =
default;
365 template <
class... IndexTypes>
366 explicit Simple_mdspan(data_handle_type ptr, IndexTypes... exts)
367 : ptr_(ptr), map_(extents_type(exts...))
369 GUDHI_CHECK(ptr !=
nullptr || empty() || Extents::rank() == 0,
"Given pointer is not properly initialized.");
372 template <
class OtherIndexType,
size_t N>
373 constexpr explicit Simple_mdspan(data_handle_type ptr,
const std::array<OtherIndexType, N>& exts)
374 : ptr_(ptr), map_(extents_type(exts))
376 GUDHI_CHECK(ptr !=
nullptr || empty() || Extents::rank() == 0,
"Given pointer is not properly initialized.");
379 Simple_mdspan(data_handle_type ptr,
const mapping_type& m) : ptr_(ptr), map_(m) {}
381 Simple_mdspan& operator=(
const Simple_mdspan& rhs) =
default;
382 Simple_mdspan& operator=(Simple_mdspan&& rhs) =
default;
385 template <
class... IndexTypes>
386 constexpr reference operator()(IndexTypes... indices)
const
388 return operator[]({
static_cast<index_type
>(indices)...});
391 template <
class IndexRange = std::initializer_list<index_type> >
392 reference operator[](
const IndexRange& indices)
const
394 return *(ptr_ + map_(indices));
397 constexpr rank_type rank() noexcept {
return map_.extents().rank(); }
399 constexpr rank_type rank_dynamic() noexcept {
return map_.extents().rank_dynamic(); }
401 static constexpr std::size_t static_extent(rank_type r)
noexcept {
return extents_type::static_extent(r); }
403 constexpr index_type extent(rank_type r)
const
405 GUDHI_CHECK(r < map_.extents().rank(),
"Out of bound index.");
406 return map_.extents().extent(r);
409 constexpr size_type size() const noexcept {
return map_.required_span_size(); }
411 constexpr bool empty() const noexcept {
return map_.required_span_size() == 0; }
413 constexpr index_type stride(rank_type r)
const {
return map_.stride(r); }
415 constexpr const extents_type& extents() const noexcept {
return map_.extents(); }
417 constexpr const data_handle_type& data_handle() const noexcept {
return ptr_; }
419 constexpr const mapping_type& mapping() const noexcept {
return map_; }
422 static constexpr bool is_always_unique() {
return mapping_type::is_always_unique(); }
425 static constexpr bool is_always_exhaustive() {
return mapping_type::is_always_exhaustive(); }
428 static constexpr bool is_always_strided() {
return mapping_type::is_always_strided(); }
431 constexpr bool is_unique()
const {
return map_.is_unique(); }
434 constexpr bool is_exhaustive()
const {
return map_.is_exhaustive(); }
437 constexpr bool is_strided()
const {
return map_.is_strided(); }
439 friend constexpr void swap(Simple_mdspan& x, Simple_mdspan& y)
noexcept
441 std::swap(x.ptr_, y.ptr_);
442 swap(x.map_, y.map_);
447 void update_extent(rank_type r, index_type new_value) { map_.update_extent(r, new_value); }
450 void update_data(data_handle_type ptr)
452 GUDHI_CHECK(ptr !=
nullptr,
"Null pointer not valid input.");
457 data_handle_type ptr_;
461template <
class CArray>
462Simple_mdspan(CArray&)
463 -> Simple_mdspan<std::remove_all_extents_t<CArray>, Gudhi::extents<std::size_t, std::extent_v<CArray, 0>>>;
465template <
class Po
inter>
466Simple_mdspan(Pointer&&)
467 -> Simple_mdspan<std::remove_pointer_t<std::remove_reference_t<Pointer>>, Gudhi::extents<std::size_t>>;
469template <
class ElementType,
class... Integrals>
470explicit Simple_mdspan(ElementType*, Integrals...)
471 -> Simple_mdspan<ElementType, Gudhi::dextents<std::size_t,
sizeof...(Integrals)>>;
473template <
class ElementType,
class OtherIndexType, std::
size_t N>
474Simple_mdspan(ElementType*,
const std::array<OtherIndexType, N>&)
475 -> Simple_mdspan<ElementType, Gudhi::dextents<std::size_t, N>>;
477template <
class ElementType,
class IndexType, std::size_t... ExtentsPack>
478Simple_mdspan(ElementType*,
const Gudhi::extents<IndexType, ExtentsPack...>&)
479 -> Simple_mdspan<ElementType, Gudhi::extents<IndexType, ExtentsPack...>>;
481template <
class ElementType,
class MappingType>
482Simple_mdspan(ElementType*,
const MappingType&)
483 -> Simple_mdspan<ElementType, typename MappingType::extents_type, typename MappingType::layout_type>;
Reproduces the behaviour of C++23 std::extents class.
Definition simple_mdspan.h:106
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14