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<wxString>(), comparison operators do the type conversion.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64106 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Jaakko Salli 2010-04-22 13:51:38 +00:00
parent a96160b58f
commit 153107b402
6 changed files with 173 additions and 67 deletions

View File

@ -402,36 +402,56 @@ 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 \
{ \
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
//
class WXDLLIMPEXP_BASE wxAnyValueTypeImplString :
public wxAnyValueTypeImplBase<wxString>
{
WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplString)
public:
wxAnyValueTypeImplString() :
wxAnyValueTypeImplBase<wxString>() { }
virtual ~wxAnyValueTypeImplString() { }
/**
Convert value into buffer of different type. Return false if
not possible.
*/
virtual bool ConvertValue(const wxAnyValueBuffer& src,
wxAnyValueType* dstType,
wxAnyValueBuffer& dst) const;
};
template<>
class wxAnyValueTypeImpl<wxString> : public wxAnyValueTypeImplString
{
public:
wxAnyValueTypeImpl() : wxAnyValueTypeImplString() { }
virtual ~wxAnyValueTypeImpl() { }
};
// 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<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;
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;
wxAnyValueTypeImpl<const wchar_t*>::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<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
@ -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<typename T>
@ -886,6 +913,19 @@ 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;
}
/**
Template function that etrieves and converts the value of this
variant to the type that T* value is.

View File

@ -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<T> \
gs_##CLASSNAME##AnyToVariantRegistration = \
wxAnyToVariantRegistrationImpl<T>(&CLASSNAME::VariantDataFactory);
wxAnyToVariantRegistrationImpl<T>(&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 \

View File

@ -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<typename T>
T As() const;

View File

@ -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<wxString>::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<bool>)
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<wxDateTime>)
//WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxObject*>)
//WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxArrayString>)

View File

@ -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") );

View File

@ -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);