-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMetaTask.hpp
More file actions
214 lines (180 loc) · 6.86 KB
/
Copy pathMetaTask.hpp
File metadata and controls
214 lines (180 loc) · 6.86 KB
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#pragma once
#include <any>
#include <functional>
#include <utility>
#include <../include/Meta.hpp>
#include <../include/MetaScheduler.hpp>
#include "MetaResourceList.h"
namespace Meta
{
// Bitset width is fixed by the finalized GLOBAL_METHOD_RESOURCE_LIST visible at this point.
// All ITasks across the program use the same width.
using TSchedulerTraits = CSchedulerTraits<GLOBAL_METHOD_RESOURCE_LIST>;
using TSchedulerBits = typename TSchedulerTraits::TBits;
class ITask
{
public:
using TTaskFunction = std::function<void()>;
ITask() = default;
explicit ITask(TTaskFunction&& task_function,
const TPriority priority = EPriority::Lowest)
: function(std::move(task_function)),
priority(priority)
{}
virtual ~ITask() = default;
virtual size_t GetNumResources() = 0;
virtual std::any GetMetaResource(size_t idx) = 0;
virtual std::any GetMetaResources() = 0;
// Bitsets over the global method registry.
// Bit B is set in METHOD_MASK if and only if this task touches the B-th registered method;
// bit B is set in CONFLICT_MASK if and only if this task conflicts with the B-th registered method.
// Both masks are compile-time constants per concrete CTask specialization,
// so the runtime cost is one virtual call plus a single bitset reference.
[[nodiscard]]
virtual const TSchedulerBits& GetMethodMask() const = 0;
[[nodiscard]]
virtual const TSchedulerBits& GetConflictMask() const = 0;
[[nodiscard]]
TPriority GetPriority() const noexcept
{
return priority;
}
void DoTask() const
{
function();
}
private:
TTaskFunction function;
TPriority priority = EPriority::Lowest;
};
template <method_resources... MethodAnnotations>
class CTask final : public ITask
{
public:
using TResources = CTypeList<MethodAnnotations...>;
using TTraits = TSchedulerTraits;
using TBits = TSchedulerBits;
// Retrieves the underlying resources of each method annotation,
// concatenates them to one tuple and filters out duplicates.
static constexpr auto GetFilteredResources();
// METHOD_MASK: bit B is set if and only if this task touches the B-th registered method.
// We start from an empty bitset and, for each annotation type the user passed to CTask<...>,
// look up its registry index and set the matching bit.
static constexpr TBits METHOD_MASK = []
{
TBits methodMask{};
// Fold over MethodAnnotations: for each type M, find its registry index and turn on that bit.
// Order does not matter; bits are independent.
((methodMask.set(TTraits::template IndexOf<MethodAnnotations>())), ...);
return methodMask;
}();
// CONFLICT_MASK: bit B is set if and only if this task conflicts with the B-th registered method.
// Each of our annotations contributes its precomputed conflict row from the global matrix;
// OR-ing those rows gives the union of all methods that conflict with anything we touch.
static constexpr TBits CONFLICT_MASK = []
{
TBits conflictMask{};
// For each of our annotation types, look up its registry index, fetch the conflict row at that index
// (a bitset of all methods that conflict with this one), and OR it into the accumulator.
((conflictMask |= TTraits::CONFLICT_ROWS[TTraits::template IndexOf<MethodAnnotations>()]), ...);
return conflictMask;
}();
CTask() = default;
explicit CTask(TTaskFunction&& task_function,
TPriority priority = EPriority::Lowest)
: ITask(std::move(task_function), priority)
{}
~CTask() override = default;
size_t GetNumResources() override
{
return NUM_RESOURCES;
}
std::any GetMetaResource(size_t idx) override
{
return GetResourceElementAt(idx, std::make_index_sequence<NUM_RESOURCES>{});
}
std::any GetMetaResources() override
{
return RESOURCES;
}
[[nodiscard]]
const TBits& GetMethodMask() const override
{
return METHOD_MASK;
}
[[nodiscard]]
const TBits& GetConflictMask() const override
{
return CONFLICT_MASK;
}
private:
static constexpr auto RESOURCES = TResources{};
static constexpr auto NUM_RESOURCES = TypeListSize(TResources{});
// Helper function to get a tuple element by runtime index
template <size_t Idx>
static std::any GetResourceElementAt(size_t idx);
// Base case: if index doesn't match any of the tuple indices
template <size_t Idx>
static std::any GetResourceElementAt(std::index_sequence<>);
// Recursive helper to iterate over the tuple
template <size_t... Idx>
static std::any GetResourceElementAt(size_t idx, std::index_sequence<Idx...>);
// concatenates all filtered resources into one tuple
static constexpr auto ConcatAllResources();
//
template <method_or_member_resources ... Resources>
static constexpr auto UniqueResources(CTypeList<Resources...>);
// filters out duplicates
template <method_or_member_resources... UnfilteredResources>
static constexpr auto FilterResources(CTypeList<UnfilteredResources...>);
};
template <method_resources ... MethodAnnotations>
template <size_t Idx>
std::any CTask<MethodAnnotations...>::GetResourceElementAt(const size_t idx)
{
if (idx == Idx)
return Meta::TypeListAt<Idx>(RESOURCES); // Return the element wrapped in std::any
return {};
// Default to an empty std::any if not the correct index
}
template <method_resources ... MethodAnnotations>
template <size_t Idx>
std::any CTask<MethodAnnotations...>::GetResourceElementAt(std::index_sequence<>)
{
return {}; // Return empty std::any if no valid index is found
}
template <method_resources ... MethodAnnotations>
template <size_t... Idx>
std::any CTask<MethodAnnotations...>::GetResourceElementAt(size_t idx, std::index_sequence<Idx...>)
{
std::any result{};
((result = idx == Idx ? Meta::TypeListAt<Idx>(RESOURCES) : result), ...); // Runtime index dispatch
return result;
}
template <method_resources ... MethodAnnotations>
constexpr auto CTask<MethodAnnotations...>::GetFilteredResources()
{
return FilterResources(UniqueResources(ConcatAllResources()));
}
template <method_resources ... MethodAnnotations>
constexpr auto CTask<MethodAnnotations...>::ConcatAllResources()
{
// each MethodAnnotations::GetFilteredResources() returns a type list of the filtered out resources
return Meta::TConcatTypeList<decltype(MethodAnnotations::GetFilteredResources())...>{};
}
template <method_resources ... MethodAnnotations>
template <method_or_member_resources ... Resources>
constexpr auto CTask<MethodAnnotations...>::UniqueResources(CTypeList<Resources...>)
{
// CTypeList<Ts...>
using TUnique = typename TUniqueTypes<Resources...>::TTypes;
return TUnique{};
}
template <method_resources ... MethodAnnotations>
template <method_or_member_resources ... UnfilteredResources>
constexpr auto CTask<MethodAnnotations...>::FilterResources(CTypeList<UnfilteredResources...>)
{
using TMethodResources = CMethodResources<UnfilteredResources...>;
return TMethodResources::GetFilteredResources();
}
}