Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/QtCore/qtaggedpointer.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // Copyright (C) 2020 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #ifndef QTAGGEDPOINTER_H
0005 #define QTAGGEDPOINTER_H
0006 
0007 #include <QtCore/qglobal.h>
0008 #include <QtCore/qalgorithms.h>
0009 #include <QtCore/qmath.h>
0010 #include <QtCore/qtypeinfo.h>
0011 
0012 QT_BEGIN_NAMESPACE
0013 
0014 namespace QtPrivate {
0015     constexpr quint8 nextByteSize(quint8 bits) { return quint8((bits + 7) / 8); }
0016 
0017     template <typename T>
0018     struct TagInfo
0019     {
0020         static constexpr size_t alignment = alignof(T);
0021         static_assert((alignment & (alignment - 1)) == 0,
0022             "Alignment of template parameter must be power of two");
0023 
0024         static constexpr quint8 tagBits = quint8{QtPrivate::qConstexprCountTrailingZeroBits(alignment)};
0025         static_assert(tagBits > 0,
0026             "Alignment of template parameter does not allow any tags");
0027 
0028         static constexpr size_t tagSize = QtPrivate::qConstexprNextPowerOfTwo(nextByteSize(tagBits));
0029         static_assert(tagSize < sizeof(quintptr),
0030             "Alignment of template parameter allows tags masking away pointer");
0031 
0032         using TagType = typename QIntegerForSize<tagSize>::Unsigned;
0033     };
0034 }
0035 
0036 template <typename T, typename Tag = typename QtPrivate::TagInfo<T>::TagType>
0037 class QTaggedPointer
0038 {
0039 public:
0040     using Type = T;
0041     using TagType = Tag;
0042 
0043     static constexpr quintptr tagMask() { return QtPrivate::TagInfo<T>::alignment - 1; }
0044     static constexpr quintptr pointerMask() { return ~tagMask(); }
0045 
0046     Q_NODISCARD_CTOR constexpr QTaggedPointer() noexcept : d(0) {}
0047     Q_NODISCARD_CTOR constexpr QTaggedPointer(std::nullptr_t) noexcept : QTaggedPointer() {}
0048 
0049     Q_NODISCARD_CTOR explicit QTaggedPointer(T *pointer, Tag tag = Tag()) noexcept
0050         : d(quintptr(pointer) | quintptr(tag))
0051     {
0052         static_assert(sizeof(Type*) == sizeof(QTaggedPointer));
0053 
0054         Q_ASSERT_X((quintptr(pointer) & tagMask()) == 0, "QTaggedPointer<T, Tag>", "Pointer is not aligned");
0055         Q_ASSERT_X((static_cast<typename QtPrivate::TagInfo<T>::TagType>(tag) & pointerMask()) == 0,
0056             "QTaggedPointer<T, Tag>::setTag", "Tag is larger than allowed by number of available tag bits");
0057     }
0058 
0059     Type &operator*() const noexcept
0060     {
0061         Q_ASSERT(data());
0062         return *data();
0063     }
0064 
0065     Type *operator->() const noexcept
0066     {
0067         return data();
0068     }
0069 
0070     explicit operator bool() const noexcept
0071     {
0072         return !isNull();
0073     }
0074 
0075 #ifdef Q_QDOC
0076     QTaggedPointer &operator=(T *other) noexcept;
0077 #else
0078     // Disables the usage of `ptr = {}`, which would go through this operator
0079     // (rather than using the implicitly-generated assignment operator).
0080     // The operators have different semantics: the ones here leave the tag intact,
0081     // the implicitly-generated one overwrites it.
0082     template <typename U,
0083               std::enable_if_t<std::is_convertible_v<U *, T *>, bool> = false>
0084     QTaggedPointer &operator=(U *other) noexcept
0085     {
0086         T *otherT = other;
0087         d = reinterpret_cast<quintptr>(otherT) | (d & tagMask());
0088         return *this;
0089     }
0090 
0091     template <typename U,
0092               std::enable_if_t<std::is_null_pointer_v<U>, bool> = false>
0093     QTaggedPointer &operator=(U) noexcept
0094     {
0095         d = reinterpret_cast<quintptr>(static_cast<T *>(nullptr)) | (d & tagMask());
0096         return *this;
0097     }
0098 #endif
0099 
0100     static constexpr Tag maximumTag() noexcept
0101     {
0102         return TagType(typename QtPrivate::TagInfo<T>::TagType(tagMask()));
0103     }
0104 
0105     void setTag(Tag tag)
0106     {
0107         Q_ASSERT_X(
0108                 (static_cast<quintptr>(tag) & pointerMask()) == 0,
0109                 "QTaggedPointer<T, Tag>::setTag",
0110                 "Tag is larger than allowed by number of available tag bits");
0111 
0112         d = (d & pointerMask()) | static_cast<quintptr>(tag);
0113     }
0114 
0115     Tag tag() const noexcept
0116     {
0117         return TagType(typename QtPrivate::TagInfo<T>::TagType(d & tagMask()));
0118     }
0119 
0120     T* data() const noexcept
0121     {
0122         return reinterpret_cast<T*>(d & pointerMask());
0123     }
0124 
0125     bool isNull() const noexcept
0126     {
0127         return !data();
0128     }
0129 
0130     void swap(QTaggedPointer &other) noexcept
0131     {
0132         std::swap(d, other.d);
0133     }
0134 
0135     friend inline bool operator==(QTaggedPointer lhs, QTaggedPointer rhs) noexcept
0136     {
0137         return lhs.data() == rhs.data();
0138     }
0139 
0140     friend inline bool operator!=(QTaggedPointer lhs, QTaggedPointer rhs) noexcept
0141     {
0142         return lhs.data() != rhs.data();
0143     }
0144 
0145     friend inline bool operator==(QTaggedPointer lhs, std::nullptr_t) noexcept
0146     {
0147         return lhs.isNull();
0148     }
0149 
0150     friend inline bool operator==(std::nullptr_t, QTaggedPointer rhs) noexcept
0151     {
0152         return rhs.isNull();
0153     }
0154 
0155     friend inline bool operator!=(QTaggedPointer lhs, std::nullptr_t) noexcept
0156     {
0157         return !lhs.isNull();
0158     }
0159 
0160     friend inline bool operator!=(std::nullptr_t, QTaggedPointer rhs) noexcept
0161     {
0162         return !rhs.isNull();
0163     }
0164 
0165     friend inline bool operator!(QTaggedPointer ptr) noexcept
0166     {
0167         return !ptr.data();
0168     }
0169 
0170     friend inline void swap(QTaggedPointer &p1, QTaggedPointer &p2) noexcept
0171     {
0172         p1.swap(p2);
0173     }
0174 
0175 protected:
0176     quintptr d;
0177 };
0178 
0179 template <typename T, typename Tag>
0180 constexpr inline std::size_t qHash(QTaggedPointer<T, Tag> p, std::size_t seed = 0) noexcept
0181 { return qHash(p.data(), seed); }
0182 
0183 template <typename T, typename Tag>
0184 class QTypeInfo<QTaggedPointer<T, Tag>>
0185     : public QTypeInfoMerger<QTaggedPointer<T, Tag>, quintptr> {};
0186 
0187 QT_END_NAMESPACE
0188 
0189 #endif // QTAGGEDPOINTER_H