1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxAny class
4 // Author: Jaakko Salli
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
19 #include "wx/string.h"
20 #include "wx/meta/movable.h"
21 #include "wx/meta/if.h"
22 #include "wx/typeinfo.h"
25 // Size of the wxAny value buffer.
28 WX_ANY_VALUE_BUFFER_SIZE
= 16
31 union wxAnyValueBuffer
38 long double m_longDouble
;
39 void ( *m_funcPtr
)(void);
40 void ( wxAnyValueBuffer::*m_mFuncPtr
)(void);
44 wxByte m_buffer
[WX_ANY_VALUE_BUFFER_SIZE
];
48 // wxAnyValueType is base class for value type functionality for C++ data
49 // types used with wxAny. Usually the default template (wxAnyValueTypeImpl<>)
50 // will create a satisfactory wxAnyValueType implementation for a data type.
52 class WXDLLIMPEXP_BASE wxAnyValueType
54 WX_DECLARE_ABSTRACT_TYPEINFO(wxAnyValueType
)
64 virtual ~wxAnyValueType()
69 This function is used for internal type matching.
71 virtual bool IsSameType(const wxAnyValueType
* otherType
) const = 0;
74 This function is called every time the data in wxAny
75 buffer needs to be freed.
77 virtual void DeleteValue(wxAnyValueBuffer
& buf
) const = 0;
80 Implement this for buffer-to-buffer copy.
83 This is the source data buffer.
86 This is the destination data buffer that is in either
87 uninitialized or freed state.
89 virtual void CopyBuffer(const wxAnyValueBuffer
& src
,
90 wxAnyValueBuffer
& dst
) const = 0;
93 Convert value into buffer of different type. Return false if
96 virtual bool ConvertValue(const wxAnyValueBuffer
& src
,
97 wxAnyValueType
* dstType
,
98 wxAnyValueBuffer
& dst
) const = 0;
101 Use this template function for checking if wxAnyValueType represents
102 a specific C++ data type.
104 @remarks This template function does not work on some older compilers
105 (such as Visual C++ 6.0). For full compiler ccompatibility
106 please use wxANY_VALUE_TYPE_CHECK_TYPE(valueTypePtr, T) macro
109 @see wxAny::CheckType()
111 // FIXME-VC6: remove this hack when VC6 is no longer supported
112 template <typename T
>
113 bool CheckType(T
* reserved
= NULL
);
118 // This method of checking the type is compatible with VC6
119 #define wxANY_VALUE_TYPE_CHECK_TYPE(valueTypePtr, T) \
120 wxAnyValueTypeImpl<T>::IsSameClass(valueTypePtr)
124 Helper macro for defining user value types.
126 Even though C++ RTTI would be fully available to use, we'd have to to
127 facilitate sub-type system which allows, for instance, wxAny with
128 signed short '15' to be treated equal to wxAny with signed long long '15'.
129 Having sm_instance is important here.
131 #define WX_DECLARE_ANY_VALUE_TYPE(CLS) \
132 friend class wxAny; \
133 WX_DECLARE_TYPEINFO_INLINE(CLS) \
135 static bool IsSameClass(const wxAnyValueType* otherType) \
137 return wxTypeId(*sm_instance) == wxTypeId(*otherType); \
139 virtual bool IsSameType(const wxAnyValueType* otherType) const \
141 return IsSameClass(otherType); \
144 static CLS* sm_instance; \
146 static wxAnyValueType* GetInstance() \
148 return sm_instance; \
152 #define WX_IMPLEMENT_ANY_VALUE_TYPE(CLS) \
153 CLS* CLS::sm_instance = new CLS();
157 // "non dll-interface class 'xxx' used as base interface
158 #pragma warning (push)
159 #pragma warning (disable:4275)
163 Following are helper classes for the wxAnyValueTypeImplBase.
169 class wxAnyValueTypeOpsMovable
172 static void DeleteValue(wxAnyValueBuffer
& buf
)
177 static void SetValue(const T
& value
,
178 wxAnyValueBuffer
& buf
)
180 memcpy(buf
.m_buffer
, &value
, sizeof(T
));
183 static const T
& GetValue(const wxAnyValueBuffer
& buf
)
185 return *(reinterpret_cast<const T
*>(&buf
.m_buffer
[0]));
191 class wxAnyValueTypeOpsGeneric
194 template<typename T2
>
198 DataHolder(const T2
& value
)
202 virtual ~DataHolder() { }
206 wxDECLARE_NO_COPY_CLASS(DataHolder
);
209 static void DeleteValue(wxAnyValueBuffer
& buf
)
211 DataHolder
<T
>* holder
= static_cast<DataHolder
<T
>*>(buf
.m_ptr
);
215 static void SetValue(const T
& value
,
216 wxAnyValueBuffer
& buf
)
218 DataHolder
<T
>* holder
= new DataHolder
<T
>(value
);
222 static const T
& GetValue(const wxAnyValueBuffer
& buf
)
224 DataHolder
<T
>* holder
= static_cast<DataHolder
<T
>*>(buf
.m_ptr
);
225 return holder
->m_value
;
229 } // namespace wxPrivate
233 Intermediate template for the generic value type implementation.
234 We can derive from this same value type for multiple actual types
235 (for instance, we can have wxAnyValueTypeImplInt for all signed
236 integer types), and also easily implement specialized templates
237 with specific dynamic type conversion.
240 class wxAnyValueTypeImplBase
: public wxAnyValueType
242 typedef typename wxIf
< wxIsMovable
<T
>::value
&&
243 sizeof(T
) <= WX_ANY_VALUE_BUFFER_SIZE
,
244 wxPrivate::wxAnyValueTypeOpsMovable
<T
>,
245 wxPrivate::wxAnyValueTypeOpsGeneric
<T
> >::value
249 wxAnyValueTypeImplBase() : wxAnyValueType() { }
250 virtual ~wxAnyValueTypeImplBase() { }
252 virtual void DeleteValue(wxAnyValueBuffer
& buf
) const
254 Ops::DeleteValue(buf
);
257 virtual void CopyBuffer(const wxAnyValueBuffer
& src
,
258 wxAnyValueBuffer
& dst
) const
260 Ops::SetValue(Ops::GetValue(src
), dst
);
264 It is important to reimplement this in any specialized template
265 classes that inherit from wxAnyValueTypeImplBase.
267 static void SetValue(const T
& value
,
268 wxAnyValueBuffer
& buf
)
270 Ops::SetValue(value
, buf
);
274 It is important to reimplement this in any specialized template
275 classes that inherit from wxAnyValueTypeImplBase.
277 static const T
& GetValue(const wxAnyValueBuffer
& buf
)
279 return Ops::GetValue(buf
);
285 Generic value type template. Note that bulk of the implementation
286 resides in wxAnyValueTypeImplBase.
289 class wxAnyValueTypeImpl
: public wxAnyValueTypeImplBase
<T
>
291 WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl
<T
>)
293 wxAnyValueTypeImpl() : wxAnyValueTypeImplBase
<T
>() { }
294 virtual ~wxAnyValueTypeImpl() { }
296 virtual bool ConvertValue(const wxAnyValueBuffer
& src
,
297 wxAnyValueType
* dstType
,
298 wxAnyValueBuffer
& dst
) const
301 wxUnusedVar(dstType
);
308 wxAnyValueTypeImpl
<T
>* wxAnyValueTypeImpl
<T
>::sm_instance
=
309 new wxAnyValueTypeImpl
<T
>();
313 // Helper macro for using same base value type implementation for multiple
314 // actual C++ data types.
316 #define WX_ANY_DEFINE_SUB_TYPE(T, CLSTYPE) \
318 class wxAnyValueTypeImpl<T> : public wxAnyValueTypeImpl##CLSTYPE \
320 typedef wxAnyBase##CLSTYPE##Type UseDataType; \
322 wxAnyValueTypeImpl() : wxAnyValueTypeImpl##CLSTYPE() { } \
323 virtual ~wxAnyValueTypeImpl() { } \
324 static void SetValue(const T& value, wxAnyValueBuffer& buf) \
326 *(reinterpret_cast<UseDataType*>(&buf.m_buffer[0])) = \
327 static_cast<UseDataType>(value); \
329 static T GetValue(const wxAnyValueBuffer& buf) \
331 return static_cast<T>( \
332 *(reinterpret_cast<const UseDataType*>(&buf.m_buffer[0]))); \
338 // Integer value types
342 typedef wxLongLong_t wxAnyBaseIntType
;
343 typedef wxULongLong_t wxAnyBaseUintType
;
345 typedef long wxAnyBaseIntType
;
346 typedef unsigned long wxAnyBaseUintType
;
350 class WXDLLIMPEXP_BASE wxAnyValueTypeImplInt
:
351 public wxAnyValueTypeImplBase
<wxAnyBaseIntType
>
353 WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplInt
)
355 wxAnyValueTypeImplInt() :
356 wxAnyValueTypeImplBase
<wxAnyBaseIntType
>() { }
357 virtual ~wxAnyValueTypeImplInt() { }
359 virtual bool ConvertValue(const wxAnyValueBuffer
& src
,
360 wxAnyValueType
* dstType
,
361 wxAnyValueBuffer
& dst
) const;
365 class WXDLLIMPEXP_BASE wxAnyValueTypeImplUint
:
366 public wxAnyValueTypeImplBase
<wxAnyBaseUintType
>
368 WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplUint
)
370 wxAnyValueTypeImplUint() :
371 wxAnyValueTypeImplBase
<wxAnyBaseUintType
>() { }
372 virtual ~wxAnyValueTypeImplUint() { }
374 virtual bool ConvertValue(const wxAnyValueBuffer
& src
,
375 wxAnyValueType
* dstType
,
376 wxAnyValueBuffer
& dst
) const;
380 WX_ANY_DEFINE_SUB_TYPE(signed long, Int
)
381 WX_ANY_DEFINE_SUB_TYPE(signed int, Int
)
382 WX_ANY_DEFINE_SUB_TYPE(signed short, Int
)
383 WX_ANY_DEFINE_SUB_TYPE(signed char, Int
)
385 WX_ANY_DEFINE_SUB_TYPE(wxLongLong_t
, Int
)
388 WX_ANY_DEFINE_SUB_TYPE(unsigned long, Uint
)
389 WX_ANY_DEFINE_SUB_TYPE(unsigned int, Uint
)
390 WX_ANY_DEFINE_SUB_TYPE(unsigned short, Uint
)
391 WX_ANY_DEFINE_SUB_TYPE(unsigned char, Uint
)
393 WX_ANY_DEFINE_SUB_TYPE(wxULongLong_t
, Uint
)
400 class WXDLLIMPEXP_BASE wxAnyValueTypeImplString
:
401 public wxAnyValueTypeImplBase
<wxString
>
403 WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplString
)
405 wxAnyValueTypeImplString() :
406 wxAnyValueTypeImplBase
<wxString
>() { }
407 virtual ~wxAnyValueTypeImplString() { }
410 Convert value into buffer of different type. Return false if
413 virtual bool ConvertValue(const wxAnyValueBuffer
& src
,
414 wxAnyValueType
* dstType
,
415 wxAnyValueBuffer
& dst
) const;
420 class wxAnyValueTypeImpl
<wxString
> : public wxAnyValueTypeImplString
423 wxAnyValueTypeImpl() : wxAnyValueTypeImplString() { }
424 virtual ~wxAnyValueTypeImpl() { }
432 class WXDLLIMPEXP_BASE wxAnyValueTypeImpl
<bool> :
433 public wxAnyValueTypeImplBase
<bool>
435 WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl
<bool>)
437 wxAnyValueTypeImpl() :
438 wxAnyValueTypeImplBase
<bool>() { }
439 virtual ~wxAnyValueTypeImpl() { }
441 virtual bool ConvertValue(const wxAnyValueBuffer
& src
,
442 wxAnyValueType
* dstType
,
443 wxAnyValueBuffer
& dst
) const;
447 // Floating point value type
449 class WXDLLIMPEXP_BASE wxAnyValueTypeImplDouble
:
450 public wxAnyValueTypeImplBase
<double>
452 WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplDouble
)
454 wxAnyValueTypeImplDouble() :
455 wxAnyValueTypeImplBase
<double>() { }
456 virtual ~wxAnyValueTypeImplDouble() { }
458 virtual bool ConvertValue(const wxAnyValueBuffer
& src
,
459 wxAnyValueType
* dstType
,
460 wxAnyValueBuffer
& dst
) const;
463 // WX_ANY_DEFINE_SUB_TYPE requires this
464 typedef double wxAnyBaseDoubleType
;
466 WX_ANY_DEFINE_SUB_TYPE(float, Double
)
467 WX_ANY_DEFINE_SUB_TYPE(double, Double
)
471 // Defines a dummy wxAnyValueTypeImpl<> with given export
472 // declaration. This is needed if a class is used with
473 // wxAny in both user shared library and application.
475 #define wxDECLARE_ANY_TYPE(CLS, DECL) \
477 class DECL wxAnyValueTypeImpl<CLS> : \
478 public wxAnyValueTypeImplBase<CLS> \
480 WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl<CLS>) \
482 wxAnyValueTypeImpl() : \
483 wxAnyValueTypeImplBase<CLS>() { } \
484 virtual ~wxAnyValueTypeImpl() { } \
486 virtual bool ConvertValue(const wxAnyValueBuffer& src, \
487 wxAnyValueType* dstType, \
488 wxAnyValueBuffer& dst) const \
491 wxUnusedVar(dstType); \
498 // Make sure some of wx's own types get the right wxAnyValueType export
499 // (this is needed only for types that are referred to from wxBase.
500 // currently we may not use any of these types from there, but let's
501 // use the macro on at least one to make sure it compiles since we can't
502 // really test it properly in unittests since a separate DLL would
505 #include "wx/datetime.h"
506 wxDECLARE_ANY_TYPE(wxDateTime
, WXDLLIMPEXP_BASE
)
509 //#include "wx/object.h"
510 //wxDECLARE_ANY_TYPE(wxObject*, WXDLLIMPEXP_BASE)
512 //#include "wx/arrstr.h"
513 //wxDECLARE_ANY_TYPE(wxArrayString, WXDLLIMPEXP_BASE)
518 // Re-enable useless VC6 warnings
519 #pragma warning (pop)
524 Let's define a discrete Null value so we don't have to really
525 ever check if wxAny.m_type pointer is NULL or not. This is an
526 optimization, mostly. Implementation of this value type is
527 "hidden" in the source file.
529 extern WXDLLIMPEXP_DATA_BASE(wxAnyValueType
*) wxAnyNullValueType
;
533 // We need to implement custom signed/unsigned int equals operators
534 // for signed/unsigned (eg. wxAny(128UL) == 128L) comparisons to work.
535 #define WXANY_IMPLEMENT_INT_EQ_OP(TS, TUS) \
536 bool operator==(TS value) const \
538 if ( wxAnyValueTypeImpl<TS>::IsSameClass(m_type) ) \
539 return (value == static_cast<TS> \
540 (wxAnyValueTypeImpl<TS>::GetValue(m_buffer))); \
541 if ( wxAnyValueTypeImpl<TUS>::IsSameClass(m_type) ) \
542 return (value == static_cast<TS> \
543 (wxAnyValueTypeImpl<TUS>::GetValue(m_buffer))); \
546 bool operator==(TUS value) const \
548 if ( wxAnyValueTypeImpl<TUS>::IsSameClass(m_type) ) \
549 return (value == static_cast<TUS> \
550 (wxAnyValueTypeImpl<TUS>::GetValue(m_buffer))); \
551 if ( wxAnyValueTypeImpl<TS>::IsSameClass(m_type) ) \
552 return (value == static_cast<TUS> \
553 (wxAnyValueTypeImpl<TS>::GetValue(m_buffer))); \
559 // The wxAny class represents a container for any type. A variant's value
560 // can be changed at run time, possibly to a different type of value.
562 // As standard, wxAny can store value of almost any type, in a fairly
563 // optimal manner even.
573 m_type
= wxAnyNullValueType
;
581 m_type
->DeleteValue(m_buffer
);
586 Various constructors.
588 wxAny(const char* value
)
590 m_type
= wxAnyNullValueType
;
591 Assign(wxString(value
));
593 wxAny(const wchar_t* value
)
595 m_type
= wxAnyNullValueType
;
596 Assign(wxString(value
));
599 wxAny(const wxAny
& any
)
601 m_type
= wxAnyNullValueType
;
606 wxAny(const T
& value
)
608 m_type
= wxAnyValueTypeImpl
<T
>::sm_instance
;
609 wxAnyValueTypeImpl
<T
>::SetValue(value
, m_buffer
);
614 Use this template function for checking if this wxAny holds
615 a specific C++ data type.
617 @remarks This template function does not work on some older compilers
618 (such as Visual C++ 6.0). For full compiler ccompatibility
619 please use wxANY_CHECK_TYPE(any, T) macro instead.
621 @see wxAnyValueType::CheckType()
623 // FIXME-VC6: remove this hack when VC6 is no longer supported
624 template <typename T
>
625 bool CheckType(T
* = NULL
)
627 return m_type
->CheckType
<T
>();
631 Returns the value type as wxAnyValueType instance.
633 @remarks You cannot reliably test whether two wxAnys are of
634 same value type by simply comparing return values
635 of wxAny::GetType(). Instead use
636 wxAnyValueType::CheckType<T>() template function.
638 const wxAnyValueType
* GetType() const
644 Tests if wxAny is null (that is, whether there is data).
648 return (m_type
== wxAnyNullValueType
);
652 Makes wxAny null (that is, clears it).
656 m_type
->DeleteValue(m_buffer
);
657 m_type
= wxAnyNullValueType
;
662 Assignment operators.
664 wxAny
& operator=(const wxAny
&any
)
672 wxAny
& operator=(const T
&value
)
674 m_type
->DeleteValue(m_buffer
);
675 m_type
= wxAnyValueTypeImpl
<T
>::sm_instance
;
676 wxAnyValueTypeImpl
<T
>::SetValue(value
, m_buffer
);
680 wxAny
& operator=(const char* value
)
681 { Assign(wxString(value
)); return *this; }
682 wxAny
& operator=(const wchar_t* value
)
683 { Assign(wxString(value
)); return *this; }
690 bool operator==(const wxString
& value
) const
692 if ( !wxAnyValueTypeImpl
<wxString
>::IsSameClass(m_type
) )
696 static_cast<wxString
>
697 (wxAnyValueTypeImpl
<wxString
>::GetValue(m_buffer
));
700 bool operator==(const char* value
) const
701 { return (*this) == wxString(value
); }
702 bool operator==(const wchar_t* value
) const
703 { return (*this) == wxString(value
); }
706 // We need to implement custom signed/unsigned int equals operators
707 // for signed/unsigned (eg. wxAny(128UL) == 128L) comparisons to work.
708 WXANY_IMPLEMENT_INT_EQ_OP(signed char, unsigned char)
709 WXANY_IMPLEMENT_INT_EQ_OP(signed short, unsigned short)
710 WXANY_IMPLEMENT_INT_EQ_OP(signed int, unsigned int)
711 WXANY_IMPLEMENT_INT_EQ_OP(signed long, unsigned long)
713 WXANY_IMPLEMENT_INT_EQ_OP(wxLongLong_t
, wxULongLong_t
)
716 bool operator==(float value
) const
718 if ( !wxAnyValueTypeImpl
<float>::IsSameClass(m_type
) )
723 (wxAnyValueTypeImpl
<float>::GetValue(m_buffer
));
726 bool operator==(double value
) const
728 if ( !wxAnyValueTypeImpl
<double>::IsSameClass(m_type
) )
733 (wxAnyValueTypeImpl
<double>::GetValue(m_buffer
));
736 bool operator==(bool value
) const
738 if ( !wxAnyValueTypeImpl
<bool>::IsSameClass(m_type
) )
741 return value
== (wxAnyValueTypeImpl
<bool>::GetValue(m_buffer
));
748 Inequality operators (implement as template).
751 bool operator!=(const T
& value
) const
752 { return !((*this) == value
); }
756 This template function converts wxAny into given type. No dynamic
757 conversion is performed, so if the type is incorrect an assertion
758 failure will occur in debug builds, and a bogus value is returned
761 @remarks This template function does not work on some older compilers
762 (such as Visual C++ 6.0). For full compiler ccompatibility
763 please use wxANY_AS(any, T) macro instead.
765 // FIXME-VC6: remove this hack when VC6 is no longer supported
767 T
As(T
* = NULL
) const
769 if ( !wxAnyValueTypeImpl
<T
>::IsSameClass(m_type
) )
771 wxFAIL_MSG("Incorrect or non-convertible data type");
774 return static_cast<T
>(wxAnyValueTypeImpl
<T
>::GetValue(m_buffer
));
778 Template function that etrieves and converts the value of this
779 variant to the type that T* value is.
781 @return Returns @true if conversion was succesfull.
784 bool GetAs(T
* value
) const
786 if ( !wxAnyValueTypeImpl
<T
>::IsSameClass(m_type
) )
788 wxAnyValueType
* otherType
=
789 wxAnyValueTypeImpl
<T
>::sm_instance
;
790 wxAnyValueBuffer temp_buf
;
792 if ( !m_type
->ConvertValue(m_buffer
, otherType
, temp_buf
) )
796 static_cast<T
>(wxAnyValueTypeImpl
<T
>::GetValue(temp_buf
));
797 otherType
->DeleteValue(temp_buf
);
801 *value
= static_cast<T
>(wxAnyValueTypeImpl
<T
>::GetValue(m_buffer
));
806 // Assignment functions
807 void AssignAny(const wxAny
& any
)
809 // Must delete value - CopyBuffer() never does that
810 m_type
->DeleteValue(m_buffer
);
812 wxAnyValueType
* newType
= any
.m_type
;
814 if ( !newType
->IsSameType(m_type
) )
817 newType
->CopyBuffer(any
.m_buffer
, m_buffer
);
821 void Assign(const T
&value
)
823 m_type
->DeleteValue(m_buffer
);
824 m_type
= wxAnyValueTypeImpl
<T
>::sm_instance
;
825 wxAnyValueTypeImpl
<T
>::SetValue(value
, m_buffer
);
829 wxAnyValueBuffer m_buffer
;
830 wxAnyValueType
* m_type
;
835 // This method of checking the type is compatible with VC6
836 #define wxANY_CHECK_TYPE(any, T) \
837 wxANY_VALUE_TYPE_CHECK_TYPE(any.GetType(), T)
841 // This method of getting the value is compatible with VC6
842 #define wxANY_AS(any, T) \
843 any.As(static_cast<T*>(NULL))
847 inline bool wxAnyValueType::CheckType(T
* reserved
)
849 wxUnusedVar(reserved
);
850 return wxAnyValueTypeImpl
<T
>::IsSameClass(this);