LUMIERA.clone/src/test/microbenchmark-adaptor.hpp
Ichthyostega 9c74466778 Tests: build an link a test-support library
This is something I wanted to clean-up since a very long time indeed,
but always postponed it, since it requires a lot of nasty clean-up and disentangling....

Several parts had been stashed away into `src/lib/test`, which are not really related:
 * the testrunner and testsuite builder
 * generic helper utilities
 * specialised test-support facilities, e.g. the EventLog

This changeset introduces a new top-level test folder and a namespace `::test`
Code from this folder is linked into a shared library `libtestsupport.so`,
which resides in the linkage hierarchy between »Vessel« and »Vault«,
yet is no longer part of the Lumiera application and only linked into the test-suite.
2026-03-06 23:16:32 +01:00

161 lines
4.6 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
MICROBENCHMARK-ADAPTOR.hpp - helper to support microbenchmarks
Copyright (C)
2023, 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 microbenchmark-adaptor.hpp
** Helpers and wrappers so simplify usage of \ref microbenchmark.hpp.
** Notably the benchmark functions expect the actual »test subject« as a
** function or lambda with signature `size_t(size_t)`. The argument will be
** the loop index and the result value will be added into a checksum, which
** also ensures that the optimiser can not unroll the benchmark loop.
** However, in practical use this strict requirement for the signature
** turned out as a nuisance; this header provides some automatic adaption
** - accept any numeric type as argument
** - accept any numeric type as checksum contribution (cast to `size_t`)
** - accept signature `void(void)`
**
*/
#ifndef TEST_MICROBENCHMARK_ADAPTOR_H
#define TEST_MICROBENCHMARK_ADAPTOR_H
#include "lib/meta/function.hpp"
#include "lib/meta/util.hpp"
namespace test{
namespace microbenchmark {
using lib::meta::enable_if;
using std::is_arithmetic;
using std::is_same;
using std::__and_;
using std::__not_;
/**
* @internal helper to expose the signature `size_t(size_t)`
* by wrapping a given lambda or functor.
*/
template<class SIG, typename SEL=void>
struct Adaptor
{
static_assert (not sizeof(SIG), "Unable to adapt given functor.");
};
template<>
struct Adaptor<size_t(size_t)>
{
template<typename FUN>
static decltype(auto)
wrap (FUN&& fun)
{
return std::forward<FUN>(fun);
}
};
template<>
struct Adaptor<void(void)>
{
template<typename FUN>
static auto
wrap (FUN&& fun)
{
return [functor=std::forward<FUN>(fun)]
(size_t) mutable
{
functor();
return size_t(1);
};
}
};
template<typename ON, typename IN>
struct Adaptor<ON(IN), enable_if<__and_<is_arithmetic<IN>, __not_<is_same<IN,size_t>>
,is_arithmetic<ON>, __not_<is_same<ON,size_t>>
>>>
{
template<typename FUN>
static auto
wrap (FUN&& fun)
{
return [functor=std::forward<FUN>(fun)]
(size_t i) mutable
{
return size_t(functor(i));
};
}
};
template<typename ON>
struct Adaptor<ON(void), enable_if<__and_<is_arithmetic<ON>, __not_<is_same<ON,size_t>>
>>>
{
template<typename FUN>
static auto
wrap (FUN&& fun)
{
return [functor=std::forward<FUN>(fun)]
(size_t) mutable
{
return size_t(functor());
};
}
};
template<typename IN>
struct Adaptor<void(IN), enable_if<__and_<is_arithmetic<IN>, __not_<is_same<IN,size_t>>
>>>
{
template<typename FUN>
static auto
wrap (FUN&& fun)
{
return [functor=std::forward<FUN>(fun)]
(size_t i) mutable
{
functor(i);
return size_t(1);
};
}
};
/**
* Adapter to expose the signature `size_t(size_t)`
* from any suitable source functor or lambda
* @note requirements
* - arity must be either zero or one argument
* - if argument or return type are present,
* they must be plain arithmetic types
* - no references allowed
* - can be `void(void)`
*/
template<typename FUN>
inline decltype(auto)
adapted4benchmark (FUN&& fun)
{
static_assert (lib::meta::_Fun<FUN>(), "Need something function-like.");
static_assert (lib::meta::_Fun<FUN>::ARITY <=1, "Function with zero or one argument required.");
using Sig = lib::meta::_Fun<FUN>::Sig;
return Adaptor<Sig>::wrap (std::forward<FUN> (fun));
}
}} // namespace test::microbenchmark
#endif /*TEST_MICROBENCHMARK_ADAPTOR_H*/