brintos

brintos / llvm-project-archived public Read only

0
0
Text · 2.7 KiB · e010837 Raw
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