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:
João Abecasis 2012-03-12 17:14:48 +01:00 committed by Qt by Nokia
parent 98c3b8a442
commit accfdc85e5
7 changed files with 165 additions and 47 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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
} }
}; };

View File

@ -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)) { }

View File

@ -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
} }
}; };

View File

@ -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"

View File

@ -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);