/**************************************************************************** ** ** Copyright (C) 2008-2012 NVIDIA Corporation. ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt 3D Studio. ** ** $QT_BEGIN_LICENSE:GPL$ ** 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 General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 or (at your option) 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.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-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QT3DS_FOUNDATION_DISCRIMINATED_UNION_H #define QT3DS_FOUNDATION_DISCRIMINATED_UNION_H #include "Qt3DSAssert.h" #include "foundation/Qt3DSSimpleTypes.h" #include "foundation/Qt3DSIntrinsics.h" #include "foundation/Qt3DSUnionCast.h" #ifdef WIN32 #pragma warning(disable : 4100) #endif namespace qt3ds { namespace foundation { template class DiscriminatedUnion { public: typedef DiscriminatedUnion TThisType; typedef TUnionTraits TTraits; typedef typename TTraits::TIdType TIdType; protected: char m_Data[TBufferSize]; // Id type must include a no-data type. TIdType m_DataType; public: DiscriminatedUnion() { TTraits::defaultConstruct(m_Data, m_DataType); } DiscriminatedUnion(const TThisType &inOther) : m_DataType(inOther.m_DataType) { TTraits::copyConstruct(m_Data, inOther.m_Data, m_DataType); } template DiscriminatedUnion(const TDataType &inType) { TTraits::copyConstruct(m_Data, m_DataType, inType); } ~DiscriminatedUnion() { TTraits::destruct(m_Data, m_DataType); } TThisType &operator=(const TThisType &inType) { if (this != &inType) { TTraits::destruct(m_Data, m_DataType); m_DataType = inType.m_DataType; TTraits::copyConstruct(m_Data, inType.m_Data, inType.m_DataType); } return *this; } typename TTraits::TIdType getType() const { return m_DataType; } template const TDataType *getDataPtr() const { return TTraits::template getDataPtr(m_Data, m_DataType); } template TDataType *getDataPtr() { return TTraits::template getDataPtr(m_Data, m_DataType); } template TDataType getData() const { const TDataType *dataPtr = getDataPtr(); if (dataPtr) return *dataPtr; QT3DS_ASSERT(false); return TDataType(); } bool operator==(const TThisType &inOther) const { return m_DataType == inOther.m_DataType && TTraits::areEqual(m_Data, inOther.m_Data, m_DataType); } bool operator!=(const TThisType &inOther) const { return m_DataType != inOther.m_DataType || TTraits::areEqual(m_Data, inOther.m_Data, m_DataType) == false; } template TRetType visit(TVisitorType inVisitor) { return TTraits::template visit(m_Data, m_DataType, inVisitor); } template TRetType visit(TVisitorType inVisitor) const { return TTraits::template visit(m_Data, m_DataType, inVisitor); } }; // Helper system to enable quicker and correct construction of union traits types struct CopyConstructVisitor { const char *m_Src; CopyConstructVisitor(const char *inSrc) : m_Src(inSrc) { } template void operator()(TDataType &inDst) { new (&inDst) TDataType(*NVUnionCast(m_Src)); } void operator()() { QT3DS_ASSERT(false); } }; template struct DestructTraits { void destruct(TDataType &inType) { inType.~TDataType(); } }; // Until compilers improve a bit, you need this for POD types else you get // unused parameter warnings. template <> struct DestructTraits { void destruct(QT3DSU8 &) {} }; template <> struct DestructTraits { void destruct(QT3DSI8 &) {} }; template <> struct DestructTraits { void destruct(QT3DSU16 &) {} }; template <> struct DestructTraits { void destruct(QT3DSI16 &) {} }; template <> struct DestructTraits { void destruct(QT3DSU32 &) {} }; template <> struct DestructTraits { void destruct(QT3DSI32 &) {} }; template <> struct DestructTraits { void destruct(QT3DSU64 &) {} }; template <> struct DestructTraits { void destruct(QT3DSI64 &) {} }; template <> struct DestructTraits { void destruct(QT3DSF32 &) {} }; template <> struct DestructTraits { void destruct(QT3DSF64 &) {} }; template <> struct DestructTraits { void destruct(bool &) {} }; template <> struct DestructTraits { void destruct(void *&) {} }; #ifdef __INTEGRITY template <> struct DestructTraits { void destruct(QT3DSVec2 &) {} }; template <> struct DestructTraits { void destruct(QT3DSVec3 &) {} }; #endif struct DestructVisitor { template void operator()(TDataType &inDst) { DestructTraits().destruct(inDst); } void operator()() { QT3DS_ASSERT(false); } }; template struct EqualVisitorTraits { bool operator()(const TDataType &lhs, const TDataType &rhs) { return lhs == rhs; } }; struct EqualVisitor { const char *m_Rhs; EqualVisitor(const char *rhs) : m_Rhs(rhs) { } template bool operator()(const TDataType &lhs) { const TDataType &rhs(*NVUnionCast(m_Rhs)); return EqualVisitorTraits()(lhs, rhs); } bool operator()() { QT3DS_ASSERT(false); return true; } }; template struct DiscriminatedUnionGenericBase : public TBase { typedef typename TBase::TIdType TIdType; static void zeroBuf(char *outDst) { qt3ds::intrinsics::memZero(outDst, TBufferSize); } static void defaultConstruct(char *outDst, TIdType &outType) { zeroBuf(outDst); outType = TBase::getNoDataId(); } template static void copyConstruct(char *outDst, TIdType &outType, const TDataType &inSrc) { zeroBuf(outDst); StaticAssert::valid_expression(); outType = TBase::template getType(); new (outDst) TDataType(inSrc); } static void copyConstruct(char *inDst, const char *inSrc, TIdType inType) { if (inType == TBase::getNoDataId()) zeroBuf(inDst); else TBase::template visit(inDst, inType, CopyConstructVisitor(inSrc)); } static void destruct(char *inDst, TIdType inType) { if (inType != TBase::getNoDataId()) TBase::template visit(inDst, inType, DestructVisitor()); zeroBuf(inDst); } template static const TDataType *getDataPtr(const char *inData, const TIdType &inType) { if (TBase::template getType() == inType) return NVUnionCast(inData); QT3DS_ASSERT(false); return NULL; } template static TDataType *getDataPtr(char *inData, const TIdType &inType) { if (TBase::template getType() == inType) return NVUnionCast(inData); QT3DS_ASSERT(false); return NULL; } static bool areEqual(const char *inLhs, const char *inRhs, TIdType inType) { if (inType != TBase::getNoDataId()) return TBase::template visit(inLhs, inType, EqualVisitor(inRhs)); else return true; } }; } } #endif