]> git.saurik.com Git - wxWidgets.git/blobdiff - include/wx/any.h
Allow wxAutomationObject::GetInstance() create new instance if needed.
[wxWidgets.git] / include / wx / any.h
index c82daa1c1a5ed0d7c03c4d1a009b60d3e3f29e4c..092e71078d7a16a487b045ed3aa3fb732fa90b5c 100644 (file)
@@ -16,8 +16,8 @@
 
 #if wxUSE_ANY
 
+#include <new> // 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 <typename T>
-    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<typename T>
-class wxAnyValueTypeOpsMovable
+class wxAnyValueTypeOpsInplace
 {
 public:
     static void DeleteValue(wxAnyValueBuffer& buf)
     {
-        wxUnusedVar(buf);
+        T* value = reinterpret_cast<T*>(&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<typename T>
 class wxAnyValueTypeImplBase : public wxAnyValueType
 {
-    typedef typename wxIf< wxIsMovable<T>::value &&
-                                sizeof(T) <= WX_ANY_VALUE_BUFFER_SIZE,
-                           wxPrivate::wxAnyValueTypeOpsMovable<T>,
+    typedef typename wxIf< sizeof(T) <= WX_ANY_VALUE_BUFFER_SIZE,
+                           wxPrivate::wxAnyValueTypeOpsInplace<T>,
                            wxPrivate::wxAnyValueTypeOpsGeneric<T> >::value
             Ops;
 
@@ -309,8 +341,7 @@ public:
 };
 
 template<typename T>
-wxAnyValueTypeImpl<T>* wxAnyValueTypeImpl<T>::sm_instance =
-    new wxAnyValueTypeImpl<T>();
+wxAnyValueTypeScopedPtr wxAnyValueTypeImpl<T>::sm_instance = new wxAnyValueTypeImpl<T>();
 
 
 //
@@ -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<wxString>
-{
-    WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplString)
-public:
-    wxAnyValueTypeImplString() :
-        wxAnyValueTypeImplBase<wxString>() { }
-    virtual ~wxAnyValueTypeImplString() { }
+#define _WX_ANY_DEFINE_CONVERTIBLE_TYPE(T, TYPENAME, CONVFUNC, GV) \
+class WXDLLIMPEXP_BASE wxAnyValueTypeImpl##TYPENAME : \
+    public wxAnyValueTypeImplBase<T> \
+{ \
+    WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl##TYPENAME) \
+public: \
+    wxAnyValueTypeImpl##TYPENAME() : \
+        wxAnyValueTypeImplBase<T>() { } \
+    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<T> : 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<wxString> : 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<wxVariantData*>
+{
+    WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplVariantData)
+public:
+    wxAnyValueTypeImplVariantData() :
+        wxAnyValueTypeImplBase<wxVariantData*>() { }
+    virtual ~wxAnyValueTypeImplVariantData() { }
+
+    virtual void DeleteValue(wxAnyValueBuffer& buf) const
+    {
+        wxVariantData* data = static_cast<wxVariantData*>(buf.m_ptr);
+        if ( data )
+            data->DecRef();
+    }
+
+    virtual void CopyBuffer(const wxAnyValueBuffer& src,
+                            wxAnyValueBuffer& dst) const
+    {
+        wxVariantData* data = static_cast<wxVariantData*>(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<wxVariantData*>(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<wxVariantData*> :
+    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<typename T>
+    wxAny(const T& value)
+    {
+        m_type = wxAnyValueTypeImpl<T>::sm_instance.get();
+        wxAnyValueTypeImpl<T>::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<const char*>::sm_instance.get();
+        wxAnyValueTypeImpl<const char*>::SetValue(value, m_buffer);
     }
     wxAny(const wchar_t* value)
     {
-        m_type = wxAnyNullValueType;
-        Assign(wxString(value));
+        m_type = wxAnyValueTypeImpl<const wchar_t*>::sm_instance.get();
+        wxAnyValueTypeImpl<const wchar_t*>::SetValue(value, m_buffer);
     }
 
     wxAny(const wxAny& any)
@@ -610,12 +755,14 @@ public:
         AssignAny(any);
     }
 
-    template<typename T>
-    wxAny(const T& value)
+#if wxUSE_VARIANT
+    wxAny(const wxVariant& variant)
     {
-        m_type = wxAnyValueTypeImpl<T>::sm_instance;
-        wxAnyValueTypeImpl<T>::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 <typename T>
-    bool CheckType(T* = NULL)
+    bool CheckType(T* = NULL) const
     {
         return m_type->CheckType<T>();
     }
@@ -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<T>() 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<typename T>
+    wxAny& operator=(const T &value)
+    {
+        m_type->DeleteValue(m_buffer);
+        m_type = wxAnyValueTypeImpl<T>::sm_instance.get();
+        wxAnyValueTypeImpl<T>::SetValue(value, m_buffer);
+        return *this;
+    }
+
     wxAny& operator=(const wxAny &any)
     {
         if (this != &any)
@@ -676,20 +842,25 @@ public:
         return *this;
     }
 
-    template<typename T>
-    wxAny& operator=(const T &value)
+#if wxUSE_VARIANT
+    wxAny& operator=(const wxVariant &variant)
     {
-        m_type->DeleteValue(m_buffer);
-        m_type = wxAnyValueTypeImpl<T>::sm_instance;
-        wxAnyValueTypeImpl<T>::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<wxString>::IsSameClass(m_type) )
+        wxString value2;
+        if ( !GetAs(&value2) )
             return false;
-
-        return value ==
-            static_cast<wxString>
-                (wxAnyValueTypeImpl<wxString>::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 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<typename T>
@@ -782,6 +954,19 @@ public:
         return static_cast<T>(wxAnyValueTypeImpl<T>::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<T>::IsSameClass(m_type) )
         {
             wxAnyValueType* otherType =
-                wxAnyValueTypeImpl<T>::sm_instance;
+                wxAnyValueTypeImpl<T>::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<wxVariantData*>::sm_instance.get();
+            wxAnyValueTypeImpl<wxVariantData*>::SetValue(data, m_buffer);
+        }
+    }
+#endif
+
     template<typename T>
     void Assign(const T &value)
     {
         m_type->DeleteValue(m_buffer);
-        m_type = wxAnyValueTypeImpl<T>::sm_instance;
+        m_type = wxAnyValueTypeImpl<T>::sm_instance.get();
         wxAnyValueTypeImpl<T>::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<T*>(NULL))
+    (any).As(static_cast<T*>(NULL))
 
 
 template<typename T>
-inline bool wxAnyValueType::CheckType(T* reserved)
+inline bool wxAnyValueType::CheckType(T* reserved) const
 {
     wxUnusedVar(reserved);
     return wxAnyValueTypeImpl<T>::IsSameClass(this);