90 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H10#define TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H11 12#include <cassert>13#include <concepts>14#include <functional>15#include <utility>16 17#if TEST_STD_VER < 2018# error invocable_with_telemetry requires C++2019#else20struct invocable_telemetry {21 int invocations;22 int moves;23 int copies;24};25 26template <class F>27class invocable_with_telemetry {28public:29 constexpr invocable_with_telemetry(F f, invocable_telemetry& telemetry) : f_(f), telemetry_(&telemetry) {}30 31 constexpr invocable_with_telemetry(invocable_with_telemetry&& other)32 requires std::move_constructible<F>33 : f_(std::move(other.f_)),34 telemetry_((assert(other.telemetry_ != nullptr), std::exchange(other.telemetry_, nullptr))) {35 ++telemetry_->moves;36 }37 38 constexpr invocable_with_telemetry(invocable_with_telemetry const& other)39 requires std::copy_constructible<F>40 : f_(other.f_), telemetry_((assert(other.telemetry_ != nullptr), other.telemetry_)) {41 ++telemetry_->copies;42 }43 44 constexpr invocable_with_telemetry& operator=(invocable_with_telemetry&& other)45 requires std::movable<F>46 {47 // Not using move-and-swap idiom to ensure that copies and moves remain accurate.48 assert(&other != this);49 assert(other.telemetry_ != nullptr);50 51 f_ = std::move(other.f_);52 telemetry_ = std::exchange(other.telemetry_, nullptr);53 54 ++telemetry_->moves;55 return *this;56 }57 58 constexpr invocable_with_telemetry& operator=(invocable_with_telemetry const& other)59 requires std::copyable<F>60 {61 // Not using copy-and-swap idiom to ensure that copies and moves remain accurate.62 assert(&other != this);63 assert(other.telemetry_ != nullptr);64 65 f_ = other.f_;66 telemetry_ = other.telemetry_;67 68 ++telemetry_->copies;69 return *this;70 }71 72 template <class... Args>73 requires std::invocable<F&, Args...>74 constexpr decltype(auto) operator()(Args&&... args) noexcept(std::is_nothrow_invocable_v<F&, Args...>) {75 assert(telemetry_);76 ++telemetry_->invocations;77 return std::invoke(f_, std::forward<Args>(args)...);78 }79 80private:81 F f_ = F();82 invocable_telemetry* telemetry_ = nullptr;83};84 85template <class F>86invocable_with_telemetry(F f, int& invocations, int& moves, int& copies) -> invocable_with_telemetry<F>;87 88#endif // TEST_STD_VER < 2089#endif // TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H90