]> git.saurik.com Git - wxWidgets.git/blobdiff - include/wx/any.h
implementation of HotKey, see #12354
[wxWidgets.git] / include / wx / any.h
index 91b1abf0f94f213beb524448969727da08ca9607..6e3877253283904337e912ebe4835c86f94808f0 100644 (file)
 
 #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"
-
+#include "wx/list.h"
 
 // Size of the wxAny value buffer.
 enum
@@ -56,7 +56,9 @@ public:
     /**
         Default constructor.
     */
-    wxAnyValueType();
+    wxAnyValueType()
+    {
+    }
 
     /**
         Destructor.
@@ -102,7 +104,7 @@ public:
         a specific C++ data type.
 
         @remarks This template function does not work on some older compilers
-                (such as Visual C++ 6.0). For full compiler ccompatibility
+                (such as Visual C++ 6.0). For full compiler compatibility
                 please use wxANY_VALUE_TYPE_CHECK_TYPE(valueTypePtr, T) macro
                 instead.
 
@@ -110,10 +112,34 @@ 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;
+
+#if wxUSE_EXTENDED_RTTI
+    virtual const wxTypeInfo* GetTypeInfo() const = 0;
+#endif
 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 +153,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 +165,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,23 +197,29 @@ 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)
     {
-        // Breaking this code into two lines should supress
+        // Breaking this code into two lines should suppress
         // GCC's 'type-punned pointer will break strict-aliasing rules'
         // warning.
         const T* value = reinterpret_cast<const T*>(&buf.m_buffer[0]);
@@ -243,9 +280,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;
 
@@ -282,6 +318,12 @@ public:
     {
         return Ops::GetValue(buf);
     }
+#if wxUSE_EXTENDED_RTTI
+    virtual const wxTypeInfo* GetTypeInfo() const 
+    {
+        return wxGetTypeInfo((T*)NULL);
+    }
+#endif
 };
 
 
@@ -309,15 +351,14 @@ public:
 };
 
 template<typename T>
-wxAnyValueTypeImpl<T>* wxAnyValueTypeImpl<T>::sm_instance =
-    new wxAnyValueTypeImpl<T>();
+wxAnyValueTypeScopedPtr wxAnyValueTypeImpl<T>::sm_instance = new wxAnyValueTypeImpl<T>();
 
 
 //
 // Helper macro for using same base value type implementation for multiple
 // actual C++ data types.
 //
-#define WX_ANY_DEFINE_SUB_TYPE(T, CLSTYPE) \
+#define _WX_ANY_DEFINE_SUB_TYPE(T, CLSTYPE) \
 template<> \
 class wxAnyValueTypeImpl<T> : public wxAnyValueTypeImpl##CLSTYPE \
 { \
@@ -338,9 +379,21 @@ public: \
         const UseDataType* sptr = \
             reinterpret_cast<const UseDataType*>(voidPtr); \
         return static_cast<T>(*sptr); \
+    } 
+
+#if wxUSE_EXTENDED_RTTI
+#define WX_ANY_DEFINE_SUB_TYPE(T, CLSTYPE) \
+_WX_ANY_DEFINE_SUB_TYPE(T, CLSTYPE)\
+    virtual const wxTypeInfo* GetTypeInfo() const  \
+    { \
+        return wxGetTypeInfo((T*)NULL); \
     } \
 };
-
+#else
+#define WX_ANY_DEFINE_SUB_TYPE(T, CLSTYPE) \
+_WX_ANY_DEFINE_SUB_TYPE(T, CLSTYPE)\
+};
+#endif
 
 //
 //  Integer value types
@@ -403,35 +456,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
@@ -507,7 +580,7 @@ public: \
 // (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
+// really test it properly in unit tests since a separate DLL would
 // be needed).
 #if wxUSE_DATETIME
     #include "wx/datetime.h"
@@ -682,20 +755,20 @@ public:
     template<typename T>
     wxAny(const T& value)
     {
-        m_type = wxAnyValueTypeImpl<T>::sm_instance;
+        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)
@@ -705,7 +778,6 @@ public:
     }
 
 #if wxUSE_VARIANT
-    template<>
     wxAny(const wxVariant& variant)
     {
         m_type = wxAnyNullValueType;
@@ -727,7 +799,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>();
     }
@@ -737,8 +809,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
     {
@@ -746,7 +819,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
     {
@@ -766,6 +848,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)
@@ -781,20 +872,17 @@ public:
     }
 #endif
 
-    template<typename T>
-    wxAny& operator=(const T &value)
+    // These two operators are needed to deal with string literals
+    wxAny& operator=(const char* value)
     {
-        m_type->DeleteValue(m_buffer);
-        m_type = wxAnyValueTypeImpl<T>::sm_instance;
-        wxAnyValueTypeImpl<T>::SetValue(value, m_buffer);
+        Assign(value);
         return *this;
     }
-
-    wxAny& operator=(const char* value)
-        { Assign(wxString(value)); return *this; }
     wxAny& operator=(const wchar_t* value)
-        { Assign(wxString(value)); return *this; }
-    //@}
+    {
+        Assign(value);
+        return *this;
+    }
 
     //@{
     /**
@@ -802,12 +890,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
@@ -866,14 +952,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 convenience, 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>
@@ -887,11 +976,30 @@ 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;
+    }
+
+#if wxUSE_EXTENDED_RTTI
+    const wxTypeInfo* GetTypeInfo() const
+    {
+        return m_type->GetTypeInfo();
+    }
+#endif
     /**
-        Template function that etrieves and converts the value of this
+        Template function that retrieves and converts the value of this
         variant to the type that T* value is.
 
-        @return Returns @true if conversion was succesfull.
+        @return Returns @true if conversion was successful.
     */
     template<typename T>
     bool GetAs(T* value) const
@@ -899,7 +1007,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) )
@@ -917,7 +1025,6 @@ public:
 
 #if wxUSE_VARIANT
     // GetAs() wxVariant specialization
-    template<>
     bool GetAs(wxVariant* value) const
     {
         return wxConvertAnyToVariant(*this, value);
@@ -957,7 +1064,7 @@ private:
         else
         {
             // If everything else fails, wrap the whole wxVariantData
-            m_type = wxAnyValueTypeImpl<wxVariantData*>::sm_instance;
+            m_type = wxAnyValueTypeImpl<wxVariantData*>::sm_instance.get();
             wxAnyValueTypeImpl<wxVariantData*>::SetValue(data, m_buffer);
         }
     }
@@ -967,7 +1074,7 @@ private:
     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);
     }
 
@@ -980,23 +1087,23 @@ 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);
 }
 
-
+WX_DECLARE_LIST_WITH_DECL(wxAny, wxAnyList, class WXDLLIMPEXP_BASE);
 
 #endif // wxUSE_ANY