15#include <boost/mp11/detail/mp_list.hpp>
16#include <boost/mp11/detail/mp_map_find.hpp>
17#include <boost/mp11/list.hpp>
18#include <boost/mp11/map.hpp>
19#include <boost/type_index.hpp>
20#include <fmt/format.h>
21#include <fmt/ranges.h>
23#include <libassert/assert.hpp>
24#include <range/v3/action/take_while.hpp>
25#include <range/v3/algorithm/any_of.hpp>
26#include <range/v3/algorithm/contains.hpp>
27#include <range/v3/algorithm/find.hpp>
28#include <range/v3/algorithm/find_if.hpp>
29#include <range/v3/algorithm/find_if_not.hpp>
30#include <range/v3/range/access.hpp>
31#include <range/v3/range/concepts.hpp>
32#include <range/v3/range/conversion.hpp>
33#include <range/v3/view/drop_while.hpp>
34#include <range/v3/view/split.hpp>
35#include <range/v3/view/split_when.hpp>
36#include <range/v3/view/take_while.hpp>
50#include <meta/meta.hpp>
59template <
typename OpFn,
StaticString Rep,
typename... Args>
69 std::array<inspection::Tokenizer<>,
sizeof...(Args)>
arg_tokens;
71 using EvalResT = std::decay_t<std::invoke_result_t<OpFn, Args...>>;
76 static constexpr std::string_view
raw_str = Rep;
82template <
template <
typename...>
typename Op,
typename... Args>
84 return Op<Args...>{{std::forward<Args>(args)...}, arg_tokens};
87template <
typename Args>
90template <
typename Arg>
93template <
typename Lhs,
typename Rhs>
96template <
typename Lhs,
typename Rhs>
99template <
typename Lhs,
typename Rhs>
102template <
typename Lhs,
typename Rhs>
105template <
typename Lhs,
typename Rhs>
108template <
typename Lhs,
typename Rhs>
113 { T::raw_str } -> std::convertible_to<std::string_view>;
114 { T::arity } -> std::convertible_to<ArityKind>;
116 { op.arg_tokens } -> std::convertible_to<std::array<inspection::Tokenizer<>,
static_cast<std::size_t
>(T::arity)>>;
118} && std::tuple_size_v<
decltype(T::args)> ==
static_cast<std::size_t
>(T::arity);
126template <StaticString Str>
131template <
typename T,
typename U>
141static_assert(boost::mp11::mp_is_map<StrToOpTMap<int, int>>::value);
145template <StaticString OpStr,
typename T,
typename U>
212template <exprs::Operator Op>
218 [[deprecated(
"====================================================================================================="
219 "=========================================================== !!!!!!!!!!!!!!!!! "
220 "Please consider providing a requirement description by using REQUIRE(..., \"<description here>\")"
221 " !!!!!!!!!!!!!!!!! "
222 "====================================================================================================="
223 "=========================================================== ")]]
228 [[deprecated(
"====================================================================================================="
229 "=========================================================== !!!!!!!!!!!!!!!!! "
230 "Please consider providing a requirement description by using REQUIRE(..., \"<description here>\")"
231 " !!!!!!!!!!!!!!!!! "
232 "====================================================================================================="
233 "=========================================================== ")]]
239 std::string description)
240 :
Requirement(decomposed_to_op(decomposed_expr, tokens),
std::move(description)) {}
244 , description_{
std::move(description)}
249 bool get_res()
const {
return static_cast<bool>(res_); }
257 if constexpr (Op::arity != Unary && Op::arity != Binary) {
258 UNIMPLEMENTED(
"Operators that are not unary or binary are not supported");
263 using Arg0T = std::tuple_element<0,
decltype(op_.args)>;
264 std::string_view arg0_str = op_.arg_tokens.at(0).get_original();
268 using ResultT =
decltype(res_);
271 .raw_str = Op::raw_str,
274 .type_index = boost::typeindex::type_id_with_cvr<ResultT>(),
275 .kind = deduce_kind<ResultT>(),
276 .is_literal =
false};
278 std::vector operands = std::apply(
279 [
this]<
typename... TupleTypes>(
const std::tuple<TupleTypes...>& ) {
280 return [
this]<
typename... Args>(Args&&... args) {
283 make_expr_value<TupleTypes>(std::forward<Args>(args), op_.arg_tokens.at(idx++))...};
289 .repr = std::move(repr), .operands = std::move(operands)}};
297 std::array<inspection::Tokenizer<>,
sizeof...(Ts)> split_tokens_arr{};
299 if constexpr (
sizeof...(Ts) == 1) {
300 split_tokens_arr.front() = tokens;
302 auto split_pos = gsl::narrow_cast<std::size_t>(
303 ranges::find_if(tokens,
304 [](
const inspection::Token& tok) {
return tok.str == std::string_view{OpStr}; }) -
305 ranges::begin(tokens));
306 split_tokens_arr.at(0) = tokens.
subseq(0, split_pos);
307 split_tokens_arr.at(1) = tokens.
subseq(split_pos + 1, tokens.
size());
310 return Op(decomposed_expr.
operands, split_tokens_arr);
313 template <
typename Val>
315 using Repr = exprs::ExpressionRepr::Repr;
316 using enum Repr::Type;
318 using DecayT = std::decay_t<Val>;
320 if constexpr (std::convertible_to<DecayT, std::string_view>) {
322 }
else if constexpr (std::integral<DecayT>) {
324 }
else if constexpr (std::floating_point<DecayT>) {
331 template <
typename OrigType,
typename Val>
332 exprs::ExpressionRepr::Repr make_repr_value(Val&& value, inspection::Tokenizer<> tokens,
333 [[maybe_unused]]
bool is_lvalue)
const {
339 bool is_literal = !ranges::any_of(
342 return {.repr =
stringize::repr(tokens, tokens.get_original(), std::forward<Val>(value)),
344 .raw_str = tokens.get_original(),
345 .raw_str_tokens = tokens | ranges::to<std::vector>(),
346 .type_index = boost::typeindex::type_id_with_cvr<OrigType>(),
347 .kind = deduce_kind<OrigType>(),
348 .is_literal = is_literal};
358 template <
typename OrigType,
typename Val>
360 using Value = exprs::ExpressionRepr::Value;
364 if constexpr (std::is_lvalue_reference_v<OrigType>) {
367 ASSERT(!std::is_reference_v<OrigType>, boost::typeindex::type_id_with_cvr<Val>());
371 return Value{.repr = make_repr_value<OrigType>(std::forward<Val>(value), tokens, is_lvalue)};
375 std::invoke_result_t<
decltype(&Op::eval), Op> res_;
376 std::string description_;
379 requires {
static_cast<bool>(res_); },
"Requirement expressions must be convertible to bool (for now)");
383template <StaticString OpStr,
typename T>
387template <StaticString OpStr,
typename T,
typename U>
Definition requirement.hpp:214
Requirement(Op op)
Definition requirement.hpp:224
bool get_res() const
Definition requirement.hpp:249
Requirement(Op op, std::string description)
Definition requirement.hpp:242
Requirement(const DecomposedExpr< OpStr, Ts... > &decomposed_expr, const inspection::Tokenizer<> &tokens, std::string description)
Definition requirement.hpp:238
Requirement(const DecomposedExpr< OpStr, Ts... > &decomposed_expr, const inspection::Tokenizer<> &tokens)
Definition requirement.hpp:234
static constexpr auto default_description
Definition requirement.hpp:216
std::string get_description() const
Definition requirement.hpp:247
exprs::ExpressionRepr get_expr_repr() const
Definition requirement.hpp:252
A fully compile-time capable string type Guaranteed to be null-terminated.
Definition static_string.hpp:59
Definition expression_inspection.hpp:1670
constexpr Tokenizer subseq(std::size_t start, std::size_t len) const
Definition expression_inspection.hpp:1679
constexpr auto size() const
Definition expression_inspection.hpp:1698
Definition concepts.hpp:12
Definition requirement.hpp:112
Basic decomposition implementation, intended for use with the REQUIRE macro Inspired by Catch2,...
#define UNIMPLEMENTED(msg,...)
For features that have not yet / are not planned to be implemented, so that I don't bang my head agai...
Definition logging.hpp:49
boost::mp11::mp_list< std::pair< MapKeyT<"==">, Equal< T, U > >, std::pair< MapKeyT<"!=">, NotEqual< T, U > >, std::pair< MapKeyT<"<">, Less< T, U > >, std::pair< MapKeyT<"<=">, LessEqual< T, U > >, std::pair< MapKeyT<">">, Greater< T, U > >, std::pair< MapKeyT<">=">, GreaterEqual< T, U > > > StrToOpTMap
Definition requirement.hpp:132
ArityKind
Definition requirement.hpp:57
constexpr auto make(std::array< inspection::Tokenizer<>, sizeof...(Args)> arg_tokens, Args &&... args)
For argument deduction purposes.
Definition requirement.hpp:83
boost::mp11::mp_second< boost::mp11::mp_map_find< detail::StrToOpTMap< T, U >, detail::MapKeyT< OpStr > > > OpStrToType
Definition requirement.hpp:146
constexpr const auto & str
str customization point object The return value of this function is guaranteed to be parsable by high...
Definition stringize.hpp:190
constexpr const auto & repr
repr customization point object The return value of this function is guaranteed to be parsable by hig...
Definition stringize.hpp:178
Definition asm_buffer.hpp:20
Requirement(DecomposedExpr< OpStr, T > &&, const inspection::Tokenizer<> &, std::string) -> Requirement< exprs::Noop< T > >
Deduction guide for a single type decomposition expr.
Definition byte_array.hpp:94
See asmgrader::stringize.
Stores references to rhs and lhs of a comparison expression, serving as an interface to the "decompos...
Definition decomposer.hpp:29
std::tuple< Types &&... > operands
Definition decomposer.hpp:33
The str field is the representation of the operator (e.g., '+', '!=').
Definition requirement.hpp:197
std::vector< Expression > operands
List of operands. Operator arity = operands.size() Probably will never support ops with higher arity ...
Definition requirement.hpp:202
Repr repr
Definition requirement.hpp:198
Definition requirement.hpp:156
std::vector< asmgrader::inspection::Token > TokenStream
Definition requirement.hpp:166
boost::typeindex::type_index type_index
This field will probably never be used, but it might be nice later for debug info.
Definition requirement.hpp:171
Type kind
Definition requirement.hpp:175
Type
A heuristic of what type the value is. May not always be perfectly accurate.
Definition requirement.hpp:174
TokenStream raw_str_tokens
Tokenized raw_str see Tokenizer.
Definition requirement.hpp:168
bool is_literal
Whether the expression is a literal value, or is composed of solely literal values....
Definition requirement.hpp:182
stringize::StringizeResult repr
Representation of the expression as by repr
Definition requirement.hpp:158
stringize::StringizeResult str
Representation of the expression's value as by str
Definition requirement.hpp:161
std::string_view raw_str
Original string (should be as generated by the # prepocessor operator)
Definition requirement.hpp:164
Definition requirement.hpp:186
Repr repr
Definition requirement.hpp:187
Representation of an expression with all components stringized.
Definition requirement.hpp:152
Expression expression
Definition requirement.hpp:205
std::variant< Value, Operator > Expression
Definition requirement.hpp:193
Definition requirement.hpp:61
std::array< inspection::Tokenizer<>, sizeof...(Args)> arg_tokens
Definition requirement.hpp:69
std::tuple< Args... > args
Definition requirement.hpp:68
static constexpr ArityKind arity
Definition requirement.hpp:78
static constexpr std::string_view raw_str
Definition requirement.hpp:76
constexpr NAryOp(std::tuple< Args... > args_, std::array< inspection::Tokenizer<>, sizeof...(Args)> arg_tokens_)
Definition requirement.hpp:63
std::decay_t< std::invoke_result_t< OpFn, Args... > > EvalResT
Definition requirement.hpp:71
EvalResT eval() const
Definition requirement.hpp:74
Definition requirement.hpp:128
@ Identifier
https://en.cppreference.com/w/cpp/language/identifiers.html
Result type of a call to str or repr
Definition stringize.hpp:39