Library: try out building a variant-model on top
* the implementation of this ''Sum Type'' got quite technical and complicated; thus better to be extracted as separate library component * use this as base for the `AltModel` * make a usage sketch, invoking only the model interactions required
This commit is contained in:
parent
8c046ee2ea
commit
d052edf91d
6 changed files with 949 additions and 204 deletions
566
src/lib/branch-case.hpp
Normal file
566
src/lib/branch-case.hpp
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
/*
|
||||
BRANCH-CASE.hpp - helpers for parsing textual specifications
|
||||
|
||||
Copyright (C)
|
||||
2024, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
**Lumiera** is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version. See the file COPYING for further details.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/** @file branch-case.hpp
|
||||
** Convenience wrappers and definitions for parsing structured definitions.
|
||||
** Whenever a specification syntax entails nested structures, extracting contents
|
||||
** with regular expressions alone becomes tricky. Without much sophistication, a
|
||||
** directly implemented simple recursive descent parser is often less brittle and
|
||||
** easier to understand and maintain. With some helper abbreviations, notably
|
||||
** a combinator scheme to work from building blocks, a hand-written solution
|
||||
** can benefit from taking short-cuts, especially related to result bindings.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_BRANCH_CASE_H
|
||||
#define LIB_BRANCH_CASE_H
|
||||
|
||||
|
||||
#include "lib/iter-adapter.hpp"
|
||||
#include "lib/meta/function.hpp"
|
||||
#include "lib/meta/trait.hpp"
|
||||
#include "lib/regex.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
|
||||
namespace util {
|
||||
namespace parse {
|
||||
|
||||
using std::move;
|
||||
using std::forward;
|
||||
using std::optional;
|
||||
using lib::meta::_Fun;
|
||||
using lib::meta::has_Sig;
|
||||
using lib::meta::NullType;
|
||||
using std::decay_t;
|
||||
using std::tuple;
|
||||
using std::array;
|
||||
|
||||
using StrView = std::string_view;
|
||||
|
||||
template<typename...TYPES>
|
||||
struct _MaxBufSiz;
|
||||
template<>
|
||||
struct _MaxBufSiz<>
|
||||
{
|
||||
static constexpr size_t siz = 0;
|
||||
};
|
||||
template<typename T, typename...TYPES>
|
||||
struct _MaxBufSiz<T,TYPES...>
|
||||
{
|
||||
static constexpr size_t siz = std::max (sizeof(T)
|
||||
,_MaxBufSiz<TYPES...>::siz);
|
||||
};
|
||||
|
||||
template<typename...TYPES>
|
||||
class BranchCase
|
||||
{
|
||||
public:
|
||||
static constexpr auto TOP = sizeof...(TYPES) -1;
|
||||
static constexpr auto SIZ = _MaxBufSiz<TYPES...>::siz;
|
||||
|
||||
template<size_t idx>
|
||||
using SlotType = std::tuple_element_t<idx, tuple<TYPES...>>;
|
||||
|
||||
protected:
|
||||
/** @internal default-created state is **invalid** */
|
||||
BranchCase() = default;
|
||||
|
||||
|
||||
size_t branch_{0};
|
||||
|
||||
alignas(int64_t)
|
||||
std::byte buffer_[SIZ];
|
||||
|
||||
template<typename TX, typename...INITS>
|
||||
TX&
|
||||
emplace (INITS&&...inits)
|
||||
{
|
||||
return * new(&buffer_) TX(forward<INITS> (inits)...);
|
||||
}
|
||||
|
||||
template<typename TX>
|
||||
TX&
|
||||
access ()
|
||||
{
|
||||
return * std::launder (reinterpret_cast<TX*> (&buffer_[0]));
|
||||
}
|
||||
|
||||
/** apply generic functor to the currently selected branch */
|
||||
template<size_t idx, class FUN>
|
||||
auto
|
||||
selectBranch (FUN&& fun)
|
||||
{
|
||||
if constexpr (0 < idx)
|
||||
if (branch_ < idx)
|
||||
return selectBranch<idx-1> (forward<FUN>(fun));
|
||||
return fun (get<idx>());
|
||||
}
|
||||
|
||||
public:
|
||||
template<class FUN>
|
||||
auto
|
||||
apply (FUN&& fun)
|
||||
{
|
||||
return selectBranch<TOP> (forward<FUN> (fun));
|
||||
}
|
||||
|
||||
~BranchCase()
|
||||
{
|
||||
apply ([this](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
access<Elm>().~Elm();
|
||||
});
|
||||
}
|
||||
|
||||
template<typename...INITS>
|
||||
BranchCase (size_t idx, INITS&& ...inits)
|
||||
: branch_{idx}
|
||||
{
|
||||
apply ([&,this](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
if constexpr (std::is_constructible_v<Elm,INITS...>)
|
||||
this->emplace<Elm> (forward<INITS> (inits)...);
|
||||
});
|
||||
}
|
||||
|
||||
BranchCase (BranchCase const& o)
|
||||
{
|
||||
branch_ = o.branch_;
|
||||
BranchCase& unConst = const_cast<BranchCase&> (o);
|
||||
unConst.apply ([this](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
this->emplace<Elm> (it);
|
||||
});
|
||||
}
|
||||
|
||||
BranchCase (BranchCase && ro)
|
||||
{
|
||||
branch_ = ro.branch_;
|
||||
ro.apply ([this](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
this->emplace<Elm> (move (it));
|
||||
});
|
||||
}
|
||||
|
||||
friend void
|
||||
swap (BranchCase& o1, BranchCase o2)
|
||||
{
|
||||
using std::swap;
|
||||
BranchCase tmp;
|
||||
o1.apply ([&](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
tmp.emplace<Elm> (move (o1.access<Elm>()));
|
||||
});
|
||||
swap (o1.branch_,o2.branch_);
|
||||
o1.apply ([&](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
o1.emplace<Elm> (move (o2.access<Elm>()));
|
||||
});
|
||||
o2.apply ([&](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
o2.emplace<Elm> (move (tmp.access<Elm>()));
|
||||
});
|
||||
}
|
||||
|
||||
BranchCase&
|
||||
operator= (BranchCase ref)
|
||||
{
|
||||
swap (*this, ref);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename...MORE>
|
||||
auto
|
||||
moveExtended()
|
||||
{
|
||||
using Extended = BranchCase<TYPES...,MORE...>;
|
||||
Extended& upFaked = reinterpret_cast<Extended&> (*this);
|
||||
return Extended (move (upFaked));
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
selected() const
|
||||
{
|
||||
return branch_;
|
||||
}
|
||||
|
||||
template<size_t idx>
|
||||
SlotType<idx>&
|
||||
get()
|
||||
{
|
||||
return access<SlotType<idx>>();
|
||||
}
|
||||
};
|
||||
|
||||
#if false ///////////////////////////////////////////////////////////////////////////////TODO accommodate
|
||||
/**
|
||||
*/
|
||||
template<class RES>
|
||||
struct Eval
|
||||
{
|
||||
using Result = RES;
|
||||
optional<RES> result;
|
||||
size_t consumed{0};
|
||||
};
|
||||
|
||||
template<class FUN>
|
||||
struct Connex
|
||||
: util::NonAssign
|
||||
{
|
||||
using PFun = FUN;
|
||||
PFun parse;
|
||||
|
||||
using Result = typename _Fun<PFun>::Ret::Result;
|
||||
|
||||
Connex (FUN&& pFun)
|
||||
: parse{move(pFun)}
|
||||
{ }
|
||||
};
|
||||
|
||||
auto
|
||||
buildConnex(NullType)
|
||||
{
|
||||
return Connex{[](StrView) -> Eval<NullType>
|
||||
{
|
||||
return {NullType{}};
|
||||
}};
|
||||
}
|
||||
using NulP = decltype(buildConnex (NullType()));
|
||||
|
||||
auto
|
||||
buildConnex (regex rex)
|
||||
{
|
||||
return Connex{[regEx = move(rex)]
|
||||
(StrView toParse) -> Eval<smatch>
|
||||
{ // skip leading whitespace...
|
||||
size_t pre = leadingWhitespace (toParse);
|
||||
toParse = toParse.substr(pre);
|
||||
auto result{matchAtStart (toParse,regEx)};
|
||||
size_t consumed = result? pre+result->length() : 0;
|
||||
return {move(result), consumed};
|
||||
}};
|
||||
}
|
||||
using Term = decltype(buildConnex (std::declval<regex>()));
|
||||
|
||||
Term
|
||||
buildConnex (string const& rexDef)
|
||||
{
|
||||
return buildConnex (regex{rexDef});
|
||||
}
|
||||
|
||||
template<class FUN>
|
||||
auto
|
||||
buildConnex (Connex<FUN> const& anchor)
|
||||
{
|
||||
return Connex{anchor};
|
||||
}
|
||||
template<class FUN>
|
||||
auto
|
||||
buildConnex (Connex<FUN> && anchor)
|
||||
{
|
||||
return Connex{move(anchor)};
|
||||
}
|
||||
|
||||
|
||||
template<class CON, class BIND>
|
||||
auto
|
||||
adaptConnex (CON&& connex, BIND&& modelBinding)
|
||||
{
|
||||
using RX = typename CON::Result;
|
||||
using Arg = lib::meta::_FunArg<BIND>;
|
||||
static_assert (std::is_constructible_v<Arg,RX>,
|
||||
"Model binding must accept preceding model result.");
|
||||
using AdaptedRes = typename _Fun<BIND>::Ret;
|
||||
return Connex{[origConnex = forward<CON>(connex)
|
||||
,binding = forward<BIND>(modelBinding)
|
||||
]
|
||||
(StrView toParse) -> Eval<AdaptedRes>
|
||||
{
|
||||
auto eval = origConnex.parse (toParse);
|
||||
if (eval.result)
|
||||
return {binding (move (*eval.result))};
|
||||
else
|
||||
return {std::nullopt};
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
/* ===== building structured models ===== */
|
||||
|
||||
/**
|
||||
* Product Model : results from a conjunction of parsing clauses,
|
||||
* which are to be accepted in sequence, one after the other.
|
||||
*/
|
||||
template<typename...RESULTS>
|
||||
struct SeqModel
|
||||
: tuple<RESULTS...>
|
||||
{
|
||||
static constexpr size_t SIZ = sizeof...(RESULTS);
|
||||
using Seq = lib::meta::TySeq<RESULTS...>;
|
||||
using Tup = std::tuple<RESULTS...>;
|
||||
|
||||
SeqModel() = default;
|
||||
|
||||
template<typename...XS, typename XX>
|
||||
SeqModel (SeqModel<XS...>&& seq, XX&& extraElm)
|
||||
: Tup{std::tuple_cat (seq.extractTuple()
|
||||
,make_tuple (forward<XX> (extraElm)) )}
|
||||
{ }
|
||||
|
||||
template<typename X1, typename X2>
|
||||
SeqModel (X1&& res1, X2&& res2)
|
||||
: Tup{move(res1), move(res2)}
|
||||
{ }
|
||||
|
||||
Tup&& extractTuple() { return move(*this); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Sum Model : results from a disjunction of parsing clauses,
|
||||
* which are are tested and accepted as alternatives, one at least.
|
||||
*/
|
||||
template<typename...CASES>
|
||||
struct AltModel
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Special case Product Model to represent iterative sequence */
|
||||
template<typename RES>
|
||||
struct IterModel
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
/** Marker-Tag for the result from a sub-expression, not to be joined */
|
||||
template<typename RES>
|
||||
struct SubModel
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
/** Standard case : combinator of two model branches */
|
||||
template<template<class...> class TAG, class R1, class R2 =void>
|
||||
struct _Join
|
||||
{
|
||||
using Result = TAG<R1,R2>;
|
||||
};
|
||||
|
||||
/** Generic case : extend a structured model by further branch */
|
||||
template<template<class...> class TAG, class...RS, class R2>
|
||||
struct _Join<TAG,TAG<RS...>,R2>
|
||||
{
|
||||
using Result = TAG<RS...,R2>;
|
||||
};
|
||||
|
||||
/** Special Case : absorb sub-expression without flattening */
|
||||
template<template<class...> class TAG, class R1, class R2>
|
||||
struct _Join<TAG,SubModel<R1>,R2>
|
||||
{
|
||||
using Result = TAG<R1,R2>;
|
||||
};
|
||||
template<template<class...> class TAG, class R1, class R2>
|
||||
struct _Join<TAG,R1, SubModel<R2>>
|
||||
{
|
||||
using Result = TAG<R1,R2>;
|
||||
};
|
||||
template<template<class...> class TAG, class R1, class R2>
|
||||
struct _Join<TAG,SubModel<R1>,SubModel<R2>>
|
||||
{
|
||||
using Result = TAG<R1,R2>;
|
||||
};
|
||||
|
||||
/** Special Case : absorb further similar elements into IterModel */
|
||||
template<class RES>
|
||||
struct _Join<IterModel, IterModel<RES>, RES>
|
||||
{
|
||||
using Result = IterModel<RES>;
|
||||
};
|
||||
|
||||
|
||||
/** accept sequence of two parse functions */
|
||||
template<class C1, class C2>
|
||||
auto
|
||||
sequenceConnex (C1&& connex1, C2&& connex2)
|
||||
{
|
||||
using R1 = typename decay_t<C1>::Result;
|
||||
using R2 = typename decay_t<C2>::Result;
|
||||
using ProductResult = typename _Join<SeqModel, R1, R2>::Result;
|
||||
using ProductEval = Eval<ProductResult>;
|
||||
return Connex{[conL = forward<C1>(connex1)
|
||||
,conR = forward<C2>(connex2)
|
||||
]
|
||||
(StrView toParse) -> ProductEval
|
||||
{
|
||||
auto eval1 = conL.parse (toParse);
|
||||
if (eval1.result)
|
||||
{
|
||||
size_t posAfter1 = eval1.consumed;
|
||||
StrView restInput = toParse.substr(posAfter1);
|
||||
auto eval2 = conR.parse (restInput);
|
||||
if (eval2.result)
|
||||
{
|
||||
uint consumedOverall = posAfter1 + eval2.consumed;
|
||||
return ProductEval{ProductResult{move(*eval1.result)
|
||||
,move(*eval2.result)}
|
||||
,consumedOverall
|
||||
};
|
||||
}
|
||||
}
|
||||
return ProductEval{std::nullopt};
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
template<class PAR>
|
||||
class Syntax;
|
||||
|
||||
|
||||
template<class CON>
|
||||
class Parser
|
||||
: public CON
|
||||
{
|
||||
using PFun = typename CON::PFun;
|
||||
static_assert (_Fun<PFun>(), "Connex must define a parse-function");
|
||||
|
||||
public:
|
||||
using Connex = CON;
|
||||
using Result = typename CON::Result;
|
||||
|
||||
using Sigi = typename _Fun<PFun>::Sig;
|
||||
//lib::test::TypeDebugger<Sigi> buggi;
|
||||
//lib::test::TypeDebugger<Result> guggi;
|
||||
|
||||
static_assert (has_Sig<PFun, Eval<Result>(StrView)>()
|
||||
,"Signature of the parse-function not suitable");
|
||||
|
||||
Eval<Result>
|
||||
operator() (StrView toParse)
|
||||
{
|
||||
return CON::parse (toParse);
|
||||
}
|
||||
|
||||
template<typename SPEC>
|
||||
Parser (SPEC&& spec)
|
||||
: CON{buildConnex (forward<SPEC> (spec))}
|
||||
{ }
|
||||
|
||||
// template<class PAR>
|
||||
// Parser (Syntax<PAR> const& anchor)
|
||||
// : CON{anchor}
|
||||
// { }
|
||||
// template<class PAR>
|
||||
// Parser (CON const& anchor)
|
||||
// : CON{anchor}
|
||||
// { }
|
||||
};
|
||||
|
||||
Parser(NullType) -> Parser<NulP>;
|
||||
Parser(regex &&) -> Parser<Term>;
|
||||
Parser(regex const&) -> Parser<Term>;
|
||||
Parser(string const&) -> Parser<Term>;
|
||||
|
||||
template<class FUN>
|
||||
Parser(Connex<FUN> const&) -> Parser<Connex<FUN>>;
|
||||
//
|
||||
// template<class PAR>
|
||||
// Parser(Syntax<PAR> const&) -> Parser<typename PAR::Connex>;
|
||||
|
||||
|
||||
template<class PAR>
|
||||
class Syntax
|
||||
: public Eval<typename PAR::Result>
|
||||
{
|
||||
PAR parse_;
|
||||
|
||||
public:
|
||||
using Connex = typename PAR::Connex;
|
||||
using Result = typename PAR::Result;
|
||||
|
||||
bool success() const { return bool(Syntax::result); }
|
||||
bool hasResult() const { return bool(Syntax::result); }
|
||||
Result& getResult() { return * Syntax::result; }
|
||||
Result&& extractResult(){ return move(getResult()); }
|
||||
|
||||
Syntax()
|
||||
: parse_{NullType()}
|
||||
{ }
|
||||
|
||||
explicit
|
||||
Syntax (PAR&& parser)
|
||||
: parse_{move (parser)}
|
||||
{ }
|
||||
|
||||
explicit
|
||||
operator bool() const
|
||||
{
|
||||
return success();
|
||||
}
|
||||
|
||||
Syntax&&
|
||||
parse (StrView toParse)
|
||||
{
|
||||
eval() = parse_(toParse);
|
||||
return move(*this);
|
||||
}
|
||||
|
||||
Connex const&
|
||||
getConny() const
|
||||
{
|
||||
return parse_;
|
||||
}
|
||||
|
||||
template<typename SPEC>
|
||||
auto
|
||||
seq (SPEC&& clauseDef)
|
||||
{
|
||||
return accept(
|
||||
sequenceConnex (move(parse_)
|
||||
,Parser{forward<SPEC> (clauseDef)}));
|
||||
}
|
||||
|
||||
private:
|
||||
Eval<Result>&
|
||||
eval()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename SPEC>
|
||||
auto
|
||||
accept (SPEC&& clauseDef)
|
||||
{
|
||||
return Syntax{Parser{forward<SPEC> (clauseDef)}};
|
||||
}
|
||||
|
||||
// template<class PAR>
|
||||
// Parser(Syntax<PAR> const&) -> Parser<typename PAR::Connex>;
|
||||
|
||||
#endif /////////////////////////////////////////////////////////////////////////////////////TODO accommodate
|
||||
}// namespace parse
|
||||
|
||||
//using parse::accept;
|
||||
}// namespace util
|
||||
|
||||
namespace lib {
|
||||
}// namespace lib
|
||||
#endif/*LIB_BRANCH_CASE_H*/
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
#define LIB_PARSE_H
|
||||
|
||||
|
||||
#include "lib/iter-adapter.hpp"
|
||||
#include "lib/branch-case.hpp"
|
||||
#include "lib/meta/function.hpp"
|
||||
#include "lib/meta/trait.hpp"
|
||||
#include "lib/regex.hpp"
|
||||
|
|
@ -53,158 +53,6 @@ namespace util {
|
|||
|
||||
using StrView = std::string_view;
|
||||
|
||||
template<typename...TYPES>
|
||||
struct _MaxBufSiz;
|
||||
template<>
|
||||
struct _MaxBufSiz<>
|
||||
{
|
||||
static constexpr size_t siz = 0;
|
||||
};
|
||||
template<typename T, typename...TYPES>
|
||||
struct _MaxBufSiz<T,TYPES...>
|
||||
{
|
||||
static constexpr size_t siz = std::max (sizeof(T)
|
||||
,_MaxBufSiz<TYPES...>::siz);
|
||||
};
|
||||
|
||||
template<typename...TYPES>
|
||||
class BranchCase
|
||||
{
|
||||
public:
|
||||
static constexpr auto TOP = sizeof...(TYPES) -1;
|
||||
static constexpr auto SIZ = _MaxBufSiz<TYPES...>::siz;
|
||||
|
||||
template<size_t idx>
|
||||
using SlotType = std::tuple_element_t<idx, tuple<TYPES...>>;
|
||||
|
||||
protected:
|
||||
size_t branch_{0};
|
||||
|
||||
alignas(int64_t)
|
||||
std::byte buffer_[SIZ];
|
||||
|
||||
template<typename TX, typename...INITS>
|
||||
TX&
|
||||
emplace (INITS&&...inits)
|
||||
{
|
||||
return * new(&buffer_) TX(forward<INITS> (inits)...);
|
||||
}
|
||||
|
||||
template<typename TX>
|
||||
TX&
|
||||
access ()
|
||||
{
|
||||
return * std::launder (reinterpret_cast<TX*> (&buffer_[0]));
|
||||
}
|
||||
|
||||
/** apply generic functor to the currently selected branch */
|
||||
template<size_t idx, class FUN>
|
||||
auto
|
||||
selectBranch (FUN&& fun)
|
||||
{
|
||||
if constexpr (0 < idx)
|
||||
if (branch_ < idx)
|
||||
return selectBranch<idx-1> (forward<FUN>(fun));
|
||||
return fun (get<idx>());
|
||||
}
|
||||
|
||||
BranchCase() = default;
|
||||
public:
|
||||
template<class FUN>
|
||||
auto
|
||||
apply (FUN&& fun)
|
||||
{
|
||||
return selectBranch<TOP> (forward<FUN> (fun));
|
||||
}
|
||||
|
||||
~BranchCase()
|
||||
{
|
||||
apply ([this](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
access<Elm>().~Elm();
|
||||
});
|
||||
}
|
||||
|
||||
template<typename...INITS>
|
||||
BranchCase (size_t idx, INITS&& ...inits)
|
||||
{
|
||||
branch_ = idx;
|
||||
apply ([&,this](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
emplace<Elm> (forward<INITS> (inits)...);
|
||||
});
|
||||
}
|
||||
|
||||
BranchCase (BranchCase const& o)
|
||||
{
|
||||
branch_ = o.branch_;
|
||||
BranchCase& unConst = const_cast<BranchCase&> (o);
|
||||
unConst.apply ([this](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
this->emplace<Elm> (it);
|
||||
});
|
||||
}
|
||||
|
||||
BranchCase (BranchCase && ro)
|
||||
{
|
||||
branch_ = ro.branch_;
|
||||
ro.apply ([this](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
this->emplace<Elm> (move (it));
|
||||
});
|
||||
}
|
||||
|
||||
friend void
|
||||
swap (BranchCase& o1, BranchCase o2)
|
||||
{
|
||||
using std::swap;
|
||||
BranchCase tmp;
|
||||
o1.apply ([&](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
tmp.emplace<Elm> (move (o1.access<Elm>()));
|
||||
});
|
||||
swap (o1.branch_,o2.branch_);
|
||||
o1.apply ([&](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
o1.emplace<Elm> (move (o2.access<Elm>()));
|
||||
});
|
||||
o2.apply ([&](auto& it)
|
||||
{ using Elm = decay_t<decltype(it)>;
|
||||
o2.emplace<Elm> (move (tmp.access<Elm>()));
|
||||
});
|
||||
}
|
||||
|
||||
BranchCase&
|
||||
operator= (BranchCase ref)
|
||||
{
|
||||
swap (*this, ref);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename...MORE>
|
||||
auto
|
||||
moveExtended()
|
||||
{
|
||||
using Extended = BranchCase<TYPES...,MORE...>;
|
||||
Extended& upFaked = reinterpret_cast<Extended&> (*this);
|
||||
return Extended (move (upFaked));
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
selected() const
|
||||
{
|
||||
return branch_;
|
||||
}
|
||||
|
||||
template<size_t idx>
|
||||
SlotType<idx>&
|
||||
get()
|
||||
{
|
||||
return access<SlotType<idx>>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
|
@ -334,8 +182,25 @@ namespace util {
|
|||
*/
|
||||
template<typename...CASES>
|
||||
struct AltModel
|
||||
: BranchCase<CASES...>
|
||||
{
|
||||
using _Model = BranchCase<CASES...>;
|
||||
|
||||
template<typename EX>
|
||||
using Additionally = AltModel<CASES...,EX>;
|
||||
|
||||
template<typename INIT, typename =lib::meta::disable_if_self<AltModel,INIT>>
|
||||
AltModel (INIT&& init)
|
||||
: _Model{_Model::TOP, forward<INIT> (init)}
|
||||
{ }
|
||||
|
||||
template<typename EX>
|
||||
Additionally<EX>
|
||||
addBranch()
|
||||
{
|
||||
Additionally<EX>& upFaked = reinterpret_cast<Additionally<EX>&> (*this);
|
||||
return {move (upFaked)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,12 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "CmdlineWrapper_test" CmdlineWrapper_test <<END
|
||||
TEST "Package result alternatives" BranchCase_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "passing the commandline" CmdlineWrapper_test <<END
|
||||
out-lit: wrapping cmdline:...
|
||||
out-lit: -->
|
||||
out-lit: wrapping cmdline:
|
||||
|
|
@ -43,7 +48,7 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "CustomSharedPtr_test" CustomSharedPtr_test <<END
|
||||
TEST "Adapted shared pointer" CustomSharedPtr_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
|
|
|||
251
tests/library/branch-case-test.cpp
Normal file
251
tests/library/branch-case-test.cpp
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
BranchCase(Test) - verify parsing textual specifications
|
||||
|
||||
Copyright (C)
|
||||
2024, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
**Lumiera** is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version. See the file COPYING for further details.
|
||||
|
||||
* *****************************************************************/
|
||||
|
||||
/** @file branch-case-test.cpp
|
||||
** unit test \ref BranchCase_test
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "lib/branch-case.hpp"
|
||||
//#include "lib/iter-explorer.hpp"
|
||||
//#include "lib/format-util.hpp"
|
||||
#include "lib/meta/tuple-helper.hpp"
|
||||
#include "lib/test/diagnostic-output.hpp"//////////////////TODO
|
||||
//#include "lib/util.hpp"
|
||||
|
||||
//#include <vector>
|
||||
//#include <memory>
|
||||
|
||||
|
||||
|
||||
namespace util {
|
||||
namespace parse{
|
||||
namespace test {
|
||||
|
||||
using lib::meta::is_Tuple;
|
||||
using std::get;
|
||||
// using util::join;
|
||||
// using util::isnil;
|
||||
// using std::vector;
|
||||
// using std::shared_ptr;
|
||||
// using std::make_shared;
|
||||
|
||||
// using LERR_(ITER_EXHAUST);
|
||||
// using LERR_(INDEX_BOUNDS);
|
||||
|
||||
|
||||
namespace { // test fixture
|
||||
|
||||
// const uint NUM_ELMS = 10;
|
||||
|
||||
// using Numz = vector<uint>;
|
||||
|
||||
} // (END)fixture
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/************************************************************************//**
|
||||
* @test verify helpers and shortcuts for simple recursive descent parsing
|
||||
* of structured data and specifications.
|
||||
*
|
||||
* @see parse.hpp
|
||||
* @see proc-node.cpp "usage example"
|
||||
*/
|
||||
class BranchCase_test : public Test
|
||||
{
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
simpleBlah();
|
||||
acceptAlternatives();
|
||||
}
|
||||
|
||||
|
||||
/** @test TODO just blah. */
|
||||
void
|
||||
simpleBlah ()
|
||||
{
|
||||
}
|
||||
|
||||
#if false ////////////////////////////////////////////////////////////////////////////TODO accommodate
|
||||
/** @test define a terminal symbol to match by parse. */
|
||||
void
|
||||
acceptTerminal()
|
||||
{
|
||||
// set up a parser function to accept some token as terminal
|
||||
auto parse = Parser{"hello (\\w+) world"};
|
||||
string toParse{"hello vile world of power"};
|
||||
auto eval = parse (toParse);
|
||||
CHECK (eval.result);
|
||||
auto res = *eval.result; // ◁——————————— the »result model« of a terminal parse is the RegExp-Matcher
|
||||
CHECK (res.ready() and not res.empty());
|
||||
CHECK (res.size() == "2"_expect );
|
||||
CHECK (res.position() == "0"_expect );
|
||||
CHECK (res.str() == "hello vile world"_expect );
|
||||
CHECK (res[1] == "vile"_expect );
|
||||
CHECK (res.suffix() == " of power"_expect );
|
||||
|
||||
auto syntax = Syntax{move (parse)}; // Build a syntax clause from the simple terminal symbol parser
|
||||
CHECK (not syntax.hasResult());
|
||||
syntax.parse (toParse);
|
||||
CHECK (syntax.success()); // Syntax clause holds an implicit state from the last parse
|
||||
CHECK (syntax.getResult()[1] == "vile"_expect);
|
||||
|
||||
// shorthand notation to start building a syntax
|
||||
auto syntax2 = accept ("(\\w+) world");
|
||||
CHECK (not syntax2.hasResult());
|
||||
syntax2.parse (toParse);
|
||||
CHECK (not syntax2.success());
|
||||
string bye{"cruel world"};
|
||||
syntax2.parse (bye);
|
||||
CHECK (syntax2.success());
|
||||
CHECK (syntax2.getResult()[1] == "cruel"_expect);
|
||||
|
||||
// going full circle: extract parser def from syntax
|
||||
// using Conn = decltype(syntax2)::Connex;
|
||||
// Conn conny{syntax2};
|
||||
// auto parse2 = Parser{conny};
|
||||
auto parse2 = Parser{syntax2.getConny()};
|
||||
CHECK (eval.result->str(1) == "vile");
|
||||
eval = parse2 (toParse);
|
||||
CHECK (not eval.result);
|
||||
eval = parse2 (bye);
|
||||
CHECK (eval.result->str(1) == "cruel");
|
||||
}
|
||||
|
||||
|
||||
/** @test define a sequence of syntax structures to match by parse. */
|
||||
void
|
||||
acceptSequential()
|
||||
{
|
||||
// Demonstration: how sequence combinator works....
|
||||
auto term1 = buildConnex ("hello");
|
||||
auto term2 = buildConnex ("world");
|
||||
auto parseSeq = [&](StrView toParse)
|
||||
{
|
||||
using R1 = decltype(term1)::Result;
|
||||
using R2 = decltype(term2)::Result;
|
||||
using ProductResult = std::tuple<R1,R2>;
|
||||
using ProductEval = Eval<ProductResult>;
|
||||
auto eval1 = term1.parse (toParse);
|
||||
if (eval1.result)
|
||||
{
|
||||
uint end1 = eval1.consumed;
|
||||
StrView restInput = toParse.substr(end1);
|
||||
auto eval2 = term2.parse (restInput);
|
||||
if (eval2.result)
|
||||
{
|
||||
uint consumedOverall = end1 + eval2.consumed;
|
||||
return ProductEval{ProductResult{move(*eval1.result)
|
||||
,move(*eval2.result)}
|
||||
,consumedOverall
|
||||
};
|
||||
}
|
||||
}
|
||||
return ProductEval{std::nullopt};
|
||||
};
|
||||
string s1{"hello millions"};
|
||||
string s2{"hello world"};
|
||||
string s3{" hello world trade "};
|
||||
|
||||
auto e1 = parseSeq(s1);
|
||||
CHECK (not e1.result); // Syntax 'hello'>>'world' does not accept "hello millions"
|
||||
auto e2 = parseSeq(s2);
|
||||
CHECK ( e2.result);
|
||||
|
||||
using SeqRes = std::decay_t<decltype(*e2.result)>; // Note: the result type depends on the actual syntax construction
|
||||
CHECK (is_Tuple<SeqRes>()); // Result model from sequence is the tuple of terminal results
|
||||
auto& [r1,r2] = *e2.result;
|
||||
CHECK (r1.str() == "hello"_expect);
|
||||
CHECK (r2.str() == "world"_expect);
|
||||
|
||||
CHECK (term2.parse(" world").result); // Note: leading whitespace skipped by the basic terminal parsers
|
||||
CHECK (term2.parse("\n \t world ").result);
|
||||
CHECK (not term2.parse(" old ").result);
|
||||
|
||||
|
||||
// DSL parse clause builder: a sequence of terminals...
|
||||
auto syntax = accept("hello").seq("world");
|
||||
|
||||
// Perform the same parse as demonstrated above....
|
||||
CHECK (not syntax.hasResult());
|
||||
syntax.parse(s1);
|
||||
CHECK (not syntax.success());
|
||||
syntax.parse(s2);
|
||||
CHECK (syntax);
|
||||
SeqRes seqModel = syntax.getResult();
|
||||
CHECK (get<0>(seqModel).str() == "hello"_expect);
|
||||
CHECK (get<1>(seqModel).str() == "world"_expect);
|
||||
|
||||
|
||||
// can build extended clause from existing one
|
||||
auto syntax2 = syntax.seq("trade");
|
||||
CHECK (not syntax2.hasResult());
|
||||
syntax2.parse(s2);
|
||||
CHECK (not syntax2.success());
|
||||
syntax2.parse(s3);
|
||||
CHECK (syntax2.success());
|
||||
auto seqModel2 = syntax2.getResult(); // Note: model of consecutive sequence is flattened into a single tuple
|
||||
CHECK (get<0>(seqModel2).str() == "hello"_expect);
|
||||
CHECK (get<1>(seqModel2).str() == "world"_expect);
|
||||
CHECK (get<2>(seqModel2).str() == "trade"_expect);
|
||||
}
|
||||
#endif /////////////////////////////////////////////////////////////////////////////////////TODO accommodate
|
||||
|
||||
/** @test TODO define alternative syntax structures to match by parse. */
|
||||
void
|
||||
acceptAlternatives()
|
||||
{
|
||||
using Branch = BranchCase<char,ushort>;
|
||||
SHOW_EXPR(sizeof(Branch));
|
||||
Branch b1{1, 42};
|
||||
SHOW_EXPR(b1.selected());
|
||||
SHOW_EXPR(b1.SIZ);
|
||||
SHOW_EXPR(b1.TOP);
|
||||
SHOW_EXPR(b1.get<1>());
|
||||
SHOW_EXPR(b1.get<0>());
|
||||
Branch b2{0,'x'};
|
||||
SHOW_EXPR(b2.selected());
|
||||
SHOW_EXPR(b2.get<1>());
|
||||
SHOW_EXPR(b2.get<0>());
|
||||
Branch b3{b1};
|
||||
SHOW_EXPR(b3.selected());
|
||||
SHOW_EXPR(b3.get<1>());
|
||||
SHOW_EXPR(b3.get<0>());
|
||||
b3 = b2;
|
||||
SHOW_EXPR(b3.selected());
|
||||
SHOW_EXPR(b3.get<1>());
|
||||
SHOW_EXPR(b3.get<0>());
|
||||
auto bx = b1.moveExtended<string>();
|
||||
SHOW_EXPR(sizeof(bx))
|
||||
SHOW_EXPR(bx.SIZ);
|
||||
SHOW_EXPR(bx.TOP);
|
||||
SHOW_EXPR(bx.selected());
|
||||
SHOW_EXPR(bx.get<1>());
|
||||
SHOW_EXPR(bx.get<0>());
|
||||
}
|
||||
};
|
||||
|
||||
LAUNCHER (BranchCase_test, "unit common");
|
||||
|
||||
|
||||
}}} // namespace util::parse::test
|
||||
|
||||
|
|
@ -216,33 +216,32 @@ namespace test {
|
|||
void
|
||||
acceptAlternatives()
|
||||
{
|
||||
using Branch = BranchCase<char,ushort>;
|
||||
SHOW_EXPR(sizeof(Branch));
|
||||
Branch b1{1, 42};
|
||||
SHOW_EXPR(b1.selected());
|
||||
SHOW_EXPR(b1.SIZ);
|
||||
SHOW_EXPR(b1.TOP);
|
||||
SHOW_EXPR(b1.get<1>());
|
||||
SHOW_EXPR(b1.get<0>());
|
||||
Branch b2{0,'x'};
|
||||
SHOW_EXPR(b2.selected());
|
||||
SHOW_EXPR(b2.get<1>());
|
||||
SHOW_EXPR(b2.get<0>());
|
||||
Branch b3{b1};
|
||||
SHOW_EXPR(b3.selected());
|
||||
SHOW_EXPR(b3.get<1>());
|
||||
SHOW_EXPR(b3.get<0>());
|
||||
b3 = b2;
|
||||
SHOW_EXPR(b3.selected());
|
||||
SHOW_EXPR(b3.get<1>());
|
||||
SHOW_EXPR(b3.get<0>());
|
||||
auto bx = b1.moveExtended<string>();
|
||||
SHOW_EXPR(sizeof(bx))
|
||||
SHOW_EXPR(bx.SIZ);
|
||||
SHOW_EXPR(bx.TOP);
|
||||
SHOW_EXPR(bx.selected());
|
||||
SHOW_EXPR(bx.get<1>());
|
||||
SHOW_EXPR(bx.get<0>());
|
||||
using R1 = char;
|
||||
using R2 = string;
|
||||
using R3 = double;
|
||||
|
||||
using A1 = AltModel<R1>;
|
||||
string s{"second"};
|
||||
using A2 = A1::Additionally<R2>;
|
||||
A2 model2{s};
|
||||
SHOW_EXPR(sizeof(A2));
|
||||
SHOW_EXPR(model2.SIZ);
|
||||
SHOW_EXPR(model2.TOP);
|
||||
SHOW_EXPR(model2.selected())
|
||||
SHOW_EXPR(model2.get<1>())
|
||||
using A3 = A2::Additionally<R3>;
|
||||
A3 model3{model2.addBranch<R3>()};
|
||||
SHOW_TYPE(A3)
|
||||
SHOW_EXPR(sizeof(A3));
|
||||
SHOW_EXPR(model3.SIZ);
|
||||
SHOW_EXPR(model3.TOP);
|
||||
SHOW_EXPR(model3.selected())
|
||||
SHOW_EXPR(model3.get<1>())
|
||||
auto res = move(model3);
|
||||
SHOW_TYPE(decltype(res))
|
||||
SHOW_EXPR(sizeof(res))
|
||||
SHOW_EXPR(res.selected())
|
||||
SHOW_EXPR(res.get<1>())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55960,19 +55960,21 @@
|
|||
<node CREATED="1737238022259" ID="ID_508598643" MODIFIED="1737238026071" TEXT="up-Copy">
|
||||
<node CREATED="1737238037257" ID="ID_1788967087" MODIFIED="1737238050739" TEXT="gegeben: AltModel<N>"/>
|
||||
<node CREATED="1737238051966" ID="ID_384770143" MODIFIED="1737238076015" TEXT="zu bauen: AltModel<N+1> mit kopierten Daten und gleichem Selektor"/>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1737238094329" ID="ID_1160578555" MODIFIED="1737238106552" TEXT="braucht Trampolin für konkrete Kopie">
|
||||
<node COLOR="#5b280f" CREATED="1737238094329" FOLDED="true" ID="ID_1160578555" MODIFIED="1737417012015" TEXT="braucht Trampolin für konkrete Kopie">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1737238147756" ID="ID_1597388632" MODIFIED="1737238159884" TEXT="statisches Array von Funktionspointern"/>
|
||||
<node CREATED="1737238206786" ID="ID_784811" MODIFIED="1737238220532" TEXT="generische Signatur void(void*,void*)"/>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1737238386277" ID="ID_499140874" MODIFIED="1737238392082" TEXT="ineffizient">
|
||||
<node BACKGROUND_COLOR="#dfd986" COLOR="#ad014c" CREATED="1737238386277" ID="ID_499140874" MODIFIED="1737416856790" TEXT="ineffizient">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1737238394241" ID="ID_1786923431" MODIFIED="1737238413594" TEXT="entweder haben wir N Teil-Arrays (Speicherverschwendung)"/>
|
||||
<node CREATED="1737238414398" ID="ID_1897860224" MODIFIED="1737238431951" TEXT="oder eine verkettete Liste von Closures (Laufzeitverschwendung)"/>
|
||||
<node CREATED="1737238441426" ID="ID_896531017" MODIFIED="1737238466027" TEXT="und im schlimmsten Fall auch noch N consecutive copies"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1737238578224" ID="ID_524632421" MODIFIED="1737238587563" TEXT="zu optimieren">
|
||||
<node COLOR="#5b280f" CREATED="1737238578224" FOLDED="true" ID="ID_524632421" MODIFIED="1737417010319" TEXT="zu optimieren">
|
||||
<icon BUILTIN="yes"/>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1737238589671" ID="ID_1560551329" MODIFIED="1737238601745" TEXT="Idee: Model-Binding in zwei Schritten">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1737238606619" ID="ID_1441095840" MODIFIED="1737238917781" TEXT="Teilergebnis + Selektor-Nr durchreichen">
|
||||
|
|
@ -55990,7 +55992,7 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1737242122676" ID="ID_486125380" MODIFIED="1737242129558" TEXT="es ist nicht so einfach">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1737242122676" ID="ID_486125380" MODIFIED="1737416836436" TEXT="es ist nicht so einfach">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1737242181419" ID="ID_699910063" MODIFIED="1737242197252" TEXT="wir geben nun mal über eine Kette verschachtelter Funktoren zurück"/>
|
||||
<node CREATED="1737242567334" ID="ID_1304062723" MODIFIED="1737242586617" TEXT="sobald der erzeugende Scope verlassen wird, ist nur noch ein Summen-Typ bekannt"/>
|
||||
|
|
@ -56024,14 +56026,15 @@
|
|||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1737244421643" ID="ID_1284583110" MODIFIED="1737245500026" TEXT="intermediärer Ergebnis-Typ: BranchResultClosure">
|
||||
<node COLOR="#5b280f" CREATED="1737244421643" ID="ID_1284583110" MODIFIED="1737416868792" TEXT="intermediärer Ergebnis-Typ: BranchResultClosure">
|
||||
<icon BUILTIN="help"/>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1737245502249" ID="ID_1174923923" MODIFIED="1737245508829" TEXT="noch nicht klar ob notwendig">
|
||||
<node CREATED="1737308551745" ID="ID_1909384704" MODIFIED="1737308569043" TEXT="denn Closure ≙ dynamischer Dispatch"/>
|
||||
<node CREATED="1737308586765" ID="ID_1360651233" MODIFIED="1737308606555" TEXT="die ganze sonstiger »Parser-Code-Insel« ist rein-statitsch typisiert"/>
|
||||
<node CREATED="1737308671866" ID="ID_1034537096" MODIFIED="1737308702736" TEXT="Zahl der Branches klein ⟹ statische Impl im Vorteil"/>
|
||||
</node>
|
||||
<node CREATED="1737245511448" ID="ID_396620339" MODIFIED="1737245792925" TEXT="Alternativ: Rückübersetzung Selector ⟼ Typ-Kontext durch rekursive Funktionen">
|
||||
<node CREATED="1737245511448" ID="ID_396620339" MODIFIED="1737416947927" TEXT="Alternativ: Rückübersetzung Selector ⟼ Typ-Kontext durch rekursive Funktionen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
|
|
@ -56040,21 +56043,29 @@
|
|||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#5c6ba3" DESTINATION="ID_724398426" ENDARROW="Default" ENDINCLINATION="134;0;" ID="Arrow_ID_961310703" STARTARROW="None" STARTINCLINATION="-244;9;"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1737416878486" ID="ID_724398426" MODIFIED="1737417001411" TEXT="versuche Zugang zum aktiven Zweig via rekursive Funktion">
|
||||
<arrowlink COLOR="#3dad9b" DESTINATION="ID_1738176168" ENDARROW="Default" ENDINCLINATION="-15;-187;" ID="Arrow_ID_387275034" STARTARROW="None" STARTINCLINATION="-287;14;"/>
|
||||
<linktarget COLOR="#5c6ba3" DESTINATION="ID_724398426" ENDARROW="Default" ENDINCLINATION="134;0;" ID="Arrow_ID_961310703" SOURCE="ID_396620339" STARTARROW="None" STARTINCLINATION="-244;9;"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1737245801576" ID="ID_1738176168" MODIFIED="1737400259658" TEXT="Skizze Datentyp">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1737308328478" ID="ID_993665414" MODIFIED="1737308352116" TEXT="erst mal einen uninitialised byte-Puffer in Basisklasse"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1737245801576" ID="ID_1738176168" MODIFIED="1737416989050" TEXT="Skizze Datentyp">
|
||||
<linktarget COLOR="#3dad9b" DESTINATION="ID_1738176168" ENDARROW="Default" ENDINCLINATION="-15;-187;" ID="Arrow_ID_387275034" SOURCE="ID_724398426" STARTARROW="None" STARTINCLINATION="-287;14;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1737308328478" ID="ID_993665414" MODIFIED="1737358352116" TEXT="erst mal einen uninitialised byte-Puffer in Basisklasse"/>
|
||||
<node CREATED="1737308370978" ID="ID_1202779435" MODIFIED="1737308383699" TEXT="typisierter Summentyp darübergelegt"/>
|
||||
<node CREATED="1737308384535" ID="ID_1448196900" MODIFIED="1737308394626" TEXT="Anordnung der Typ-Parameter: Rückwärts gehend">
|
||||
<node CREATED="1737308397038" ID="ID_977244135" MODIFIED="1737308410928" TEXT="also der letzte / höchste Zweig zuerst"/>
|
||||
<node CREATED="1737308411588" ID="ID_1539400054" MODIFIED="1737308423294" TEXT="damit rekursiv-delegierende Implementierung möglich"/>
|
||||
</node>
|
||||
<node CREATED="1737309034680" ID="ID_1283731567" MODIFIED="1737309052170" TEXT="Code-Struktur überlegen">
|
||||
<node COLOR="#338800" CREATED="1737309034680" ID="ID_1283731567" MODIFIED="1737416599812" TEXT="Code-Struktur überlegen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1737309053966" ID="ID_1359722232" MODIFIED="1737309190105" TEXT="Destuktor aufrufen ?">
|
||||
<node BACKGROUND_COLOR="#fefc4e" COLOR="#351d75" CREATED="1737309093248" ID="ID_321904108" MODIFIED="1737309152195" TEXT="�� Invariante: stets ein Zweig belegt">
|
||||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
|
|
@ -56065,7 +56076,7 @@
|
|||
<node CREATED="1737309245044" ID="ID_1229816718" MODIFIED="1737309255638" TEXT="er müßte nämlich den Typ im Buffer kennen"/>
|
||||
<node CREATED="1737309258330" ID="ID_414435446" MODIFIED="1737309277292" TEXT="sonst ist es mehr wie eine Member-Komponente"/>
|
||||
</node>
|
||||
<node CREATED="1737309306808" ID="ID_1247810717" MODIFIED="1737309311710" TEXT="zwei Alternativen...">
|
||||
<node COLOR="#435e98" CREATED="1737309306808" FOLDED="true" ID="ID_1247810717" MODIFIED="1737416659077" TEXT="zwei Alternativen...">
|
||||
<node CREATED="1737309312755" ID="ID_1765693019" MODIFIED="1737323819640" TEXT="inkrementeller Dekorator">
|
||||
<icon BUILTIN="full-1"/>
|
||||
<node CREATED="1737309344095" ID="ID_1218238487" MODIFIED="1737309351610" TEXT="Buffer ist tatsächlich Basis"/>
|
||||
|
|
@ -56086,8 +56097,8 @@
|
|||
<icon BUILTIN="full-2"/>
|
||||
<node CREATED="1737309866960" ID="ID_1933240925" MODIFIED="1737309878323" TEXT="es gibt nur ein Objekt, das den Buffer direkt (private) hält"/>
|
||||
<node CREATED="1737309879188" ID="ID_1269779979" MODIFIED="1737309905040" TEXT="für jeden Aufruf wird rekursiv eine Typ-Projektion darübergelegt für die Zugriffe"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1737309983889" ID="ID_217989124" MODIFIED="1737309993912" TEXT="Machbarkeit nicht klar ⟹ Prototyping">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#435e98" CREATED="1737309983889" ID="ID_217989124" MODIFIED="1737416577611" TEXT="Machbarkeit nicht klar ⟹ Prototyping">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1737309995672" ID="ID_317094642" MODIFIED="1737310007874" TEXT="brauche rekursiv getypte Hilfsfunktionen">
|
||||
<node CREATED="1737310409584" ID="ID_1587656830" MODIFIED="1737310412828" TEXT="emplace"/>
|
||||
<node CREATED="1737310413472" ID="ID_190878994" MODIFIED="1737310416083" TEXT="destroy"/>
|
||||
|
|
@ -56137,19 +56148,20 @@
|
|||
</html></richcontent>
|
||||
<icon BUILTIN="forward"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1737317456624" ID="ID_846126551" MODIFIED="1737317483349" TEXT="grundsätzliches Problem: Variant-Returntype nicht möglich">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1737317456624" ID="ID_846126551" MODIFIED="1737416545012" TEXT="grundsätzliches Problem: Variant-Returntype nicht möglich">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node COLOR="#5b280f" CREATED="1737317489124" ID="ID_233312745" MODIFIED="1737317528208" TEXT="Funktion kann keinen vom Parameter abhängigen Rückgabetyp haben">
|
||||
<icon BUILTIN="closed"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1737317639568" ID="ID_526309958" MODIFIED="1737317717888" TEXT="diese Einschränkung betrifft jedes Konstrukt für einen Summen-Typ (in C++)">
|
||||
<node BACKGROUND_COLOR="#e6ce96" COLOR="#fa002a" CREATED="1737317639568" ID="ID_526309958" MODIFIED="1737416557265" TEXT="diese Einschränkung betrifft jedes Konstrukt für einen Summen-Typ (in C++)">
|
||||
<arrowlink COLOR="#d2005b" DESTINATION="ID_1314826159" ENDARROW="Default" ENDINCLINATION="58;-95;" ID="Arrow_ID_1280018433" STARTARROW="None" STARTINCLINATION="-542;20;"/>
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1737323796942" ID="ID_1671873045" MODIFIED="1737323808699" TEXT="Diskussion">
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1737323796942" ID="ID_1671873045" MODIFIED="1737416667635" TEXT="Diskussion">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1737323821990" ID="ID_1562513052" MODIFIED="1737323951827" TEXT="die Variante-2 erschien mir zunächst attraktiver">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -56190,8 +56202,7 @@
|
|||
...weil praktisch alle Kern-Methoden nun in zweifacher Ausfertigung gecodet werden müssen: einmal rekursiv, und einmal für den Abschluß
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1737392934472" ID="ID_642107000" MODIFIED="1737393084265" TEXT="zudem erzwingt Variante-1 eine umgekehrte Ordnung der Typ-Parameter">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -56207,8 +56218,7 @@
|
|||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1737317603366" ID="ID_1314826159" MODIFIED="1737317708664" TEXT="grundsätzliche Einschränkung: Zugriff erfordert statisch bekannten Typ">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1737317603366" FOLDED="true" ID="ID_1314826159" MODIFIED="1737416679265" TEXT="grundsätzliche Einschränkung: Zugriff erfordert statisch bekannten Typ">
|
||||
<linktarget COLOR="#d2005b" DESTINATION="ID_1314826159" ENDARROW="Default" ENDINCLINATION="58;-95;" ID="Arrow_ID_1280018433" SOURCE="ID_526309958" STARTARROW="None" STARTINCLINATION="-542;20;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1737317726468" ID="ID_1400201299" MODIFIED="1737317872607" TEXT="jeder »Varant«-Type (und auch Union) unterliegt dieser Einschränkung"/>
|
||||
|
|
@ -56341,9 +56351,28 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1737416683769" ID="ID_529397551" MODIFIED="1737416793839" STYLE="fork">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
<b>Fazit</b>: implementierbar mit generischem λ-Visitor
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<font NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="forward"/>
|
||||
<node COLOR="#78442f" CREATED="1737416738497" ID="ID_1423783090" MODIFIED="1737416781408" TEXT="nicht schön">
|
||||
<icon BUILTIN="smiley-oh"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1737395464420" ID="ID_1924549712" MODIFIED="1737400254287" STYLE="fork" TEXT="Konstruktor und Zuweisung">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#78442f" CREATED="1737416754887" ID="ID_1690525518" MODIFIED="1737416781408" TEXT="mehr so grade noch die Kurve gekratzt">
|
||||
<icon BUILTIN="smiley-oh"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1737395464420" ID="ID_1924549712" MODIFIED="1737416078316" TEXT="Konstruktor und Zuweisung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1737395472148" ID="ID_1934503205" MODIFIED="1737400253142" TEXT="zunächst einmal: Konstruktor immer auf den TOP-Slot">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
|
|
@ -56362,10 +56391,40 @@
|
|||
<node COLOR="#338800" CREATED="1737400227088" ID="ID_389977912" MODIFIED="1737400253142" TEXT="Extension in erweiterten Branch">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1737416084226" ID="ID_485111355" MODIFIED="1737416132543" TEXT="muß Lambda für alle Zweige compilierbar machen">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1737416138738" ID="ID_591886707" MODIFIED="1737416157124" TEXT="ärgerlich — stehe mit dem Rücken zur Wand hier"/>
|
||||
<node CREATED="1737416487683" ID="ID_136717181" MODIFIED="1737416503156" TEXT="das Lambda wird für alle Typen instantiiert"/>
|
||||
<node CREATED="1737416505524" ID="ID_456255326" MODIFIED="1737416522220" TEXT="abdichten mit std::is_constructible">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1737417020140" ID="ID_1230396959" MODIFIED="1737417037546" TEXT="sehr komplex ⟹ in Hilfskomponente auslagern">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1737417038777" ID="ID_158901588" MODIFIED="1737417051363" TEXT="lib/branch-case.hpp"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1737417051936" ID="ID_1310118315" MODIFIED="1737417056450" TEXT="BranchCase_test">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1737417060920" ID="ID_644848240" MODIFIED="1737417078580" TEXT="auf dieser Basis das AltModel definieren">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1737417079594" ID="ID_883955221" MODIFIED="1737417091878" TEXT="erst mal die Einzelschritte durchspielen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1737417093057" ID="ID_1036480281" MODIFIED="1737417121178" TEXT="Typ konstruieren"/>
|
||||
<node COLOR="#435e98" CREATED="1737417099856" ID="ID_820603798" MODIFIED="1737417121178" TEXT="einen Branch belegen"/>
|
||||
<node COLOR="#435e98" CREATED="1737417104216" ID="ID_188551502" MODIFIED="1737417121178" TEXT="danach noch ein up-Copy"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1737417129349" ID="ID_1317057698" MODIFIED="1737417137972" TEXT="Struktur für den Kombinator darstellen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1737417144217" ID="ID_375516701" MODIFIED="1737417153090" TEXT="in einen Connex-Builder verpacken">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1737048820482" ID="ID_235554745" MODIFIED="1737048832524" TEXT="generisches Model-Binding"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue