Library: extract summation of pipeline results

...first used as part of the test harness;
seemingly this is a generic and generally useful shortcut,
similar to algorithm::reduce (or some kind of fold-left operation)
This commit is contained in:
Fischlurch 2023-09-23 19:39:08 +02:00
parent b15281d44b
commit b416a67bb9
3 changed files with 52 additions and 17 deletions

View file

@ -389,12 +389,13 @@ namespace lib {
* within the same processing step; and in addition, it allows the processing step to * within the same processing step; and in addition, it allows the processing step to
* remain agnostic with respect to the adaptation and concrete type of the functor/lambda. * remain agnostic with respect to the adaptation and concrete type of the functor/lambda.
* @tparam FUN either the signature, or something _"function-like"_ passed as functor to be bound * @tparam FUN either the signature, or something _"function-like"_ passed as functor to be bound
* @tparam SRC (optional) but need to specify the source iterator type to apply when passing * @tparam SRC source type to feed to the function to be adapted.
* a generic lambda or template as FUN. Such a generic functor will be _instantiated_ * @remark Especially need to specify the source iterator type to apply when passing a generic lambda
* passing the type `SRC&` as argument. This instantiation may fail (and abort compilation), * or template as FUN. Such a generic functor will be _instantiated_ passing the type `SRC&`
* but when it succeeds, we can infer the result type `Res` from the generic lambda * as argument. This instantiation may fail (and abort compilation), but when it succeeds,
* the result type `Res` can be inferred from the generic lambda.
*/ */
template<class FUN, typename SRC =void> template<class FUN, typename SRC>
struct _FunTraits struct _FunTraits
{ {
/** handle all regular "function-like" entities */ /** handle all regular "function-like" entities */
@ -1588,7 +1589,7 @@ namespace lib {
} }
/** /**
* _terminal builder_ to invoke a functor for side effect on the complete pipeline. * _terminal builder_ to invoke a functor for side effect on the complete pipeline.
* @note exhausts and discards the pipeline itself * @note exhausts and discards the pipeline itself
*/ */
template<class FUN> template<class FUN>
@ -1601,6 +1602,29 @@ namespace lib {
consumeFun (pipeline); consumeFun (pipeline);
} }
/**
* _terminal builder_ to invoke sum up resulting number values from the pipeline.
* @return accumulation of all results from the pipeline, combined by `std::plus`
*/
template<class FUN>
auto
resultSum (FUN&& accessor)
{
auto accessVal = iter_explorer::_FunTraits<FUN,SRC>::adaptFunctor (forward<FUN> (accessor));
value_type sum{};
SRC& pipeline = *this;
for ( ; pipeline; ++pipeline)
sum += accessVal (pipeline);
return sum;
}
auto
resultSum()
{
return IterExplorer::resultSum ([](const reference val){ return val; });
}
/** _terminal builder_ to pour and materialise all results from this Pipeline. /** _terminal builder_ to pour and materialise all results from this Pipeline.
* @tparam CON a STL compliant container to store generated values (defaults to `vector`) * @tparam CON a STL compliant container to store generated values (defaults to `vector`)
* @return new instance of the target container, filled with all values * @return new instance of the target container, filled with all values

View file

@ -44,9 +44,6 @@
#include "lib/error.hpp" #include "lib/error.hpp"
#include "lib/nocopy.hpp" #include "lib/nocopy.hpp"
//#include "include/logging.h"
//#include "lib/meta/function.hpp"
//#include "lib/result.hpp"
#include <thread> #include <thread>
#include <atomic> #include <atomic>
@ -54,12 +51,6 @@
namespace lib { namespace lib {
// using lib::Literal;
// namespace error = lumiera::error;
// using error::LERR_(STATE);
// using error::LERR_(EXTERNAL);
/** /**
* A one time N-fold mutual synchronisation barrier. * A one time N-fold mutual synchronisation barrier.
@ -76,12 +67,13 @@ namespace lib {
std::atomic_int latch_; std::atomic_int latch_;
public: public:
/** @param nFold the number of participants to sync */ /** @param nFold the number of participants to sync (min. 2)*/
explicit explicit
SyncBarrier (uint nFold =2) SyncBarrier (uint nFold =2)
: latch_{int(nFold)} : latch_{int(nFold)}
{ {
REQUIRE (nFold >= 2, "Pointless to sync less than two participants."); REQUIRE (nFold >= 2, "Pointless to sync less than two participants.");
ENSURE (nFold < 100'000, "Danger territory.... sync 100k Threads??");
} }
void void
@ -93,7 +85,7 @@ namespace lib {
while (0 < latch_.load (std::memory_order_relaxed)); while (0 < latch_.load (std::memory_order_relaxed));
else else
latch_.store (0, std::memory_order_relaxed); latch_.store (0, std::memory_order_relaxed);
} } // prevent spurious calls from wrapping
}; };

View file

@ -286,6 +286,7 @@ namespace test{
verify_FilterChanges(); verify_FilterChanges();
verify_asIterSource(); verify_asIterSource();
verify_IterSource(); verify_IterSource();
verify_resultSum();
verify_effuse(); verify_effuse();
verify_depthFirstExploration(); verify_depthFirstExploration();
@ -1069,6 +1070,24 @@ namespace test{
/** @test verify _terminal operation_ to sum up all values from the pipeline.
*/
void
verify_resultSum()
{
auto accumulated = explore(CountDown{6})
.transform([](int i){ return i-1; })
.resultSum();
using Res = decltype(accumulated);
CHECK (lib::test::showType<Res>() == "int"_expect);
auto expectedSum = [](auto N){ return N*(N+1) / 2; };
CHECK (accumulated == expectedSum(5));
}
/** @test verify _terminal operation_ to append all results into a container. /** @test verify _terminal operation_ to append all results into a container.
*/ */
void void