File: invocable_with_telemetry.h

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 1,998,492 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (89 lines) | stat: -rw-r--r-- 2,789 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H
#define TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H

#include <cassert>
#include <concepts>
#include <functional>
#include <utility>

#if TEST_STD_VER < 20
#  error invocable_with_telemetry requires C++20
#else
struct invocable_telemetry {
  int invocations;
  int moves;
  int copies;
};

template <class F>
class invocable_with_telemetry {
public:
  constexpr invocable_with_telemetry(F f, invocable_telemetry& telemetry) : f_(f), telemetry_(&telemetry) {}

  constexpr invocable_with_telemetry(invocable_with_telemetry&& other)
    requires std::move_constructible<F>
      : f_(std::move(other.f_)),
        telemetry_((assert(other.telemetry_ != nullptr), std::exchange(other.telemetry_, nullptr))) {
    ++telemetry_->moves;
  }

  constexpr invocable_with_telemetry(invocable_with_telemetry const& other)
    requires std::copy_constructible<F>
      : f_(other.f_), telemetry_((assert(other.telemetry_ != nullptr), other.telemetry_)) {
    ++telemetry_->copies;
  }

  constexpr invocable_with_telemetry& operator=(invocable_with_telemetry&& other)
    requires std::movable<F>
  {
    // Not using move-and-swap idiom to ensure that copies and moves remain accurate.
    assert(&other != this);
    assert(other.telemetry_ != nullptr);

    f_         = std::move(other.f_);
    telemetry_ = std::exchange(other.telemetry_, nullptr);

    ++telemetry_->moves;
    return *this;
  }

  constexpr invocable_with_telemetry& operator=(invocable_with_telemetry const& other)
    requires std::copyable<F>
  {
    // Not using copy-and-swap idiom to ensure that copies and moves remain accurate.
    assert(&other != this);
    assert(other.telemetry_ != nullptr);

    f_         = other.f_;
    telemetry_ = other.telemetry_;

    ++telemetry_->copies;
    return *this;
  }

  template <class... Args>
    requires std::invocable<F&, Args...>
  constexpr decltype(auto) operator()(Args&&... args) noexcept(std::is_nothrow_invocable_v<F&, Args...>) {
    assert(telemetry_);
    ++telemetry_->invocations;
    return std::invoke(f_, std::forward<Args>(args)...);
  }

private:
  F f_                            = F();
  invocable_telemetry* telemetry_ = nullptr;
};

template <class F>
invocable_with_telemetry(F f, int& invocations, int& moves, int& copies) -> invocable_with_telemetry<F>;

#endif // TEST_STD_VER < 20
#endif // TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H