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 12 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
2 changes: 1 addition & 1 deletion benchmark/BenchmarkExamples.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class ConfigOptions : public BenchmarkInterface {
auto numSigns =
manager.addOption("num-signs", "The number of street signs.",
&numberOfStreetSigns_, 10000);
manager.addValidator([](const int& num) { return num >= 0; },
manager.addValidator([](const int& num) -> bool { return num >= 0; },
"The number of street signs must be at least 0!",
"Negative numbers, or floating point numbers, are not "
"allowed for the configuration option \"num-signs\".",
Expand Down
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
24 changes: 24 additions & 0 deletions src/backports/concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@
#ifdef QLEVER_CPP_17
#define QL_CONCEPT_OR_NOTHING(...)
#define QL_CONCEPT_OR_TYPENAME(...) typename
#define CPP_and_def CPP_and_sfinae_def
#else
#define QL_CONCEPT_OR_NOTHING(...) __VA_ARGS__
#define QL_CONCEPT_OR_TYPENAME(...) __VA_ARGS__
#define CPP_and_def CPP_and
#endif

// The namespace `ql::concepts` includes concepts that are contained in the
Expand All @@ -53,3 +55,25 @@ using namespace std;

} // namespace concepts
} // namespace ql

// A template with a requires clause
/// INTERNAL ONLY
#define QL_TEMPLATE_NO_DEFAULT_SFINAE_AUX_0(...) \
, std::enable_if_t< \
CPP_PP_CAT(QL_TEMPLATE_NO_DEFAULT_SFINAE_AUX_3_, __VA_ARGS__), int> = \
0 > CPP_PP_IGNORE_CXX2A_COMPAT_END

#define QL_TEMPLATE_NO_DEFAULT_SFINAE_AUX_3_requires

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

#define QL_TEMPLATE_NO_DEFAULT_SFINAE_AUX_(...) \
CPP_PP_CAT(QL_TEMPLATE_NO_DEFAULT_SFINAE_AUX_, \
QL_TEMPLATE_SFINAE_AUX_WHICH_(__VA_ARGS__, )) \
(__VA_ARGS__)

#define QL_TEMPLATE_NO_DEFAULT(...) \
CPP_PP_IGNORE_CXX2A_COMPAT_BEGIN \
template <__VA_ARGS__ QL_TEMPLATE_NO_DEFAULT_SFINAE_AUX_
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::setupCancellationHandle(
const ad_utility::websocket::QueryId& queryId, TimeLimit timeLimit)
-> ad_utility::isInstantiation<
CancellationHandleAndTimeoutTimerCancel> auto {
-> QL_CONCEPT_OR_NOTHING(ad_utility::isInstantiation<
CancellationHandleAndTimeoutTimerCancel>) auto {

Check warning on line 472 in src/engine/Server.cpp

View check run for this annotation

Codecov / codecov/patch

src/engine/Server.cpp#L472

Added line #L472 was not covered by tests
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
41 changes: 37 additions & 4 deletions src/global/Pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <string>
#include <vector>

#include "backports/concepts.h"
#include "global/Id.h"
#include "util/ExceptionHandling.h"
#include "util/File.h"
Expand Down Expand Up @@ -71,6 +72,40 @@ struct CompactStringVectorWriter;

}

// TODO<joka921, picciuca> : The following doesn't work if there is no `begin()`
// member in 17 mode. We need a different solution for this, but this is
// currently only used in tests. Postponing this for now.
#if false
#ifdef QLEVER_CPP_17
template <typename T, typename = void>
struct IsIteratorOfIterator : std::false_type {};

template <typename T>
struct IsIteratorOfIterator<
T, std::void_t<decltype(*(T::iterator::value_type::begin()))>>
: std::true_type {};

template <typename T, typename DataType>
CPP_concept IteratorOfIterator =
(IsIteratorOfIterator<T>::value &&
ad_utility::SimilarTo<decltype(*(T::iterator::value_type::begin())),
DataType>);
#else
template <typename T, typename DataType>
concept IteratorOfIterator = requires(T t) {
{ *(t.begin()->begin()) } -> ad_utility::SimilarTo<DataType>;
};
#endif

#endif

template <typename T, typename U>
concept DummySimilar = ad_utility::SimilarTo<T, U>;
template <typename T, typename DataType>
concept IteratorOfIterator = requires(T t) {
{ *(t.begin()->begin()) } -> DummySimilar<DataType>;
};

/**
* @brief Stores a list of variable length data of a single type (e.g.
* c-style strings). The data is stored in a single contiguous block
Expand Down Expand Up @@ -102,10 +137,8 @@ class CompactVectorOfStrings {
* @brief Fills this CompactVectorOfStrings with input.
* @param The input from which to build the vector.
*/
template <typename T>
requires requires(T t) {
{ *(t.begin()->begin()) } -> ad_utility::SimilarTo<data_type>;
} void build(const T& input) {
CPP_template(typename T)(
requires IteratorOfIterator<T, data_type>) void build(const T& input) {
// Also make room for the end offset of the last element.
_offsets.reserve(input.size() + 1);
size_t dataSize = 0;
Expand Down
15 changes: 8 additions & 7 deletions src/index/CompressedRelation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -752,13 +752,14 @@ size_t CompressedRelationReader::getResultSizeOfScan(
}

// ____________________________________________________________________________
IdTable CompressedRelationReader::getDistinctColIdsAndCountsImpl(
ad_utility::InvocableWithConvertibleReturnType<
Id, const CompressedBlockMetadata::PermutedTriple&> auto idGetter,
const ScanSpecification& scanSpec,
const std::vector<CompressedBlockMetadata>& allBlocksMetadata,
const CancellationHandle& cancellationHandle,
const LocatedTriplesPerBlock& locatedTriplesPerBlock) const {
CPP_template_def(typename IdGetter)(
requires ad_utility::InvocableWithConvertibleReturnType<
IdGetter, Id, const CompressedBlockMetadata::PermutedTriple&>) IdTable
CompressedRelationReader::getDistinctColIdsAndCountsImpl(
IdGetter idGetter, const ScanSpecification& scanSpec,
const std::vector<CompressedBlockMetadata>& allBlocksMetadata,
const CancellationHandle& cancellationHandle,
const LocatedTriplesPerBlock& locatedTriplesPerBlock) const {
// The result has two columns: one for the distinct `Id`s and one for their
// counts.
IdTableStatic<2> table(allocator_);
Expand Down
Loading
Loading