diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2020-08-25 11:58:09 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-09-01 13:35:39 +0200 |
commit | 4fbb2f66d6144953837361e808845edb181b124e (patch) | |
tree | 86d2c9222560c8e3c547277e60553afe8ed43356 /src/corelib/kernel/qmetacontainer.h | |
parent | 83ad54c1241efa359355f531dabb4de5be33aa32 (diff) |
Add a QMetaSequence interface
This is in line with QMetaType and will be used to implement a mutable
QSequentialIterable. Later on, a QMetaAssociation will be added as
well, to implement a mutable QAssociativeIterable.
The code here represents the minimal set of functionality needed to have
a practical sequential container. The functionality is not completely
orthogonal. In particular, the index based operations could be
implemented in terms of iterator-based operations.
Task-number: QTBUG-81716
Change-Id: Ibd41eb7db248a774673c701549d9a03cbf2e48b6
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/corelib/kernel/qmetacontainer.h')
-rw-r--r-- | src/corelib/kernel/qmetacontainer.h | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/src/corelib/kernel/qmetacontainer.h b/src/corelib/kernel/qmetacontainer.h new file mode 100644 index 0000000000..c663d1ce24 --- /dev/null +++ b/src/corelib/kernel/qmetacontainer.h @@ -0,0 +1,594 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETACONTAINER_H +#define QMETACONTAINER_H + +#include <QtCore/qcontainerinfo.h> +#include <QtCore/qflags.h> +#include <QtCore/qglobal.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_NAMESPACE + +namespace QtMetaContainerPrivate { + +enum IteratorCapability : quint8 { + ForwardCapability = 1 << 0, + BiDirectionalCapability = 1 << 1, + RandomAccessCapability = 1 << 2, +}; + +Q_DECLARE_FLAGS(IteratorCapabilities, IteratorCapability) +Q_DECLARE_OPERATORS_FOR_FLAGS(IteratorCapabilities) + +class QMetaSequenceInterface +{ +public: + enum Position : quint8 { AtBegin, AtEnd, Random }; + + ushort revision; + IteratorCapabilities iteratorCapabilities; + Position addRemovePosition; + QMetaType valueMetaType; + + using SizeFn = qsizetype(*)(const void *); + SizeFn sizeFn; + using ClearFn = void(*)(void *); + ClearFn clearFn; + + using ElementAtIndexFn = void(*)(const void *, qsizetype, void *); + ElementAtIndexFn elementAtIndexFn; + using SetElementAtIndexFn = void(*)(void *, qsizetype, const void *); + SetElementAtIndexFn setElementAtIndexFn; + + using AddElementFn = void(*)(void *, const void *); + AddElementFn addElementFn; + using RemoveElementFn = void(*)(void *); + RemoveElementFn removeElementFn; + + using CreateIteratorFn = void *(*)(void *, Position); + CreateIteratorFn createIteratorFn; + using DestroyIteratorFn = void(*)(const void *); + DestroyIteratorFn destroyIteratorFn; + using CompareIteratorFn = bool(*)(const void *, const void *); + CompareIteratorFn compareIteratorFn; + using CopyIteratorFn = void(*)(void *, const void *); + CopyIteratorFn copyIteratorFn; + using AdvanceIteratorFn = void(*)(void *, qsizetype); + AdvanceIteratorFn advanceIteratorFn; + using DiffIteratorFn = qsizetype(*)(const void *, const void *); + DiffIteratorFn diffIteratorFn; + using ElementAtIteratorFn = void(*)(const void *, void *); + ElementAtIteratorFn elementAtIteratorFn; + using SetElementAtIteratorFn = void(*)(const void *, const void *); + SetElementAtIteratorFn setElementAtIteratorFn; + using InsertElementAtIteratorFn = void(*)(void *, const void *, const void *); + InsertElementAtIteratorFn insertElementAtIteratorFn; + using EraseElementAtIteratorFn = void(*)(void *, const void *); + EraseElementAtIteratorFn eraseElementAtIteratorFn; + + using CreateConstIteratorFn = void *(*)(const void *, Position); + CreateConstIteratorFn createConstIteratorFn; + DestroyIteratorFn destroyConstIteratorFn; + CompareIteratorFn compareConstIteratorFn; + CopyIteratorFn copyConstIteratorFn; + AdvanceIteratorFn advanceConstIteratorFn; + DiffIteratorFn diffConstIteratorFn; + ElementAtIteratorFn elementAtConstIteratorFn; +}; + +template<typename C> +class QMetaSequenceForContainer +{ + template <typename Iterator> + static constexpr IteratorCapabilities capabilitiesForIterator() + { + using Tag = typename std::iterator_traits<Iterator>::iterator_category; + IteratorCapabilities caps {}; + if constexpr (std::is_base_of_v<std::forward_iterator_tag, Tag>) + caps |= ForwardCapability; + if constexpr (std::is_base_of_v<std::bidirectional_iterator_tag, Tag>) + caps |= BiDirectionalCapability; + if constexpr (std::is_base_of_v<std::random_access_iterator_tag, Tag>) + caps |= RandomAccessCapability; + return caps; + } + + static constexpr IteratorCapabilities getIteratorCapabilities() + { + if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) + return capabilitiesForIterator<QContainerTraits::iterator<C>>(); + else if constexpr (QContainerTraits::has_const_iterator_v<C>) + return capabilitiesForIterator<QContainerTraits::const_iterator<C>>(); + else + return {}; + } + + static constexpr QMetaSequenceInterface::Position getAddRemovePosition() + { + if constexpr (QContainerTraits::has_push_back_v<C> && QContainerTraits::has_pop_back_v<C>) + return QMetaSequenceInterface::AtEnd; + if constexpr (QContainerTraits::has_push_front_v<C> && QContainerTraits::has_pop_front_v<C>) + return QMetaSequenceInterface::AtBegin; + return QMetaSequenceInterface::Random; + } + + static constexpr QMetaType getValueMetaType() + { + return QMetaType::fromType<typename C::value_type>(); + } + + static constexpr QMetaSequenceInterface::SizeFn getSizeFn() + { + if constexpr (QContainerTraits::has_size_v<C>) { + return [](const void *c) -> qsizetype { return static_cast<const C *>(c)->size(); }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::ClearFn getClearFn() + { + if constexpr (QContainerTraits::has_clear_v<C>) { + return [](void *c) { return static_cast<C *>(c)->clear(); }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::ElementAtIndexFn getElementAtIndexFn() + { + if constexpr (QContainerTraits::has_at_v<C>) { + return [](const void *c, qsizetype i, void *r) { + *static_cast<QContainerTraits::value_type<C> *>(r) + = static_cast<const C *>(c)->at(i); + }; + } else if constexpr (QContainerTraits::can_get_at_index_v<C>) { + return [](const void *c, qsizetype i, void *r) { + *static_cast<QContainerTraits::value_type<C> *>(r) + = (*static_cast<const C *>(c))[i]; + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::SetElementAtIndexFn getSetElementAtIndexFn() + { + if constexpr (QContainerTraits::can_set_at_index_v<C>) { + return [](void *c, qsizetype i, const void *e) { + (*static_cast<C *>(c))[i] + = *static_cast<const QContainerTraits::value_type<C> *>(e); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::AddElementFn getAddElementFn() + { + if constexpr (QContainerTraits::has_push_back_v<C>) { + return [](void *c, const void *v) { + static_cast<C *>(c)->push_back( + *static_cast<const QContainerTraits::value_type<C> *>(v)); + }; + } else if constexpr (QContainerTraits::has_push_front_v<C>) { + return [](void *c, const void *v) { + static_cast<C *>(c)->push_front( + *static_cast<const QContainerTraits::value_type<C> *>(v)); + }; + } else if constexpr (QContainerTraits::has_insert_v<C>) { + return [](void *c, const void *v) { + static_cast<C *>(c)->insert( + *static_cast<const QContainerTraits::value_type<C> *>(v)); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::RemoveElementFn getRemoveElementFn() + { + if constexpr (QContainerTraits::has_pop_back_v<C>) { + return [](void *c) { static_cast<C *>(c)->pop_back(); }; + } else if constexpr (QContainerTraits::has_pop_front_v<C>) { + return [](void *c) { static_cast<C *>(c)->pop_front(); }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::CreateIteratorFn getCreateIteratorFn() + { + if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) { + return [](void *c, QMetaSequenceInterface::Position p) -> void* { + using Iterator = QContainerTraits::iterator<C>; + switch (p) { + case QMetaSequenceInterface::AtBegin: + case QMetaSequenceInterface::Random: + return new Iterator(static_cast<C *>(c)->begin()); + break; + case QMetaSequenceInterface::AtEnd: + return new Iterator(static_cast<C *>(c)->end()); + break; + } + return nullptr; + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::DestroyIteratorFn getDestroyIteratorFn() + { + if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) { + return [](const void *i) { + using Iterator = QContainerTraits::iterator<C>; + delete static_cast<const Iterator *>(i); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::CompareIteratorFn getCompareIteratorFn() + { + if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) { + return [](const void *i, const void *j) { + using Iterator = QContainerTraits::iterator<C>; + return *static_cast<const Iterator *>(i) == *static_cast<const Iterator *>(j); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::CopyIteratorFn getCopyIteratorFn() + { + if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) { + return [](void *i, const void *j) { + using Iterator = QContainerTraits::iterator<C>; + *static_cast<Iterator *>(i) = *static_cast<const Iterator *>(j); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::AdvanceIteratorFn getAdvanceIteratorFn() + { + if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) { + return [](void *i, qsizetype step) { + std::advance(*static_cast<QContainerTraits::iterator<C> *>(i), step); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::DiffIteratorFn getDiffIteratorFn() + { + if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) { + return [](const void *i, const void *j) -> qsizetype { + return std::distance(*static_cast<const QContainerTraits::iterator<C> *>(j), + *static_cast<const QContainerTraits::iterator<C> *>(i)); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::ElementAtIteratorFn getElementAtIteratorFn() + { + if constexpr (QContainerTraits::has_iterator_v<C> + && QContainerTraits::can_get_at_iterator_v<C> && !std::is_const_v<C>) { + return [](const void *i, void *r) { + *static_cast<QContainerTraits::value_type<C> *>(r) = + *(*static_cast<const QContainerTraits::iterator<C> *>(i)); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::SetElementAtIteratorFn getSetElementAtIteratorFn() + { + if constexpr (QContainerTraits::has_iterator_v<C> + && QContainerTraits::can_set_at_iterator_v<C> && !std::is_const_v<C>) { + return [](const void *i, const void *e) { + *(*static_cast<const QContainerTraits::iterator<C> *>(i)) + = *static_cast<const QContainerTraits::value_type<C> *>(e); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::InsertElementAtIteratorFn getInsertElementAtIteratorFn() + { + if constexpr (QContainerTraits::has_iterator_v<C> + && QContainerTraits::can_insert_at_iterator_v<C> && !std::is_const_v<C>) { + return [](void *c, const void *i, const void *e) { + static_cast<C *>(c)->insert( + *static_cast<const QContainerTraits::iterator<C> *>(i), + *static_cast<const QContainerTraits::value_type<C> *>(e)); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::EraseElementAtIteratorFn getEraseElementAtIteratorFn() + { + if constexpr (QContainerTraits::has_iterator_v<C> + && QContainerTraits::can_erase_at_iterator_v<C> && !std::is_const_v<C>) { + return [](void *c, const void *i) { + static_cast<C *>(c)->erase(*static_cast<const QContainerTraits::iterator<C> *>(i)); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::CreateConstIteratorFn getCreateConstIteratorFn() + { + if constexpr (QContainerTraits::has_const_iterator_v<C>) { + return [](const void *c, QMetaSequenceInterface::Position p) -> void* { + using Iterator = QContainerTraits::const_iterator<C>; + switch (p) { + case QMetaSequenceInterface::AtBegin: + case QMetaSequenceInterface::Random: + return new Iterator(static_cast<const C *>(c)->begin()); + break; + case QMetaSequenceInterface::AtEnd: + return new Iterator(static_cast<const C *>(c)->end()); + break; + } + return nullptr; + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::DestroyIteratorFn getDestroyConstIteratorFn() + { + if constexpr (QContainerTraits::has_const_iterator_v<C>) { + return [](const void *i) { + using Iterator = QContainerTraits::const_iterator<C>; + delete static_cast<const Iterator *>(i); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::CompareIteratorFn getCompareConstIteratorFn() + { + if constexpr (QContainerTraits::has_const_iterator_v<C>) { + return [](const void *i, const void *j) { + using Iterator = QContainerTraits::const_iterator<C>; + return *static_cast<const Iterator *>(i) == *static_cast<const Iterator *>(j); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::CopyIteratorFn getCopyConstIteratorFn() + { + if constexpr (QContainerTraits::has_const_iterator_v<C>) { + return [](void *i, const void *j) { + using Iterator = QContainerTraits::const_iterator<C>; + *static_cast<Iterator *>(i) = *static_cast<const Iterator *>(j); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::AdvanceIteratorFn getAdvanceConstIteratorFn() + { + if constexpr (QContainerTraits::has_const_iterator_v<C>) { + return [](void *i, qsizetype step) { + std::advance(*static_cast<QContainerTraits::const_iterator<C> *>(i), step); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::DiffIteratorFn getDiffConstIteratorFn() + { + if constexpr (QContainerTraits::has_const_iterator_v<C>) { + return [](const void *i, const void *j) -> qsizetype { + return std::distance(*static_cast<const QContainerTraits::const_iterator<C> *>(j), + *static_cast<const QContainerTraits::const_iterator<C> *>(i)); + }; + } else { + return nullptr; + } + } + + static constexpr QMetaSequenceInterface::ElementAtIteratorFn getElementAtConstIteratorFn() + { + if constexpr (QContainerTraits::has_const_iterator_v<C> + && QContainerTraits::can_get_at_iterator_v<C>) { + return [](const void *i, void *r) { + *static_cast<QContainerTraits::value_type<C> *>(r) = + *(*static_cast<const QContainerTraits::const_iterator<C> *>(i)); + }; + } else { + return nullptr; + } + } + +public: + static QMetaSequenceInterface metaSequence; +}; + +template<typename C> +QMetaSequenceInterface QMetaSequenceForContainer<C>::metaSequence = { + /*.revision=*/ 0, + /*.iteratorCapabilities=*/ getIteratorCapabilities(), + /*.addRemovePosition=*/ getAddRemovePosition(), + /*.valueMetaType=*/ getValueMetaType(), + /*.sizeFn=*/ getSizeFn(), + /*.clearFn=*/ getClearFn(), + /*.elementAtIndexFn=*/ getElementAtIndexFn(), + /*.setElementAtIndexFn=*/ getSetElementAtIndexFn(), + /*.addElementFn=*/ getAddElementFn(), + /*.removeLastElementFn=*/ getRemoveElementFn(), + /*.createIteratorFn=*/ getCreateIteratorFn(), + /*.destroyIteratorFn=*/ getDestroyIteratorFn(), + /*.equalIteratorFn=*/ getCompareIteratorFn(), + /*.copyIteratorFn=*/ getCopyIteratorFn(), + /*.advanceIteratorFn=*/ getAdvanceIteratorFn(), + /*.diffIteratorFn=*/ getDiffIteratorFn(), + /*.elementAtIteratorFn=*/ getElementAtIteratorFn(), + /*.setElementAtIteratorFn=*/ getSetElementAtIteratorFn(), + /*.insertElementAtIteratorFn=*/ getInsertElementAtIteratorFn(), + /*.eraseElementAtIteratorFn=*/ getEraseElementAtIteratorFn(), + /*.createConstIteratorFn=*/ getCreateConstIteratorFn(), + /*.destroyConstIteratorFn=*/ getDestroyConstIteratorFn(), + /*.equalConstIteratorFn=*/ getCompareConstIteratorFn(), + /*.copyConstIteratorFn=*/ getCopyConstIteratorFn(), + /*.advanceConstIteratorFn=*/ getAdvanceConstIteratorFn(), + /*.diffConstIteratorFn=*/ getDiffConstIteratorFn(), + /*.elementAtConstIteratorFn=*/ getElementAtConstIteratorFn(), +}; + +template<typename C> +constexpr QMetaSequenceInterface *qMetaSequenceInterfaceForContainer() +{ + return &QMetaSequenceForContainer<C>::metaSequence; +} + +} // namespace QtMetaContainerPrivate + +class Q_CORE_EXPORT QMetaSequence +{ +public: + QMetaSequence() = default; + explicit QMetaSequence(QtMetaContainerPrivate::QMetaSequenceInterface *d) : d_ptr(d) {} + + template<typename T> + static constexpr QMetaSequence fromContainer() + { + return QMetaSequence(QtMetaContainerPrivate::qMetaSequenceInterfaceForContainer<T>()); + } + + bool hasForwardIterator() const; + bool hasBidirectionalIterator() const; + bool hasRandomAccessIterator() const; + + QMetaType valueMetaType() const; + + bool isOrdered() const; + bool addsAndRemovesElementsAtBegin() const; + bool addsAndRemovesElementsAtEnd() const; + + bool hasSize() const; + qsizetype size(const void *container) const; + + bool canClear() const; + void clear(void *container) const; + + bool canGetElementAtIndex() const; + void elementAtIndex(const void *container, qsizetype index, void *result) const; + + bool canSetElementAtIndex() const; + void setElementAtIndex(void *container, qsizetype index, const void *element) const; + + bool canAddElement() const; + void addElement(void *container, const void *element) const; + + bool canRemoveElement() const; + void removeElement(void *container) const; + + bool hasIterator() const; + void *begin(void *container) const; + void *end(void *container) const; + void destroyIterator(const void *iterator) const; + bool compareIterator(const void *i, const void *j) const; + void copyIterator(void *target, const void *source) const; + void advanceIterator(void *iterator, qsizetype step) const; + qsizetype diffIterator(const void *i, const void *j) const; + + bool canGetElementAtIterator() const; + void elementAtIterator(const void *iterator, void *result) const; + + bool canSetElementAtIterator() const; + void setElementAtIterator(const void *iterator, const void *element) const; + + bool canInsertElementAtIterator() const; + void insertElementAtIterator(void *container, const void *iterator, const void *element) const; + + bool canEraseElementAtIterator() const; + void eraseElementAtIterator(void *container, const void *iterator) const; + + bool hasConstIterator() const; + void *constBegin(const void *container) const; + void *constEnd(const void *container) const; + void destroyConstIterator(const void *iterator) const; + bool compareConstIterator(const void *i, const void *j) const; + void copyConstIterator(void *target, const void *source) const; + void advanceConstIterator(void *iterator, qsizetype step) const; + qsizetype diffConstIterator(const void *i, const void *j) const; + + bool canGetElementAtConstIterator() const; + void elementAtConstIterator(const void *iterator, void *result) const; + + friend bool operator==(const QMetaSequence &a, const QMetaSequence &b) + { + return a.d_ptr == b.d_ptr; + } + friend bool operator!=(const QMetaSequence &a, const QMetaSequence &b) + { + return a.d_ptr != b.d_ptr; + } + +private: + QtMetaContainerPrivate::QMetaSequenceInterface *d_ptr = nullptr; +}; + +QT_END_NAMESPACE + +#endif // QMETACONTAINER_H |