openMSX
ProfileCounters.hh
Go to the documentation of this file.
1#ifndef PROFILECOUNTERS_HH
2#define PROFILECOUNTERS_HH
3
4#include "enumerate.hh"
5#include <array>
6#include <iostream>
7
8//
9// Quick and dirty reflection on C++ enums (in the future replace with c++23 reflexpr).
10//
11
12// Print an enum type as a string, for example:
13// os << EnumTypeName<SomeEnumType>() << '\n';
14template<typename E> struct EnumTypeName {};
15// You _must_ overload 'operator<<' for all enum types for which you want this to work.
16template<typename E> std::ostream& operator<<(std::ostream& os, EnumTypeName<E>) = delete;
17
18// Print an enum value as a string, for example:
19// os << EnumValueName{myEnumValue} << '\n';
20template<typename E> struct EnumValueName
21{
22 explicit EnumValueName(E e_) : e(e_) {}
23 E e;
24};
25// You _must_ overload 'operator<<' for all enum types for which you want this to work.
26template<typename E> std::ostream& operator<<(std::ostream& os, EnumValueName<E> evn) = delete;
27
28
29
30
31// A collection of (simple) profile counters:
32// - Counters start at zero.
33// - An individual counter can be incremented by 1 via 'tick(<counter-id>)'.
34// - When this 'ProfileCounters' object is destroyed it prints the value of each
35// counter.
36//
37// Template parameters:
38// - bool ENABLED:
39// when false, the optimizer should be able to completely optimize-out all
40// profile related code
41// - typename ENUM:
42// Must be a c++ enum (or enum class) which satisfies the following requirements:
43// * The numerical values must be 0, 1, ... IOW the values must be usable as
44// indices in an array. (This is automatically the case if you don't
45// manually assign numeric values).
46// * There must be an enum value with the name 'NUM' which has a numerical
47// value equal to the number of other values in this enum. (This is
48// automatically the case if you put 'NUM' last in the list of enum
49// values).
50// * You must overload the following two functions for the type 'ENUM':
51// std::ostream& operator<<(std::ostream& os, EnumTypeName<ENUM>);
52// std::ostream& operator<<(std::ostream& os, EnumValueName<ENUM> evn);
53//
54// Example usage:
55// enum class WidgetProfileCounter {
56// CALCULATE,
57// INVALIDATE,
58// NUM // must be last
59// };
60// std::ostream& operator<<(std::ostream& os, EnumTypeName<WidgetProfileCounter>)
61// {
62// return os << "WidgetProfileCounter";
63// }
64// std::ostream& operator<<(std::ostream& os, EnumValueName<WidgetProfileCounter> evn)
65// {
66// std::string_view names[size_t(WidgetProfileCounter::NUM)] = {
67// "calculate"sv, "invalidate"sv
68// };
69// return os << names[size_t(evn.e)];
70// }
71//
72// constexpr bool PRINT_WIDGET_PROFILE = true; // possibly depending on some #define
73//
74// struct Widget : private ProfileCounters<PRINT_WIDGET_PROFILE, WidgetProfileCounter>
75// {
76// void calculate() {
77// tick(WidgetProfileCounter::CALCULATE);
78// // ...
79// }
80// void invalidate() {
81// tick(WidgetProfileCounter::CALCULATE);
82// // ...
83// }
84// };
85
86template<bool ENABLED, typename ENUM>
88{
89public:
94
95 // Print counters on destruction.
97 std::cout << "-- Profile counters: " << EnumTypeName<ENUM>() << " -- " << static_cast<void*>(this) << '\n';
98 for (auto [i, count] : enumerate(counters)) {
99 std::cout << EnumValueName{ENUM(i)} << ": " << count << '\n';
100 }
101 }
102
103 // Increment
104 void tick(ENUM e) const {
105 ++counters[size_t(e)];
106 }
107
108private:
109 static constexpr auto NUM = size_t(ENUM::NUM); // value 'ENUM::NUM' must exist
110 mutable std::array<unsigned, NUM> counters = {};
111};
112
113
114// Specialization for when profiling is disabled.
115// This class is simple enough so that it can be completely optimized away.
116template<typename ENUM>
117class ProfileCounters<false, ENUM>
118{
119public:
120 void tick(ENUM) const { /*nothing*/ }
121};
122
123#endif
std::ostream & operator<<(std::ostream &os, EnumTypeName< E >)=delete
ProfileCounters & operator=(const ProfileCounters &)=delete
ProfileCounters(ProfileCounters &&)=delete
void tick(ENUM e) const
ProfileCounters & operator=(ProfileCounters &&)=delete
ProfileCounters(const ProfileCounters &)=delete
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition enumerate.hh:28