From: Jaakko Salli Date: Thu, 22 Apr 2010 13:51:38 +0000 (+0000) Subject: Allow wxAny to contain 'const char*' or 'const wchar_t*'. This was previously not... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/153107b4021fe0e6c3ad2ed510d3225f138eee83 Allow wxAny to contain 'const char*' or 'const wchar_t*'. This was previously not possible since these pointers were converted to wxString, as convenient means to work with string literals. Now pointers (to string literals) are stored instead, and As(), comparison operators do the type conversion. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64106 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/any.h b/include/wx/any.h index 2e9a9af4e5..64930ef66b 100644 --- a/include/wx/any.h +++ b/include/wx/any.h @@ -403,35 +403,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 -{ - WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplString) -public: - wxAnyValueTypeImplString() : - wxAnyValueTypeImplBase() { } - virtual ~wxAnyValueTypeImplString() { } +#define _WX_ANY_DEFINE_CONVERTIBLE_TYPE(T, TYPENAME, CONVFUNC, GV) \ +class WXDLLIMPEXP_BASE wxAnyValueTypeImpl##TYPENAME : \ + public wxAnyValueTypeImplBase \ +{ \ + WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl##TYPENAME) \ +public: \ + wxAnyValueTypeImpl##TYPENAME() : \ + wxAnyValueTypeImplBase() { } \ + 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 : 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 : 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 @@ -686,16 +706,16 @@ public: wxAnyValueTypeImpl::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::sm_instance; + wxAnyValueTypeImpl::SetValue(value, m_buffer); } - wxAny(const wchar_t* value) { - m_type = wxAnyNullValueType; - Assign(wxString(value)); + m_type = wxAnyValueTypeImpl::sm_instance; + wxAnyValueTypeImpl::SetValue(value, m_buffer); } wxAny(const wxAny& any) @@ -789,11 +809,17 @@ public: } #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; + } //@{ /** @@ -801,12 +827,10 @@ public: */ bool operator==(const wxString& value) const { - if ( !wxAnyValueTypeImpl::IsSameClass(m_type) ) + wxString value2; + if ( !GetAs(&value2) ) return false; - - return value == - static_cast - (wxAnyValueTypeImpl::GetValue(m_buffer)); + return value == value2; } bool operator==(const char* value) const @@ -865,14 +889,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 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 @@ -886,6 +913,19 @@ public: return static_cast(wxAnyValueTypeImpl::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. diff --git a/include/wx/variant.h b/include/wx/variant.h index 852be3bb6b..671db18c65 100644 --- a/include/wx/variant.h +++ b/include/wx/variant.h @@ -404,10 +404,13 @@ private: virtual bool GetAsAny(wxAny* any) const; \ static wxVariantData* VariantDataFactory(const wxAny& any); -#define REGISTER_WXANY_CONVERSION(T, CLASSNAME) \ +#define _REGISTER_WXANY_CONVERSION(T, CLASSNAME, FUNC) \ static wxAnyToVariantRegistrationImpl \ gs_##CLASSNAME##AnyToVariantRegistration = \ - wxAnyToVariantRegistrationImpl(&CLASSNAME::VariantDataFactory); + wxAnyToVariantRegistrationImpl(&FUNC); + +#define REGISTER_WXANY_CONVERSION(T, CLASSNAME) \ +_REGISTER_WXANY_CONVERSION(T, CLASSNAME, CLASSNAME::VariantDataFactory) #define IMPLEMENT_TRIVIAL_WXANY_CONVERSION(T, CLASSNAME) \ bool CLASSNAME::GetAsAny(wxAny* any) const \ diff --git a/interface/wx/any.h b/interface/wx/any.h index 826d2b7a14..2a8a22c3e6 100644 --- a/interface/wx/any.h +++ b/interface/wx/any.h @@ -104,14 +104,17 @@ public: ~wxAny(); /** - 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 may not work properly with Visual C++ - 6. For full compiler compatibility, 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. */ template T As() const; diff --git a/src/common/any.cpp b/src/common/any.cpp index 56e315eb95..ac960455b3 100644 --- a/src/common/any.cpp +++ b/src/common/any.cpp @@ -374,12 +374,16 @@ bool wxAnyValueTypeImplUint::ConvertValue(const wxAnyValueBuffer& src, return true; } -bool wxAnyValueTypeImplString::ConvertValue(const wxAnyValueBuffer& src, - wxAnyValueType* dstType, - wxAnyValueBuffer& dst) const +// Convert wxString to destination wxAny value type +bool wxAnyConvertString(const wxString& value, + wxAnyValueType* dstType, + wxAnyValueBuffer& dst) { - wxString value = GetValue(src); - if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) ) + if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) ) + { + wxAnyValueTypeImpl::SetValue(value, dst); + } + else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) ) { wxAnyBaseIntType value2; #ifdef wxLongLong_t @@ -411,14 +415,15 @@ bool wxAnyValueTypeImplString::ConvertValue(const wxAnyValueBuffer& src, else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, bool) ) { bool value2; - value.MakeLower(); - if ( value == wxS("true") || - value == wxS("yes") || - value == wxS('1') ) + wxString s(value); + s.MakeLower(); + if ( s == wxS("true") || + s == wxS("yes") || + s == wxS('1') ) value2 = true; - else if ( value == wxS("false") || - value == wxS("no") || - value == wxS('0') ) + else if ( s == wxS("false") || + s == wxS("no") || + s == wxS('0') ) value2 = false; else return false; @@ -493,10 +498,13 @@ bool wxAnyValueTypeImplDouble::ConvertValue(const wxAnyValueBuffer& src, WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplInt) WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplUint) -WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplString) WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl) WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplDouble) +WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplwxString) +WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplConstCharPtr) +WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplConstWchar_tPtr) + WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl) //WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl) //WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl) diff --git a/src/common/variant.cpp b/src/common/variant.cpp index 0470d2d4b3..1820f4b8d5 100644 --- a/src/common/variant.cpp +++ b/src/common/variant.cpp @@ -879,6 +879,26 @@ protected: IMPLEMENT_TRIVIAL_WXANY_CONVERSION(wxString, wxVariantDataString) +#if wxUSE_ANY +// This allows converting string literal wxAnys to string variants +wxVariantData* wxVariantDataFromConstCharPAny(const wxAny& any) +{ + return new wxVariantDataString(wxANY_AS(any, const char*)); +} + +wxVariantData* wxVariantDataFromConstWchar_tPAny(const wxAny& any) +{ + return new wxVariantDataString(wxANY_AS(any, const wchar_t*)); +} + +_REGISTER_WXANY_CONVERSION(const char*, + ConstCharP, + wxVariantDataFromConstCharPAny) +_REGISTER_WXANY_CONVERSION(const wchar_t*, + ConstWchar_tP, + wxVariantDataFromConstWchar_tPAny) +#endif + bool wxVariantDataString::Eq(wxVariantData& data) const { wxASSERT_MSG( (data.GetType() == wxT("string")), wxT("wxVariantDataString::Eq: argument mismatch") ); diff --git a/tests/any/anytest.cpp b/tests/any/anytest.cpp index e215f48905..8bdd8a2369 100644 --- a/tests/any/anytest.cpp +++ b/tests/any/anytest.cpp @@ -32,6 +32,7 @@ public: private: CPPUNIT_TEST_SUITE( wxAnyTestCase ); + CPPUNIT_TEST( CheckType ); CPPUNIT_TEST( Equality ); CPPUNIT_TEST( As ); CPPUNIT_TEST( GetAs ); @@ -40,6 +41,7 @@ private: CPPUNIT_TEST( CustomTemplateSpecialization ); CPPUNIT_TEST_SUITE_END(); + void CheckType(); void Equality(); void As(); void GetAs(); @@ -164,6 +166,19 @@ wxAnyTestCase::wxAnyTestCase() m_anyVoidPtr2 = dummyVoidPointer; } +void wxAnyTestCase::CheckType() +{ + wxAny nullAny; + CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(nullAny, wxString)); + + CPPUNIT_ASSERT(wxANY_CHECK_TYPE(m_anyCharString2, const char*)); + CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyCharString2, wxString)); + CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyCharString2, const wchar_t*)); + CPPUNIT_ASSERT(wxANY_CHECK_TYPE(m_anyWcharString2, const wchar_t*)); + CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyWcharString2, wxString)); + CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyWcharString2, const char*)); +} + void wxAnyTestCase::Equality() { // @@ -243,8 +258,12 @@ void wxAnyTestCase::As() wxString k = wxANY_AS(m_anyStringString1, wxString); CPPUNIT_ASSERT(k == "abc"); wxString l = wxANY_AS(m_anyCharString1, wxString); + const char* cptr = wxANY_AS(m_anyCharString1, const char*); CPPUNIT_ASSERT(l == "abc"); + CPPUNIT_ASSERT(cptr); wxString m = wxANY_AS(m_anyWcharString1, wxString); + const wchar_t* wcptr = wxANY_AS(m_anyWcharString1, const wchar_t*); + CPPUNIT_ASSERT(wcptr); CPPUNIT_ASSERT(m == "abc"); bool n = wxANY_AS(m_anyBool1, bool); CPPUNIT_ASSERT(n); @@ -488,6 +507,19 @@ void wxAnyTestCase::wxVariantConversions() CPPUNIT_ASSERT(res); CPPUNIT_ASSERT(variant.GetString() == "ABC"); + // Must be able to build string wxVariant from wxAny built from + // string literal + any = "ABC"; + res = any.GetAs(&variant); + CPPUNIT_ASSERT(res); + CPPUNIT_ASSERT(variant.GetType() == "string"); + CPPUNIT_ASSERT(variant.GetString() == "ABC"); + any = L"ABC"; + res = any.GetAs(&variant); + CPPUNIT_ASSERT(res); + CPPUNIT_ASSERT(variant.GetType() == "string"); + CPPUNIT_ASSERT(variant.GetString() == L"ABC"); + any = vDouble; double d = wxANY_AS(any, double); CPPUNIT_ASSERT_DOUBLES_EQUAL(d, TEST_FLOAT_CONST, FEQ_DELTA);