#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"
// Size of the wxAny value buffer.
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<>)
//
class WXDLLIMPEXP_BASE wxAnyValueType
{
+ WX_DECLARE_ABSTRACT_TYPEINFO(wxAnyValueType)
public:
/**
Default constructor.
*/
- wxAnyValueType();
+ wxAnyValueType()
+ {
+ }
/**
Destructor.
{
}
- /**
- This function is used for internal type matching.
- */
- virtual wxAnyClassInfo GetClassInfo() const = 0;
-
/**
This function is used for internal type matching.
*/
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;
*/
// 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) \
wxAnyValueTypeImpl<T>::IsSameClass(valueTypePtr)
- //valueTypePtr->CheckType(static_cast<T*>(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.
+
+ 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; \
+ 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.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__
{
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)
{
- return *(reinterpret_cast<const T*>(&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<const T*>(&buf.m_buffer[0]);
+ return *value;
}
};
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;
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);
}
};
template<typename T>
-wxAnyValueTypeImpl<T>* wxAnyValueTypeImpl<T>::sm_instance =
- new wxAnyValueTypeImpl<T>();
+wxAnyValueTypeScopedPtr wxAnyValueTypeImpl<T>::sm_instance = new wxAnyValueTypeImpl<T>();
//
virtual ~wxAnyValueTypeImpl() { } \
static void SetValue(const T& value, wxAnyValueBuffer& buf) \
{ \
- *(reinterpret_cast<UseDataType*>(&buf.m_buffer[0])) = \
- static_cast<UseDataType>(value); \
+ void* voidPtr = reinterpret_cast<void*>(&buf.m_buffer[0]); \
+ UseDataType* dptr = reinterpret_cast<UseDataType*>(voidPtr); \
+ *dptr = static_cast<UseDataType>(value); \
} \
static T GetValue(const wxAnyValueBuffer& buf) \
{ \
- return static_cast<T>( \
- *(reinterpret_cast<const UseDataType*>(&buf.m_buffer[0]))); \
+ const void* voidPtr = \
+ reinterpret_cast<const void*>(&buf.m_buffer[0]); \
+ const UseDataType* sptr = \
+ reinterpret_cast<const UseDataType*>(voidPtr); \
+ return static_cast<T>(*sptr); \
} \
};
//
-// 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
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<CLS> : \
+ public wxAnyValueTypeImplBase<CLS> \
+{ \
+ WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl<CLS>) \
+public: \
+ wxAnyValueTypeImpl() : \
+ wxAnyValueTypeImplBase<CLS>() { } \
+ 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<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
#pragma warning (pop)
}
+#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.
/**
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)
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
+
//@}
/**
*/
// 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>();
}
@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
{
}
/**
- 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
{
/**
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)
{
- AssignAny(any);
+ if (this != &any)
+ AssignAny(any);
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;
+ }
//@{
/**
*/
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
//@}
/**
- 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>
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.
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) )
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<wxVariantData*>::sm_instance.get();
+ wxAnyValueTypeImpl<wxVariantData*>::SetValue(data, m_buffer);
}
- m_type->CopyBuffer(any.m_buffer, 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);
}
//
// 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);