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

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated versions of those, I will merge them in here myself later today or tomorrow.

#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()`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting this TODO for later, s.t. I can have a look at it again.

// 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