diff --git a/Phys/FunctorCore/include/Functors/Function.h b/Phys/FunctorCore/include/Functors/Function.h index 0da4569cbd6a7cd30c6b339231276b185546d5bf..ff8fb84edf57087029157a3866285978bc9cedc2 100644 --- a/Phys/FunctorCore/include/Functors/Function.h +++ b/Phys/FunctorCore/include/Functors/Function.h @@ -11,6 +11,8 @@ #pragma once #include "Functors/Core.h" #include "Functors/Optional.h" +#include "Functors/type_name.h" +#include "Gaudi/Algorithm.h" #include "LHCbMath/MatVec.h" #include "SelKernel/Utilities.h" #include <cmath> @@ -300,6 +302,28 @@ namespace Functors { constexpr auto Identity = TrivialFunctor{ "Identity", []<typename T>( T&& t ) -> decltype( auto ) { return std::forward<T>( t ); } }; + /** @class Logger + * @brief Trivial functor that prints the argument, and then returns it + */ + class Logger : public Function { + std::string m_format; + + public: + Logger( std::string format ) : m_format{ std::move( format ) } {} + + auto prepare( EventContext const&, TopLevelInfo const& top_level ) const { + return [alg = top_level.algorithm(), format = std::string_view{ m_format }]<typename T>( T&& t ) -> T&& { + using GaudiUtils::operator<<; + std::stringstream s; + s << t; + alg->always() << fmt::format( fmt::runtime( format ), fmt::arg( "arg_type", type_name<T>() ), + fmt::arg( "arg", s.view() ) ) + << endmsg; + return std::forward<T>( t ); + }; + } + }; + /** @class Column Instantiated with a "label" , when acting on object T returns T("label") */ diff --git a/Phys/FunctorCore/include/Functors/type_name.h b/Phys/FunctorCore/include/Functors/type_name.h new file mode 100644 index 0000000000000000000000000000000000000000..b46022056d226d662d5ca556f782f91dd09c55a5 --- /dev/null +++ b/Phys/FunctorCore/include/Functors/type_name.h @@ -0,0 +1,55 @@ +/*****************************************************************************\ +* (c) Copyright 2021, Matthew Rodusek (bitwizeshift) +* +* based on https://bitwizeshift.github.io/posts/2021/03/09/getting-an-unmangled-type-name-at-compile-time +* +\*****************************************************************************/ +#pragma once +#include <array> // std::array +#include <string> +#include <string_view> +#include <utility> // std::index_sequence + +namespace details { + template <std::size_t... Is> + constexpr auto as_array( std::string_view str, std::index_sequence<Is...> ) { + return std::array{ str[Is]... }; + } + + template <typename T> + constexpr auto type_name_array() { +#if defined( __clang__ ) + constexpr auto prefix = std::string_view{ "[T = " }; + constexpr auto suffix = std::string_view{ "]" }; + constexpr auto function = std::string_view{ __PRETTY_FUNCTION__ }; +#elif defined( __GNUC__ ) + constexpr auto prefix = std::string_view{ "with T = " }; + constexpr auto suffix = std::string_view{ "]" }; + constexpr auto function = std::string_view{ __PRETTY_FUNCTION__ }; +#elif defined( _MSC_VER ) + constexpr auto prefix = std::string_view{ "type_name_array<" }; + constexpr auto suffix = std::string_view{ ">(void)" }; + constexpr auto function = std::string_view{ __FUNCSIG__ }; +#else +# error Unsupported compiler +#endif + + constexpr auto start = function.find( prefix ) + prefix.size(); + constexpr auto end = function.rfind( suffix ); + static_assert( start < end ); + + constexpr auto name = function.substr( start, ( end - start ) ); + return as_array( name, std::make_index_sequence<name.size()>{} ); + } + + template <typename T> + struct type_name_holder { + static inline constexpr auto value = type_name_array<T>(); + }; +} // namespace details + +template <typename T> +constexpr std::string_view type_name() { + constexpr auto& value = details::type_name_holder<T>::value; + return std::string_view{ value.data(), value.size() }; +} diff --git a/Phys/FunctorCore/python/Functors/__init__.py b/Phys/FunctorCore/python/Functors/__init__.py index 95d7d5e04920634ac04c3ecbd848e4b8b24dcaa1..922b102bce3e40cb49e0de5c93704e1a7c3df606 100644 --- a/Phys/FunctorCore/python/Functors/__init__.py +++ b/Phys/FunctorCore/python/Functors/__init__.py @@ -1604,6 +1604,19 @@ PPHASMUONINFO = Functor( ALL = Functor("ALL", "AcceptAll", "Accept everything; always evaluates to 'true'.") NONE = Functor("NONE", "AcceptNone", "Accept nothing; always evaluates to 'false'.") IDENTITY = Functor("IDENTITY", "Identity", "Returns the same value.") +LOGGER = Functor( + "LOGGER", + "Logger", + "Print argument, and then return the same value.", + Params=[ + ( + "Format", + "formatstring: use {arg} to specify the argument, and {arg_type} to print type of the argument", + str, + ) + ], +) + COLUMN = Functor( "COLUMN", "Column_t", diff --git a/Phys/FunctorCore/tests/options/test_functors_tested.py b/Phys/FunctorCore/tests/options/test_functors_tested.py index f2a679f6115f262aa4f52bab9092a15591b036ab..eab163d681fa14b7a1b61b8fbb511d2ab6f11f04 100644 --- a/Phys/FunctorCore/tests/options/test_functors_tested.py +++ b/Phys/FunctorCore/tests/options/test_functors_tested.py @@ -61,6 +61,7 @@ exceptions = [ "Functors::Common::Median", "Functors::Column_t", "Functors::Identity", + "Functors::Logger", "Functors::Particle::ParticlePropertyUser", "Functors::PID::RichThresholdDe", "Functors::PID::RichThresholdKa",