2024-11-14 22:10:43 +01:00
|
|
|
/* try.cpp - to try out and experiment with new features....
|
2007-08-17 00:36:07 +02:00
|
|
|
* scons will create the binary bin/try
|
2014-08-16 02:04:29 +02:00
|
|
|
*/
|
2026-09-13 18:53:22 +02:00
|
|
|
// 09/26 - ways to build a cyclically wrapping number domain
|
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
|
|
|
// 03/26 - runtime index access and iteration over tuple-likes
|
2025-06-22 19:42:03 +02:00
|
|
|
// 06/25 - provide a concept to accept _tuple-like_ objects
|
clean-up: simplify function-closure -- avoiding `std::function`
A very performance relevant shortcoming of the existing implementation
of partial function closure is that the result is always wrapped into a
std::function, which typically causes a heap allocation when more than
a single pre-bound argument must be stored — which is annoying,
since the underlying Binder provides inline storage and thus
could be handled directly as a value object.
However, returning the Binder directly is also problematic, since
this object is outfitted with several overloaded function call operators,
which defeats most techniques to detect a function signature. Notably,
relevant down-stream metaprogramming code, like the tuple-closure used
in the `NodeBuilder` would break when being confronted directly with
a binder object.
An investigation shows that there is no direct remedy, short of
wrapping the binder into another functor. This can be accomplished
with a helper template, that generates a wrapper; however, this
wrapper builder must be supplied with explicit type information
regarding the function arguments (precisely because this type
signature can not be picked up from the Binder object itself)
2025-06-06 19:44:24 +02:00
|
|
|
// 06/25 - investigate function type detection of std::bind Binders
|
Buffer-Provider: investigate Problem with embedded type-constructor-arguments
This is a possible extension which frequently comes up again during the design of the Engine.
Basically, the `TypeHandler` in the metadata-descriptor used by the `BufferProvder` could capture
additional context-arguments, which are then later passed to an object instance embedded into the buffer.
Yesterday I attempted to use this feature for a simple demonstration in `NodeBasic_test`,
just to find out that passing additional constructor arguments to the capture fails with
a confusing compilation error message. This failure could be traced down to the function binder;
and what at first sight seemed to be a compiler error, turned out to be a quite logical limitation:
When we »close« some objects of the constructor, but delay the construction itself, we'll have to
store a copy in the constructor-λ. And this implies, that we'll have to change the types
used for instantiation of the compiler, so that the construction-function can be invoked
by passing references from the captured copy of the additional arguments.
When naively passing those forwarded arguments into the std::bind()-call,
the resulting functor will fail at instantiation, when the compiler attempts
to generate the function-call `operator()`
see: https://stackoverflow.com/q/30968573/444796
2024-12-16 23:01:57 +01:00
|
|
|
// 12/24 - investigate problem when perfect-forwarding into a binder
|
2024-12-12 04:38:55 +01:00
|
|
|
// 12/24 - investigate overload resolution on a templated function similar to std::get
|
2024-11-14 22:10:43 +01:00
|
|
|
// 11/24 - how to define a bare object location comparison predicate
|
2023-11-27 21:58:37 +01:00
|
|
|
// 11/23 - prototype for grouping from iterator
|
2012-01-07 03:28:12 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @file try.cpp
|
2026-09-13 18:53:22 +02:00
|
|
|
* Investigate techniques for creating a cyclically wrapping numeric domain.
|
|
|
|
|
* Actually this could be achieved with my `floordiv()` utility, yet the ramifications
|
|
|
|
|
* were not clear -- so I settled to build a stand-alone solution, based on the naive modulus
|
|
|
|
|
* technique, attempting to fix the negative offsets. It became clear that this approach would
|
|
|
|
|
* have to consider the domain boundaries and identify cases that could not be handlet. At that
|
|
|
|
|
* point, I used Claude to scrutinise and improve my draft, leading to a generic tool that is
|
|
|
|
|
* now relocated into the \ref util-quant.hpp header
|
|
|
|
|
* @see lib::par::Scale
|
2012-01-07 03:28:12 +01:00
|
|
|
*/
|
|
|
|
|
|
2020-03-07 19:39:51 +01:00
|
|
|
|
2016-01-06 04:36:53 +01:00
|
|
|
#include "lib/format-cout.hpp"
|
2026-09-13 18:53:22 +02:00
|
|
|
#include "lib/util-quant.hpp"
|
2018-08-16 21:40:10 +02:00
|
|
|
#include "lib/util.hpp"
|
2019-04-19 18:37:30 +02:00
|
|
|
|
2026-09-13 18:53:22 +02:00
|
|
|
#include <cmath>
|
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
|
|
|
|
2026-09-13 18:53:22 +02:00
|
|
|
template<typename NUM>
|
|
|
|
|
constexpr NUM _MAX = std::numeric_limits<NUM>::max();
|
|
|
|
|
|
|
|
|
|
template<typename NUM>
|
|
|
|
|
constexpr NUM _MIN = std::numeric_limits<NUM>::lowest();
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-09-13 18:53:22 +02:00
|
|
|
template<typename N>
|
|
|
|
|
void
|
|
|
|
|
showCase (N val, N minVal, N maxVal)
|
|
|
|
|
{
|
|
|
|
|
cout << "val:"<<val<<" (min:"<<minVal<<" , max:"<<maxVal<<") ->"<< util::cyclicWrap (val,minVal,maxVal)<<endl;
|
|
|
|
|
}
|
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
|
|
|
|
2026-09-13 18:53:22 +02:00
|
|
|
template<typename N>
|
|
|
|
|
void
|
|
|
|
|
showFloorDiv (N num, N den)
|
|
|
|
|
{
|
|
|
|
|
cout << "FloorDiv:"<<num<<" / "<<den<<" ->"<< util::floordiv(num,den)<<endl;
|
|
|
|
|
}
|
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
|
|
|
|
2026-09-13 18:53:22 +02:00
|
|
|
template<typename N>
|
|
|
|
|
void
|
|
|
|
|
showFloorWrap (N num, N den)
|
|
|
|
|
{
|
|
|
|
|
auto fwrap = util::floorwrap (num,den);
|
|
|
|
|
cout << "FloorWrap:"<<num<<" / "<<den<<" -> q="<<fwrap.quot<<" r="<<fwrap.rem<<endl;
|
|
|
|
|
}
|
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
|
|
|
|
2024-12-12 15:55:02 +01:00
|
|
|
|
2016-01-05 03:32:24 +01:00
|
|
|
int
|
|
|
|
|
main (int, char**)
|
|
|
|
|
{
|
2026-09-13 18:53:22 +02:00
|
|
|
const int PER = 3;
|
|
|
|
|
int i = -5;
|
|
|
|
|
int d = i / PER;
|
|
|
|
|
cout << "d="<<d<<endl;
|
|
|
|
|
cout << "fd="<<util::floordiv(i,PER)<<endl;
|
2023-11-20 02:00:56 +01:00
|
|
|
|
2026-09-13 18:53:22 +02:00
|
|
|
uint u = _MAX<uint>;
|
clean-up: simplify function-closure -- avoiding `std::function`
A very performance relevant shortcoming of the existing implementation
of partial function closure is that the result is always wrapped into a
std::function, which typically causes a heap allocation when more than
a single pre-bound argument must be stored — which is annoying,
since the underlying Binder provides inline storage and thus
could be handled directly as a value object.
However, returning the Binder directly is also problematic, since
this object is outfitted with several overloaded function call operators,
which defeats most techniques to detect a function signature. Notably,
relevant down-stream metaprogramming code, like the tuple-closure used
in the `NodeBuilder` would break when being confronted directly with
a binder object.
An investigation shows that there is no direct remedy, short of
wrapping the binder into another functor. This can be accomplished
with a helper template, that generates a wrapper; however, this
wrapper builder must be supplied with explicit type information
regarding the function arguments (precisely because this type
signature can not be picked up from the Binder object itself)
2025-06-06 19:44:24 +02:00
|
|
|
|
2026-09-13 18:53:22 +02:00
|
|
|
cout << u << " fd="<<util::floordiv(u,uint(PER))<<" ...re="<<PER*util::floordiv(u,uint(PER))<<endl;
|
2024-12-12 15:55:02 +01:00
|
|
|
|
2026-09-13 18:53:22 +02:00
|
|
|
showFloorDiv (7,5);
|
|
|
|
|
showFloorDiv (-7,5);
|
|
|
|
|
showFloorDiv (7,-5);
|
|
|
|
|
showFloorDiv (-7,-5);
|
|
|
|
|
|
|
|
|
|
showFloorWrap (7,5);
|
|
|
|
|
showFloorWrap (-7,5);
|
|
|
|
|
showFloorWrap (7,-5);
|
|
|
|
|
showFloorWrap (-7,-5);
|
|
|
|
|
|
|
|
|
|
showFloorWrap (_MAX<int>,1);
|
|
|
|
|
showFloorWrap (_MAX<int>,2);
|
|
|
|
|
showFloorWrap (_MAX<int>,5);
|
|
|
|
|
|
|
|
|
|
showFloorWrap (_MIN<int>,1);
|
|
|
|
|
showFloorWrap (_MIN<int>,2);
|
|
|
|
|
showFloorWrap (_MIN<int>,5);
|
|
|
|
|
|
|
|
|
|
showFloorWrap (_MAX<int>,-1);
|
|
|
|
|
showFloorWrap (_MAX<int>,-2);
|
|
|
|
|
showFloorWrap (_MAX<int>,-5);
|
|
|
|
|
|
|
|
|
|
showFloorDiv (_MAX<int>,1);
|
|
|
|
|
showFloorDiv (_MAX<int>,2);
|
|
|
|
|
showFloorDiv (_MAX<int>,5);
|
|
|
|
|
|
|
|
|
|
showFloorDiv (_MIN<int>,1);
|
|
|
|
|
showFloorDiv (_MIN<int>,2);
|
|
|
|
|
showFloorDiv (_MIN<int>,5);
|
|
|
|
|
|
|
|
|
|
showFloorDiv (_MAX<int>,-1);
|
|
|
|
|
showFloorDiv (_MAX<int>,-2);
|
|
|
|
|
showFloorDiv (_MAX<int>,-5);
|
|
|
|
|
|
|
|
|
|
showFloorWrap (_MAX<uint>,1u);
|
|
|
|
|
showFloorWrap (_MAX<uint>,2u);
|
|
|
|
|
showFloorWrap (_MAX<uint>,5u);
|
|
|
|
|
|
|
|
|
|
showFloorDiv (_MAX<uint>,1u);
|
|
|
|
|
showFloorDiv (_MAX<uint>,2u);
|
|
|
|
|
showFloorDiv (_MAX<uint>,5u);
|
|
|
|
|
|
|
|
|
|
showCase<int>(-7,-5,5);
|
|
|
|
|
showCase<int>(-6,-5,5);
|
|
|
|
|
showCase<int>(-5,-5,5);
|
|
|
|
|
showCase<int>(-4,-5,5);
|
|
|
|
|
showCase<int>(+5,-5,5);
|
|
|
|
|
showCase<int>(+6,-5,5);
|
|
|
|
|
showCase<int>(+7,-5,5);
|
|
|
|
|
showCase<int>(+8,-5,5);
|
|
|
|
|
showCase<int>(+9,-5,5);
|
|
|
|
|
showCase<int>(+10,-5,5);
|
|
|
|
|
showCase<int>(+11,-5,5);
|
|
|
|
|
showCase<int>(+12,-5,5);
|
|
|
|
|
showCase<int>(+14,-5,5);
|
|
|
|
|
showCase<int>(+15,-5,5);
|
|
|
|
|
showCase<int>( -7,-10,-7);
|
|
|
|
|
showCase<int>( -8,-10,-7);
|
|
|
|
|
showCase<int>( -9,-10,-7);
|
|
|
|
|
showCase<int>(-10,-10,-7);
|
|
|
|
|
showCase<int>(-11,-10,-7);
|
|
|
|
|
showCase<int>(-12,-10,-7);
|
|
|
|
|
showCase<int>(-13,-10,-7);
|
|
|
|
|
showCase<int>(-14,-10,-7);
|
|
|
|
|
showCase<int>(-15,-10,-7);
|
|
|
|
|
|
|
|
|
|
showCase<uint>(5,1000,1003);
|
|
|
|
|
|
|
|
|
|
showCase<float>(0.2 ,-2,-1.8);
|
|
|
|
|
showCase<float>(0 ,-2,-1.8);
|
|
|
|
|
showCase<float>(-0.8,-2,-1.8);
|
|
|
|
|
showCase<float>(-1.79,-2,-1.8);
|
|
|
|
|
showCase<float>(-1.8,-2,-1.8);
|
|
|
|
|
showCase<float>(-1.81,-2,-1.8);
|
|
|
|
|
showCase<float>(-1.99,-2,-1.8);
|
|
|
|
|
showCase<float>(-2 ,-2,-1.8);
|
|
|
|
|
showCase<float>(-2.01,-2,-1.8);
|
2025-06-23 23:02:15 +02:00
|
|
|
|
2025-06-23 04:23:55 +02:00
|
|
|
|
Buffer-Provider: investigate Problem with embedded type-constructor-arguments
This is a possible extension which frequently comes up again during the design of the Engine.
Basically, the `TypeHandler` in the metadata-descriptor used by the `BufferProvder` could capture
additional context-arguments, which are then later passed to an object instance embedded into the buffer.
Yesterday I attempted to use this feature for a simple demonstration in `NodeBasic_test`,
just to find out that passing additional constructor arguments to the capture fails with
a confusing compilation error message. This failure could be traced down to the function binder;
and what at first sight seemed to be a compiler error, turned out to be a quite logical limitation:
When we »close« some objects of the constructor, but delay the construction itself, we'll have to
store a copy in the constructor-λ. And this implies, that we'll have to change the types
used for instantiation of the compiler, so that the construction-function can be invoked
by passing references from the captured copy of the additional arguments.
When naively passing those forwarded arguments into the std::bind()-call,
the resulting functor will fail at instantiation, when the compiler attempts
to generate the function-call `operator()`
see: https://stackoverflow.com/q/30968573/444796
2024-12-16 23:01:57 +01:00
|
|
|
cout << "\n.gulp." <<endl;
|
2007-08-17 00:36:07 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|