mirror of
https://github.com/ZDoom/zdoom-macos-deps.git
synced 2024-11-26 05:41:14 +00:00
1141 lines
30 KiB
C
1141 lines
30 KiB
C
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Name: wx/any.h
|
||
|
// Purpose: wxAny class
|
||
|
// Author: Jaakko Salli
|
||
|
// Modified by:
|
||
|
// Created: 07/05/2009
|
||
|
// Copyright: (c) wxWidgets team
|
||
|
// Licence: wxWindows licence
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#ifndef _WX_ANY_H_
|
||
|
#define _WX_ANY_H_
|
||
|
|
||
|
#include "wx/defs.h"
|
||
|
|
||
|
#if wxUSE_ANY
|
||
|
|
||
|
#include <new> // for placement new
|
||
|
#include "wx/string.h"
|
||
|
#include "wx/meta/if.h"
|
||
|
#include "wx/typeinfo.h"
|
||
|
#include "wx/list.h"
|
||
|
|
||
|
// Size of the wxAny value buffer.
|
||
|
enum
|
||
|
{
|
||
|
WX_ANY_VALUE_BUFFER_SIZE = 16
|
||
|
};
|
||
|
|
||
|
union wxAnyValueBuffer
|
||
|
{
|
||
|
union Alignment
|
||
|
{
|
||
|
#if wxHAS_INT64
|
||
|
wxInt64 m_int64;
|
||
|
#endif
|
||
|
long double m_longDouble;
|
||
|
void ( *m_funcPtr )(void);
|
||
|
void ( wxAnyValueBuffer::*m_mFuncPtr )(void);
|
||
|
} m_alignment;
|
||
|
|
||
|
void* m_ptr;
|
||
|
wxByte m_buffer[WX_ANY_VALUE_BUFFER_SIZE];
|
||
|
|
||
|
wxAnyValueBuffer()
|
||
|
{
|
||
|
m_ptr = NULL;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// wxAnyValueType is base class for value type functionality for C++ data
|
||
|
// types used with wxAny. Usually the default template (wxAnyValueTypeImpl<>)
|
||
|
// will create a satisfactory wxAnyValueType implementation for a data type.
|
||
|
//
|
||
|
class WXDLLIMPEXP_BASE wxAnyValueType
|
||
|
{
|
||
|
WX_DECLARE_ABSTRACT_TYPEINFO(wxAnyValueType)
|
||
|
public:
|
||
|
/**
|
||
|
Default constructor.
|
||
|
*/
|
||
|
wxAnyValueType()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Destructor.
|
||
|
*/
|
||
|
virtual ~wxAnyValueType()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
This function is used for internal type matching.
|
||
|
*/
|
||
|
virtual bool IsSameType(const wxAnyValueType* otherType) const = 0;
|
||
|
|
||
|
/**
|
||
|
This function is called every time the data in wxAny
|
||
|
buffer needs to be freed.
|
||
|
*/
|
||
|
virtual void DeleteValue(wxAnyValueBuffer& buf) const = 0;
|
||
|
|
||
|
/**
|
||
|
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;
|
||
|
|
||
|
/**
|
||
|
Convert value into buffer of different type. Return false if
|
||
|
not possible.
|
||
|
*/
|
||
|
virtual bool ConvertValue(const wxAnyValueBuffer& src,
|
||
|
wxAnyValueType* dstType,
|
||
|
wxAnyValueBuffer& dst) const = 0;
|
||
|
|
||
|
/**
|
||
|
Use this template function for checking if wxAnyValueType represents
|
||
|
a specific C++ data type.
|
||
|
|
||
|
@see wxAny::CheckType()
|
||
|
*/
|
||
|
template <typename T>
|
||
|
bool CheckType() 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;
|
||
|
};
|
||
|
|
||
|
|
||
|
// Deprecated macro for checking the type which was originally introduced for
|
||
|
// MSVC6 compatibility and is not needed any longer now that this compiler is
|
||
|
// not supported any more.
|
||
|
#define wxANY_VALUE_TYPE_CHECK_TYPE(valueTypePtr, T) \
|
||
|
wxAnyValueTypeImpl<T>::IsSameClass(valueTypePtr)
|
||
|
|
||
|
|
||
|
/**
|
||
|
Helper macro for defining user value types.
|
||
|
|
||
|
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 bool IsSameClass(const wxAnyValueType* otherType) \
|
||
|
{ \
|
||
|
return AreSameClasses(*sm_instance.get(), *otherType); \
|
||
|
} \
|
||
|
virtual bool IsSameType(const wxAnyValueType* otherType) const wxOVERRIDE \
|
||
|
{ \
|
||
|
return IsSameClass(otherType); \
|
||
|
} \
|
||
|
private: \
|
||
|
static bool AreSameClasses(const wxAnyValueType& a, const wxAnyValueType& b) \
|
||
|
{ \
|
||
|
return wxTypeId(a) == wxTypeId(b); \
|
||
|
} \
|
||
|
static wxAnyValueTypeScopedPtr sm_instance; \
|
||
|
public: \
|
||
|
static wxAnyValueType* GetInstance() \
|
||
|
{ \
|
||
|
return sm_instance.get(); \
|
||
|
}
|
||
|
|
||
|
|
||
|
#define WX_IMPLEMENT_ANY_VALUE_TYPE(CLS) \
|
||
|
wxAnyValueTypeScopedPtr CLS::sm_instance(new CLS());
|
||
|
|
||
|
|
||
|
/**
|
||
|
Following are helper classes for the wxAnyValueTypeImplBase.
|
||
|
*/
|
||
|
namespace wxPrivate
|
||
|
{
|
||
|
|
||
|
template<typename T>
|
||
|
class wxAnyValueTypeOpsInplace
|
||
|
{
|
||
|
public:
|
||
|
static void DeleteValue(wxAnyValueBuffer& buf)
|
||
|
{
|
||
|
GetValue(buf).~T();
|
||
|
}
|
||
|
|
||
|
static void SetValue(const T& value,
|
||
|
wxAnyValueBuffer& buf)
|
||
|
{
|
||
|
// Use placement new
|
||
|
void* const place = buf.m_buffer;
|
||
|
::new(place) T(value);
|
||
|
}
|
||
|
|
||
|
static const T& GetValue(const wxAnyValueBuffer& buf)
|
||
|
{
|
||
|
// Use a union to avoid undefined behaviour (and gcc -Wstrict-alias
|
||
|
// warnings about it) which would occur if we just casted a wxByte
|
||
|
// pointer to a T one.
|
||
|
union
|
||
|
{
|
||
|
const T* ptr;
|
||
|
const wxByte *buf;
|
||
|
} u;
|
||
|
u.buf = buf.m_buffer;
|
||
|
|
||
|
return *u.ptr;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
template<typename T>
|
||
|
class wxAnyValueTypeOpsGeneric
|
||
|
{
|
||
|
public:
|
||
|
template<typename T2>
|
||
|
class DataHolder
|
||
|
{
|
||
|
public:
|
||
|
DataHolder(const T2& value)
|
||
|
: m_value(value)
|
||
|
{
|
||
|
}
|
||
|
virtual ~DataHolder() { }
|
||
|
|
||
|
T2 m_value;
|
||
|
private:
|
||
|
wxDECLARE_NO_COPY_CLASS(DataHolder);
|
||
|
};
|
||
|
|
||
|
static void DeleteValue(wxAnyValueBuffer& buf)
|
||
|
{
|
||
|
DataHolder<T>* holder = static_cast<DataHolder<T>*>(buf.m_ptr);
|
||
|
delete holder;
|
||
|
}
|
||
|
|
||
|
static void SetValue(const T& value,
|
||
|
wxAnyValueBuffer& buf)
|
||
|
{
|
||
|
DataHolder<T>* holder = new DataHolder<T>(value);
|
||
|
buf.m_ptr = holder;
|
||
|
}
|
||
|
|
||
|
static const T& GetValue(const wxAnyValueBuffer& buf)
|
||
|
{
|
||
|
DataHolder<T>* holder = static_cast<DataHolder<T>*>(buf.m_ptr);
|
||
|
return holder->m_value;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
template <typename T>
|
||
|
struct wxAnyAsImpl;
|
||
|
|
||
|
} // namespace wxPrivate
|
||
|
|
||
|
|
||
|
/**
|
||
|
Intermediate template for the generic value type implementation.
|
||
|
We can derive from this same value type for multiple actual types
|
||
|
(for instance, we can have wxAnyValueTypeImplInt for all signed
|
||
|
integer types), and also easily implement specialized templates
|
||
|
with specific dynamic type conversion.
|
||
|
*/
|
||
|
template<typename T>
|
||
|
class wxAnyValueTypeImplBase : public wxAnyValueType
|
||
|
{
|
||
|
typedef typename wxIf< sizeof(T) <= WX_ANY_VALUE_BUFFER_SIZE,
|
||
|
wxPrivate::wxAnyValueTypeOpsInplace<T>,
|
||
|
wxPrivate::wxAnyValueTypeOpsGeneric<T> >::value
|
||
|
Ops;
|
||
|
|
||
|
public:
|
||
|
wxAnyValueTypeImplBase() : wxAnyValueType() { }
|
||
|
virtual ~wxAnyValueTypeImplBase() { }
|
||
|
|
||
|
virtual void DeleteValue(wxAnyValueBuffer& buf) const wxOVERRIDE
|
||
|
{
|
||
|
Ops::DeleteValue(buf);
|
||
|
}
|
||
|
|
||
|
virtual void CopyBuffer(const wxAnyValueBuffer& src,
|
||
|
wxAnyValueBuffer& dst) const wxOVERRIDE
|
||
|
{
|
||
|
Ops::SetValue(Ops::GetValue(src), dst);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
It is important to reimplement this in any specialized template
|
||
|
classes that inherit from wxAnyValueTypeImplBase.
|
||
|
*/
|
||
|
static void SetValue(const T& value,
|
||
|
wxAnyValueBuffer& buf)
|
||
|
{
|
||
|
Ops::SetValue(value, buf);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
It is important to reimplement this in any specialized template
|
||
|
classes that inherit from wxAnyValueTypeImplBase.
|
||
|
*/
|
||
|
static const T& GetValue(const wxAnyValueBuffer& buf)
|
||
|
{
|
||
|
return Ops::GetValue(buf);
|
||
|
}
|
||
|
#if wxUSE_EXTENDED_RTTI
|
||
|
virtual const wxTypeInfo* GetTypeInfo() const
|
||
|
{
|
||
|
return wxGetTypeInfo((T*)NULL);
|
||
|
}
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
|
||
|
/*
|
||
|
Generic value type template. Note that bulk of the implementation
|
||
|
resides in wxAnyValueTypeImplBase.
|
||
|
*/
|
||
|
template<typename T>
|
||
|
class wxAnyValueTypeImpl : public wxAnyValueTypeImplBase<T>
|
||
|
{
|
||
|
WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl<T>)
|
||
|
public:
|
||
|
wxAnyValueTypeImpl() : wxAnyValueTypeImplBase<T>() { }
|
||
|
virtual ~wxAnyValueTypeImpl() { }
|
||
|
|
||
|
virtual bool ConvertValue(const wxAnyValueBuffer& src,
|
||
|
wxAnyValueType* dstType,
|
||
|
wxAnyValueBuffer& dst) const wxOVERRIDE
|
||
|
{
|
||
|
wxUnusedVar(src);
|
||
|
wxUnusedVar(dstType);
|
||
|
wxUnusedVar(dst);
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename 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) \
|
||
|
template<> \
|
||
|
class wxAnyValueTypeImpl<T> : public wxAnyValueTypeImpl##CLSTYPE \
|
||
|
{ \
|
||
|
typedef wxAnyBase##CLSTYPE##Type UseDataType; \
|
||
|
public: \
|
||
|
wxAnyValueTypeImpl() : wxAnyValueTypeImpl##CLSTYPE() { } \
|
||
|
virtual ~wxAnyValueTypeImpl() { } \
|
||
|
static void SetValue(const T& value, wxAnyValueBuffer& buf) \
|
||
|
{ \
|
||
|
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) \
|
||
|
{ \
|
||
|
const void* voidPtr = \
|
||
|
reinterpret_cast<const void*>(&buf.m_buffer[0]); \
|
||
|
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
|
||
|
//
|
||
|
|
||
|
#ifdef wxLongLong_t
|
||
|
typedef wxLongLong_t wxAnyBaseIntType;
|
||
|
typedef wxULongLong_t wxAnyBaseUintType;
|
||
|
#else
|
||
|
typedef long wxAnyBaseIntType;
|
||
|
typedef unsigned long wxAnyBaseUintType;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
class WXDLLIMPEXP_BASE wxAnyValueTypeImplInt :
|
||
|
public wxAnyValueTypeImplBase<wxAnyBaseIntType>
|
||
|
{
|
||
|
WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplInt)
|
||
|
public:
|
||
|
wxAnyValueTypeImplInt() :
|
||
|
wxAnyValueTypeImplBase<wxAnyBaseIntType>() { }
|
||
|
virtual ~wxAnyValueTypeImplInt() { }
|
||
|
|
||
|
virtual bool ConvertValue(const wxAnyValueBuffer& src,
|
||
|
wxAnyValueType* dstType,
|
||
|
wxAnyValueBuffer& dst) const wxOVERRIDE;
|
||
|
};
|
||
|
|
||
|
|
||
|
class WXDLLIMPEXP_BASE wxAnyValueTypeImplUint :
|
||
|
public wxAnyValueTypeImplBase<wxAnyBaseUintType>
|
||
|
{
|
||
|
WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplUint)
|
||
|
public:
|
||
|
wxAnyValueTypeImplUint() :
|
||
|
wxAnyValueTypeImplBase<wxAnyBaseUintType>() { }
|
||
|
virtual ~wxAnyValueTypeImplUint() { }
|
||
|
|
||
|
virtual bool ConvertValue(const wxAnyValueBuffer& src,
|
||
|
wxAnyValueType* dstType,
|
||
|
wxAnyValueBuffer& dst) const wxOVERRIDE;
|
||
|
};
|
||
|
|
||
|
|
||
|
WX_ANY_DEFINE_SUB_TYPE(signed long, Int)
|
||
|
WX_ANY_DEFINE_SUB_TYPE(signed int, Int)
|
||
|
WX_ANY_DEFINE_SUB_TYPE(signed short, Int)
|
||
|
WX_ANY_DEFINE_SUB_TYPE(signed char, Int)
|
||
|
#ifdef wxLongLong_t
|
||
|
WX_ANY_DEFINE_SUB_TYPE(wxLongLong_t, Int)
|
||
|
#endif
|
||
|
|
||
|
WX_ANY_DEFINE_SUB_TYPE(unsigned long, Uint)
|
||
|
WX_ANY_DEFINE_SUB_TYPE(unsigned int, Uint)
|
||
|
WX_ANY_DEFINE_SUB_TYPE(unsigned short, Uint)
|
||
|
WX_ANY_DEFINE_SUB_TYPE(unsigned char, Uint)
|
||
|
#ifdef wxLongLong_t
|
||
|
WX_ANY_DEFINE_SUB_TYPE(wxULongLong_t, Uint)
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//
|
||
|
// This macro is used in header, but then in source file we must have:
|
||
|
// WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl##TYPENAME)
|
||
|
//
|
||
|
#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 wxOVERRIDE \
|
||
|
{ \
|
||
|
GV value = GetValue(src); \
|
||
|
return CONVFUNC(value, dstType, dst); \
|
||
|
} \
|
||
|
}; \
|
||
|
template<> \
|
||
|
class wxAnyValueTypeImpl<T> : public wxAnyValueTypeImpl##TYPENAME \
|
||
|
{ \
|
||
|
public: \
|
||
|
wxAnyValueTypeImpl() : wxAnyValueTypeImpl##TYPENAME() { } \
|
||
|
virtual ~wxAnyValueTypeImpl() { } \
|
||
|
};
|
||
|
|
||
|
#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&) \
|
||
|
|
||
|
//
|
||
|
// 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)
|
||
|
#ifndef wxNO_IMPLICIT_WXSTRING_ENCODING
|
||
|
WX_ANY_DEFINE_CONVERTIBLE_TYPE(const char*, ConstCharPtr,
|
||
|
wxAnyConvertString, wxString)
|
||
|
#endif
|
||
|
WX_ANY_DEFINE_CONVERTIBLE_TYPE(const wchar_t*, ConstWchar_tPtr,
|
||
|
wxAnyConvertString, wxString)
|
||
|
|
||
|
//
|
||
|
// Bool value type
|
||
|
//
|
||
|
template<>
|
||
|
class WXDLLIMPEXP_BASE wxAnyValueTypeImpl<bool> :
|
||
|
public wxAnyValueTypeImplBase<bool>
|
||
|
{
|
||
|
WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl<bool>)
|
||
|
public:
|
||
|
wxAnyValueTypeImpl() :
|
||
|
wxAnyValueTypeImplBase<bool>() { }
|
||
|
virtual ~wxAnyValueTypeImpl() { }
|
||
|
|
||
|
virtual bool ConvertValue(const wxAnyValueBuffer& src,
|
||
|
wxAnyValueType* dstType,
|
||
|
wxAnyValueBuffer& dst) const wxOVERRIDE;
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Floating point value type
|
||
|
//
|
||
|
class WXDLLIMPEXP_BASE wxAnyValueTypeImplDouble :
|
||
|
public wxAnyValueTypeImplBase<double>
|
||
|
{
|
||
|
WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplDouble)
|
||
|
public:
|
||
|
wxAnyValueTypeImplDouble() :
|
||
|
wxAnyValueTypeImplBase<double>() { }
|
||
|
virtual ~wxAnyValueTypeImplDouble() { }
|
||
|
|
||
|
virtual bool ConvertValue(const wxAnyValueBuffer& src,
|
||
|
wxAnyValueType* dstType,
|
||
|
wxAnyValueBuffer& dst) const wxOVERRIDE;
|
||
|
};
|
||
|
|
||
|
// WX_ANY_DEFINE_SUB_TYPE requires this
|
||
|
typedef double wxAnyBaseDoubleType;
|
||
|
|
||
|
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<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 wxOVERRIDE \
|
||
|
{ \
|
||
|
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 unit tests 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 wxOVERRIDE
|
||
|
{
|
||
|
wxVariantData* data = static_cast<wxVariantData*>(buf.m_ptr);
|
||
|
if ( data )
|
||
|
data->DecRef();
|
||
|
}
|
||
|
|
||
|
virtual void CopyBuffer(const wxAnyValueBuffer& src,
|
||
|
wxAnyValueBuffer& dst) const wxOVERRIDE
|
||
|
{
|
||
|
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 wxOVERRIDE
|
||
|
{
|
||
|
wxUnusedVar(src);
|
||
|
wxUnusedVar(dstType);
|
||
|
wxUnusedVar(dst);
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<>
|
||
|
class wxAnyValueTypeImpl<wxVariantData*> :
|
||
|
public wxAnyValueTypeImplVariantData
|
||
|
{
|
||
|
public:
|
||
|
wxAnyValueTypeImpl() : wxAnyValueTypeImplVariantData() { }
|
||
|
virtual ~wxAnyValueTypeImpl() { }
|
||
|
};
|
||
|
|
||
|
#endif // wxUSE_VARIANT
|
||
|
|
||
|
|
||
|
/*
|
||
|
Let's define a discrete Null value so we don't have to really
|
||
|
ever check if wxAny.m_type pointer is NULL or not. This is an
|
||
|
optimization, mostly. Implementation of this value type is
|
||
|
"hidden" in the source file.
|
||
|
*/
|
||
|
extern WXDLLIMPEXP_DATA_BASE(wxAnyValueType*) wxAnyNullValueType;
|
||
|
|
||
|
|
||
|
//
|
||
|
// We need to implement custom signed/unsigned int equals operators
|
||
|
// for signed/unsigned (eg. wxAny(128UL) == 128L) comparisons to work.
|
||
|
#define WXANY_IMPLEMENT_INT_EQ_OP(TS, TUS) \
|
||
|
bool operator==(TS value) const \
|
||
|
{ \
|
||
|
if ( wxAnyValueTypeImpl<TS>::IsSameClass(m_type) ) \
|
||
|
return (value == static_cast<TS> \
|
||
|
(wxAnyValueTypeImpl<TS>::GetValue(m_buffer))); \
|
||
|
if ( wxAnyValueTypeImpl<TUS>::IsSameClass(m_type) ) \
|
||
|
return (value == static_cast<TS> \
|
||
|
(wxAnyValueTypeImpl<TUS>::GetValue(m_buffer))); \
|
||
|
return false; \
|
||
|
} \
|
||
|
bool operator==(TUS value) const \
|
||
|
{ \
|
||
|
if ( wxAnyValueTypeImpl<TUS>::IsSameClass(m_type) ) \
|
||
|
return (value == static_cast<TUS> \
|
||
|
(wxAnyValueTypeImpl<TUS>::GetValue(m_buffer))); \
|
||
|
if ( wxAnyValueTypeImpl<TS>::IsSameClass(m_type) ) \
|
||
|
return (value == static_cast<TUS> \
|
||
|
(wxAnyValueTypeImpl<TS>::GetValue(m_buffer))); \
|
||
|
return false; \
|
||
|
}
|
||
|
|
||
|
|
||
|
#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.
|
||
|
//
|
||
|
// As standard, wxAny can store value of almost any type, in a fairly
|
||
|
// optimal manner even.
|
||
|
//
|
||
|
class wxAny
|
||
|
{
|
||
|
public:
|
||
|
/**
|
||
|
Default constructor.
|
||
|
*/
|
||
|
wxAny()
|
||
|
{
|
||
|
m_type = wxAnyNullValueType;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Destructor.
|
||
|
*/
|
||
|
~wxAny()
|
||
|
{
|
||
|
m_type->DeleteValue(m_buffer);
|
||
|
}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
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
|
||
|
#ifndef wxNO_IMPLICIT_WXSTRING_ENCODING
|
||
|
wxAny(const char* value)
|
||
|
{
|
||
|
m_type = wxAnyValueTypeImpl<const char*>::sm_instance.get();
|
||
|
wxAnyValueTypeImpl<const char*>::SetValue(value, m_buffer);
|
||
|
}
|
||
|
#endif
|
||
|
wxAny(const wchar_t* value)
|
||
|
{
|
||
|
m_type = wxAnyValueTypeImpl<const wchar_t*>::sm_instance.get();
|
||
|
wxAnyValueTypeImpl<const wchar_t*>::SetValue(value, m_buffer);
|
||
|
}
|
||
|
|
||
|
wxAny(const wxAny& any)
|
||
|
{
|
||
|
m_type = wxAnyNullValueType;
|
||
|
AssignAny(any);
|
||
|
}
|
||
|
|
||
|
#if wxUSE_VARIANT
|
||
|
wxAny(const wxVariant& variant)
|
||
|
{
|
||
|
m_type = wxAnyNullValueType;
|
||
|
AssignVariant(variant);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//@}
|
||
|
|
||
|
/**
|
||
|
Use this template function for checking if this wxAny holds
|
||
|
a specific C++ data type.
|
||
|
|
||
|
@see wxAnyValueType::CheckType()
|
||
|
*/
|
||
|
template <typename T>
|
||
|
bool CheckType() const
|
||
|
{
|
||
|
return m_type->CheckType<T>();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Returns the value type as wxAnyValueType instance.
|
||
|
|
||
|
@remarks You cannot reliably test whether two wxAnys are of
|
||
|
same value type by simply comparing return values
|
||
|
of wxAny::GetType(). Instead, use wxAny::HasSameType().
|
||
|
|
||
|
@see HasSameType()
|
||
|
*/
|
||
|
const wxAnyValueType* GetType() const
|
||
|
{
|
||
|
return m_type;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
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
|
||
|
{
|
||
|
return (m_type == wxAnyNullValueType);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Makes wxAny null (that is, clears it).
|
||
|
*/
|
||
|
void MakeNull()
|
||
|
{
|
||
|
m_type->DeleteValue(m_buffer);
|
||
|
m_type = wxAnyNullValueType;
|
||
|
}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
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)
|
||
|
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
|
||
|
#ifndef wxNO_IMPLICIT_WXSTRING_ENCODING
|
||
|
wxAny& operator=(const char* value)
|
||
|
{
|
||
|
Assign(value);
|
||
|
return *this;
|
||
|
}
|
||
|
#endif
|
||
|
wxAny& operator=(const wchar_t* value)
|
||
|
{
|
||
|
Assign(value);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
Equality operators.
|
||
|
*/
|
||
|
bool operator==(const wxString& value) const
|
||
|
{
|
||
|
wxString value2;
|
||
|
if ( !GetAs(&value2) )
|
||
|
return false;
|
||
|
return value == value2;
|
||
|
}
|
||
|
|
||
|
#ifndef wxNO_IMPLICIT_WXSTRING_ENCODING
|
||
|
bool operator==(const char* value) const
|
||
|
{ return (*this) == wxString(value); }
|
||
|
#endif // wxNO_IMPLICIT_WXSTRING_ENCODING
|
||
|
bool operator==(const wchar_t* value) const
|
||
|
{ return (*this) == wxString(value); }
|
||
|
|
||
|
//
|
||
|
// We need to implement custom signed/unsigned int equals operators
|
||
|
// for signed/unsigned (eg. wxAny(128UL) == 128L) comparisons to work.
|
||
|
WXANY_IMPLEMENT_INT_EQ_OP(signed char, unsigned char)
|
||
|
WXANY_IMPLEMENT_INT_EQ_OP(signed short, unsigned short)
|
||
|
WXANY_IMPLEMENT_INT_EQ_OP(signed int, unsigned int)
|
||
|
WXANY_IMPLEMENT_INT_EQ_OP(signed long, unsigned long)
|
||
|
#ifdef wxLongLong_t
|
||
|
WXANY_IMPLEMENT_INT_EQ_OP(wxLongLong_t, wxULongLong_t)
|
||
|
#endif
|
||
|
|
||
|
wxGCC_WARNING_SUPPRESS(float-equal)
|
||
|
|
||
|
bool operator==(float value) const
|
||
|
{
|
||
|
if ( !wxAnyValueTypeImpl<float>::IsSameClass(m_type) )
|
||
|
return false;
|
||
|
|
||
|
return value ==
|
||
|
static_cast<float>
|
||
|
(wxAnyValueTypeImpl<float>::GetValue(m_buffer));
|
||
|
}
|
||
|
|
||
|
bool operator==(double value) const
|
||
|
{
|
||
|
if ( !wxAnyValueTypeImpl<double>::IsSameClass(m_type) )
|
||
|
return false;
|
||
|
|
||
|
return value ==
|
||
|
static_cast<double>
|
||
|
(wxAnyValueTypeImpl<double>::GetValue(m_buffer));
|
||
|
}
|
||
|
|
||
|
wxGCC_WARNING_RESTORE(float-equal)
|
||
|
|
||
|
bool operator==(bool value) const
|
||
|
{
|
||
|
if ( !wxAnyValueTypeImpl<bool>::IsSameClass(m_type) )
|
||
|
return false;
|
||
|
|
||
|
return value == (wxAnyValueTypeImpl<bool>::GetValue(m_buffer));
|
||
|
}
|
||
|
|
||
|
//@}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
Inequality operators (implement as template).
|
||
|
*/
|
||
|
template<typename T>
|
||
|
bool operator!=(const T& value) const
|
||
|
{ return !((*this) == value); }
|
||
|
//@}
|
||
|
|
||
|
/**
|
||
|
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 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.
|
||
|
*/
|
||
|
template <typename T>
|
||
|
T As(T* = NULL) const
|
||
|
{
|
||
|
return wxPrivate::wxAnyAsImpl<T>::DoAs(*this);
|
||
|
}
|
||
|
|
||
|
// Semi private helper: get the value without coercion, for all types.
|
||
|
template <typename T>
|
||
|
T RawAs() const
|
||
|
{
|
||
|
if ( !wxAnyValueTypeImpl<T>::IsSameClass(m_type) )
|
||
|
{
|
||
|
wxFAIL_MSG("Incorrect or non-convertible data type");
|
||
|
}
|
||
|
|
||
|
return static_cast<T>(wxAnyValueTypeImpl<T>::GetValue(m_buffer));
|
||
|
}
|
||
|
|
||
|
#if wxUSE_EXTENDED_RTTI
|
||
|
const wxTypeInfo* GetTypeInfo() const
|
||
|
{
|
||
|
return m_type->GetTypeInfo();
|
||
|
}
|
||
|
#endif
|
||
|
/**
|
||
|
Template function that retrieves and converts the value of this
|
||
|
variant to the type that T* value is.
|
||
|
|
||
|
@return Returns @true if conversion was successful.
|
||
|
*/
|
||
|
template<typename T>
|
||
|
bool GetAs(T* value) const
|
||
|
{
|
||
|
if ( !wxAnyValueTypeImpl<T>::IsSameClass(m_type) )
|
||
|
{
|
||
|
wxAnyValueType* otherType =
|
||
|
wxAnyValueTypeImpl<T>::sm_instance.get();
|
||
|
wxAnyValueBuffer temp_buf;
|
||
|
|
||
|
if ( !m_type->ConvertValue(m_buffer, otherType, temp_buf) )
|
||
|
return false;
|
||
|
|
||
|
*value =
|
||
|
static_cast<T>(wxAnyValueTypeImpl<T>::GetValue(temp_buf));
|
||
|
otherType->DeleteValue(temp_buf);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
*value = static_cast<T>(wxAnyValueTypeImpl<T>::GetValue(m_buffer));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
#if wxUSE_VARIANT
|
||
|
// GetAs() wxVariant specialization
|
||
|
bool GetAs(wxVariant* value) const
|
||
|
{
|
||
|
return wxConvertAnyToVariant(*this, value);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
private:
|
||
|
#ifdef wxNO_IMPLICIT_WXSTRING_ENCODING
|
||
|
wxAny(const char*); // Disabled
|
||
|
wxAny& operator=(const char *&value); // Disabled
|
||
|
wxAny& operator=(const char value[]); // Disabled
|
||
|
wxAny& operator==(const char *value); // Disabled
|
||
|
#endif
|
||
|
|
||
|
// Assignment functions
|
||
|
void AssignAny(const wxAny& any)
|
||
|
{
|
||
|
// 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() )
|
||
|
{
|
||
|
// 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.get();
|
||
|
wxAnyValueTypeImpl<T>::SetValue(value, m_buffer);
|
||
|
}
|
||
|
|
||
|
// Data
|
||
|
wxAnyValueBuffer m_buffer;
|
||
|
wxAnyValueType* m_type;
|
||
|
};
|
||
|
|
||
|
|
||
|
namespace wxPrivate
|
||
|
{
|
||
|
|
||
|
// Dispatcher for template wxAny::As() implementation which is different for
|
||
|
// wxString and all the other types: the generic implementation check if the
|
||
|
// value is of the right type and returns it.
|
||
|
template <typename T>
|
||
|
struct wxAnyAsImpl
|
||
|
{
|
||
|
static T DoAs(const wxAny& any)
|
||
|
{
|
||
|
return any.RawAs<T>();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Specialization for wxString does coercion.
|
||
|
template <>
|
||
|
struct wxAnyAsImpl<wxString>
|
||
|
{
|
||
|
static wxString DoAs(const wxAny& any)
|
||
|
{
|
||
|
wxString value;
|
||
|
if ( !any.GetAs(&value) )
|
||
|
{
|
||
|
wxFAIL_MSG("Incorrect or non-convertible data type");
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
// See comment for wxANY_VALUE_TYPE_CHECK_TYPE.
|
||
|
#define wxANY_CHECK_TYPE(any, T) \
|
||
|
wxANY_VALUE_TYPE_CHECK_TYPE((any).GetType(), T)
|
||
|
|
||
|
|
||
|
// This macro shouldn't be used any longer for the same reasons as
|
||
|
// wxANY_VALUE_TYPE_CHECK_TYPE(), just call As() directly.
|
||
|
#define wxANY_AS(any, T) \
|
||
|
(any).As(static_cast<T*>(NULL))
|
||
|
|
||
|
|
||
|
template<typename T>
|
||
|
inline bool wxAnyValueType::CheckType() const
|
||
|
{
|
||
|
return wxAnyValueTypeImpl<T>::IsSameClass(this);
|
||
|
}
|
||
|
|
||
|
WX_DECLARE_LIST_WITH_DECL(wxAny, wxAnyList, class WXDLLIMPEXP_BASE);
|
||
|
|
||
|
#endif // wxUSE_ANY
|
||
|
|
||
|
#endif // _WX_ANY_H_
|