Skip to content

Commit

Permalink
Use CPP_template_lambda and CPP_template_lambda_mut
Browse files Browse the repository at this point in the history
  • Loading branch information
krzysztof-tyb committed Feb 14, 2025
1 parent a61c2fe commit 5251f9e
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 92 deletions.
10 changes: 9 additions & 1 deletion src/backports/concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@
// `CPP_lambda(capture)(arg)(requires ...)`: Expands lambda to use
// `requires` in C++20 mode and `std::enable_if_t` in C++17 mode.
//
// `CPP_lambda_mut(capture)(arg)(requires ...)`: Same as
// `CPP_lambda` but for mutable lambdas.
//
// `CPP_template_lambda(capture)(typenames...)(arg)(requires ...)`: Expands
// lambda with (C++20) explicit gemplate parameters to use
// lambda with (C++20) explicit template parameters to use
// `requires` in C++20 mode and `std::enable_if_t` in C++17 mode.
//
// `CPP_template_lambda_mut(capture)(typenames...)(arg)(requires ...)`: Same as
// `CPP_template_lambda` but for mutable lambdas.
//
// Example usages:
//
// `QL_CONCEPT_OR_NOTHING(std::view) auto x = someFunction();`
Expand Down Expand Up @@ -64,6 +70,7 @@
#define CPP_lambda CPP_lambda_sfinae
#define CPP_template_lambda CPP_template_lambda_sfinae
#define CPP_lambda_mut CPP_lambda_mut_sfinae
#define CPP_template_lambda_mut CPP_template_lambda_mut_sfinae
#else
#define QL_CONCEPT_OR_NOTHING(...) __VA_ARGS__
#define QL_CONCEPT_OR_TYPENAME(...) __VA_ARGS__
Expand All @@ -76,6 +83,7 @@
#define CPP_lambda CPP_LAMBDA_20
#define CPP_template_lambda CPP_TEMPLATE_LAMBDA_20
#define CPP_lambda_mut CPP_lambda_mut_20
#define CPP_template_lambda_mut CPP_TEMPLATE_LAMBDA_MUT_20
#endif

// The namespace `ql::concepts` includes concepts that are contained in the
Expand Down
11 changes: 11 additions & 0 deletions src/backports/cppTemplate2.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@

#define CPP_TEMPLATE_LAMBDA_20(...) [__VA_ARGS__] CPP_TEMPLATE_LAMBDA_ARGS

#define CPP_TEMPLATE_LAMBDA_MUT_20(...) \
[__VA_ARGS__] CPP_TEMPLATE_LAMBDA_MUT_ARGS

