X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ca5a36146e952e42f2152e6f456b799eb958df5f..7118e711dcf3bdb543d5e20cac2c45d50c691979:/include/wx/any.h diff --git a/include/wx/any.h b/include/wx/any.h index 102f75926e..b5dac8fb7c 100644 --- a/include/wx/any.h +++ b/include/wx/any.h @@ -19,6 +19,7 @@ #include "wx/string.h" #include "wx/meta/movable.h" #include "wx/meta/if.h" +#include "wx/typeinfo.h" // Size of the wxAny value buffer. @@ -43,9 +44,6 @@ union wxAnyValueBuffer wxByte m_buffer[WX_ANY_VALUE_BUFFER_SIZE]; }; -typedef void (*wxAnyClassInfo)(); - - // // wxAnyValueType is base class for value type functionality for C++ data // types used with wxAny. Usually the default template (wxAnyValueTypeImpl<>) @@ -53,6 +51,7 @@ typedef void (*wxAnyClassInfo)(); // class WXDLLIMPEXP_BASE wxAnyValueType { + WX_DECLARE_ABSTRACT_TYPEINFO(wxAnyValueType) public: /** Default constructor. @@ -66,11 +65,6 @@ public: { } - /** - This function is used for internal type matching. - */ - virtual wxAnyClassInfo GetClassInfo() const = 0; - /** This function is used for internal type matching. */ @@ -83,9 +77,14 @@ public: virtual void DeleteValue(wxAnyValueBuffer& buf) const = 0; /** - Implement this for buffer-to-buffer copy. src.m_ptr can - be expected to be NULL if value type of previously stored - data was different. + Implement this for buffer-to-buffer copy. + + @param src + This is the source data buffer. + + @param dst + This is the destination data buffer that is in either + uninitialized or freed state. */ virtual void CopyBuffer(const wxAnyValueBuffer& src, wxAnyValueBuffer& dst) const = 0; @@ -120,28 +119,22 @@ private: #define wxANY_VALUE_TYPE_CHECK_TYPE(valueTypePtr, T) \ wxAnyValueTypeImpl::IsSameClass(valueTypePtr) - //valueTypePtr->CheckType(static_cast(NULL)) - /** Helper macro for defining user value types. - NB: We really cannot compare sm_classInfo directly in IsSameClass(), - but instead call sm_instance->GetClassInfo(). The former technique - broke at least on GCC 4.2 (but worked on VC8 shared build). + Even though C++ RTTI would be fully available to use, we'd have to to + facilitate sub-type system which allows, for instance, wxAny with + signed short '15' to be treated equal to wxAny with signed long long '15'. + Having sm_instance is important here. */ #define WX_DECLARE_ANY_VALUE_TYPE(CLS) \ friend class wxAny; \ + WX_DECLARE_TYPEINFO_INLINE(CLS) \ public: \ - static void sm_classInfo() {} \ - \ - virtual wxAnyClassInfo GetClassInfo() const \ - { \ - return sm_classInfo; \ - } \ static bool IsSameClass(const wxAnyValueType* otherType) \ { \ - return sm_instance->GetClassInfo() == otherType->GetClassInfo(); \ + return wxTypeId(*sm_instance) == wxTypeId(*otherType); \ } \ virtual bool IsSameType(const wxAnyValueType* otherType) const \ { \ @@ -189,7 +182,11 @@ public: static const T& GetValue(const wxAnyValueBuffer& buf) { - return *(reinterpret_cast(&buf.m_buffer[0])); + // Breaking this code into two lines should supress + // GCC's 'type-punned pointer will break strict-aliasing rules' + // warning. + const T* value = reinterpret_cast(&buf.m_buffer[0]); + return *value; } }; @@ -259,13 +256,11 @@ public: virtual void DeleteValue(wxAnyValueBuffer& buf) const { Ops::DeleteValue(buf); - buf.m_ptr = NULL; // This is important } virtual void CopyBuffer(const wxAnyValueBuffer& src, wxAnyValueBuffer& dst) const { - Ops::DeleteValue(dst); Ops::SetValue(Ops::GetValue(src), dst); } @@ -332,13 +327,17 @@ public: \ virtual ~wxAnyValueTypeImpl() { } \ static void SetValue(const T& value, wxAnyValueBuffer& buf) \ { \ - *(reinterpret_cast(&buf.m_buffer[0])) = \ - static_cast(value); \ + void* voidPtr = reinterpret_cast(&buf.m_buffer[0]); \ + UseDataType* dptr = reinterpret_cast(voidPtr); \ + *dptr = static_cast(value); \ } \ static T GetValue(const wxAnyValueBuffer& buf) \ { \ - return static_cast( \ - *(reinterpret_cast(&buf.m_buffer[0]))); \ + const void* voidPtr = \ + reinterpret_cast(&buf.m_buffer[0]); \ + const UseDataType* sptr = \ + reinterpret_cast(voidPtr); \ + return static_cast(*sptr); \ } \ }; @@ -404,35 +403,55 @@ WX_ANY_DEFINE_SUB_TYPE(wxULongLong_t, Uint) // -// String value type +// This macro is used in header, but then in source file we must have: +// WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl##TYPENAME) // -class WXDLLIMPEXP_BASE wxAnyValueTypeImplString : - public wxAnyValueTypeImplBase -{ - WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplString) -public: - wxAnyValueTypeImplString() : - wxAnyValueTypeImplBase() { } - virtual ~wxAnyValueTypeImplString() { } +#define _WX_ANY_DEFINE_CONVERTIBLE_TYPE(T, TYPENAME, CONVFUNC, GV) \ +class WXDLLIMPEXP_BASE wxAnyValueTypeImpl##TYPENAME : \ + public wxAnyValueTypeImplBase \ +{ \ + WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl##TYPENAME) \ +public: \ + wxAnyValueTypeImpl##TYPENAME() : \ + wxAnyValueTypeImplBase() { } \ + virtual ~wxAnyValueTypeImpl##TYPENAME() { } \ + virtual bool ConvertValue(const wxAnyValueBuffer& src, \ + wxAnyValueType* dstType, \ + wxAnyValueBuffer& dst) const \ + { \ + GV value = GetValue(src); \ + return CONVFUNC(value, dstType, dst); \ + } \ +}; \ +template<> \ +class wxAnyValueTypeImpl : public wxAnyValueTypeImpl##TYPENAME \ +{ \ +public: \ + wxAnyValueTypeImpl() : wxAnyValueTypeImpl##TYPENAME() { } \ + virtual ~wxAnyValueTypeImpl() { } \ +}; - /** - Convert value into buffer of different type. Return false if - not possible. - */ - virtual bool ConvertValue(const wxAnyValueBuffer& src, - wxAnyValueType* dstType, - wxAnyValueBuffer& dst) const; +#define WX_ANY_DEFINE_CONVERTIBLE_TYPE(T, TYPENAME, CONVFUNC, BT) \ +_WX_ANY_DEFINE_CONVERTIBLE_TYPE(T, TYPENAME, CONVFUNC, BT) \ -}; +#define WX_ANY_DEFINE_CONVERTIBLE_TYPE_BASE(T, TYPENAME, CONVFUNC) \ +_WX_ANY_DEFINE_CONVERTIBLE_TYPE(T, TYPENAME, \ + CONVFUNC, const T&) \ -template<> -class wxAnyValueTypeImpl : public wxAnyValueTypeImplString -{ -public: - wxAnyValueTypeImpl() : wxAnyValueTypeImplString() { } - virtual ~wxAnyValueTypeImpl() { } -}; +// +// String value type +// + +// Convert wxString to destination wxAny value type +extern WXDLLIMPEXP_BASE bool wxAnyConvertString(const wxString& value, + wxAnyValueType* dstType, + wxAnyValueBuffer& dst); +WX_ANY_DEFINE_CONVERTIBLE_TYPE_BASE(wxString, wxString, wxAnyConvertString) +WX_ANY_DEFINE_CONVERTIBLE_TYPE(const char*, ConstCharPtr, + wxAnyConvertString, wxString) +WX_ANY_DEFINE_CONVERTIBLE_TYPE(const wchar_t*, ConstWchar_tPtr, + wxAnyConvertString, wxString) // // Bool value type @@ -476,6 +495,123 @@ WX_ANY_DEFINE_SUB_TYPE(float, Double) WX_ANY_DEFINE_SUB_TYPE(double, Double) +// +// Defines a dummy wxAnyValueTypeImpl<> with given export +// declaration. This is needed if a class is used with +// wxAny in both user shared library and application. +// +#define wxDECLARE_ANY_TYPE(CLS, DECL) \ +template<> \ +class DECL wxAnyValueTypeImpl : \ + public wxAnyValueTypeImplBase \ +{ \ + WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl) \ +public: \ + wxAnyValueTypeImpl() : \ + wxAnyValueTypeImplBase() { } \ + virtual ~wxAnyValueTypeImpl() { } \ + \ + virtual bool ConvertValue(const wxAnyValueBuffer& src, \ + wxAnyValueType* dstType, \ + wxAnyValueBuffer& dst) const \ + { \ + wxUnusedVar(src); \ + wxUnusedVar(dstType); \ + wxUnusedVar(dst); \ + return false; \ + } \ +}; + + +// Make sure some of wx's own types get the right wxAnyValueType export +// (this is needed only for types that are referred to from wxBase. +// currently we may not use any of these types from there, but let's +// use the macro on at least one to make sure it compiles since we can't +// really test it properly in unittests since a separate DLL would +// be needed). +#if wxUSE_DATETIME + #include "wx/datetime.h" + wxDECLARE_ANY_TYPE(wxDateTime, WXDLLIMPEXP_BASE) +#endif + +//#include "wx/object.h" +//wxDECLARE_ANY_TYPE(wxObject*, WXDLLIMPEXP_BASE) + +//#include "wx/arrstr.h" +//wxDECLARE_ANY_TYPE(wxArrayString, WXDLLIMPEXP_BASE) + + +#if wxUSE_VARIANT + +class WXDLLIMPEXP_FWD_BASE wxAnyToVariantRegistration; + +// Because of header inter-dependencies, cannot include this earlier +#include "wx/variant.h" + +// +// wxVariantData* data type implementation. For cases when appropriate +// wxAny<->wxVariant conversion code is missing. +// + +class WXDLLIMPEXP_BASE wxAnyValueTypeImplVariantData : + public wxAnyValueTypeImplBase +{ + WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplVariantData) +public: + wxAnyValueTypeImplVariantData() : + wxAnyValueTypeImplBase() { } + virtual ~wxAnyValueTypeImplVariantData() { } + + virtual void DeleteValue(wxAnyValueBuffer& buf) const + { + wxVariantData* data = static_cast(buf.m_ptr); + if ( data ) + data->DecRef(); + } + + virtual void CopyBuffer(const wxAnyValueBuffer& src, + wxAnyValueBuffer& dst) const + { + wxVariantData* data = static_cast(src.m_ptr); + if ( data ) + data->IncRef(); + dst.m_ptr = data; + } + + static void SetValue(wxVariantData* value, + wxAnyValueBuffer& buf) + { + value->IncRef(); + buf.m_ptr = value; + } + + static wxVariantData* GetValue(const wxAnyValueBuffer& buf) + { + return static_cast(buf.m_ptr); + } + + virtual bool ConvertValue(const wxAnyValueBuffer& src, + wxAnyValueType* dstType, + wxAnyValueBuffer& dst) const + { + wxUnusedVar(src); + wxUnusedVar(dstType); + wxUnusedVar(dst); + return false; + } +}; + +template<> +class wxAnyValueTypeImpl : + public wxAnyValueTypeImplVariantData +{ +public: + wxAnyValueTypeImpl() : wxAnyValueTypeImplVariantData() { } + virtual ~wxAnyValueTypeImpl() { } +}; + +#endif // wxUSE_VARIANT + #ifdef __VISUALC6__ // Re-enable useless VC6 warnings #pragma warning (pop) @@ -517,6 +653,22 @@ bool operator==(TUS value) const \ } +#if wxUSE_VARIANT + +// Note that the following functions are implemented outside wxAny class +// so that it can reside entirely in header and lack the export declaration. + +// Helper function used to associate wxAnyValueType with a wxVariantData. +extern WXDLLIMPEXP_BASE void +wxPreRegisterAnyToVariant(wxAnyToVariantRegistration* reg); + +// This function performs main wxAny to wxVariant conversion duties. +extern WXDLLIMPEXP_BASE bool +wxConvertAnyToVariant(const wxAny& any, wxVariant* variant); + +#endif // wxUSE_VARIANT + + // // The wxAny class represents a container for any type. A variant's value // can be changed at run time, possibly to a different type of value. @@ -547,15 +699,23 @@ public: /** Various constructors. */ + template + wxAny(const T& value) + { + m_type = wxAnyValueTypeImpl::sm_instance; + wxAnyValueTypeImpl::SetValue(value, m_buffer); + } + + // These two constructors are needed to deal with string literals wxAny(const char* value) { - m_type = wxAnyNullValueType; - Assign(wxString(value)); + m_type = wxAnyValueTypeImpl::sm_instance; + wxAnyValueTypeImpl::SetValue(value, m_buffer); } wxAny(const wchar_t* value) { - m_type = wxAnyNullValueType; - Assign(wxString(value)); + m_type = wxAnyValueTypeImpl::sm_instance; + wxAnyValueTypeImpl::SetValue(value, m_buffer); } wxAny(const wxAny& any) @@ -564,12 +724,14 @@ public: AssignAny(any); } - template - wxAny(const T& value) +#if wxUSE_VARIANT + wxAny(const wxVariant& variant) { - m_type = wxAnyValueTypeImpl::sm_instance; - wxAnyValueTypeImpl::SetValue(value, m_buffer); + m_type = wxAnyNullValueType; + AssignVariant(variant); } +#endif + //@} /** @@ -623,12 +785,6 @@ public: /** Assignment operators. */ - wxAny& operator=(const wxAny &any) - { - AssignAny(any); - return *this; - } - template wxAny& operator=(const T &value) { @@ -638,11 +794,32 @@ public: return *this; } + wxAny& operator=(const wxAny &any) + { + if (this != &any) + AssignAny(any); + return *this; + } + +#if wxUSE_VARIANT + wxAny& operator=(const wxVariant &variant) + { + AssignVariant(variant); + return *this; + } +#endif + + // These two operators are needed to deal with string literals wxAny& operator=(const char* value) - { Assign(wxString(value)); return *this; } + { + Assign(value); + return *this; + } wxAny& operator=(const wchar_t* value) - { Assign(wxString(value)); return *this; } - //@} + { + Assign(value); + return *this; + } //@{ /** @@ -650,12 +827,10 @@ public: */ bool operator==(const wxString& value) const { - if ( !wxAnyValueTypeImpl::IsSameClass(m_type) ) + wxString value2; + if ( !GetAs(&value2) ) return false; - - return value == - static_cast - (wxAnyValueTypeImpl::GetValue(m_buffer)); + return value == value2; } bool operator==(const char* value) const @@ -714,14 +889,17 @@ public: //@} /** - This template function converts wxAny into given type. No dynamic - conversion is performed, so if the type is incorrect an assertion - failure will occur in debug builds, and a bogus value is returned - in release ones. + This template function converts wxAny into given type. In most cases + no type conversion is performed, so if the type is incorrect an + assertion failure will occur. - @remarks This template function does not work on some older compilers - (such as Visual C++ 6.0). For full compiler ccompatibility - please use wxANY_AS(any, T) macro instead. + @remarks For conveniency, conversion is done when T is wxString. This + is useful when a string literal (which are treated as + const char* and const wchar_t*) has been assigned to wxAny. + + This template function may not work properly with Visual C++ + 6. For full compiler compatibility, please use + wxANY_AS(any, T) macro instead. */ // FIXME-VC6: remove this hack when VC6 is no longer supported template @@ -735,6 +913,19 @@ public: return static_cast(wxAnyValueTypeImpl::GetValue(m_buffer)); } + // Allow easy conversion from 'const char *' etc. to wxString + // FIXME-VC6: remove this hack when VC6 is no longer supported + //template<> + wxString As(wxString*) const + { + wxString value; + if ( !GetAs(&value) ) + { + wxFAIL_MSG("Incorrect or non-convertible data type"); + } + return value; + } + /** Template function that etrieves and converts the value of this variant to the type that T* value is. @@ -763,17 +954,52 @@ public: return true; } +#if wxUSE_VARIANT + // GetAs() wxVariant specialization + bool GetAs(wxVariant* value) const + { + return wxConvertAnyToVariant(*this, value); + } +#endif + private: // Assignment functions void AssignAny(const wxAny& any) { - if ( !any.m_type->IsSameType(m_type) ) + // Must delete value - CopyBuffer() never does that + m_type->DeleteValue(m_buffer); + + wxAnyValueType* newType = any.m_type; + + if ( !newType->IsSameType(m_type) ) + m_type = newType; + + newType->CopyBuffer(any.m_buffer, m_buffer); + } + +#if wxUSE_VARIANT + void AssignVariant(const wxVariant& variant) + { + wxVariantData* data = variant.GetData(); + + if ( data && data->GetAsAny(this) ) + return; + + m_type->DeleteValue(m_buffer); + + if ( variant.IsNull() ) { - m_type->DeleteValue(m_buffer); - m_type = any.m_type; + // Init as Null + m_type = wxAnyNullValueType; + } + else + { + // If everything else fails, wrap the whole wxVariantData + m_type = wxAnyValueTypeImpl::sm_instance; + wxAnyValueTypeImpl::SetValue(data, m_buffer); } - m_type->CopyBuffer(any.m_buffer, m_buffer); } +#endif template void Assign(const T &value) @@ -792,13 +1018,13 @@ private: // // This method of checking the type is compatible with VC6 #define wxANY_CHECK_TYPE(any, T) \ - wxANY_VALUE_TYPE_CHECK_TYPE(any.GetType(), T) + wxANY_VALUE_TYPE_CHECK_TYPE((any).GetType(), T) // // This method of getting the value is compatible with VC6 #define wxANY_AS(any, T) \ - any.As(static_cast(NULL)) + (any).As(static_cast(NULL)) template