Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
branch-case.hpp
Go to the documentation of this file.
1/*
2 BRANCH-CASE.hpp - variant-like data type to capture different result types
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
73#ifndef LIB_BRANCH_CASE_H
74#define LIB_BRANCH_CASE_H
75
76
77#include "lib/meta/util.hpp"
78
79#include <utility>
80#include <cstddef>
81#include <tuple>
82
83namespace lib {
84
85 using std::move;
86 using std::forward;
87 using std::decay_t;
88 using std::tuple;
89
90
91 namespace {// Metaprogramming helper
92
93 template<typename...TYPES>
94 struct _MaxBuf;
95
96 template<>
97 struct _MaxBuf<>
98 {
99 static constexpr size_t siz = 0;
100 static constexpr size_t align = 0;
101 };
102
103 template<typename T, typename...TYPES>
104 struct _MaxBuf<T,TYPES...>
105 {
106 static constexpr size_t siz = std::max (sizeof(T),_MaxBuf<TYPES...>::siz);
107 static constexpr size_t align = std::max (alignof(T),_MaxBuf<TYPES...>::align);
108 };
109 }//(End)Meta-helper
110
111
112
113 /*********************************************************************/
121 template<typename...TYPES>
123 {
124 public:
125 static constexpr auto TOP = sizeof...(TYPES) -1;
126 static constexpr auto SIZ = _MaxBuf<TYPES...>::siz;
127
128 template<size_t idx>
129 using SlotType = std::tuple_element_t<idx, tuple<TYPES...>>;
130
131 protected:
132 BranchCase() = default;
133
135 size_t branch_{0};
136
139 alignas(_MaxBuf<TYPES...>::align)
140 std::byte buffer_[SIZ];
141
142
143 template<typename TX, typename...INITS>
144 TX&
145 emplace (INITS&&...inits)
146 {
147 return * new(&buffer_) TX(forward<INITS> (inits)...);
148 }
149
150 template<typename TX>
151 TX&
153 {
154 return * std::launder (reinterpret_cast<TX*> (&buffer_[0]));
155 }
156
158 template<size_t idx, class FUN>
159 auto
160 selectBranch (FUN&& fun)
161 {
162 if constexpr (0 < idx)
163 if (branch_ < idx)
164 return selectBranch<idx-1> (forward<FUN>(fun));
165 return fun (get<idx>());
166 }
167
168
169 public:
176 template<class FUN>
177 auto
178 accept (FUN&& visitor)
179 {
180 return selectBranch<TOP> (forward<FUN> (visitor));
181 }
182
184 {
185 accept ([this](auto& it)
186 { using Elm = decay_t<decltype(it)>;
187 access<Elm>().~Elm();
188 });
189 }
190
192 template<typename...INITS>
193 BranchCase (size_t idx, INITS&& ...inits)
194 : branch_{idx}
195 {
196 accept ([&,this](auto& it)
197 { using Elm = decay_t<decltype(it)>;
198 if constexpr (std::is_constructible_v<Elm,INITS...>)
199 this->emplace<Elm> (forward<INITS> (inits)...);
200 });
201 }
202
204 {
205 branch_ = o.branch_;
206 BranchCase& unConst = const_cast<BranchCase&> (o);
207 unConst.accept ([this](auto& it)
208 { using Elm = decay_t<decltype(it)>;
209 this->emplace<Elm> (it);
210 });
211 }
212
214 {
215 branch_ = ro.branch_;
216 ro.accept ([this](auto& it)
217 { using Elm = decay_t<decltype(it)>;
218 this->emplace<Elm> (move (it));
219 });
220 }
221
222 friend void
224 {
225 using std::swap;
226 BranchCase tmp;
227 tmp.branch_ = o1.branch_;
228 o1.accept ([&](auto& it)
229 { using Elm = decay_t<decltype(it)>;
230 tmp.emplace<Elm> (move (o1.access<Elm>()));
231 });
232 swap (o1.branch_,o2.branch_);
233 o1.accept ([&](auto& it)
234 { using Elm = decay_t<decltype(it)>;
235 o1.emplace<Elm> (move (o2.access<Elm>()));
236 });
237 o2.accept ([&](auto& it)
238 { using Elm = decay_t<decltype(it)>;
239 o2.emplace<Elm> (move (tmp.access<Elm>()));
240 });
241 }
242
245 {
246 swap (*this, ref);
247 return *this;
248 }
249
250
251 size_t
252 selected() const
253 {
254 return branch_;
255 }
256
260 template<size_t idx>
261 SlotType<idx>&
263 {
264 return access<SlotType<idx>>();
265 }
266
270 auto
272 {
273 return accept([](auto val){ return val; });
274 }
275 };
276
277}// namespace lib
278#endif/*LIB_BRANCH_CASE_H*/
A Sum Type to hold alternative results from a branched evaluation.
SlotType< idx > & get()
re-access the value, using compile-time slot-index param.
TX & emplace(INITS &&...inits)
size_t selected() const
BranchCase(BranchCase &&ro)
std::byte buffer_[SIZ]
opaque inline storage buffer with suitable size and alignment
static constexpr auto SIZ
friend void swap(BranchCase &o1, BranchCase &o2)
BranchCase(size_t idx, INITS &&...inits)
Standard constructor: select branch and provide initialiser.
BranchCase(BranchCase const &o)
size_t branch_
selector field to designate the chosen branch
BranchCase()=default
auto getAny()
access the selected value of a homogeneous model.
auto selectBranch(FUN &&fun)
apply generic functor to the currently selected branch
auto accept(FUN &&visitor)
Accept a visitor-functor (double dispatch).
BranchCase & operator=(BranchCase ref)
static constexpr auto TOP
std::tuple_element_t< idx, tuple< TYPES... > > SlotType
Simple and lightweight helpers for metaprogramming and type detection.
Implementation namespace for support and library code.