Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
hetero-data.hpp
Go to the documentation of this file.
1/*
2 HETERO-DATA.hpp - handle chain of heterogeneous data blocks
3
4 Copyright (C)
5 2024, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12*/
13
14
69#ifndef LIB_HETERO_DATA_H
70#define LIB_HETERO_DATA_H
71
72
73#include "lib/error.hpp"
74#include "lib/nocopy.hpp"
75#include "lib/meta/typelist.hpp"
79
80#include <utility>
81#include <tuple>
82
83
84namespace lib {
85
93 template<typename...DATA>
94 class HeteroData;
95
99 {
100 StorageLoc* next{nullptr};
101 };
102
104 template<size_t seg, typename...DATA>
106 : protected StorageLoc
107 , std::tuple<DATA...>
108 {
109 using Tuple = std::tuple<DATA...>;
110
111 using Tuple::tuple;
112
113 template<typename SPEC>
115 template<typename SPEC>
117
118 template<size_t slot> auto& get() noexcept { return std::get<slot>(*this); }
119 template<typename X> auto& get() noexcept { return std::get<X>(*this); }
120 };
121
122
129 template<size_t seg, typename...DATA, class TAIL>
130 class HeteroData<meta::Node<StorageFrame<seg, DATA...>,TAIL>>
131 : StorageFrame<seg, DATA...>
132 {
135 using Tuple = std::tuple<DATA...>;
136 using Frame = StorageFrame<seg, DATA...>;
137
138 static constexpr size_t localSiz = sizeof...(DATA);
139
140 template<size_t slot>
141 static constexpr bool isLocal = slot < localSiz;
142
143 template<size_t slot>
144 using PickType = std::conditional_t<isLocal<slot>, std::tuple_element<slot,Tuple>
145 , typename _Tail::template PickType<slot-localSiz>>;
146 // need to use this helper to prevent eager evaluation on Elm_t<i>
147 _Tail&
149 {
150 if (Frame::next == nullptr) // Halt system by breaking noexcept
151 throw lumiera::error::Fatal{"HeteroData storage logic broken: follow-up extent not(yet) allocated"};
152 return * reinterpret_cast<_Tail*> (Frame::next);
153 }
154
155 template<typename...SPEC>
156 static _Self&
158 {
159 return reinterpret_cast<_Self&> (frontChain);
160 }
161 template<typename...SPEC>
162 static _Self const&
163 recast (HeteroData<SPEC...> const& frontChain)
164 {
165 return reinterpret_cast<_Self const&> (frontChain);
166 }
167
168
169 template<typename...XX>
170 friend class HeteroData;
171
172 using Frame::Frame;
173
174
175 public:
176 HeteroData() = default;
177
178 static constexpr size_t
180 {
181 return localSiz + _Tail::size();
182 }
183
185 template<size_t slot>
187
188
190 template<size_t slot>
192 get() noexcept
193 {
194 static_assert (slot < size(), "HeteroData access index beyond defined data");
195 if constexpr (slot < localSiz)
196 return std::get<slot> (*this);
197 else
198 return accessTail().template get<slot-localSiz>();
199 }
200
201 template<size_t slot>
202 Elm_t<slot> const&
203 get() const noexcept
204 {
205 return const_cast<HeteroData*>(this)->get<slot>();
206 }
207
208
215 template<size_t slot>
216 struct Accessor
217 {
219
220 template<class SPEC>
221 static Type&
223 {
224 auto& fullChain = _Self::recast (frontEnd);
225 return fullChain.template get<slot>();
226 }
227
228 template<typename HH>
229 Type& operator() (HH& frontEnd) const { return Accessor::retrieveData (frontEnd); }
230 };
231
247 template<typename...VALS>
248 struct Chain
249 {
250 using Segments = meta::Node<Frame,TAIL>; // ◁———this type describes current chain structure
253 // ...and this would be the extended chain structure
254 template<typename...INIT>
255 static NewFrame
256 build (INIT&& ...initArgs)
257 {
258 return {initArgs ...}; // Note: NewFrame is non-copyable
259 }
260 template<typename...INIT>
261 static NewFrame&
262 emplace (void* storage, INIT&& ...initArgs)
263 {
264 return * new(storage) NewFrame{initArgs ...};
265 }
266
267 template<class HET>
268 static auto&
269 recast (HET& frontChain)
270 {
271 return ChainType::recast (frontChain);
272 }
273
274 template<typename...XVALS>
275 using ChainExtent = ChainType::template Chain<XVALS...>;
276
277 template<size_t slot>
278 using Accessor = ChainType::template Accessor<_Self::size()+slot>;
279
280 template<typename X>
281 using AccessorFor = Accessor<meta::indexOfType<X,VALS...>()>;
282 };
283 };
284
288 template<>
289 class HeteroData<meta::Nil>
290 {
291 public:
292 static size_t constexpr size() { return 0; }
293
294 template<size_t>
295 using Elm_t = void;
296 template<size_t>
297 using PickType = void;
298 };
299
300 /*************************************************************************/
306 template<typename...DATA>
308 : public HeteroData<meta::Node<StorageFrame<0, DATA...>, meta::Nil>>
309 {
311
312 public:
313 using NewFrame = _FrontBlock::Frame;
316
317 template<typename...INIT>
318 static HeteroData
319 build (INIT&& ...initArgs)
320 {
321 return {initArgs ...};
322 }
323 };
324
325
326 namespace {
340 inline StorageLoc*&
341 checkedTraversal (size_t segments, StorageLoc* last)
342 {
343 REQUIRE(last);
344 while (segments and last->next)
345 {
346 last = last->next;
347 --segments;
348 }
349 ASSERT (last->next == nullptr and segments == 1
350 ,"Failure to attach new data segment to HeteroData: "
351 "assumed type structure does not match real connectivity, "
352 "end-of-chain encountered with %d type segment(s) remaining"
353 , segments);
354 return last->next;
355 }
356
364 inline void
365 checkedDetach (size_t segments, StorageLoc* seg, void* chainBlock)
366 {
367 REQUIRE(seg);
368 while (segments and seg->next)
369 if (segments == 1 and seg->next == chainBlock)
370 {
371 seg->next = nullptr;
372 return;
373 }
374 else
375 {
376 seg = seg->next;
377 --segments;
378 }
379 NOTREACHED ("Failure to detach a data segment from HeteroData: "
380 "assumed type structure does not match real connectivity");
381 }
382 }//(End)helper
383
384
400 template<size_t seg, typename...DATA>
401 template<typename SPEC>
402 inline void
404 {
405 StorageLoc* firstSeg = reinterpret_cast<StorageLoc*> (&prefixChain);
406 StorageLoc*& lastLink = checkedTraversal (seg, firstSeg);
407 ENSURE (lastLink == nullptr);
408 lastLink = this;
409 }
410
412 template<size_t seg, typename...DATA>
413 template<typename SPEC>
414 inline void
416 {
417 StorageLoc* firstSeg = reinterpret_cast<StorageLoc*> (&prefixChain);
418 checkedDetach (seg, firstSeg, this);
419 }
420}// namespace lib
421
422
423
424
425namespace std { // Specialisation to support C++ »Tuple Protocol« and structured bindings.
426
428 template<typename...DATA>
429 struct tuple_size<lib::HeteroData<DATA...> >
430 : integral_constant<size_t, lib::HeteroData<DATA...>::size()>
431 { };
432
434 template<size_t I, typename...DATA>
435 struct tuple_element<I, lib::HeteroData<DATA...> >
436 {
437 using type = lib::HeteroData<DATA...>::template Elm_t<I>;
438 };
439 template<size_t I>
440 struct tuple_element<I, lib::HeteroData<lib::meta::Nil> >
441 {
442 static_assert ("accessing element-type of an empty HeteroData block");
443 };
444
445 // Note: deliberately NOT providing a free get<i> function.
446 // Overload resolution would fail, since it attempts to instantiate std::get<i>(tuple) as a candidate,
447 // which triggers an assertion failure when using an index valid only for the full chain, not the base tuple
448
449
451 template<size_t seg, typename...DATA>
452 struct tuple_size<lib::StorageFrame<seg,DATA...> >
453 : tuple_size<typename lib::StorageFrame<seg,DATA...>::Tuple>
454 { };
455
457 template<size_t I, size_t seg, typename...DATA>
458 struct tuple_element<I, lib::StorageFrame<seg,DATA...> >
459 : tuple_element<I, typename lib::StorageFrame<seg,DATA...>::Tuple>
460 { };
461
462 // no need to define an overload for std::get<i>
463 // (other than a template specialisation, it will use base-type conversion to std::tuple on its argument;
464
465}// namespace std
466#endif /*LIB_HETERO_DATA_H*/
static size_t constexpr size()
static _Self const & recast(HeteroData< SPEC... > const &frontChain)
static _Self & recast(HeteroData< SPEC... > &frontChain)
HeteroData()=default
< data elements shall be populated through the builder front-ends
PickType< slot >::type Elm_t
access type to reside in the given slot of the complete chain
Elm_t< slot > & get() noexcept
access data elements within complete chain by index pos
std::conditional_t< isLocal< slot >, std::tuple_element< slot, Tuple >, typename _Tail::template PickType< slot-localSiz > > PickType
A setup with chained data tuples residing in distributed storage.
_FrontBlock::Frame NewFrame
static HeteroData build(INIT &&...initArgs)
HeteroData< meta::Node< StorageFrame< 0, DATA... >, meta::Nil > > _FrontBlock
Derived specific exceptions within Lumiera's exception hierarchy.
Definition error.hpp:193
Any copy and copy construction prohibited.
Definition nocopy.hpp:38
Lumiera error handling (C++ interface).
void checkedDetach(size_t segments, StorageLoc *seg, void *chainBlock)
StorageLoc *& checkedTraversal(size_t segments, StorageLoc *last)
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
»Empty« mark
Definition typelist.hpp:82
Type list with head and tail; T ≡ Nil marks list end.
Definition typelist.hpp:90
Implementation namespace for support and library code.
STL namespace.
lib::HeteroData< DATA... >::template Elm_t< I > type
Mix-Ins to allow or prohibit various degrees of copying and cloning.
ChainType::template Accessor< _Self::size()+slot > Accessor
StorageFrame< meta::count< Segments >::value, VALS... > NewFrame
static NewFrame & emplace(void *storage, INIT &&...initArgs)
HeteroData< typename meta::Append< Segments, NewFrame >::List > ChainType
individual storage frame in a chain, holding a data tuple
void detachFrom(HeteroData< SPEC > &)
cleanly detach this storage frame from the HeteroData prefix-chain.
auto & get() noexcept
std::tuple< DATA... > Tuple
void linkInto(HeteroData< SPEC > &)
Attach a new storage frame at the end of an existing HeteroData-chain.
linked list of StorageFrame elements
StorageLoc * next
Metaprogramming: Helpers for manipulating lists-of-types.
Metaprogramming: simple helpers for working with lists-of-types.
A template metaprogramming technique for manipulating collections of types.
Some basic facilities for manipulating type sequences.