Fallback implementation of Q_ALIGNOF
For all practical purposes, the fallback introduced here returns the desired value. Having a fallback enables unconditional use of Q_ALIGNOF. For compilers that provide native support for it, Q_ALIGNOF is otherwise #defined in qcompilerdetection.h. Change-Id: Ie148ca8936cbbf8b80fe87771a14797c39a9d30c Reviewed-by: Marc Mutz <marc.mutz@kdab.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
98c3b8a442
commit
accfdc85e5
@ -248,6 +248,56 @@ typedef quint64 qulonglong;
|
|||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
|
|
||||||
|
namespace QtPrivate {
|
||||||
|
template <class T>
|
||||||
|
struct AlignOfHelper
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
T type;
|
||||||
|
|
||||||
|
AlignOfHelper();
|
||||||
|
~AlignOfHelper();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct AlignOf_Default
|
||||||
|
{
|
||||||
|
enum { Value = sizeof(AlignOfHelper<T>) - sizeof(T) };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> struct AlignOf : AlignOf_Default<T> { };
|
||||||
|
template <class T> struct AlignOf<T &> : AlignOf<T> {};
|
||||||
|
template <size_t N, class T> struct AlignOf<T[N]> : AlignOf<T> {};
|
||||||
|
|
||||||
|
#ifdef Q_COMPILER_RVALUE_REFS
|
||||||
|
template <class T> struct AlignOf<T &&> : AlignOf<T> {};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(Q_PROCESSOR_X86_32) && !defined(Q_OS_WIN)
|
||||||
|
template <class T> struct AlignOf_WorkaroundForI386Abi { enum { Value = sizeof(T) }; };
|
||||||
|
|
||||||
|
// x86 ABI weirdness
|
||||||
|
// Alignment of naked type is 8, but inside struct has alignment 4.
|
||||||
|
template <> struct AlignOf<double> : AlignOf_WorkaroundForI386Abi<double> {};
|
||||||
|
template <> struct AlignOf<qint64> : AlignOf_WorkaroundForI386Abi<qint64> {};
|
||||||
|
template <> struct AlignOf<quint64> : AlignOf_WorkaroundForI386Abi<quint64> {};
|
||||||
|
#ifdef Q_CC_CLANG
|
||||||
|
// GCC and Clang seem to disagree wrt to alignment of arrays
|
||||||
|
template <size_t N> struct AlignOf<double[N]> : AlignOf_Default<double> {};
|
||||||
|
template <size_t N> struct AlignOf<qint64[N]> : AlignOf_Default<qint64> {};
|
||||||
|
template <size_t N> struct AlignOf<quint64[N]> : AlignOf_Default<quint64> {};
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
} // namespace QtPrivate
|
||||||
|
|
||||||
|
#define QT_EMULATED_ALIGNOF(T) \
|
||||||
|
(size_t(QT_PREPEND_NAMESPACE(QtPrivate)::AlignOf<T>::Value))
|
||||||
|
|
||||||
|
#ifndef Q_ALIGNOF
|
||||||
|
#define Q_ALIGNOF(T) QT_EMULATED_ALIGNOF(T)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
quintptr and qptrdiff is guaranteed to be the same size as a pointer, i.e.
|
quintptr and qptrdiff is guaranteed to be the same size as a pointer, i.e.
|
||||||
|
|
||||||
|
@ -1095,11 +1095,7 @@ int QMetaStringTable::enter(const QByteArray &value)
|
|||||||
|
|
||||||
int QMetaStringTable::preferredAlignment()
|
int QMetaStringTable::preferredAlignment()
|
||||||
{
|
{
|
||||||
#ifdef Q_ALIGNOF
|
|
||||||
return Q_ALIGNOF(QByteArrayData);
|
return Q_ALIGNOF(QByteArrayData);
|
||||||
#else
|
|
||||||
return sizeof(void *);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the size (in bytes) required for serializing this string table.
|
// Returns the size (in bytes) required for serializing this string table.
|
||||||
|
@ -170,11 +170,7 @@ private:
|
|||||||
}
|
}
|
||||||
int alignOfTypedData() const
|
int alignOfTypedData() const
|
||||||
{
|
{
|
||||||
#ifdef Q_ALIGNOF
|
|
||||||
return qMax<int>(sizeof(void*), Q_ALIGNOF(Data));
|
return qMax<int>(sizeof(void*), Q_ALIGNOF(Data));
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -257,13 +257,8 @@ class QHash
|
|||||||
return reinterpret_cast<Node *>(node);
|
return reinterpret_cast<Node *>(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_ALIGNOF
|
|
||||||
static inline int alignOfNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(Node)); }
|
static inline int alignOfNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(Node)); }
|
||||||
static inline int alignOfDummyNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(DummyNode)); }
|
static inline int alignOfDummyNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(DummyNode)); }
|
||||||
#else
|
|
||||||
static inline int alignOfNode() { return 0; }
|
|
||||||
static inline int alignOfDummyNode() { return 0; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline QHash() : d(const_cast<QHashData *>(&QHashData::shared_null)) { }
|
inline QHash() : d(const_cast<QHashData *>(&QHashData::shared_null)) { }
|
||||||
|
@ -331,11 +331,7 @@ private:
|
|||||||
}
|
}
|
||||||
static Q_DECL_CONSTEXPR int alignOfTypedData()
|
static Q_DECL_CONSTEXPR int alignOfTypedData()
|
||||||
{
|
{
|
||||||
#ifdef Q_ALIGNOF
|
|
||||||
return Q_ALIGNOF(AlignmentDummy);
|
return Q_ALIGNOF(AlignmentDummy);
|
||||||
#else
|
|
||||||
return sizeof(void *);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ private slots:
|
|||||||
void qstaticassert();
|
void qstaticassert();
|
||||||
void qConstructorFunction();
|
void qConstructorFunction();
|
||||||
void isEnum();
|
void isEnum();
|
||||||
|
void qAlignOf();
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_QGlobal::qIsNull()
|
void tst_QGlobal::qIsNull()
|
||||||
@ -415,5 +416,115 @@ void tst_QGlobal::isEnum()
|
|||||||
#undef IS_ENUM_FALSE
|
#undef IS_ENUM_FALSE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Empty {};
|
||||||
|
template <class T> struct AlignmentInStruct { T dummy; };
|
||||||
|
|
||||||
|
typedef int (*fun) ();
|
||||||
|
typedef int (Empty::*memFun) ();
|
||||||
|
|
||||||
|
#define TEST_AlignOf(type, alignment) \
|
||||||
|
do { \
|
||||||
|
TEST_AlignOf_impl(type, alignment); \
|
||||||
|
\
|
||||||
|
TEST_AlignOf_impl(type &, alignment); \
|
||||||
|
TEST_AlignOf_RValueRef(type &&, alignment); \
|
||||||
|
\
|
||||||
|
TEST_AlignOf_impl(type [5], alignment); \
|
||||||
|
TEST_AlignOf_impl(type (&) [5], alignment); \
|
||||||
|
\
|
||||||
|
TEST_AlignOf_impl(AlignmentInStruct<type>, alignment); \
|
||||||
|
\
|
||||||
|
/* Some internal sanity validation, just for fun */ \
|
||||||
|
TEST_AlignOf_impl(AlignmentInStruct<type [5]>, alignment); \
|
||||||
|
TEST_AlignOf_impl(AlignmentInStruct<type &>, Q_ALIGNOF(void *)); \
|
||||||
|
TEST_AlignOf_impl(AlignmentInStruct<type (&) [5]>, \
|
||||||
|
Q_ALIGNOF(void *)); \
|
||||||
|
TEST_AlignOf_RValueRef(AlignmentInStruct<type &&>, \
|
||||||
|
Q_ALIGNOF(void *)); \
|
||||||
|
} while (false) \
|
||||||
|
/**/
|
||||||
|
|
||||||
|
#ifdef Q_COMPILER_RVALUE_REFS
|
||||||
|
#define TEST_AlignOf_RValueRef(type, alignment) \
|
||||||
|
TEST_AlignOf_impl(type, alignment)
|
||||||
|
#else
|
||||||
|
#define TEST_AlignOf_RValueRef(type, alignment) do {} while (false)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TEST_AlignOf_impl(type, alignment) \
|
||||||
|
do { \
|
||||||
|
QCOMPARE(Q_ALIGNOF(type), size_t(alignment)); \
|
||||||
|
/* Compare to native operator for compilers that support it,
|
||||||
|
otherwise... erm... check consistency! :-) */ \
|
||||||
|
QCOMPARE(QT_EMULATED_ALIGNOF(type), Q_ALIGNOF(type)); \
|
||||||
|
} while (false)
|
||||||
|
/**/
|
||||||
|
|
||||||
|
void tst_QGlobal::qAlignOf()
|
||||||
|
{
|
||||||
|
// Built-in types, except 64-bit integers and double
|
||||||
|
TEST_AlignOf(char, 1);
|
||||||
|
TEST_AlignOf(signed char, 1);
|
||||||
|
TEST_AlignOf(unsigned char, 1);
|
||||||
|
TEST_AlignOf(qint8, 1);
|
||||||
|
TEST_AlignOf(quint8, 1);
|
||||||
|
TEST_AlignOf(qint16, 2);
|
||||||
|
TEST_AlignOf(quint16, 2);
|
||||||
|
TEST_AlignOf(qint32, 4);
|
||||||
|
TEST_AlignOf(quint32, 4);
|
||||||
|
TEST_AlignOf(void *, sizeof(void *));
|
||||||
|
|
||||||
|
// Depends on platform and compiler, disabling test for now
|
||||||
|
// TEST_AlignOf(long double, 16);
|
||||||
|
|
||||||
|
// Empty struct
|
||||||
|
TEST_AlignOf(Empty, 1);
|
||||||
|
|
||||||
|
// Function pointers
|
||||||
|
TEST_AlignOf(fun, Q_ALIGNOF(void *));
|
||||||
|
TEST_AlignOf(memFun, Q_ALIGNOF(void *));
|
||||||
|
|
||||||
|
|
||||||
|
// 64-bit integers and double
|
||||||
|
TEST_AlignOf_impl(qint64, 8);
|
||||||
|
TEST_AlignOf_impl(quint64, 8);
|
||||||
|
TEST_AlignOf_impl(double, 8);
|
||||||
|
|
||||||
|
TEST_AlignOf_impl(qint64 &, 8);
|
||||||
|
TEST_AlignOf_impl(quint64 &, 8);
|
||||||
|
TEST_AlignOf_impl(double &, 8);
|
||||||
|
|
||||||
|
TEST_AlignOf_RValueRef(qint64 &&, 8);
|
||||||
|
TEST_AlignOf_RValueRef(quint64 &&, 8);
|
||||||
|
TEST_AlignOf_RValueRef(double &&, 8);
|
||||||
|
|
||||||
|
// 32-bit x86 ABI idiosyncrasies
|
||||||
|
#if defined(Q_PROCESSOR_X86_32) && !defined(Q_OS_WIN)
|
||||||
|
TEST_AlignOf_impl(AlignmentInStruct<qint64>, 4);
|
||||||
|
#else
|
||||||
|
TEST_AlignOf_impl(AlignmentInStruct<qint64>, 8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_AlignOf_impl(AlignmentInStruct<quint64>, Q_ALIGNOF(AlignmentInStruct<qint64>));
|
||||||
|
TEST_AlignOf_impl(AlignmentInStruct<double>, Q_ALIGNOF(AlignmentInStruct<qint64>));
|
||||||
|
|
||||||
|
// 32-bit x86 ABI, Clang disagrees with gcc
|
||||||
|
#if !defined(Q_PROCESSOR_X86_32) || !defined(Q_CC_CLANG)
|
||||||
|
TEST_AlignOf_impl(qint64 [5], Q_ALIGNOF(qint64));
|
||||||
|
#else
|
||||||
|
TEST_AlignOf_impl(qint64 [5], Q_ALIGNOF(AlignmentInStruct<qint64>));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_AlignOf_impl(qint64 (&) [5], Q_ALIGNOF(qint64 [5]));
|
||||||
|
TEST_AlignOf_impl(quint64 [5], Q_ALIGNOF(quint64 [5]));
|
||||||
|
TEST_AlignOf_impl(quint64 (&) [5], Q_ALIGNOF(quint64 [5]));
|
||||||
|
TEST_AlignOf_impl(double [5], Q_ALIGNOF(double [5]));
|
||||||
|
TEST_AlignOf_impl(double (&) [5], Q_ALIGNOF(double [5]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef TEST_AlignOf
|
||||||
|
#undef TEST_AlignOf_RValueRef
|
||||||
|
#undef TEST_AlignOf_impl
|
||||||
|
|
||||||
QTEST_MAIN(tst_QGlobal)
|
QTEST_MAIN(tst_QGlobal)
|
||||||
#include "tst_qglobal.moc"
|
#include "tst_qglobal.moc"
|
||||||
|
@ -868,41 +868,15 @@ void tst_QMetaType::construct_data()
|
|||||||
create_data();
|
create_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef Q_ALIGNOF
|
|
||||||
template<uint N>
|
|
||||||
struct RoundToNextHighestPowerOfTwo
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
enum { V1 = N-1 };
|
|
||||||
enum { V2 = V1 | (V1 >> 1) };
|
|
||||||
enum { V3 = V2 | (V2 >> 2) };
|
|
||||||
enum { V4 = V3 | (V3 >> 4) };
|
|
||||||
enum { V5 = V4 | (V4 >> 8) };
|
|
||||||
enum { V6 = V5 | (V5 >> 16) };
|
|
||||||
public:
|
|
||||||
enum { Value = V6 + 1 };
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
struct TypeAlignment
|
|
||||||
{
|
|
||||||
#ifdef Q_ALIGNOF
|
|
||||||
enum { Value = Q_ALIGNOF(T) };
|
|
||||||
#else
|
|
||||||
enum { Value = RoundToNextHighestPowerOfTwo<sizeof(T)>::Value };
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
template<int ID>
|
template<int ID>
|
||||||
static void testConstructHelper()
|
static void testConstructHelper()
|
||||||
{
|
{
|
||||||
typedef typename MetaEnumToType<ID>::Type Type;
|
typedef typename MetaEnumToType<ID>::Type Type;
|
||||||
QMetaType info(ID);
|
QMetaType info(ID);
|
||||||
int size = info.sizeOf();
|
int size = info.sizeOf();
|
||||||
void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value);
|
void *storage1 = qMallocAligned(size, Q_ALIGNOF(Type));
|
||||||
void *actual1 = QMetaType::construct(ID, storage1, /*copy=*/0);
|
void *actual1 = QMetaType::construct(ID, storage1, /*copy=*/0);
|
||||||
void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value);
|
void *storage2 = qMallocAligned(size, Q_ALIGNOF(Type));
|
||||||
void *actual2 = info.construct(storage2, /*copy=*/0);
|
void *actual2 = info.construct(storage2, /*copy=*/0);
|
||||||
QCOMPARE(actual1, storage1);
|
QCOMPARE(actual1, storage1);
|
||||||
QCOMPARE(actual2, storage2);
|
QCOMPARE(actual2, storage2);
|
||||||
@ -971,9 +945,9 @@ static void testConstructCopyHelper()
|
|||||||
QMetaType info(ID);
|
QMetaType info(ID);
|
||||||
int size = QMetaType::sizeOf(ID);
|
int size = QMetaType::sizeOf(ID);
|
||||||
QCOMPARE(info.sizeOf(), size);
|
QCOMPARE(info.sizeOf(), size);
|
||||||
void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value);
|
void *storage1 = qMallocAligned(size, Q_ALIGNOF(Type));
|
||||||
void *actual1 = QMetaType::construct(ID, storage1, expected);
|
void *actual1 = QMetaType::construct(ID, storage1, expected);
|
||||||
void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value);
|
void *storage2 = qMallocAligned(size, Q_ALIGNOF(Type));
|
||||||
void *actual2 = info.construct(storage2, expected);
|
void *actual2 = info.construct(storage2, expected);
|
||||||
QCOMPARE(actual1, storage1);
|
QCOMPARE(actual1, storage1);
|
||||||
QCOMPARE(actual2, storage2);
|
QCOMPARE(actual2, storage2);
|
||||||
|
Loading…
Reference in New Issue
Block a user