AsmGrader 0.0.0
Loading...
Searching...
No Matches
metadata.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <boost/mp11/algorithm.hpp>
4#include <boost/mp11/detail/mp_append.hpp>
5#include <boost/mp11/detail/mp_list.hpp>
6#include <boost/mp11/detail/mp_rename.hpp>
7#include <boost/mp11/integral.hpp>
8#include <boost/mp11/list.hpp>
9
10#include <concepts>
11#include <cstddef>
12#include <functional>
13#include <optional>
14#include <string_view>
15#include <tuple>
16#include <type_traits>
17#include <utility>
18#include <variant>
19
21
23{
24 std::string_view name;
25 std::string_view exec_name;
26
27 // NOLINTNEXTLINE(readability-identifier-naming, bugprone-easily-swappable-parameters)
28 consteval explicit Assignment(std::string_view name_, std::string_view exec_name_)
29 : name{name_}
30 , exec_name{exec_name_} {}
31
32 // Example:
33 // Assignment{"lab2-1.out"} -> {"lab2-1", "lab2-1.out"}
34 consteval explicit Assignment(std::string_view exec_name_out)
35 : name{exec_name_out.substr(0, exec_name_out.find('.'))}
36 , exec_name{exec_name_out} {}
37
38 constexpr bool operator==(const Assignment&) const = default;
39};
40
42{
43 constexpr bool operator==(const ProfOnlyTag&) const = default;
44};
45
46constexpr auto ProfOnly = ProfOnlyTag{}; // NOLINT
47
48struct Weight
49{
50 std::size_t points;
51
52 constexpr bool operator==(const Weight&) const = default;
53};
54
55namespace detail::meta {
56
57using namespace boost::mp11;
58
59template <typename T>
60using NormalizedT = std::decay_t<T>;
61
62template <template <typename...> class TypeList, typename... Ts>
63using NormalizedTypeList = mp_rename<mp_transform<std::decay_t, mp_list<Ts...>>, TypeList>;
64
65template <typename T>
66consteval bool is_normalized() {
67 return std::same_as<NormalizedT<T>, T>;
68}
69
70static_assert(
71 std::same_as<NormalizedTypeList<std::tuple, int, int&, const int, const int&>, std::tuple<int, int, int, int>>);
72
73using MetadataAttrTs = mp_list<Assignment, ProfOnlyTag, Weight>;
74
75// The type `T` if `T` is not void, otherwise std::monostate
76template <typename T>
77using TypeOrMonostate = std::conditional_t<std::same_as<NormalizedT<T>, void>, std::monostate, T>;
78
79template <std::size_t I, typename... Ts>
80using Get = mp_at<mp_list<Ts...>, mp_int<I>>;
81
82template <typename List, typename T>
83static constexpr bool Has = mp_find<List, T>::value != mp_size<List>::value;
84
85template <typename Orig, typename... New>
87
88template <typename Orig, typename First, typename... New>
89struct MergeUnqImpl<Orig, First, New...>
90{
91 static constexpr bool DoAddFirst = !Has<Orig, First>;
92 using WithAddedFirst = mp_push_back<Orig, First>;
93 using FirstMergeRes = std::conditional_t<DoAddFirst, WithAddedFirst, Orig>;
94
95 using type = MergeUnqImpl<FirstMergeRes, New...>::type;
96};
97
98template <typename Orig>
99struct MergeUnqImpl<Orig>
100{
101 using type = Orig;
102};
103
104template <typename Orig, typename... New>
105using MergeUnq = MergeUnqImpl<Orig, New...>::type;
106
107static_assert(std::same_as<MergeUnq<mp_list<int>, int>, mp_list<int>>);
108static_assert(std::same_as<MergeUnq<mp_list<int>, int, int>, mp_list<int>>);
109static_assert(std::same_as<MergeUnq<mp_list<int>, double>, mp_list<int, double>>);
110static_assert(std::same_as<MergeUnq<mp_list<int>, double, int, double>, mp_list<int, double>>);
111static_assert(std::same_as<MergeUnq<mp_list<int, double>, double, int, double>, mp_list<int, double>>);
112
113} // namespace detail::meta
114
115template <typename... MetadataTypes>
117{
118public:
119 static_assert(
121 "To prevent dangling references and other issues, all type parameters of Metadata should be normalized."
122 "Use the provided deduction guide.");
123
124 template <typename... Args>
125 // prevent this from becoming move/copy constructor
126 requires(sizeof...(Args) != 1 ||
127 !(std::same_as<detail::meta::NormalizedT<detail::meta::Get<0, Args...>>, Metadata<MetadataTypes...>>))
128 explicit consteval Metadata(Args&&... args);
129
130 template <typename... Args>
131 friend consteval auto create(Args&&... args);
132
133 template <typename OtherMetadataType>
134 consteval auto operator|(OtherMetadataType&& attr) const;
135
136 template <typename... OtherMetadataTypes>
137 consteval auto operator|(Metadata<OtherMetadataTypes...> other) const;
138
139 template <typename MetadataType>
140 constexpr std::optional<MetadataType> get() const;
141
142 template <typename MetadataType, typename Func>
143 constexpr std::optional<detail::meta::TypeOrMonostate<std::invoke_result_t<Func, MetadataType>>>
144 get_and(Func&& func) const;
145
146 template <typename T>
147 static consteval bool has();
148
149private:
150 template <typename... LArgs, typename... RArgs, std::size_t I = 0>
151 static consteval auto merge_impl(std::tuple<LArgs...> largs, std::tuple<RArgs...> rargs);
152
153 template <typename... LArgs, typename RArg>
154 static consteval auto merge_impl(std::tuple<LArgs...> largs, RArg&& rarg);
155
156 template <typename... Args>
157 explicit consteval Metadata(std::tuple<Args...> data);
158
159 std::tuple<MetadataTypes...> data_;
160
161 template <typename... Ts>
162 friend class Metadata;
163};
164
165// Deduction guides
166template <typename... Args>
168
169template <typename... Args>
170Metadata(std::tuple<Args...>) -> Metadata<Args...>;
171
172template <typename... Args>
173consteval auto create(Args&&... args) {
174 return (Metadata<>{} | ... | std::forward<Args>(args));
175}
176
177// Function template definitions
178
179template <typename... MetadataTypes>
180template <typename... Args>
181 requires(sizeof...(Args) != 1 ||
182 !(std::same_as<detail::meta::NormalizedT<detail::meta::Get<0, Args...>>, Metadata<MetadataTypes...>>))
184 : data_{std::forward<Args>(args)...} {}
185
186template <typename... MetadataTypes>
187template <typename... Args>
188consteval Metadata<MetadataTypes...>::Metadata(std::tuple<Args...> data)
189 : data_{data} {}
190
191template <typename... MetadataTypes>
192template <typename... OtherMetadataTypes>
193consteval auto Metadata<MetadataTypes...>::operator|([[maybe_unused]] Metadata<OtherMetadataTypes...> other) const {
194 return (*this | ... | std::get<OtherMetadataTypes>(other.data_));
195}
196
197template <typename... MetadataTypes>
198template <typename OtherMetadataType>
199consteval auto Metadata<MetadataTypes...>::operator|(OtherMetadataType&& attr) const {
200 using boost::mp11::mp_apply;
201
202 auto merge_res = merge_impl(data_, std::forward<OtherMetadataType>(attr));
203
204 using MetadataType = mp_apply<Metadata, decltype(merge_res)>;
205
206 return MetadataType{merge_res};
207}
208
209template <typename... MetadataTypes>
210template <typename MetadataType>
211constexpr std::optional<MetadataType> Metadata<MetadataTypes...>::get() const {
212 if constexpr (has<MetadataType>()) {
213 return std::get<MetadataType>(data_);
214 }
215
216 return std::nullopt;
217}
218
219template <typename... MetadataTypes>
220template <typename MetadataType, typename Func>
221constexpr std::optional<detail::meta::TypeOrMonostate<std::invoke_result_t<Func, MetadataType>>>
223 if constexpr (has<MetadataType>()) {
224 return std::invoke(std::forward<Func>(func), *get<MetadataType>());
225 }
226
227 return std::nullopt;
228}
229
230template <typename... MetadataTypes>
231template <typename T>
233 using boost::mp11::mp_find, boost::mp11::mp_list;
234
235 using TypeList = mp_list<MetadataTypes...>;
236 constexpr auto IDX = mp_find<TypeList, T>::value;
237
238 return IDX < sizeof...(MetadataTypes);
239}
240
241template <typename... MetadataTypes>
242template <typename... LArgs, typename... RArgs, std::size_t I>
243consteval auto Metadata<MetadataTypes...>::merge_impl(std::tuple<LArgs...> largs, std::tuple<RArgs...> rargs) {
244 if constexpr (I >= sizeof...(LArgs)) {
245 return largs;
246 } else {
247 largs = merge_impl<I + 1>(largs, rargs);
248
249 return merge_impl(largs, std::get<I>(rargs));
250 }
251}
252
253template <typename... MetadataTypes>
254template <typename... LArgs, typename RArg>
255consteval auto Metadata<MetadataTypes...>::merge_impl(std::tuple<LArgs...> largs, RArg&& rarg) {
256 using boost::mp11::mp_find, boost::mp11::mp_list, detail::meta::NormalizedT;
257
258 using Ls = mp_list<LArgs...>;
259 using R = NormalizedT<RArg>;
260
261 constexpr auto IDX = mp_find<Ls, R>::value;
262
263 if constexpr (IDX == sizeof...(LArgs)) {
264 // RArg type does NOT exist in largs; just concatenate, no merge
265 return std::tuple_cat(largs, // could `move` largs here, but it's consteval anyways...
266 std::tuple{std::forward<RArg>(rarg)});
267 } else {
268 // RArg type DOES exist in largs; merge by just replacing IDX
269 std::get<IDX>(largs) = std::forward<RArg>(rarg);
270 return largs;
271 }
272}
273
275
276// Each TU has its own static global definition of this free function
277// Overload resolution will always prefer the non-template version of the fn,
278// allowing the user to specify "file" (TU) defaults by simply overloading the fn.
279template <typename T = void>
280static consteval auto global_file_metadata() {
281 return Metadata{};
282}
283
284} // namespace asmgrader::metadata
Definition metadata.hpp:117
friend class Metadata
Definition metadata.hpp:162
friend consteval auto create(Args &&... args)
Definition metadata.hpp:173
static consteval bool has()
Definition metadata.hpp:232
constexpr std::optional< MetadataType > get() const
Definition metadata.hpp:211
constexpr std::optional< detail::meta::TypeOrMonostate< std::invoke_result_t< Func, MetadataType > > > get_and(Func &&func) const
Definition metadata.hpp:222
consteval auto operator|(OtherMetadataType &&attr) const
Definition metadata.hpp:199
consteval bool is_normalized()
Definition metadata.hpp:66
std::decay_t< T > NormalizedT
Definition metadata.hpp:60
MergeUnqImpl< Orig, New... >::type MergeUnq
Definition metadata.hpp:105
mp_at< mp_list< Ts... >, mp_int< I > > Get
Definition metadata.hpp:80
mp_list< Assignment, ProfOnlyTag, Weight > MetadataAttrTs
Definition metadata.hpp:73
std::conditional_t< std::same_as< NormalizedT< T >, void >, std::monostate, T > TypeOrMonostate
Definition metadata.hpp:77
mp_rename< mp_transform< std::decay_t, mp_list< Ts... > >, TypeList > NormalizedTypeList
Definition metadata.hpp:63
Definition metadata.hpp:20
consteval auto create(Args &&... args)
Definition metadata.hpp:173
constexpr auto ProfOnly
Definition metadata.hpp:46
constexpr Metadata DEFAULT_METADATA
Definition metadata.hpp:274
Metadata(Args &&...) -> Metadata< detail::meta::NormalizedT< Args >... >
Definition metadata.hpp:23
constexpr bool operator==(const Assignment &) const =default
consteval Assignment(std::string_view exec_name_out)
Definition metadata.hpp:34
std::string_view name
Definition metadata.hpp:24
consteval Assignment(std::string_view name_, std::string_view exec_name_)
Definition metadata.hpp:28
std::string_view exec_name
Definition metadata.hpp:25
Definition metadata.hpp:42
constexpr bool operator==(const ProfOnlyTag &) const =default
Definition metadata.hpp:49
constexpr bool operator==(const Weight &) const =default
std::size_t points
Definition metadata.hpp:50
std::conditional_t< DoAddFirst, WithAddedFirst, Orig > FirstMergeRes
Definition metadata.hpp:93
mp_push_back< Orig, First > WithAddedFirst
Definition metadata.hpp:92
MergeUnqImpl< FirstMergeRes, New... >::type type
Definition metadata.hpp:95