Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport of some concepts from util to C++17 #1741

Merged
merged 25 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6dca129
this is a working version.
joka921 Feb 10, 2025
607d8bb
Also implement the `cppTemplate2` macro.
joka921 Feb 10, 2025
2ddfca9
Backport of some concepts from util to C++17
gpicciuca Jan 31, 2025
d58b3de
First steps that are working.
joka921 Jan 31, 2025
0a1bfc0
Also fixed the `isInstantion` occurence.
joka921 Jan 31, 2025
f844150
Working cpp20 build with util module concepts backport
gpicciuca Feb 5, 2025
a61f539
Fix some bugs.
joka921 Feb 5, 2025
c9511e5
Small fixes and Views and Iterators backporting
gpicciuca Feb 6, 2025
cb679e1
Fix the `ViewsTest` for now.
joka921 Feb 6, 2025
ad90c03
Bring this back to compilation
joka921 Feb 7, 2025
a035e0a
Backport concept isInstantiation
gpicciuca Feb 10, 2025
c4af1cc
Backport TypeTraits Similar-concepts
gpicciuca Feb 10, 2025
cb610e9
Backport BulkResultForDecoder
gpicciuca Feb 10, 2025
8b2f5f5
Rewrite enable_if_t occurrences
gpicciuca Feb 11, 2025
cd4851f
Playing around with variadic templates.
joka921 Feb 11, 2025
97a6fb3
Fix the warning...
joka921 Feb 11, 2025
acc9eab
Implement the variadic template.
joka921 Feb 11, 2025
83c25c3
Merge branch 'cpp-variadic-template' into cpp-template-2
joka921 Feb 11, 2025
45397d2
Missing newline.
joka921 Feb 11, 2025
8eb834e
Merge branch 'cpp-template-2' into cpp17-concepts-backport-2
joka921 Feb 12, 2025
988dcc7
Adreesed all but one TODO in the review.
joka921 Feb 12, 2025
2e872fa
Waiting for sonarcloud until we push this again.
joka921 Feb 12, 2025
25dc99f
Fixed some sonarcloud issues, next pass is going on.
joka921 Feb 12, 2025
1fd066f
Fix a renaming bug.
joka921 Feb 12, 2025
993ed08
Add a unit test.
joka921 Feb 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ LineEnding: LF
InsertNewlineAtEOF: true
RequiresClausePosition: SingleLine
IndentRequiresClause: false
AttributeMacros: [CPP_member, CPP_auto_member, CPP_fun, CPP_auto_fun]
# TODO<joka921> Update to Clang-format-17 and then we can have much nicer CPP_... macros.
#Macros:
# - CPP_template_2(x)=template<x> requires
...
36 changes: 19 additions & 17 deletions benchmark/JoinAlgorithmBenchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,27 +770,29 @@ class GeneralInterfaceImplementation : public BenchmarkInterface {
};
};
auto generateBiggerEqualLambdaDesc =
[](const ad_utility::isInstantiation<
ad_utility::ConstConfigOptionProxy> auto& option,
const auto& minimumValue, bool canBeEqual) {
return absl::StrCat("'", option.getConfigOption().getIdentifier(),
"' must be bigger than",
canBeEqual ? ", or equal to," : "", " ",
minimumValue, ".");
};
[]<typename OptionType,
typename = std::enable_if_t<ad_utility::isInstantiation<
OptionType, ad_utility::ConstConfigOptionProxy>>>(
const OptionType& option, const auto& minimumValue,
bool canBeEqual) {
return absl::StrCat("'", option.getConfigOption().getIdentifier(),
"' must be bigger than",
canBeEqual ? ", or equal to," : "", " ", minimumValue,
".");
};

// Object with a `operator()` for the `<=` operator.
auto lessEqualLambda = std::less_equal<size_t>{};
auto generateLessEqualLambdaDesc =
[](const ad_utility::isInstantiation<
ad_utility::ConstConfigOptionProxy> auto& lhs,
const ad_utility::isInstantiation<
ad_utility::ConstConfigOptionProxy> auto& rhs) {
return absl::StrCat("'", lhs.getConfigOption().getIdentifier(),
"' must be smaller than, or equal to, "
"'",
rhs.getConfigOption().getIdentifier(), "'.");
};
[]<typename OptionType,
typename = std::enable_if_t<ad_utility::isInstantiation<
OptionType, ad_utility::ConstConfigOptionProxy>>>(
const OptionType& lhs, const OptionType& rhs) {
return absl::StrCat("'", lhs.getConfigOption().getIdentifier(),
"' must be smaller than, or equal to, "
"'",
rhs.getConfigOption().getIdentifier(), "'.");
};

