139034388SChristopher Di Bella //===----------------------------------------------------------------------===// 239034388SChristopher Di Bella // 339034388SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 439034388SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information. 539034388SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 639034388SChristopher Di Bella // 739034388SChristopher Di Bella //===----------------------------------------------------------------------===// 839034388SChristopher Di Bella 939034388SChristopher Di Bella #ifndef TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H 1039034388SChristopher Di Bella #define TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H 1139034388SChristopher Di Bella 1239034388SChristopher Di Bella #include <cassert> 1339034388SChristopher Di Bella #include <concepts> 1439034388SChristopher Di Bella #include <functional> 1539034388SChristopher Di Bella #include <utility> 1639034388SChristopher Di Bella 1739034388SChristopher Di Bella #if TEST_STD_VER < 20 1839034388SChristopher Di Bella # error invocable_with_telemetry requires C++20 1939034388SChristopher Di Bella #else 2039034388SChristopher Di Bella struct invocable_telemetry { 2139034388SChristopher Di Bella int invocations; 2239034388SChristopher Di Bella int moves; 2339034388SChristopher Di Bella int copies; 2439034388SChristopher Di Bella }; 2539034388SChristopher Di Bella 2639034388SChristopher Di Bella template <class F> 2739034388SChristopher Di Bella class invocable_with_telemetry { 2839034388SChristopher Di Bella public: invocable_with_telemetry(F f,invocable_telemetry & telemetry)2939034388SChristopher Di Bella constexpr invocable_with_telemetry(F f, invocable_telemetry& telemetry) : f_(f), telemetry_(&telemetry) {} 3039034388SChristopher Di Bella invocable_with_telemetry(invocable_with_telemetry && other)3139034388SChristopher Di Bella constexpr invocable_with_telemetry(invocable_with_telemetry&& other) 3239034388SChristopher Di Bella requires std::move_constructible<F> 3339034388SChristopher Di Bella : f_(std::move(other.f_)), 34*98031968SKrystian Stasiowski telemetry_((assert(other.telemetry_ != nullptr), std::exchange(other.telemetry_, nullptr))) { 3539034388SChristopher Di Bella ++telemetry_->moves; 3639034388SChristopher Di Bella } 3739034388SChristopher Di Bella invocable_with_telemetry(invocable_with_telemetry const & other)3839034388SChristopher Di Bella constexpr invocable_with_telemetry(invocable_with_telemetry const& other) 3939034388SChristopher Di Bella requires std::copy_constructible<F> 4039034388SChristopher Di Bella : f_(other.f_), telemetry_((assert(other.telemetry_ != nullptr), other.telemetry_)) { 4139034388SChristopher Di Bella ++telemetry_->copies; 4239034388SChristopher Di Bella } 4339034388SChristopher Di Bella 4439034388SChristopher Di Bella constexpr invocable_with_telemetry& operator=(invocable_with_telemetry&& other) 4539034388SChristopher Di Bella requires std::movable<F> 4639034388SChristopher Di Bella { 4739034388SChristopher Di Bella // Not using move-and-swap idiom to ensure that copies and moves remain accurate. 4839034388SChristopher Di Bella assert(&other != this); 4939034388SChristopher Di Bella assert(other.telemetry_ != nullptr); 5039034388SChristopher Di Bella 5139034388SChristopher Di Bella f_ = std::move(other.f_); 5239034388SChristopher Di Bella telemetry_ = std::exchange(other.telemetry_, nullptr); 5339034388SChristopher Di Bella 5439034388SChristopher Di Bella ++telemetry_->moves; 5539034388SChristopher Di Bella return *this; 5639034388SChristopher Di Bella } 5739034388SChristopher Di Bella 5839034388SChristopher Di Bella constexpr invocable_with_telemetry& operator=(invocable_with_telemetry const& other) 5939034388SChristopher Di Bella requires std::copyable<F> 6039034388SChristopher Di Bella { 6139034388SChristopher Di Bella // Not using copy-and-swap idiom to ensure that copies and moves remain accurate. 6239034388SChristopher Di Bella assert(&other != this); 6339034388SChristopher Di Bella assert(other.telemetry_ != nullptr); 6439034388SChristopher Di Bella 6539034388SChristopher Di Bella f_ = other.f_; 6639034388SChristopher Di Bella telemetry_ = other.telemetry_; 6739034388SChristopher Di Bella 6839034388SChristopher Di Bella ++telemetry_->copies; 6939034388SChristopher Di Bella return *this; 7039034388SChristopher Di Bella } 7139034388SChristopher Di Bella 7239034388SChristopher Di Bella template <class... Args> 7339034388SChristopher Di Bella requires std::invocable<F&, Args...> decltype(auto)7439034388SChristopher Di Bella constexpr decltype(auto) operator()(Args&&... args) noexcept(std::is_nothrow_invocable_v<F&, Args...>) { 7539034388SChristopher Di Bella assert(telemetry_); 7639034388SChristopher Di Bella ++telemetry_->invocations; 7739034388SChristopher Di Bella return std::invoke(f_, std::forward<Args>(args)...); 7839034388SChristopher Di Bella } 7939034388SChristopher Di Bella 8039034388SChristopher Di Bella private: 8139034388SChristopher Di Bella F f_ = F(); 8239034388SChristopher Di Bella invocable_telemetry* telemetry_ = nullptr; 8339034388SChristopher Di Bella }; 8439034388SChristopher Di Bella 8539034388SChristopher Di Bella template <class F> 8639034388SChristopher Di Bella invocable_with_telemetry(F f, int& invocations, int& moves, int& copies) -> invocable_with_telemetry<F>; 8739034388SChristopher Di Bella 8839034388SChristopher Di Bella #endif // TEST_STD_VER < 20 8939034388SChristopher Di Bella #endif // TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H 90