2

I'm trying to build an intrusive profiler in which tags are hand placed. It would be very nice if those tags could be translated into integers that directly index into a data structure at compile time so runtime code for the profile tag was as small as possible (perhaps appending an integer identifier to a ring buffer, for example).

Is it possible to use constexpr to do this completely at compile time? Needless to say, the tags will be occurring in several different compilation units.

I've discovered that taking the address of an extern is constexpr friendly in C++17, but I haven't thought of a way to make this do what I want.

Is there a way to do what I want, or is it simply not possible? The main hurdle I see is that it seems like it would require some compile time state to transferred between compilation units. Using the extern trick, you can kind of accomplish this, but I'm not sure the state that's being shared is useful for what I want to do.

Here's an example of what I'm talking about:

file1.cpp:

#include <ProfilerThing.h>

#define xstr(a) str(a)
#define str(a) $a

int function1()
{
    static constexpr auto token1 = MakeGlobalToken(__PRETTY_FUNCTION__ " at " __FILE__ ": " xstr(__LINE__));
    BeginProfile(token1);

    EndProfile(token1);
}

file2.cpp:

int function2()
{
    static constexpr auto token2 = MakeGlobalToken(__PRETTY_FUNCTION__ " at " __FILE__ ": " xstr(__LINE__));
    BeginProfile(token2);

    EndProfile(token2);
}

What would MakeGlobalToken have to look like? Is it even possible to write? token1 and token2 have to be unique. And, ideally, they would be indexes into some sort of data structure.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194

1 Answers1

2

The first thing that comes to mind is addresses. They are guaranteed to be unique and are readily hashable.

template<auto>
struct token
{
    inline static struct {} dummy;
};

template<auto x>
constexpr void* MakeGlobalToken()
{
    return &token<x>::dummy;
}

Used as

inline std::unordered_map<void*, int> logger;

void BeginProfile(void* token)
{
    logger[token]++;
}

void EndProfile(void* token)
{
    logger[token]++;
}

int function1()
{
    static constexpr auto token1 = MakeGlobalToken<function1>();
    BeginProfile(token1);

    EndProfile(token1);
}

int function2()
{
    static constexpr auto token2 = MakeGlobalToken<function2>();
    BeginProfile(token2);

    EndProfile(token2);
}
Passer By
  • 19,325
  • 6
  • 49
  • 96