-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstatic_local_tracker.hpp
141 lines (115 loc) · 5.72 KB
/
static_local_tracker.hpp
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#pragma once
#include <cassert>
#include <mutex>
#include <shared_mutex>
#include <source_location>
#include <string_view>
#include <typeinfo>
#include <type_traits>
#include <unordered_map>
#include "deps/helpers/strong_type.hpp"
template <typename T>
struct std::hash<StrongType<std::string_view, T>>
{
constexpr std::size_t operator()(const StrongType<std::string_view, T> strong) const noexcept
{
return std::hash<std::string_view>{}(strong.get());
}
};
namespace StaticLocalTracker
{
using VarNameTag = struct Func;
using FuncNameTag = struct Func;
using FileNameTag = struct File;
using VarName = StrongType<std::string_view, VarNameTag>;
using FuncName = StrongType<std::string_view, FuncNameTag>;
using FileName = StrongType<std::string_view, FileNameTag>;
class static_local
{
private:
void* m_ptr;
const std::type_info* m_type_info;
public:
static_local() = default;
template<typename T>
static_local(T& var) :
m_ptr{&var},
m_type_info{&typeid(T)}
{}
static_local(const static_local&) = default;
template<typename T>
T* get()
{
if (typeid(T) == *m_type_info)
return reinterpret_cast<T*>(m_ptr);
else
return nullptr;
}
};
using _static_locals_t = std::unordered_map<VarName, static_local>;
using _func_to_static_locals_t = std::unordered_map<FuncName, _static_locals_t>;
using _file_to_funcs_t = std::unordered_map<FileName, _func_to_static_locals_t>;
// Global tracker
inline _file_to_funcs_t _global_statics_tracker{};
template<typename T>
void _track_impl(T& var, VarName var_name, const std::source_location place = std::source_location::current())
{
auto file_name = FileName{place.file_name()};
auto func_name = FuncName{place.function_name()};
_global_statics_tracker[file_name][func_name].insert({var_name, var});
}
template<typename T>
T* _get_impl(FileName file_name, FuncName func_name, VarName var_name)
{
if (_global_statics_tracker.contains(file_name) and _global_statics_tracker.at(file_name).contains(func_name) and _global_statics_tracker.at(file_name).at(func_name).contains(var_name))
return _global_statics_tracker.at(file_name).at(func_name).at(var_name).template get<T>();
return nullptr;
}
template<typename T>
T* _get_impl(FuncName func_name, VarName var_name)
{
for (const auto& [file_name, funcs] : _global_statics_tracker)
if (_global_statics_tracker.at(file_name).contains(func_name) and _global_statics_tracker.at(file_name).at(func_name).contains(var_name))
return _global_statics_tracker.at(file_name).at(func_name).at(var_name).template get<T>();
return nullptr;
}
template<typename T>
T* _get_impl(VarName var_name)
{
for (const auto& [file_name, funcs] : _global_statics_tracker)
for (const auto& [func_name, vars] : _global_statics_tracker.at(file_name))
if (_global_statics_tracker.at(file_name).at(func_name).contains(var_name))
return _global_statics_tracker.at(file_name).at(func_name).at(var_name).template get<T>();
return nullptr;
}
// Shared mutex to support simultanious reading and writing to global tracker
inline std::shared_mutex _global_static_tracker_mtx;
} // namespace StaticLocalTracker
// Adds static local variable to global tracking
#define STATIC_LOCAL_TRACK(var) [[maybe_unused]] static auto _tracker = []{ \
std::unique_lock lk{StaticLocalTracker::_global_static_tracker_mtx}; \
StaticLocalTracker::_track_impl<std::decay_t<decltype(var)>>(var, StaticLocalTracker::VarName{std::string_view{#var}}); \
return 0; \
}()
// Copies static local by <type> and <name> to variable
#define STATIC_LOCAL_COPY(type, name) []() -> type { \
std::shared_lock lk{StaticLocalTracker::_global_static_tracker_mtx}; \
static_assert(std::is_copy_constructible_v<type>, "type should be copy constructible"); \
auto* ptr = StaticLocalTracker::_get_impl<type>(StaticLocalTracker::VarName{std::string_view{#name}}); \
assert(ptr != nullptr); \
return *ptr; \
}()
// Copies static local to variable by out parameter
#define STATIC_LOCAL_COPY_TO(var) { \
std::shared_lock lk{StaticLocalTracker::_global_static_tracker_mtx}; \
auto* _ptr = StaticLocalTracker::_get_impl<decltype(var)>(StaticLocalTracker::VarName{std::string_view{#var}}); \
assert(_ptr != nullptr); \
var = *_ptr; \
}
// Obtains reference to static local object by <type> and <name>
#define STATIC_LOCAL_GET_REF(type, name) []() -> type& { \
std::shared_lock lk{StaticLocalTracker::_global_static_tracker_mtx}; \
auto* ptr = StaticLocalTracker::_get_impl<type>(StaticLocalTracker::VarName{std::string_view{#name}}); \
assert(ptr != nullptr); \
return *ptr; \
}()