// Adding the validators.

Expand Down
4 changes: 2 additions & 2 deletions benchmark/infrastructure/BenchmarkMeasurementContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,8 @@ class ResultTable : public BenchmarkMetadataGetter {

@param row, column Which table entry to read. Starts with `(0,0)`.
*/
template <ad_utility::SameAsAnyTypeIn<EntryType> T>
T getEntry(const size_t row, const size_t column) const {
CPP_template(typename T)(requires ad_utility::SameAsAnyTypeIn<T, EntryType>) T
getEntry(const size_t row, const size_t column) const {
AD_CONTRACT_CHECK(row < numRows() && column < numColumns());
static_assert(!ad_utility::isSimilar<T, std::monostate>);

Expand Down
12 changes: 6 additions & 6 deletions benchmark/infrastructure/BenchmarkToJson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ provided translation function for the vector entries.
@tparam TranslationFunction Has to be a function, that takes `VectorType`
and returns a `nlohmann:json` object.
*/
template <typename VectorType, ad_utility::InvocableWithExactReturnType<
nlohmann::ordered_json, VectorType>
TranslationFunction>
static nlohmann::json transformIntoJsonArray(
const std::vector<VectorType>& vec,
TranslationFunction translationFunction) {
CPP_template(typename VectorType, typename TranslationFunction)(
requires ad_utility::InvocableWithExactReturnType<
TranslationFunction, nlohmann::ordered_json,
VectorType>) static nlohmann::json
transformIntoJsonArray(const std::vector<VectorType>& vec,
TranslationFunction translationFunction) {
/*
Without explicit instantiation, `nlohmann::nlohmann::ordered_json` is not
guaranteed, to always interpret a `push_back` correctly. For instance,
Expand Down
5 changes: 3 additions & 2 deletions benchmark/util/ResultTableColumnOperations.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ Column number together with the type of value, that can be found inside the
column. Note, that **all** entries in the column must have the same type,
because of `ResultTable::getEntry`.
*/
template <ad_utility::SameAsAnyTypeIn<ResultTable::EntryType> Type>
struct ColumnNumWithType {
CPP_template(typename Type)(
requires ad_utility::SameAsAnyTypeIn<
Type, ResultTable::EntryType>) struct ColumnNumWithType {
using ColumnType = Type;
const size_t columnNum_;
};
Expand Down
25 changes: 21 additions & 4 deletions src/backports/concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#pragma once

#include <concepts/concepts.hpp>

#include "backports/cppTemplate2.h"
#ifndef QLEVER_CPP_17
#include <concepts>
#endif
Expand Down Expand Up @@ -32,24 +34,39 @@
// NOTE: The macros are variadic to allow for commas in the argument, like in
// the second example above.

// Additionally define the macros `CPP_template_2` and `CPP_and_2` that can
// be used to constrain member functions of classes where the outer class
// has already been constrained with `CPP_template`. For a detailed example, see
// the `test/backports/ConceptsTest.cpp` file.

#ifdef QLEVER_CPP_17
#define QL_CONCEPT_OR_NOTHING(...)
#define QL_CONCEPT_OR_TYPENAME(...) typename
#define CPP_template_2 CPP_template_2_SFINAE
#define CPP_and_2 CPP_and_2_sfinae
#define CPP_and_def CPP_and_sfinae_def
#define CPP_and_2_def CPP_and_2_def_sfinae
#define CPP_variadic_template CPP_template_NO_DEFAULT_SFINAE
#define CPP_member_def CPP_member_def_sfinae
#else
#define QL_CONCEPT_OR_NOTHING(...) __VA_ARGS__
#define QL_CONCEPT_OR_TYPENAME(...) __VA_ARGS__
#define CPP_template_2 CPP_template
#define CPP_and_2 CPP_and
#define CPP_and_def CPP_and
#define CPP_and_2_def CPP_and
#define CPP_variadic_template CPP_template
#define CPP_member_def CPP_member
#endif

// The namespace `ql::concepts` includes concepts that are contained in the
// C++20 standard as well as in `range-v3`.
namespace ql {
namespace concepts {
namespace ql::concepts {

#ifdef QLEVER_CPP_17
using namespace ::concepts;
#else
using namespace std;
#endif

} // namespace concepts
} // namespace ql
} // namespace ql::concepts
60 changes: 60 additions & 0 deletions src/backports/cppTemplate2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2024, University of Freiburg
// Chair of Algorithms and Data Structures
// Author: Johannes Kalmbach <[email protected]>

#pragma once
#include <concepts/concepts.hpp>

// The internal reimplementation of a `CPP_variadic_template` macro
// that can be used for variadic template functions.
#define CPP_TEMPLATE_NO_DEFAULT_SFINAE_AUX_0(...) \
, std::enable_if_t<CPP_PP_CAT(CPP_TEMPLATE_SFINAE_AUX_3_, __VA_ARGS__), \
int> = 0 > CPP_PP_IGNORE_CXX2A_COMPAT_END

#define CPP_TEMPLATE_NO_DEFAULT_SFINAE_AUX_3_requires

#define CPP_TEMPLATE_NO_DEFAULT_SFINAE_AUX_WHICH_(FIRST, ...) \
CPP_PP_EVAL(CPP_PP_CHECK, \
CPP_PP_CAT(CPP_TEMPLATE_SFINAE_PROBE_CONCEPT_, FIRST))

#define CPP_TEMPLATE_NO_DEFAULT_SFINAE_AUX_(...) \
CPP_PP_CAT(CPP_TEMPLATE_NO_DEFAULT_SFINAE_AUX_, \
CPP_TEMPLATE_NO_DEFAULT_SFINAE_AUX_WHICH_(__VA_ARGS__, )) \
(__VA_ARGS__)

#define CPP_template_NO_DEFAULT_SFINAE(...) \
CPP_PP_IGNORE_CXX2A_COMPAT_BEGIN \
template <__VA_ARGS__ CPP_TEMPLATE_NO_DEFAULT_SFINAE_AUX_

// The internal reimplementation of a `CPP_template_2` and `CPP_and_2` macro
// that can be used for class members when the outer class has already been
// constrained using `CPP_template`.
#define CPP_TEMPLATE_2_SFINAE_AUX_0(...) \
, bool CPP_true_2 = true, \
std::enable_if_t < \
CPP_PP_CAT(CPP_TEMPLATE_SFINAE_AUX_3_, __VA_ARGS__) && \
CPP_BOOL(CPP_true_2), \
int > = 0 > CPP_PP_IGNORE_CXX2A_COMPAT_END

#define CPP_TEMPLATE_2_SFINAE_AUX_3_requires

#define CPP_TEMPLATE_2_SFINAE_AUX_WHICH_(FIRST, ...) \
CPP_PP_EVAL(CPP_PP_CHECK, \
CPP_PP_CAT(CPP_TEMPLATE_SFINAE_PROBE_CONCEPT_, FIRST))

#define CPP_TEMPLATE_2_SFINAE_AUX_(...) \
CPP_PP_CAT(CPP_TEMPLATE_2_SFINAE_AUX_, \
CPP_TEMPLATE_2_SFINAE_AUX_WHICH_(__VA_ARGS__, )) \
(__VA_ARGS__)

#define CPP_template_2_SFINAE(...) \
CPP_PP_IGNORE_CXX2A_COMPAT_BEGIN \
template <__VA_ARGS__ CPP_TEMPLATE_2_SFINAE_AUX_

/// INTERNAL ONLY
#define CPP_and_def_sfinae &&CPP_BOOL(CPP_true), int >, std::enable_if_t <
#define CPP_and_2_sfinae &&CPP_BOOL(CPP_true_2), int > = 0, std::enable_if_t <
#define CPP_and_2_def_sfinae &&CPP_BOOL(CPP_true_2), int >, std::enable_if_t <

#define CPP_member_def_sfinae \
template <bool (&CPP_true_fn)(::concepts::detail::xNil)>
2 changes: 1 addition & 1 deletion src/engine/ExportQueryExecutionTrees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@ cppcoro::generator<std::string> ExportQueryExecutionTrees::computeResult(

auto inner =
ad_utility::ConstexprSwitch<csv, tsv, octetStream, turtle, sparqlXml,
sparqlJson, qleverJson>(compute, mediaType);
sparqlJson, qleverJson>{}(compute, mediaType);
return convertStreamGeneratorForChunkedTransfer(std::move(inner));
}

Expand Down
17 changes: 9 additions & 8 deletions src/engine/Filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ ProtoResult Filter::computeResult(bool requestLaziness) {
}

// _____________________________________________________________________________
template <ad_utility::SimilarTo<IdTable> Table>
IdTable Filter::filterIdTable(std::vector<ColumnIndex> sortedBy,
Table&& idTable,
const LocalVocab& localVocab) const {
CPP_template_def(typename Table)(requires ad_utility::SimilarTo<Table, IdTable>)
IdTable Filter::filterIdTable(std::vector<ColumnIndex> sortedBy,
Table&& idTable,
const LocalVocab& localVocab) const {
size_t width = idTable.numColumns();
IdTable result{width, getExecutionContext()->getAllocator()};

Expand All @@ -120,10 +120,11 @@ IdTable Filter::filterIdTable(std::vector<ColumnIndex> sortedBy,
}

// _____________________________________________________________________________
template <int WIDTH, ad_utility::SimilarTo<IdTable> Table>
void Filter::computeFilterImpl(IdTable& dynamicResultTable, Table&& inputTable,
const LocalVocab& localVocab,
std::vector<ColumnIndex> sortedBy) const {
CPP_template_def(int WIDTH, typename Table)(
requires ad_utility::SimilarTo<Table, IdTable>) void Filter::
computeFilterImpl(IdTable& dynamicResultTable, Table&& inputTable,
const LocalVocab& localVocab,
std::vector<ColumnIndex> sortedBy) const {
AD_CONTRACT_CHECK(inputTable.numColumns() == WIDTH || WIDTH == 0);
IdTableStatic<WIDTH> resultTable =
std::move(dynamicResultTable).toStatic<static_cast<size_t>(WIDTH)>();
Expand Down
17 changes: 10 additions & 7 deletions src/engine/Filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,16 @@ class Filter : public Operation {
ProtoResult computeResult(bool requestLaziness) override;

// Perform the actual filter operation of the data provided.
template <int WIDTH, ad_utility::SimilarTo<IdTable> Table>
void computeFilterImpl(IdTable& dynamicResultTable, Table&& input,
const LocalVocab& localVocab,
std::vector<ColumnIndex> sortedBy) const;
CPP_template(int WIDTH, typename Table)(
requires ad_utility::SimilarTo<
Table, IdTable>) void computeFilterImpl(IdTable& dynamicResultTable,
Table&& input,
const LocalVocab& localVocab,
std::vector<ColumnIndex>
sortedBy) const;

// Run `computeFilterImpl` on the provided IdTable
template <ad_utility::SimilarTo<IdTable> Table>
IdTable filterIdTable(std::vector<ColumnIndex> sortedBy, Table&& idTable,
const LocalVocab& localVocab) const;
CPP_template(typename Table)(requires ad_utility::SimilarTo<Table, IdTable>)
IdTable filterIdTable(std::vector<ColumnIndex> sortedBy, Table&& idTable,
const LocalVocab& localVocab) const;
};
4 changes: 2 additions & 2 deletions src/engine/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,8 +468,8 @@ auto Server::cancelAfterDeadline(
// _____________________________________________________________________________
auto Server::setupCancellationHandle(
const ad_utility::websocket::QueryId& queryId, TimeLimit timeLimit)
-> ad_utility::isInstantiation<
CancellationHandleAndTimeoutTimerCancel> auto {
-> QL_CONCEPT_OR_NOTHING(ad_utility::isInstantiation<
CancellationHandleAndTimeoutTimerCancel>) auto {
auto cancellationHandle = queryRegistry_.getCancellationHandle(queryId);
AD_CORRECTNESS_CHECK(cancellationHandle);
cancellationHandle->startWatchDog();
Expand Down
19 changes: 11 additions & 8 deletions src/engine/Server.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,10 @@ class Server {

using SharedCancellationHandle = ad_utility::SharedCancellationHandle;

template <ad_utility::isInstantiation<absl::Cleanup> CancelTimeout>
struct CancellationHandleAndTimeoutTimerCancel {
CPP_template(typename CancelTimeout)(
requires ad_utility::isInstantiation<
CancelTimeout,
absl::Cleanup>) struct CancellationHandleAndTimeoutTimerCancel {
SharedCancellationHandle handle_;
/// Object of type `absl::Cleanup` that when destroyed cancels the timer
/// that would otherwise invoke the cancellation of the `handle_` via the
Expand All @@ -109,10 +111,11 @@ class Server {
// Clang doesn't seem to be able to automatically deduce the type correctly.
// and GCC 11 thinks deduction guides are not allowed within classes.
#ifdef __clang__
template <ad_utility::isInstantiation<absl::Cleanup> CancelTimeout>
CancellationHandleAndTimeoutTimerCancel(SharedCancellationHandle,
CancelTimeout)
-> CancellationHandleAndTimeoutTimerCancel<CancelTimeout>;
CPP_template(typename CancelTimeout)(
requires ad_utility::isInstantiation<CancelTimeout, absl::Cleanup>)
CancellationHandleAndTimeoutTimerCancel(SharedCancellationHandle,
CancelTimeout)
-> CancellationHandleAndTimeoutTimerCancel<CancelTimeout>;
#endif

/// Handle a single HTTP request. Check whether a file request or a query was
Expand Down Expand Up @@ -241,8 +244,8 @@ class Server {
/// member can be invoked to cancel the imminent cancellation via timeout.
auto setupCancellationHandle(const ad_utility::websocket::QueryId& queryId,
TimeLimit timeLimit)
-> ad_utility::isInstantiation<
CancellationHandleAndTimeoutTimerCancel> auto;
-> QL_CONCEPT_OR_NOTHING(ad_utility::isInstantiation<
CancellationHandleAndTimeoutTimerCancel>) auto;

/// Check if the access token is valid. Return true if the access token
/// exists and is valid. Return false if there's no access token passed.
Expand Down
6 changes: 4 additions & 2 deletions src/engine/idTable/IdTableRow.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,10 @@ class RowReference
// The `cbegin` and `cend` functions are implicitly inherited from `Base`.

// __________________________________________________________________________
template <ad_utility::SimilarTo<RowReference> R>
friend void swap(R&& a, R&& b) requires(!isConst) {
CPP_template(typename R)(
requires ad_utility::SimilarTo<RowReference, R>) friend void swap(R&& a,
R&& b)
requires(!isConst) {
return Base::swapImpl(AD_FWD(a), AD_FWD(b));
}

Expand Down
9 changes: 7 additions & 2 deletions src/engine/sparqlExpressions/RelationalExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,13 @@ requires isVectorResult<S> auto idGenerator(const S& values, size_t targetSize,

// For the `Variable` and `SetOfIntervals` class, the generator from the
// `sparqlExpressions` module already yields the `ValueIds`.
template <ad_utility::SimilarToAny<Variable, ad_utility::SetOfIntervals> S>
auto idGenerator(S input, size_t targetSize, const EvaluationContext* context) {
CPP_template(typename S)(
requires ad_utility::SimilarToAny<
S, Variable,
ad_utility::SetOfIntervals>) auto idGenerator(S input,
size_t targetSize,
const EvaluationContext*
context) {
return sparqlExpression::detail::makeGenerator(std::move(input), targetSize,
context);
}
Expand Down
17 changes: 10 additions & 7 deletions src/engine/sparqlExpressions/SparqlExpressionTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,10 @@ concept SingleExpressionResult =
ad_utility::SimilarToAnyTypeIn<T, ExpressionResult>;

// Copy an expression result.
inline ExpressionResult copyExpressionResult(
ad_utility::SimilarTo<ExpressionResult> auto&& result) {
CPP_template(typename ResultT)(
requires ad_utility::SimilarTo<ResultT,
ExpressionResult>) inline ExpressionResult
copyExpressionResult(ResultT&& result) {
auto copyIfCopyable =
[]<SingleExpressionResult R>(const R& x) -> ExpressionResult {
if constexpr (requires { R{AD_FWD(x)}; }) {
Expand Down Expand Up @@ -332,11 +334,12 @@ std::optional<ExpressionResult> evaluateOnSpecializedFunctionsIfPossible(
// for multiple `ValueGetters` because there can be multiple `ValueGetters` as
// well as zero or more `SpezializedFunctions`, but there can only be a single
// parameter pack in C++.
template <
size_t NumOperands,
ad_utility::isInstantiation<FunctionAndValueGetters>
FunctionAndValueGettersT,
ad_utility::isInstantiation<SpecializedFunction>... SpecializedFunctions>
template <size_t NumOperands,
QL_CONCEPT_OR_TYPENAME(
ad_utility::isInstantiation<FunctionAndValueGetters>)
FunctionAndValueGettersT,
QL_CONCEPT_OR_TYPENAME(ad_utility::isInstantiation<
SpecializedFunction>)... SpecializedFunctions>
struct Operation {
private:
using OriginalValueGetters = typename FunctionAndValueGettersT::ValueGetters;
Expand Down
Loading
Loading