LUMIERA.clone/tests/12metaprogramming.tests
Ichthyostega 0760525ea5 Library: deep dive into type reconciliation and tuple handling
This commit is the aggregated result of extended research
that is only loosely related to current development topics.

One theme was the construction of nested data structures using tuples,
which faces some difficulties due to tuple manipulations being limited
almost entirely to compile-time processing. However, the barrier between
compile-time and runtime can be overcome with the help of a dispatcher
table -- which leads to the secondary problem to handle the diverse
tuple elements with a common, generic functor. Such a functor can be
constructed, if and only if those element types are ''reconcilable''

The STDLIB provides two metafunctions, `std::common_type` and
`std::common_refernce`, which however pose some challenges for the
task at hand, since they include additional processing. In the end,
a custom version of the ''basic type reconciliation'' was implemented
and tested, and then used as foundation to build a dispatcher table
for runtime-indexed access and iteration over tuples.

As an aside, several deeply hidden bugs in our library code were resolved,
and the tuple-helpers, tuple string rendering and associated utilities
were regrouped and modernised.

As result of this research work, the following components are provided:
- meta/common-result
- meta/fun-trampoline
- meta/tuple-index-adaptor
2026-04-07 06:32:23 +02:00

546 lines
16 KiB
Text

TESTING "Metaprogramming facilities and techniques" ./test-suite --group=common
TEST "casting or converting access helper" AccessCasted_test <<END
out-lit: can_downcast<B,D> = 1
out-lit: can_downcast<B*,D*> = 1
out-lit: can_downcast<B&,D&> = 1
out-lit: can_downcast<B&,D*> = 0
out-lit: can_downcast<B*,D&> = 0
out-lit: can_downcast<B*&,D*&> = 1
out-lit: can_downcast<D*&,D*&> = 1
out-lit: can_downcast<D*,E*> = 1
out-lit: can_downcast<E*,F*> = 1
out-lit: has_RTTI<D*> = 0
out-lit: has_RTTI<E*> = 1
out-lit: has_RTTI<F*> = 1
out-lit: is_convertible<D,D&> = 0
out-lit: is_convertible<D&,D> = 1
out-lit: can_use_dynamic_downcast<D,D&> = 0
out-lit: can_use_conversion<D,D&> = 0
out-lit: can_use_dynamic_downcast<B*,D*> = 0
out-lit: can_use_conversion<D*,B*> = 1
out-lit: can_use_dynamic_downcast<D*&,D*&> = 0
out-lit: can_use_conversion<D*&,D*&> = 1
out-lit: can_use_conversion<D*,E*> = 0
out-lit: can_use_dynamic_downcast<D*&,E*> = 0
out-lit: can_use_conversion<E*,F*> = 0
out-lit: can_use_dynamic_downcast<E*,F*> = 1
out-lit: === standard case: References ===
out: Access\(D as D&\) .+D.. adr=╲\w{8} ↗«D»
out: Access\(D& as D&\) .+D.. adr=╲\w{8} ↗«D»
out-lit: === build a value object ===
out: Access.D as D. .+D.. adr=╲\w{8} ↗«D»
out: Access.D& as D. .+D.. adr=╲\w{8} ↗«D»
out: Access.D&& as D. .+D.. adr=╲\w{8} ↗«D»
out-lit: === take a pointer ===
out: Access.D as D\*. .+╲\w{8}
out: Access.D& as D\*. .+╲\w{8}
out-lit: === dereference a pointer ===
out: Access.D\* as D&. .+D.. adr=╲\w{8} ↗«D»
out: Access.D\* as D. .+D.. adr=╲\w{8} ↗«D»
out: Access.D\*&& as D. .+D.. adr=╲\w{8} ↗«D»
out-lit: === const correctness ===
out: Access.D as D const&. .+D.. adr=╲\w{8} ↗«D»
out: Access.D& as D const&. .+D.. adr=╲\w{8} ↗«D»
out: Access.D as const D. .+D.. adr=╲\w{8} ↗«D»
out: Access.D& as const D. .+D.. adr=╲\w{8} ↗«D»
out: Access.D as const D\*. .+╲\w{8}
out: Access.D& as const D\*. .+╲\w{8}
out: Access.D\* as D const&. .+D.. adr=╲\w{8} ↗«D»
out: Access.D\* as const D. .+D.. adr=╲\w{8} ↗«D»
out: Access.const D as D const&. .+D.. adr=╲\w{8} ↗«D»
out: Access.D const& as D const&. .+D.. adr=╲\w{8} ↗«D»
out: Access.const D as const D. .+D.. adr=╲\w{8} ↗«D»
out: Access.D const& as const D. .+D.. adr=╲\w{8} ↗«D»
out: Access.const D as const D\*..+╲\w{8}
out: Access.D const& as const D\*..+╲\w{8}
out: Access.const D\* as D const&..+D.. adr=╲\w{8} ↗«D»
out: Access.const D\* as const D. .+D.. adr=╲\w{8} ↗«D»
out: Access.D const& as D. .+D.. adr=╲\w{8} ↗«D»
out: Access.D const&& as D. .+D.. adr=╲\w{8} ↗«D»
out-lit: === work cases: actual conversions ===
out: Access.B& as B&. .+B.. adr=╲\w{8} ↗«B»
out: Access.D& as B&. .+B.. adr=╲\w{8} ↗«B»
out: Access.B\* as B\*. .+╲\w{8}
out: Access.D\* as B\*. .+╲\w{8}
out: Access.D& as B\*. .+╲\w{8}
out: Access.D\* as B&. .+B.. adr=╲\w{8} ↗«B»
out: Access.B\*& as B\*&. .+╲\w{8}
out: Access.D\*& as D\*&. .+╲\w{8}
out: Access.D& as const B\*. .+╲\w{8}
out: Access.D\* as B const&. .+B.. adr=╲\w{8} ↗«B»
out: Access.D const& as const B\*..+╲\w{8}
out: Access.const D\* as B const&..+B.. adr=╲\w{8} ↗«B»
out: Access.E\(F\)& as F&. .+F.. adr=╲\w{8} ↗«F»
out: Access.E\(F\)\* as F\*. .+╲\w{8}
out: Access.E\(F\)\* as F&. .+F.. adr=╲\w{8} ↗«F»
out: Access.E\(F\)& as F\*. .+╲\w{8}
out: Access.F\\* as X\*. .+╲\w{8}
out: Access.X\(F\)\* as X\*. .+╲\w{8}
out: Access.F\* as B&. .+B.. adr=╲\w{8} ↗«B»
out: Access.F\* as E&*. .+E.. adr=╲\w{8} ↗«F»
out-lit: Access(int as double) --->2
out-lit: Access(float as long) --->3
return: 0
END
TEST "Common reconciled return types" CommonResult_test <<END
return: 0
END
TEST "Duck typing support" DuckDetector_test <<END
out: HasNested_Core<PropperGander> : Yes
out: HasNested_Core<Propaganda> : No
out: HasMember_honk<PropperGander> : Yes
out: HasMember_honk<Propaganda> : Yes
out: HasFunSig_honk<PropperGander> : Yes
out: HasFunSig_honk<Propaganda> : No
return: 0
END
TEST "Duck detect extension points" DuckDetectorExtension_test <<END
return: 0
END
TEST "functional closure" FunctionClosure_test <<END
out-lit: List1 :-<1>-<2>-<3>-
out-lit: List2 :-<5>-<6>-<7>-
out-lit: Args :-<5>-<9>-
out-lit: NewArgs :-<1>-<5>-<9>-
out-lit: :
out-lit: : ---Bind----
out-lit: tup0 :«tuple<>»──()
out-lit: tup1 :«tuple<int>»──(11)
out-lit: tup2 :«tuple<int, int>»──(11,12)
out-lit: tup3 :«tuple<int, int, int>»──(11,12,13)
return: 0
END
TEST "functional composition" FunctionComposition_test <<END
return: 0
END
TEST "function type erasure" FunctionErasure_test <<END
return: 0
END
TEST "function signature trait" FunctionSignature_test <<END
return: 0
END
TEST "generate functor trampoline" FunTrampoline_test <<END
return: 0
END
TEST "member function late binding" LateBindInstance_test <<END
return: 0
END
TEST "metaprogramming helpers" MetaUtils_test <<END
return: 0
END
TEST "Lumiera Iterator Concept" IterAdapter_test 20 <<END
out-lit: ::20::19::18::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1
out-lit: ::20::19::18::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1
out-lit: ++21++22++23++24++25++26++27++28++29++30++31++32++33++34++35++36++37++38++39
out-lit: ::0::1::2::3::4::5::6::7::8::9::10::11::12::13::14::15::16::17::18::19
out-lit: ::0::1::2::3::4::5::6::7::8::9::10::11::12::13::14::15::16::17::18::19
return: 0
END
TEST "Lumiera Iterator Adapter for STL" IterAdapterSTL_test <<END
out-lit: -----filter-distinct-values---vector<int>
out-lit: iter::eachDistinct
out-lit: iter::eachDistinct::1
out-lit: iter::eachDistinct::1::2::3::1
out-lit: iter::eachDistinct::1::2::3::1
out-lit: -----iterateMapKeyVal---map<int, int>
out-lit: iter::eachKey::0::1::2::3::4::5::6::7::8::9
out-lit: iter::eachKey::0::1::2::3::4::5::6::7::8::9
out-lit: iter::eachVal::0::2::4::6::8::10::12::14::16::18
out-lit: iter::eachVal::0::2::4::6::8::10::12::14::16::18
out-lit: iter::eachDistinctKey::0::1::2::3::4::5::6::7::8::9
out-lit: -----iterateMapKeyVal---unordered_map<int, int>
out: iter::eachKey::.::.::.::.::.::.::.::.::.::.
out: iter::eachVal::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+
out: iter::eachDistinctKey::.::.::.::.::.::.::.::.::.::.
out-lit: -----iterateMapKeyVal---multimap<int, int>
out-lit: iter::eachKey::0::0::0::0::0::0::0::0::0::0::1::1::1::1::1::1::1::1::1::2::2::2::2::2::2::2::2::3::3::3::3::3::3::3::4::4::4::4::4::4::5::5::5::5::5::6::6::6::6::7::7::7::8::8::9
out-lit: iter::eachKey::0::0::0::0::0::0::0::0::0::0::1::1::1::1::1::1::1::1::1::2::2::2::2::2::2::2::2::3::3::3::3::3::3::3::4::4::4::4::4::4::5::5::5::5::5::6::6::6::6::7::7::7::8::8::9
out-lit: iter::eachVal::10::9::8::7::6::5::4::3::2::1::9::8::7::6::5::4::3::2::1::8::7::6::5::4::3::2::1::7::6::5::4::3::2::1::6::5::4::3::2::1::5::4::3::2::1::4::3::2::1::3::2::1::2::1::1
out-lit: iter::eachVal::10::9::8::7::6::5::4::3::2::1::9::8::7::6::5::4::3::2::1::8::7::6::5::4::3::2::1::7::6::5::4::3::2::1::6::5::4::3::2::1::5::4::3::2::1::4::3::2::1::3::2::1::2::1::1
out-lit: iter::eachDistinctKey::0::1::2::3::4::5::6::7::8::9
out-lit: -----iterateMapKeyVal---unordered_multimap<int, int>
out: iter::eachKey::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.::.
out: iter::eachVal::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+
out: iter::eachDistinctKey::.::.::.::.::.::.::.::.::.::.
out-lit: -----iterateValues4Key---multimap<int, int>
out-lit: iter::eachValForKey::10::9::8::7::6::5::4::3::2::1
out-lit: -----iterateValues4Key---unordered_multimap<int, int>
out: iter::eachValForKey::.+::.+::.+::.+::.+::.+::.+::.+::.+::.+
out-lit: snapshot-0-1-2-3-4-5-6-7-8-9
out-lit: snapshot-0-1-2-3-4-5-6-7-8-9
out-lit: snapshot-22-44
return: 0
END
TEST "Lumiera Iterator Tools" IterTools_test <<END
return: 0
END
TEST "Lumiera state-core iteration" IterCoreAdapter_test 20 <<END
return: 0
END
TEST "forward/backward iterator" IterCursor_test 20 <<END
return: 0
END
TEST "index-based iterator" IndexIter_test 20 <<END
return: 0
END
TEST "Iterable data source" IterSource_test 13 <<END
out: ::13::12::11::10::9::8::7::6::5::4::3::2::1
out: ::.............::............::...........::..........::.........::........::.......::......::.....::....::...::..::.$
out-lit: ::3s250ms::3s::2s750ms::2s500ms::2s250ms::2s::1s750ms::1s500ms::1s250ms::1s::750ms::500ms::250ms
out: (::X...........){13}$
out: (::.+s){13}$
out: (::X...........){13}$
out: (::.+s){13}$
out: distinct_keys::0::1::2::3::4::5::6::7::8::9::10::11::12
out: values_4_key(::[0-9]{1,2})+
out: distinct_keys(::[0-9]{1,2}){13}
out: values_4_key(::[0-9]{1,2})+
return: 0
END
TEST "Iterator tree exploration" IterExplorer_test <<END
out-lit: 4-3-2-1
out: Search in random tree: toFind = .....
out: Protocol of the search: .+\-.+\-.+\-.+\-.+
return: 0
END
TEST "Stack-like iterator" IterStack_test <<END
return: 0
END
TEST "Queue-like iterator" IterQueue_test <<END
return: 0
END
TEST "Tuple-zipped iterators" IterZip_test <<END
return: 0
END
TEST "Iterable type detection" IterableClassification_test <<END
return: 0
END
TEST "Linked iterable elements" LinkedElements_test <<END
return: 0
END
TEST "Polymorphic value objects" PolymorphicValue_test <<END
return: 0
END
TEST "Generated data records" PropBuilder_test <<END
return: 0
END
TEST "Variadic template diagnostics" TestHelperVariadic_test <<END
out-lit: --no-arg--
out-lit: :.
out-lit: --reference--
out: .+#1.+ Type: double& .+Adr╲.+
out-lit: :.
out-lit: --value--
out: .+#1.+ Type: double && .+Adr╲.+
out-lit: :.
out-lit: --two values--
out: .+#2.+ Type: char \[4\] const& .+Adr╲.+
out: .+#1.+ Type: long && .+Adr╲.+
out-lit: :.
out-lit: --references--
out: .+#3.+ Type: double& .+Adr╲.+
out: .+#2.+ Type: double const& .+Adr╲.+
out: .+#1.+ Type: double && .+Adr╲.+
out-lit: :.
out-lit: --baseclass--
out: .+#1.+ Type: Interface const& .+Adr╲.+
out-lit: :.
return: 0
END
TEST "Runtime-indexed tuple access" TupleIdxAdaptor_test <<END
return: 0
END
TEST "Helper to show demangled C++ names" TypeDemangling_test <<END
out: .+lib.meta.test.Space.+Outer.+Inner
out-lit: lib::meta::test::Space const* (*)(lib::meta::test::Outer<lib::meta::test::Space>::Inner const&&)
return: 0
END
TEST "Helper for human readable type display" TypeDisplay_test <<END
return: 0
END
TEST "Loki Type-List" TypeList_test <<END
out-lit: - 21 -- 13 -- 8 -- 5 -- 3 -- 2 -- 1 -- The End -
return: 0
END
TEST "Simple Type-List utilities" TypeListUtil_test <<END
return: 0
END
TEST "Type driven class generation" TypeListGenerator_test <<END
out: ctor DoIt<Block<13> >
out: ctor DoIt<Block< 8> >
out: ctor DoIt<Block< 5> >
out: ctor DoIt<Block< 3> >
out: ctor DoIt<Block< 2> >
out: ctor DoIt<Block< 1> >
out: devouring__Block< 2>__
out: devouring__Block< 5>__
out: devouring__Block<13>__
out: gulp!
out: dtor DoIt<Block< 1> >
out: dtor DoIt<Block< 2> >
out: dtor DoIt<Block< 3> >
out: dtor DoIt<Block< 5> >
out: dtor DoIt<Block< 8> >
out: dtor DoIt<Block<13> >
return: 0
END
TEST "Typelist manipulation" TypeListManip_test <<END
out-lit: List1 :-<1>-<2>-<3>-
out-lit: List2 :-<5>-<6>-<7>-
return: 0
END
TEST "type sequence manipulation" TypeSeqManip_test <<END
return: 0
END
TEST "tuple value pre-binding closure" TupleClosure_test <<END
return: 0
END
TEST "tuple metaprogramming helpers" TupleHelper_test <<END
out-lit: L1 :-<1>-<3>-<5>-
out-lit: L2 :-<2>-<4>-
out-lit: L3 :-<7>-
out-lit: Tup1 :TUPLE-<1>-<3>-<5>-
out-lit: Tup1() :«tuple<Num<1>, Num<3>, Num<5> >»──((1),(3),(5))
out-lit: tup1x :«tuple<Num<1>, Num<3>, Num<5> >»──({11},(3),{55})
out-lit: «tuple<Num<1>, Num<3>, Num<5> >»──((1),(3),(5))
out-lit: «tuple<int, Num<1>, Num<3>, Num<5> >»──(22,{11},{33},(5))
out-lit: «tuple<>»──()
out: sizeof. tuple<Num<1>, Num<3>, Num<5> > . = 12
out: sizeof. tuple<int, Num<1>, Num<3>, Num<5> > . = 16
out-lit: sizeof( tuple<> ) = 1
out-lit: sizeof( tuple<> ) = 1
return: 0
END
TEST "tuple initialisation from GenNode" TupleRecordInit_test <<END
out: Rec...GenNode.+DataCap.«string».lalü, GenNode.+DataCap.«int».42
out: Rec...GenNode.+DataCap.«string».lalü, GenNode.+DataCap.«string».lala, GenNode.+DataCap.«int».12, GenNode.+DataCap.«int».34, GenNode.+DataCap.«double».5.6, GenNode.+DataCap.«Time».0:09:08.007
out-lit: «tuple<string, int>»──(lalü,42)
out-lit: «tuple<idi::EntryID<long>, Symbol, int, long, double, Duration>»──(ID<long>-lal,lala,12,34,5.6,≺548s7ms≻)
return: 0
END
TEST "variadic type manipulations" VariadicHelper_test <<END
return: 0
END
TEST "variadic argument manipulation" VariadicArgumentPicker_test <<END
out: 4╎N<1>──.─┼N<2>──.─┼N<3>──.─┼N<3>──.─┤
out: 4╎N<0>──.─┼N<1>──.─┼N<2>──.─┼N<3>──.─┤
out: 4╎N<3>──.─┼N<2>──.─┼N<1>──.─┼N<0>──.─┤
out: 2╎N<1>──.─┼N<0>──.─┤
out: 2╎N<2>──.─┼N<3>──.─┤
return: 0
END
TEST "Typelist combinations generator" GeneratorCombinations_test <<END
out-lit: Cartesian :
out-lit: +---<1>-<2>-+
out-lit: +---<1>-<4>-+
out-lit: +---<1>-<6>-+
out-lit: +---<3>-<2>-+
out-lit: +---<3>-<4>-+
out-lit: +---<3>-<6>-+
out-lit: +---<5>-<2>-+
out-lit: +---<5>-<4>-+
out-lit: +---<5>-<6>-+-
out-lit: All-Test-Combinations--<12>-<14>-<16>-<32>-<34>-<36>-<52>-<54>-<56>-|
return: 0
END
TEST "Type-based contexts" TypedCounter_test <<END
return: 0
END
TEST "Type-based family member IDs" TypedFamilyMemberID_test <<END
return: 0
END
TEST "for-each operations" UtilForeach_test 10 <<END
out: ---:check_foreach_plain
out: :10:9:8:7:6:5:4:3:2:1
out: :10$
out: ---:check_foreach_plain
out: :10:9:8:7:6:5:4:3:2:1
out: :10$
out: ---:check_foreach_bind
out: :20:19:18:17:16:15:14:13:12:11
out: :20$
out: :20:18:16:14:12:10:8:6:4:2
out: :20$
out: ---:check_foreach_bind
out: :20:19:18:17:16:15:14:13:12:11
out: :20$
out: :20:18:16:14:12:10:8:6:4:2
out: :20$
out: ---:check_foreach_bind_const
out: :20:19:18:17:16:15:14:13:12:11
out: :20$
out: :20:18:16:14:12:10:8:6:4:2
out: :20$
out: :20:38:54:68:80:90:98:104:108:110
out: :130:148:164:178:190:200:208:214:218:220
out: :240
out: ---:check_foreach_memFun
out: :10:19:27:34:40:45:49:52:54:55
out: :10$
out: :10:19:27:34:40:45:49:52:54:55
out: :65:74:82:89:95:100:104:107:109:110
out: :120
out: sum=120
out: ---:check_foreach_memFun
out: :10:19:27:34:40:45:49:52:54:55
out: :10$
out: :10:19:27:34:40:45:49:52:54:55
out: :65:74:82:89:95:100:104:107:109:110
out: :120
out: sum=120
out: ---:check_foreach_lambda
out: ---:check_existence_quant
out: ---:assign_to_input
out: :20:19:18:17:16:15:14:13:12:11
out: :30:29:28:27:26:25:24:23:22:21
out: :40:39:38:37:36:35:34:33:32:31
out: :50:49:48:47:46:45:44:43:42:41
out: :60
out: :70
out: :80:59:58:57:56:55:54:53:52:51
out: :90:69:68:67:66:65:64:63:62:61
out: :100$
out: ---:assign_to_var
out: :90:149:207:264:320:375:429:482:534:585
out: :675:734:792:849:905:960:1014:1067:1119:1170
out: :1260:1319:1377:1434:1490:1545:1599:1652:1704:1755
out: sum=1755
out: :90:149:207:264:320:375:429:482:534:585
out: :675:734:792:849:905:960:1014:1067:1119:1170
out: :1260:1319:1377:1434:1490:1545:1599:1652:1704:1755
out: sum=1755
out: :90
out: :180
out: :270
out: sum=270
out: ---:assign_to_input
out: :20:19:18:17:16:15:14:13:12:11
out: :30:29:28:27:26:25:24:23:22:21
out: :40:39:38:37:36:35:34:33:32:31
out: :50:49:48:47:46:45:44:43:42:41
out: :60
out: :70
out: :80:59:58:57:56:55:54:53:52:51
out: :90:69:68:67:66:65:64:63:62:61
out: :100$
out: ---:assign_to_var
out: :90:149:207:264:320:375:429:482:534:585
out: :675:734:792:849:905:960:1014:1067:1119:1170
out: :1260:1319:1377:1434:1490:1545:1599:1652:1704:1755
out: sum=1755
out: :90:149:207:264:320:375:429:482:534:585
out: :675:734:792:849:905:960:1014:1067:1119:1170
out: :1260:1319:1377:1434:1490:1545:1599:1652:1704:1755
out: sum=1755
out: :90
out: :180
out: :270
out: sum=270
out: ---:wrapped_container_passing
out: :10:9:8:7:6:5:4:3:2:1
out: :-20:-21:-22:-23:-24:-25:-26:-27:-28:-29
out: ---:check_invoke_on_each
out: :0:1:2:3:4:5
out: :0$
out: :0:1$
out: :0:1:2:3:4:5
out: :0$
out: :0:1$
return: 0
END
TEST "Virtual copying of opaque objects" VirtualCopySupport_test <<END
return: 0
END