// The internals of the `CPP_lambda` template
#define CPP_LAMBDA_SFINAE_ARGS(...) \
(__VA_ARGS__ CPP_LAMBDA_SFINAE_AUX_
Expand All @@ -89,9 +92,15 @@ CPP_PP_CAT(CPP_LAMBDA_SFINAE_AUX_3_, __VA_ARGS__) \
#define CPP_TEMPLATE_LAMBDA_ARGS_sfinae(...) \
<__VA_ARGS__> CPP_LAMBDA_SFINAE_ARGS

#define CPP_TEMPLATE_LAMBDA_MUT_ARGS_sfinae(...) \
<__VA_ARGS__> CPP_LAMBDA_MUT_SFINAE_ARGS

#define CPP_template_lambda_sfinae(...) \
[__VA_ARGS__] CPP_TEMPLATE_LAMBDA_ARGS_sfinae

#define CPP_template_lambda_mut_sfinae(...) \
[__VA_ARGS__] CPP_TEMPLATE_LAMBDA_MUT_ARGS_sfinae

#define CPP_LAMBDA_SFINAE_AUX_3_requires

#define CPP_LAMBDA_ARGS(...) (__VA_ARGS__) CPP_LAMBDA_AUX_
Expand All @@ -105,6 +114,8 @@ CPP_PP_CAT(CPP_LAMBDA_SFINAE_AUX_3_, __VA_ARGS__) \

#define CPP_TEMPLATE_LAMBDA_ARGS(...) <__VA_ARGS__> CPP_LAMBDA_ARGS

#define CPP_TEMPLATE_LAMBDA_MUT_ARGS(...) <__VA_ARGS__> CPP_LAMBDA_ARGS_MUT

#define CPP_lambda_mut_sfinae(...) \
CPP_PP_IGNORE_CXX2A_COMPAT_BEGIN \
[__VA_ARGS__] CPP_LAMBDA_MUT_SFINAE_ARGS
Expand Down
14 changes: 5 additions & 9 deletions src/engine/Bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,10 @@ IdTable Bind::computeExpressionBind(
idTable.addEmptyColumn();
auto outputColumn = idTable.getColumn(idTable.numColumns() - 1);

auto visitor = CPP_lambda_mut(&)(auto&& singleResult)(
requires sparqlExpression::SingleExpressionResult<
std::decay_t<decltype(singleResult)>>) {
constexpr static bool isVariable =
std::is_same_v<std::decay_t<decltype(singleResult)>, ::Variable>;
constexpr static bool isStrongId =
std::is_same_v<std::decay_t<decltype(singleResult)>, Id>;
auto visitor = CPP_template_lambda_mut(&)(typename T)(T && singleResult)(
requires sparqlExpression::SingleExpressionResult<T>) {
constexpr static bool isVariable = std::is_same_v<T, ::Variable>;
constexpr static bool isStrongId = std::is_same_v<T, Id>;

if constexpr (isVariable) {
auto columnIndex =
Expand All @@ -180,8 +177,7 @@ IdTable Bind::computeExpressionBind(
ad_utility::chunkedFill(outputColumn, singleResult, CHUNK_SIZE,
[this]() { checkCancellation(); });
} else {
constexpr bool isConstant =
sparqlExpression::isConstantResult<decltype(singleResult)>;
constexpr bool isConstant = sparqlExpression::isConstantResult<T>;

auto resultGenerator = sparqlExpression::detail::makeGenerator(
AD_FWD(singleResult), outputColumn.size(), &evaluationContext);
Expand Down
12 changes: 5 additions & 7 deletions src/engine/Filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,11 @@ CPP_template_def(int WIDTH, typename Table)(
// NOTE: the explicit (seemingly redundant) capture of `resultTable` is
// required to work around a bug in Clang 17, see
// https://github.com/llvm/llvm-project/issues/61267
auto computeResult =
CPP_lambda(this, &resultTable = resultTable, &input, &inputTable,
&dynamicResultTable, &evaluationContext)(auto&& singleResult)(
requires sparqlExpression::SingleExpressionResult<
std::decay_t<decltype(singleResult)>>) {
if constexpr (std::is_same_v<std::decay_t<decltype(singleResult)>,
ad_utility::SetOfIntervals>) {
auto computeResult = CPP_template_lambda(
this, &resultTable = resultTable, &input, &inputTable,
&dynamicResultTable, &evaluationContext)(typename T)(T && singleResult)(
requires sparqlExpression::SingleExpressionResult<T>) {
if constexpr (std::is_same_v<T, ad_utility::SetOfIntervals>) {
AD_CONTRACT_CHECK(input.size() == evaluationContext.size());
// If the expression result is given as a set of intervals, we copy
// the corresponding parts of `input` to `resultTable`.
Expand Down
50 changes: 22 additions & 28 deletions src/engine/GroupBy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,17 +208,13 @@ void GroupBy::processGroup(
evaluationContext._previousResultsFromSameGroup.at(resultColumn) =
sparqlExpression::copyExpressionResult(expressionResult);

auto visitor = CPP_lambda_mut(&)(auto&& singleResult)(
requires sparqlExpression::SingleExpressionResult<
std::decay_t<decltype(singleResult)>>) {
constexpr static bool isStrongId =
std::is_same_v<std::decay_t<decltype(singleResult)>, Id>;
AD_CONTRACT_CHECK(sparqlExpression::isConstantResult<
std::decay_t<decltype(singleResult)>>);
auto visitor = CPP_template_lambda_mut(&)(typename T)(T && singleResult)(
requires sparqlExpression::SingleExpressionResult<T>) {
constexpr static bool isStrongId = std::is_same_v<T, Id>;
AD_CONTRACT_CHECK(sparqlExpression::isConstantResult<T>);
if constexpr (isStrongId) {
resultEntry = singleResult;
} else if constexpr (sparqlExpression::isConstantResult<
std::decay_t<decltype(singleResult)>>) {
} else if constexpr (sparqlExpression::isConstantResult<T>) {
resultEntry = sparqlExpression::detail::constantExpressionResultToId(
AD_FWD(singleResult), *localVocab);
} else {
Expand Down Expand Up @@ -1101,10 +1097,9 @@ void GroupBy::extractValues(
sparqlExpression::ExpressionResult&& expressionResult,
sparqlExpression::EvaluationContext& evaluationContext,
IdTable* resultTable, LocalVocab* localVocab, size_t outCol) {
auto visitor = CPP_lambda_mut(&evaluationContext, &resultTable, &localVocab,
&outCol)(auto&& singleResult)(
requires sparqlExpression::SingleExpressionResult<
std::decay_t<decltype(singleResult)>>) {
auto visitor = CPP_template_lambda_mut(&evaluationContext, &resultTable,
&localVocab, &outCol)(typename T)(
T && singleResult)(requires sparqlExpression::SingleExpressionResult<T>) {
auto generator = sparqlExpression::detail::makeGenerator(
AD_FWD(singleResult), evaluationContext.size(), &evaluationContext);

Expand Down Expand Up @@ -1484,25 +1479,24 @@ static constexpr auto makeProcessGroupsVisitor =
[](size_t blockSize,
const sparqlExpression::EvaluationContext* evaluationContext,
const std::vector<size_t>& hashEntries) {
return
[blockSize, evaluationContext, &hashEntries]<typename T, typename A>(
T&& singleResult, A& aggregationDataVector) {
CPP_assert(sparqlExpression::SingleExpressionResult<T>);
CPP_assert(VectorOfAggregationData<A>);
auto generator = sparqlExpression::detail::makeGenerator(
std::forward<T>(singleResult), blockSize, evaluationContext);
return CPP_template_lambda(blockSize, evaluationContext, &hashEntries)(
typename T, typename A)(T && singleResult, A & aggregationDataVector)(
requires sparqlExpression::SingleExpressionResult<T> &&
VectorOfAggregationData<A>) {
auto generator = sparqlExpression::detail::makeGenerator(
std::forward<T>(singleResult), blockSize, evaluationContext);

auto hashEntryIndex = 0;
auto hashEntryIndex = 0;

for (const auto& val : generator) {
auto vectorOffset = hashEntries[hashEntryIndex];
auto& aggregateData = aggregationDataVector.at(vectorOffset);
for (const auto& val : generator) {
auto vectorOffset = hashEntries[hashEntryIndex];
auto& aggregateData = aggregationDataVector.at(vectorOffset);

aggregateData.addValue(val, evaluationContext);
aggregateData.addValue(val, evaluationContext);

++hashEntryIndex;
}
};
++hashEntryIndex;
}
};
};

// _____________________________________________________________________________
Expand Down
10 changes: 4 additions & 6 deletions src/engine/LazyGroupBy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,10 @@ void LazyGroupBy::processBlock(
evaluationContext);

visitAggregate(
CPP_lambda(blockSize, &evaluationContext)(auto& aggregateData,
auto&& singleResult)(
requires VectorOfAggregationData<
std::decay_t<std::decay_t<decltype(aggregateData)>>> &&
sparqlExpression::SingleExpressionResult<
std::decay_t<decltype(singleResult)>>) {
CPP_template_lambda(blockSize, &evaluationContext)(
typename A, typename T)(A & aggregateData, T && singleResult)(
requires VectorOfAggregationData<A> &&
sparqlExpression::SingleExpressionResult<T>) {
auto generator = sparqlExpression::detail::makeGenerator(
AD_FWD(singleResult), blockSize, &evaluationContext);

Expand Down
31 changes: 15 additions & 16 deletions src/engine/sparqlExpressions/AggregateExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,9 @@ using AGG_EXP = AggregateExpression<
// with arguments and result of type `NumericValue` (which is a `std::variant`).
template <typename NumericOperation>
inline auto makeNumericExpressionForAggregate() {
return [](const auto&... args)
return []<typename... Args>(const Args&... args)
-> CPP_ret(NumericValue)(
requires(concepts::same_as<std::decay_t<decltype(args)>,
NumericValue>&&...)) {
requires(concepts::same_as<Args, NumericValue>&&...)) {
auto visitor = []<typename... Ts>(const Ts&... t) -> NumericValue {
if constexpr ((... || std::is_same_v<NotNumeric, Ts>)) {
return NotNumeric{};
Expand Down Expand Up @@ -184,19 +183,19 @@ inline const auto compareIdsOrStrings =

// Aggregate expression for MIN and MAX.
template <valueIdComparators::Comparison comparison>
inline const auto minMaxLambdaForAllTypes =
[]<typename T>(const T& a, const T& b, const EvaluationContext* ctx) {
CPP_assert(SingleExpressionResult<T>);
auto actualImpl = [ctx](const auto& x, const auto& y) {
return compareIdsOrStrings<comparison>(x, y, ctx);
};
if constexpr (ad_utility::isSimilar<T, Id>) {
return std::get<Id>(actualImpl(a, b));
} else {
// TODO<joka921> We should definitely move strings here.
return std::visit(actualImpl, a, b);
}
};
inline const auto minMaxLambdaForAllTypes = CPP_template_lambda()(typename T)(
const T& a, const T& b,
const EvaluationContext* ctx)(requires SingleExpressionResult<T>) {
auto actualImpl = [ctx](const auto& x, const auto& y) {
return compareIdsOrStrings<comparison>(x, y, ctx);
};
if constexpr (ad_utility::isSimilar<T, Id>) {
return std::get<Id>(actualImpl(a, b));
} else {
// TODO<joka921> We should definitely move strings here.
return std::visit(actualImpl, a, b);
}
};
constexpr inline auto minLambdaForAllTypes =
minMaxLambdaForAllTypes<valueIdComparators::Comparison::LT>;
constexpr inline auto maxLambdaForAllTypes =
Expand Down
27 changes: 12 additions & 15 deletions src/engine/sparqlExpressions/ConditionalExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,10 @@ class CoalesceExpression : public VariadicExpression {
std::get<Id>(x) == Id::makeUndefined());
};

auto visitConstantExpressionResult = CPP_lambda(
&nextUnboundIndices, &unboundIndices, &isUnbound, &result,
ctx)(auto&& childResult)(
requires SingleExpressionResult<std::decay_t<decltype(childResult)>> &&
isConstantResult<std::decay_t<decltype(childResult)>>) {
auto visitConstantExpressionResult =
CPP_template_lambda(&nextUnboundIndices, &unboundIndices, &isUnbound,
&result, ctx)(typename T)(T && childResult)(
requires SingleExpressionResult<T> && isConstantResult<T>) {
IdOrLiteralOrIri constantResult{AD_FWD(childResult)};
if (isUnbound(constantResult)) {
nextUnboundIndices = std::move(unboundIndices);
Expand All @@ -94,11 +93,10 @@ class CoalesceExpression : public VariadicExpression {
// result so far is unbound, and the child result is bound. While doing so,
// set up the `nextUnboundIndices` vector for the next step.
auto visitVectorExpressionResult =
CPP_lambda(&result, &unboundIndices, &nextUnboundIndices, &ctx,
&isUnbound)(auto&& childResult)(requires CPP_NOT(
isConstantResult<std::decay_t<decltype(childResult)>> &&
SingleExpressionResult<std::decay_t<decltype(childResult)>> &&
std::is_rvalue_reference_v<decltype(childResult)>)) {
CPP_template_lambda(&result, &unboundIndices, &nextUnboundIndices, &ctx,
&isUnbound)(typename T)(T && childResult)(
requires CPP_NOT(isConstantResult<T> && SingleExpressionResult<T> &&
std::is_rvalue_reference_v<T&&>)) {
auto gen = detail::makeGenerator(AD_FWD(childResult), ctx->size(), ctx);
// Iterator to the next index where the result so far is unbound.
auto unboundIdxIt = unboundIndices.begin();
Expand Down Expand Up @@ -128,14 +126,13 @@ class CoalesceExpression : public VariadicExpression {
},
[ctx]() { ctx->cancellationHandle_->throwIfCancelled(); });
};
auto visitExpressionResult = CPP_lambda(
auto visitExpressionResult = CPP_template_lambda(
&visitConstantExpressionResult,
&visitVectorExpressionResult)(auto&& childResult)(
requires SingleExpressionResult<std::decay_t<decltype(childResult)>> &&
std::is_rvalue_reference_v<decltype(childResult)>) {
&visitVectorExpressionResult)(typename T)(T && childResult)(
requires SingleExpressionResult<T> && std::is_rvalue_reference_v<T&&>) {
// If the previous expression result is a constant, we can skip the
// loop.
if constexpr (isConstantResult<std::decay_t<decltype(childResult)>>) {
if constexpr (isConstantResult<T>) {
visitConstantExpressionResult(AD_FWD(childResult));
} else {
visitVectorExpressionResult(AD_FWD(childResult));
Expand Down
12 changes: 6 additions & 6 deletions src/engine/sparqlExpressions/SparqlExpressionGenerators.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ CPP_template(typename Input, typename Transformation = std::identity)(
/// Generate `numItems` many values from the `input` and apply the
/// `valueGetter` to each of the values.
inline auto valueGetterGenerator =
CPP_lambda()(size_t numElements, EvaluationContext* context, auto&& input,
auto&& valueGetter)(
requires SingleExpressionResult<std::decay_t<decltype(input)>>) {
auto transformation = CPP_lambda(context, valueGetter)(auto&& i)(
requires ranges::invocable<std::decay_t<decltype(valueGetter)>,
decltype(i), EvaluationContext*>) {
CPP_template_lambda()(typename ValueGetter, typename Input)(
size_t numElements, EvaluationContext* context, Input&& input,
ValueGetter&& valueGetter)(requires SingleExpressionResult<Input>) {
auto transformation =
CPP_template_lambda(context, valueGetter)(typename I)(I && i)(
requires ranges::invocable<ValueGetter, I&&, EvaluationContext*>) {
context->cancellationHandle_->throwIfCancelled();
return valueGetter(AD_FWD(i), context);
};
Expand Down
8 changes: 4 additions & 4 deletions src/engine/sparqlExpressions/StringExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,10 +382,10 @@ class ConcatExpression : public detail::VariadicExpression {
// If the result is a string, then all the previously evaluated children
// were constants (see above).
std::variant<std::string, StringVec> result{std::string{""}};
auto visitSingleExpressionResult = CPP_lambda(&ctx, &result)(auto&& s)(
requires SingleExpressionResult<std::decay_t<decltype(s)>> &&
std::is_rvalue_reference_v<decltype(s)>) {
if constexpr (isConstantResult<std::decay_t<decltype(s)>>) {
auto visitSingleExpressionResult = CPP_template_lambda(
&ctx, &result)(typename T)(T && s)(requires SingleExpressionResult<T> &&
std::is_rvalue_reference_v<T&&>) {
if constexpr (isConstantResult<T>) {
std::string strFromConstant = StringValueGetter{}(s, ctx).value_or("");
if (std::holds_alternative<std::string>(result)) {
// All previous children were constants, and the current child also is
Expand Down

0 comments on commit 5251f9e

Please sign in to comment.