forked from qt-creator/qt-creator
Sqlite: Make sqlite range usable for std::ranges
Adding a sentinel and making the iterator copyable makes it possible to use it as a range in std::views. Change-Id: I100edb39b601a2e02fd424115e362c67f2de39f1 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -140,13 +140,20 @@ private:
|
||||
Database &m_database;
|
||||
};
|
||||
|
||||
template <> SQLITE_EXPORT int BaseStatement::fetchValue<int>(int column) const;
|
||||
template <> SQLITE_EXPORT long BaseStatement::fetchValue<long>(int column) const;
|
||||
template <> SQLITE_EXPORT long long BaseStatement::fetchValue<long long>(int column) const;
|
||||
template <> SQLITE_EXPORT double BaseStatement::fetchValue<double>(int column) const;
|
||||
extern template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue<Utils::SmallStringView>(int column) const;
|
||||
extern template SQLITE_EXPORT Utils::SmallString BaseStatement::fetchValue<Utils::SmallString>(int column) const;
|
||||
extern template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue<Utils::PathString>(int column) const;
|
||||
template<>
|
||||
SQLITE_EXPORT int BaseStatement::fetchValue<int>(int column) const;
|
||||
template<>
|
||||
SQLITE_EXPORT long BaseStatement::fetchValue<long>(int column) const;
|
||||
template<>
|
||||
SQLITE_EXPORT long long BaseStatement::fetchValue<long long>(int column) const;
|
||||
template<>
|
||||
SQLITE_EXPORT double BaseStatement::fetchValue<double>(int column) const;
|
||||
extern template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue<Utils::SmallStringView>(
|
||||
int column) const;
|
||||
extern template SQLITE_EXPORT Utils::SmallString BaseStatement::fetchValue<Utils::SmallString>(
|
||||
int column) const;
|
||||
extern template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue<Utils::PathString>(
|
||||
int column) const;
|
||||
|
||||
template<typename BaseStatement, int ResultCount, int BindParameterCount>
|
||||
class StatementImplementation : public BaseStatement
|
||||
@@ -207,12 +214,15 @@ public:
|
||||
template<typename T>
|
||||
struct is_container : std::false_type
|
||||
{};
|
||||
|
||||
template<typename... Args>
|
||||
struct is_container<std::vector<Args...>> : std::true_type
|
||||
{};
|
||||
|
||||
template<typename... Args>
|
||||
struct is_container<QList<Args...>> : std::true_type
|
||||
{};
|
||||
|
||||
template<typename T, qsizetype Prealloc>
|
||||
struct is_container<QVarLengthArray<T, Prealloc>> : std::true_type
|
||||
{};
|
||||
@@ -436,6 +446,9 @@ public:
|
||||
class BaseSqliteResultRange
|
||||
{
|
||||
public:
|
||||
class SqliteResultSentinel
|
||||
{};
|
||||
|
||||
class SqliteResultIteratator
|
||||
{
|
||||
public:
|
||||
@@ -447,44 +460,58 @@ public:
|
||||
|
||||
SqliteResultIteratator(StatementImplementation &statement,
|
||||
const source_location &sourceLocation)
|
||||
: m_statement{statement}
|
||||
, m_sourceLocation{sourceLocation}
|
||||
, m_hasNext{m_statement.next(sourceLocation)}
|
||||
: m_statement{&statement}
|
||||
, m_sourceLocation{&sourceLocation}
|
||||
, m_hasNext{m_statement->next(sourceLocation)}
|
||||
{}
|
||||
|
||||
SqliteResultIteratator(StatementImplementation &statement,
|
||||
const source_location &sourceLocation,
|
||||
bool hasNext)
|
||||
: m_statement{statement}
|
||||
, m_sourceLocation{sourceLocation}
|
||||
: m_statement{&statement}
|
||||
, m_sourceLocation{&sourceLocation}
|
||||
, m_hasNext{hasNext}
|
||||
{}
|
||||
|
||||
SqliteResultIteratator(const SqliteResultIteratator &) = delete;
|
||||
SqliteResultIteratator &operator=(const SqliteResultIteratator &) = delete;
|
||||
|
||||
SqliteResultIteratator(SqliteResultIteratator &&other) noexcept
|
||||
: m_statement{other.m_statement}
|
||||
, m_sourceLocation{other.m_sourceLocation}
|
||||
, m_hasNext{std::exchange(other.m_hasNext, false)}
|
||||
{}
|
||||
|
||||
SqliteResultIteratator &operator=(SqliteResultIteratator &&other) noexcept
|
||||
{
|
||||
m_statement = other.m_statement;
|
||||
m_sourceLocation = other.m_sourceLocation;
|
||||
m_hasNext = std::exchange(other.m_hasNext, false);
|
||||
}
|
||||
|
||||
SqliteResultIteratator &operator++()
|
||||
{
|
||||
m_hasNext = m_statement.next(m_sourceLocation);
|
||||
m_hasNext = m_statement->next(*m_sourceLocation);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator++(int) { m_hasNext = m_statement.next(m_sourceLocation); }
|
||||
|
||||
friend bool operator==(const SqliteResultIteratator &first,
|
||||
const SqliteResultIteratator &second)
|
||||
friend bool operator==(const SqliteResultIteratator &first, SqliteResultSentinel)
|
||||
{
|
||||
return first.m_hasNext == second.m_hasNext;
|
||||
return !first.m_hasNext;
|
||||
}
|
||||
|
||||
friend bool operator!=(const SqliteResultIteratator &first,
|
||||
const SqliteResultIteratator &second)
|
||||
friend bool operator!=(const SqliteResultIteratator &first, SqliteResultSentinel)
|
||||
{
|
||||
return !(first == second);
|
||||
return first.m_hasNext;
|
||||
}
|
||||
|
||||
value_type operator*() const { return m_statement.createValue<ResultType>(); }
|
||||
void operator++(int) { m_hasNext = m_statement->next(*m_sourceLocation); }
|
||||
|
||||
private:
|
||||
StatementImplementation &m_statement;
|
||||
const source_location &m_sourceLocation;
|
||||
value_type operator*() const { return m_statement->createValue<ResultType>(); }
|
||||
|
||||
public:
|
||||
StatementImplementation *m_statement;
|
||||
const source_location *m_sourceLocation;
|
||||
bool m_hasNext = false;
|
||||
};
|
||||
|
||||
@@ -496,19 +523,20 @@ public:
|
||||
BaseSqliteResultRange(StatementImplementation &statement, const source_location &sourceLocation)
|
||||
: m_statement{statement}
|
||||
, m_sourceLocation{sourceLocation}
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
BaseSqliteResultRange(BaseSqliteResultRange &) = delete;
|
||||
BaseSqliteResultRange &operator=(BaseSqliteResultRange &) = delete;
|
||||
BaseSqliteResultRange &operator=(BaseSqliteResultRange &&) = delete;
|
||||
BaseSqliteResultRange(const BaseSqliteResultRange &) = default;
|
||||
BaseSqliteResultRange(BaseSqliteResultRange &&) = default;
|
||||
BaseSqliteResultRange &operator=(const BaseSqliteResultRange &) = default;
|
||||
BaseSqliteResultRange &operator=(BaseSqliteResultRange &&) = default;
|
||||
|
||||
iterator begin() & { return iterator{m_statement, m_sourceLocation}; }
|
||||
|
||||
iterator end() & { return iterator{m_statement, m_sourceLocation, false}; }
|
||||
auto end() & { return SqliteResultSentinel{}; }
|
||||
|
||||
const_iterator begin() const & { return iterator{m_statement}; }
|
||||
const_iterator end() const & { return iterator{m_statement, false}; }
|
||||
|
||||
auto end() const & { return SqliteResultSentinel{}; }
|
||||
|
||||
private:
|
||||
using TracerCategory = std::decay_t<decltype(sqliteHighLevelCategory())>;
|
||||
@@ -587,10 +615,17 @@ private:
|
||||
Resetter(Resetter &) = delete;
|
||||
Resetter &operator=(Resetter &) = delete;
|
||||
|
||||
Resetter(Resetter &&other)
|
||||
Resetter(Resetter &&other) noexcept
|
||||
: statement{std::exchange(other.statement, nullptr)}
|
||||
{}
|
||||
|
||||
Resetter &operator=(Resetter &&other) noexcept
|
||||
{
|
||||
statement = std::exchange(other.statement, nullptr);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset() noexcept
|
||||
{
|
||||
if (statement)
|
||||
@@ -601,7 +636,7 @@ private:
|
||||
|
||||
~Resetter() noexcept { reset(); }
|
||||
|
||||
StatementImplementation *statement;
|
||||
StatementImplementation *statement = nullptr;
|
||||
};
|
||||
|
||||
struct ValueGetter
|
||||
@@ -612,12 +647,19 @@ private:
|
||||
{}
|
||||
|
||||
explicit operator bool() const { return statement.fetchIntValue(column); }
|
||||
|
||||
operator int() const { return statement.fetchIntValue(column); }
|
||||
|
||||
operator long() const { return statement.fetchLongValue(column); }
|
||||
|
||||
operator long long() const { return statement.fetchLongLongValue(column); }
|
||||
|
||||
operator double() const { return statement.fetchDoubleValue(column); }
|
||||
|
||||
operator Utils::SmallStringView() { return statement.fetchSmallStringViewValue(column); }
|
||||
|
||||
operator BlobView() { return statement.fetchBlobValue(column); }
|
||||
|
||||
operator ValueView() { return statement.fetchValueView(column); }
|
||||
|
||||
template<typename ConversionType, typename = std::enable_if_t<ConversionType::IsBasicId::value>>
|
||||
@@ -694,8 +736,7 @@ private:
|
||||
template<typename Callable, int... ColumnIndices>
|
||||
CallbackControl callCallable(Callable &&callable, std::integer_sequence<int, ColumnIndices...>)
|
||||
{
|
||||
return invokeCallable(std::forward<Callable>(callable),
|
||||
ValueGetter(*this, ColumnIndices)...);
|
||||
return invokeCallable(std::forward<Callable>(callable), ValueGetter(*this, ColumnIndices)...);
|
||||
}
|
||||
|
||||
template<typename Callable>
|
||||
|
@@ -2373,11 +2373,9 @@ SourceIds ProjectStorage::filterSourceIdsWithoutType(const SourceIds &updatedSou
|
||||
|
||||
SourceIds sourceIdsWithoutTypeSourceIds;
|
||||
sourceIdsWithoutTypeSourceIds.reserve(updatedSourceIds.size());
|
||||
std::set_difference(updatedSourceIds.begin(),
|
||||
updatedSourceIds.end(),
|
||||
sourceIdsOfTypes.begin(),
|
||||
sourceIdsOfTypes.end(),
|
||||
std::back_inserter(sourceIdsWithoutTypeSourceIds));
|
||||
std::ranges::set_difference(updatedSourceIds,
|
||||
sourceIdsOfTypes,
|
||||
std::back_inserter(sourceIdsWithoutTypeSourceIds));
|
||||
|
||||
return sourceIdsWithoutTypeSourceIds;
|
||||
}
|
||||
@@ -2395,8 +2393,8 @@ TypeIds ProjectStorage::fetchTypeIds(const SourceIds &sourceIds)
|
||||
void ProjectStorage::unique(SourceIds &sourceIds)
|
||||
{
|
||||
std::ranges::sort(sourceIds);
|
||||
auto newEnd = std::unique(sourceIds.begin(), sourceIds.end());
|
||||
sourceIds.erase(newEnd, sourceIds.end());
|
||||
auto removed = std::ranges::unique(sourceIds);
|
||||
sourceIds.erase(removed.begin(), removed.end());
|
||||
}
|
||||
|
||||
void ProjectStorage::synchronizeTypeTraits(TypeId typeId, Storage::TypeTraits traits)
|
||||
@@ -4847,7 +4845,7 @@ bool ProjectStorage::isBasedOn_(TypeId typeId, TypeIds... baseTypeIds) const
|
||||
|
||||
auto range = s->selectPrototypeAndExtensionIdsStatement.rangeWithTransaction<TypeId>(typeId);
|
||||
|
||||
auto isBasedOn = std::any_of(range.begin(), range.end(), [&](TypeId currentTypeId) {
|
||||
auto isBasedOn = std::ranges::any_of(range, [&](TypeId currentTypeId) {
|
||||
return ((currentTypeId == baseTypeIds) || ...);
|
||||
});
|
||||
|
||||
|
@@ -113,7 +113,10 @@ protected:
|
||||
template<typename Range>
|
||||
static auto toValues(Range &&range)
|
||||
{
|
||||
return std::vector<typename Range::value_type>{range.begin(), range.end()};
|
||||
std::vector<typename Range::value_type> values;
|
||||
for (auto &&elem : range)
|
||||
values.push_back(std::move(elem));
|
||||
return values;
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -909,8 +912,7 @@ TEST_F(SqliteStatement, get_single_range_without_arguments)
|
||||
{
|
||||
ReadStatement<1> statement("SELECT name FROM test", database);
|
||||
|
||||
auto range = statement.range<Utils::SmallStringView>();
|
||||
std::vector<Utils::SmallString> values{range.begin(), range.end()};
|
||||
auto values = toValues(statement.range<Utils::SmallString>());
|
||||
|
||||
ASSERT_THAT(values, UnorderedElementsAre("bar", "foo", "poo"));
|
||||
}
|
||||
@@ -960,8 +962,7 @@ TEST_F(SqliteStatement, get_single_sqlite_range_without_arguments)
|
||||
ReadStatement<1> statement("SELECT number FROM test", database);
|
||||
database.execute("INSERT INTO test VALUES (NULL, NULL, NULL)");
|
||||
|
||||
auto range = statement.range<FooValue>();
|
||||
std::vector<FooValue> values{range.begin(), range.end()};
|
||||
auto values = toValues(statement.range<FooValue>());
|
||||
|
||||
ASSERT_THAT(values, UnorderedElementsAre(Eq("blah"), Eq(23.3), Eq(40), IsNull()));
|
||||
}
|
||||
@@ -994,8 +995,7 @@ TEST_F(SqliteStatement, get_struct_range_without_arguments)
|
||||
{
|
||||
ReadStatement<3> statement("SELECT name, number, value FROM test", database);
|
||||
|
||||
auto range = statement.range<Output>();
|
||||
std::vector<Output> values{range.begin(), range.end()};
|
||||
auto values = toValues(statement.range<Output>());
|
||||
|
||||
ASSERT_THAT(values,
|
||||
UnorderedElementsAre(Output{"bar", "blah", 1},
|
||||
@@ -1032,8 +1032,7 @@ TEST_F(SqliteStatement, get_range_for_single_output_with_binding_multiple_times)
|
||||
ReadStatement<1, 1> statement("SELECT name FROM test WHERE number=?", database);
|
||||
statement.values<Utils::SmallString, 3>(40);
|
||||
|
||||
auto range = statement.range<Utils::SmallStringView>(40);
|
||||
std::vector<Utils::SmallString> values{range.begin(), range.end()};
|
||||
auto values = toValues(statement.range<Utils::SmallString>(40));
|
||||
|
||||
ASSERT_THAT(values, ElementsAre("poo"));
|
||||
}
|
||||
@@ -1044,8 +1043,7 @@ TEST_F(SqliteStatement, get_range_with_transaction_for_single_output_with_bindin
|
||||
statement.values<Utils::SmallString, 3>(40);
|
||||
database.unlock();
|
||||
|
||||
std::vector<Utils::SmallString> values = toValues(
|
||||
statement.rangeWithTransaction<Utils::SmallString>(40));
|
||||
auto values = toValues(statement.rangeWithTransaction<Utils::SmallString>(40));
|
||||
|
||||
ASSERT_THAT(values, ElementsAre("poo"));
|
||||
database.lock();
|
||||
@@ -1068,8 +1066,7 @@ TEST_F(SqliteStatement, get_range_for_multiple_output_values_and_multiple_query_
|
||||
ReadStatement<3, 3> statement(
|
||||
"SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database);
|
||||
|
||||
auto range = statement.range<Tuple>("bar", "blah", 1);
|
||||
std::vector<Tuple> values{range.begin(), range.end()};
|
||||
auto values = toValues(statement.range<Tuple>("bar", "blah", 1));
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1}));
|
||||
}
|
||||
@@ -1105,12 +1102,10 @@ TEST_F(SqliteStatement, call_get_range_for_multiple_output_values_and_multiple_q
|
||||
ReadStatement<3, 2> statement("SELECT name, number, value FROM test WHERE name=? AND number=?",
|
||||
database);
|
||||
{
|
||||
auto range = statement.range<Tuple>("bar", "blah");
|
||||
std::vector<Tuple> values1{range.begin(), range.end()};
|
||||
auto values1 = toValues(statement.range<Tuple>("bar", "blah"));
|
||||
}
|
||||
|
||||
auto range2 = statement.range<Tuple>("bar", "blah");
|
||||
std::vector<Tuple> values{range2.begin(), range2.end()};
|
||||
auto values = toValues(statement.range<Tuple>("bar", "blah"));
|
||||
|
||||
ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1}));
|
||||
}
|
||||
|
Reference in New Issue
Block a user