X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5caf524dff950e9c312f32788b09d701b3b4f3ca..58ce18f2fdadecffb21e27555115af708325cf18:/include/wx/any.h?ds=inline diff --git a/include/wx/any.h b/include/wx/any.h index 4ddd7b4c1c..092e71078d 100644 --- a/include/wx/any.h +++ b/include/wx/any.h @@ -16,8 +16,8 @@ #if wxUSE_ANY +#include // for placement new #include "wx/string.h" -#include "wx/meta/movable.h" #include "wx/meta/if.h" #include "wx/typeinfo.h" @@ -56,7 +56,9 @@ public: /** Default constructor. */ - wxAnyValueType(); + wxAnyValueType() + { + } /** Destructor. @@ -110,10 +112,30 @@ public: */ // FIXME-VC6: remove this hack when VC6 is no longer supported template - bool CheckType(T* reserved = NULL); + bool CheckType(T* reserved = NULL) const; +private: +}; + + +// +// We need to allocate wxAnyValueType instances in heap, and need to use +// scoped ptr to properly deallocate them in dynamic library use cases. +// Here we have a minimal specialized scoped ptr implementation to deal +// with various compiler-specific problems with template class' static +// member variable of template type with explicit constructor which +// is initialized in global scope. +// +class wxAnyValueTypeScopedPtr +{ +public: + wxAnyValueTypeScopedPtr(wxAnyValueType* ptr) : m_ptr(ptr) { } + ~wxAnyValueTypeScopedPtr() { delete m_ptr; } + wxAnyValueType* get() const { return m_ptr; } private: + wxAnyValueType* m_ptr; }; + // // This method of checking the type is compatible with VC6 #define wxANY_VALUE_TYPE_CHECK_TYPE(valueTypePtr, T) \ @@ -127,6 +149,11 @@ private: 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. + + NB: We really need to have wxAnyValueType instances allocated + in heap. They are stored as static template member variables, + and with them we just can't be too careful (eg. not allocating + them in heap broke the type identification in GCC). */ #define WX_DECLARE_ANY_VALUE_TYPE(CLS) \ friend class wxAny; \ @@ -134,23 +161,23 @@ private: public: \ static bool IsSameClass(const wxAnyValueType* otherType) \ { \ - return wxTypeId(*sm_instance) == wxTypeId(*otherType); \ + return wxTypeId(*sm_instance.get()) == wxTypeId(*otherType); \ } \ virtual bool IsSameType(const wxAnyValueType* otherType) const \ { \ return IsSameClass(otherType); \ } \ private: \ - static CLS* sm_instance; \ + static wxAnyValueTypeScopedPtr sm_instance; \ public: \ static wxAnyValueType* GetInstance() \ { \ - return sm_instance; \ + return sm_instance.get(); \ } #define WX_IMPLEMENT_ANY_VALUE_TYPE(CLS) \ - CLS* CLS::sm_instance = new CLS(); +wxAnyValueTypeScopedPtr CLS::sm_instance(new CLS()); #ifdef __VISUALC6__ @@ -166,18 +193,24 @@ namespace wxPrivate { template -class wxAnyValueTypeOpsMovable +class wxAnyValueTypeOpsInplace { public: static void DeleteValue(wxAnyValueBuffer& buf) { - wxUnusedVar(buf); + T* value = reinterpret_cast(&buf.m_buffer[0]); + value->~T(); + + // Some compiler may given 'unused variable' warnings without this + wxUnusedVar(value); } static void SetValue(const T& value, wxAnyValueBuffer& buf) { - memcpy(buf.m_buffer, &value, sizeof(T)); + // Use placement new + void* const place = buf.m_buffer; + ::new(place) T(value); } static const T& GetValue(const wxAnyValueBuffer& buf) @@ -243,9 +276,8 @@ public: template class wxAnyValueTypeImplBase : public wxAnyValueType { - typedef typename wxIf< wxIsMovable::value && - sizeof(T) <= WX_ANY_VALUE_BUFFER_SIZE, - wxPrivate::wxAnyValueTypeOpsMovable, + typedef typename wxIf< sizeof(T) <= WX_ANY_VALUE_BUFFER_SIZE, + wxPrivate::wxAnyValueTypeOpsInplace, wxPrivate::wxAnyValueTypeOpsGeneric >::value Ops; @@ -309,8 +341,7 @@ public: }; template -wxAnyValueTypeImpl* wxAnyValueTypeImpl::sm_instance = - new wxAnyValueTypeImpl(); +wxAnyValueTypeScopedPtr wxAnyValueTypeImpl::sm_instance = new wxAnyValueTypeImpl(); // @@ -403,35 +434,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 @@ -521,6 +572,76 @@ public: \ //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 @@ -563,6 +684,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. @@ -593,15 +730,23 @@ public: /** Various constructors. */ + template + wxAny(const T& value) + { + m_type = wxAnyValueTypeImpl::sm_instance.get(); + 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.get(); + wxAnyValueTypeImpl::SetValue(value, m_buffer); } wxAny(const wchar_t* value) { - m_type = wxAnyNullValueType; - Assign(wxString(value)); + m_type = wxAnyValueTypeImpl::sm_instance.get(); + wxAnyValueTypeImpl::SetValue(value, m_buffer); } wxAny(const wxAny& any) @@ -610,12 +755,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 + //@} /** @@ -630,7 +777,7 @@ public: */ // FIXME-VC6: remove this hack when VC6 is no longer supported template - bool CheckType(T* = NULL) + bool CheckType(T* = NULL) const { return m_type->CheckType(); } @@ -640,8 +787,9 @@ public: @remarks You cannot reliably test whether two wxAnys are of same value type by simply comparing return values - of wxAny::GetType(). Instead use - wxAnyValueType::CheckType() template function. + of wxAny::GetType(). Instead, use wxAny::HasSameType(). + + @see HasSameType() */ const wxAnyValueType* GetType() const { @@ -649,7 +797,16 @@ public: } /** - Tests if wxAny is null (that is, whether there is data). + Returns @true if this and another wxAny have the same + value type. + */ + bool HasSameType(const wxAny& other) const + { + return GetType()->IsSameType(other.GetType()); + } + + /** + Tests if wxAny is null (that is, whether there is no data). */ bool IsNull() const { @@ -669,6 +826,15 @@ public: /** Assignment operators. */ + template + wxAny& operator=(const T &value) + { + m_type->DeleteValue(m_buffer); + m_type = wxAnyValueTypeImpl::sm_instance.get(); + wxAnyValueTypeImpl::SetValue(value, m_buffer); + return *this; + } + wxAny& operator=(const wxAny &any) { if (this != &any) @@ -676,20 +842,25 @@ public: return *this; } - template - wxAny& operator=(const T &value) +#if wxUSE_VARIANT + wxAny& operator=(const wxVariant &variant) { - m_type->DeleteValue(m_buffer); - m_type = wxAnyValueTypeImpl::sm_instance; - wxAnyValueTypeImpl::SetValue(value, m_buffer); + 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; + } //@{ /** @@ -697,12 +868,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 @@ -761,14 +930,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 compatibility - 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 @@ -782,6 +954,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. @@ -794,7 +979,7 @@ public: if ( !wxAnyValueTypeImpl::IsSameClass(m_type) ) { wxAnyValueType* otherType = - wxAnyValueTypeImpl::sm_instance; + wxAnyValueTypeImpl::sm_instance.get(); wxAnyValueBuffer temp_buf; if ( !m_type->ConvertValue(m_buffer, otherType, temp_buf) ) @@ -810,6 +995,14 @@ 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) @@ -825,11 +1018,35 @@ private: 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() ) + { + // Init as Null + m_type = wxAnyNullValueType; + } + else + { + // If everything else fails, wrap the whole wxVariantData + m_type = wxAnyValueTypeImpl::sm_instance.get(); + wxAnyValueTypeImpl::SetValue(data, m_buffer); + } + } +#endif + template void Assign(const T &value) { m_type->DeleteValue(m_buffer); - m_type = wxAnyValueTypeImpl::sm_instance; + m_type = wxAnyValueTypeImpl::sm_instance.get(); wxAnyValueTypeImpl::SetValue(value, m_buffer); } @@ -842,17 +1059,17 @@ 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 -inline bool wxAnyValueType::CheckType(T* reserved) +inline bool wxAnyValueType::CheckType(T* reserved) const { wxUnusedVar(reserved); return wxAnyValueTypeImpl::IsSameClass(this);