Move QMinimalFlatSet from QtDeclarative to QtCore

This is a copy of qtdeclarative/src/quick/util/qminimalflatset_p.h as
of qtdeclarative/1e6cb2462ee87476a5eab7c71735c001a46c7b55, with the
following changes:

- Use a different header guard name. The header guard name is being
  changed in qtdeclarative in parallel, but don't let there be a
  window in which there might be a conflict.

- Add a type alias for QVarLengthArray-backed QMinimalFlatSet.

- Remove the qtquickglobal.h header.

- Adjust the introducing comment to the new home.

I've seen several use-cases for this in QtBase the last few days, so
it's time to move it into a more central place and get more users.

Change-Id: I03397edf8e885d3100c529b41dbf99e2a1184542
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Marc Mutz 2024-02-13 13:10:37 +01:00
parent 1214edc0d9
commit 9afd95eb68
2 changed files with 147 additions and 0 deletions

View File

@ -290,6 +290,7 @@ qt_internal_add_module(Core
tools/qmap.h
tools/qmargins.cpp tools/qmargins.h
tools/qmessageauthenticationcode.h
tools/qminimalflatset_p.h
tools/qoffsetstringarray_p.h
tools/qpair.h
tools/qpoint.cpp tools/qpoint.h

View File

@ -0,0 +1,146 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTCORE_QMINIMALFLATSET_P_H
#define QTCORE_QMINIMALFLATSET_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qcontainerfwd.h>
#include <QtCore/private/qglobal_p.h>
//#define QMINIMAL_FLAT_SET_DEBUG
#ifdef QMINIMAL_FLAT_SET_DEBUG
# include <QtCore/qscopeguard.h>
# include <QtCore/qdebug.h>
# define QMINIMAL_FLAT_SET_PRINT_AT_END \
const auto sg = qScopeGuard([&] { qDebug() << this << *this; });
#else
# define QMINIMAL_FLAT_SET_PRINT_AT_END
#endif
#include <algorithm> // for std::lower_bound
QT_BEGIN_NAMESPACE
/*
This is a minimal version of a QFlatSet, the std::set version of QFlatMap.
Like QFlatMap, it has linear insertion and removal, not logarithmic, like
real QMap and std::set, so it's only a good container if you either have
very few entries or lots, but with separate setup and lookup stages.
Because a full QFlatSet would be 10x the work on writing this minimal one,
we keep it here for now. When more users pop up and the class has matured a
bit, we can consider moving it as QFlatSet alongside QFlatMap.
*/
template <typename T, typename Container = QList<T>>
class QMinimalFlatSet
{
Container c;
public:
// compiler-generated default ctor is ok!
// compiler-generated copy/move ctor/assignment operators are ok!
// compiler-generated dtor is ok!
using const_iterator = typename Container::const_iterator;
using iterator = const_iterator;
using const_reverse_iterator = typename Container::const_reverse_iterator;
using reverse_iterator = const_reverse_iterator;
using value_type = T;
iterator begin() const { return c.cbegin(); }
iterator end() const { return c.cend(); }
iterator cbegin() const { return begin(); }
iterator cend() const { return cend(); }
reverse_iterator rbegin() const { return c.crbegin(); }
reverse_iterator rend() const { return c.crend(); }
reverse_iterator crbegin() const { return rbegin(); }
reverse_iterator crend() const { return rend(); }
void clear() {
QMINIMAL_FLAT_SET_PRINT_AT_END
c.clear();
}
auto size() const { return c.size(); }
auto count() const { return size(); }
bool isEmpty() const { return size() == 0; }
std::pair<iterator, bool> insert(value_type &&v)
{
QMINIMAL_FLAT_SET_PRINT_AT_END
const auto r = lookup(v);
if (r.exists)
return {r.it, false};
else
return {c.insert(r.it, std::move(v)), true};
}
std::pair<iterator, bool> insert(const value_type &v)
{
QMINIMAL_FLAT_SET_PRINT_AT_END
const auto r = lookup(v);
if (r.exists)
return {r.it, false};
else
return {c.insert(r.it, v), true};
}
void erase(const value_type &v)
{
QMINIMAL_FLAT_SET_PRINT_AT_END
const auto r = lookup(v);
if (r.exists)
c.erase(r.it);
}
void remove(const value_type &v) { erase(v); }
bool contains(const value_type &v) const
{
return lookup(v).exists;
}
const Container &values() const & { return c; }
Container values() && { return std::move(c); }
private:
auto lookup(const value_type &v) const
{
struct R {
iterator it;
bool exists;
};
const auto it = std::lower_bound(c.cbegin(), c.cend(), v);
return R{it, it != c.cend() && !(v < *it)};
}
#ifdef QMINIMAL_FLAT_SET_DEBUG
friend QDebug operator<<(QDebug dbg, const QMinimalFlatSet &set)
{
const QDebugStateSaver saver(dbg);
dbg.nospace() << "QMinimalFlatSet{";
for (auto &e : set)
dbg << e << ", ";
return dbg << "}";
}
#endif
};
#undef QMINIMAL_FLAT_SET_PRINT_AT_END
template <typename T, qsizetype N = QVarLengthArrayDefaultPrealloc>
using QMinimalVarLengthFlatSet = QMinimalFlatSet<T, QVarLengthArray<T, N>>;
QT_END_NAMESPACE
#endif // QTCORE_QMINIMALFLATSET_P_H