X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c5fe6a5bee092251f08fa204c8857c36af865157..ec080ef1873995bcd9b20b0fc1a6d208a78540d3:/src/common/any.cpp?ds=sidebyside diff --git a/src/common/any.cpp b/src/common/any.cpp index 1b12110c3f..0fa1368257 100644 --- a/src/common/any.cpp +++ b/src/common/any.cpp @@ -27,21 +27,26 @@ #include "wx/vector.h" #include "wx/module.h" +#include "wx/hashmap.h" +#include "wx/hashset.h" using namespace wxPrivate; +#if wxUSE_VARIANT + //------------------------------------------------------------------------- // wxAnyValueTypeGlobals //------------------------------------------------------------------------- +WX_DECLARE_HASH_MAP(wxAnyValueType*, + wxVariantDataFactory, + wxPointerHash, + wxPointerEqual, + wxAnyTypeToVariantDataFactoryMap); + // -// Helper class to manage wxAnyValueType instances and other -// related global variables. -// -// 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). +// Helper class to manage global variables related to type conversion +// between wxAny and wxVariant. // class wxAnyValueTypeGlobals { @@ -51,21 +56,155 @@ public: } ~wxAnyValueTypeGlobals() { - for ( size_t i=0; i(type_); + + wxAnyTypeToVariantDataFactoryMap& anyToVariant = m_anyToVariant; + wxAnyTypeToVariantDataFactoryMap::const_iterator it; + it = anyToVariant.find(type); + if ( it != anyToVariant.end() ) + return it->second; + + // Not found, handle pre-registrations + size_t i = m_anyToVariantRegs.size(); + while ( i > 0 ) + { + i--; + wxAnyToVariantRegistration* reg = m_anyToVariantRegs[i]; + wxAnyValueType* assocType = reg->GetAssociatedType(); + if ( assocType ) + { + // Both variant data and wxAnyValueType have been + // now been properly initialized, so remove the + // pre-registration entry and move data to anyToVarian + // map. + anyToVariant[assocType] = reg->GetFactory(); + m_anyToVariantRegs.erase( m_anyToVariantRegs.begin() + i ); + } + } + + // Then try again + it = anyToVariant.find(type); + if ( it != anyToVariant.end() ) + return it->second; + + // Finally, attempt to find a compatible type + for ( it = anyToVariant.begin(); it != anyToVariant.end(); it++ ) + { + if ( type->IsSameType(it->first) ) + { + wxVariantDataFactory f = it->second; + anyToVariant[type] = f; + return f; + } + } + + // Nothing found + return NULL; } private: - wxVector m_valueTypes; + wxAnyTypeToVariantDataFactoryMap m_anyToVariant; + wxVector m_anyToVariantRegs; }; static wxAnyValueTypeGlobals* g_wxAnyValueTypeGlobals = NULL; + +WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplVariantData) + +void wxPreRegisterAnyToVariant(wxAnyToVariantRegistration* reg) +{ + if ( !g_wxAnyValueTypeGlobals ) + g_wxAnyValueTypeGlobals = new wxAnyValueTypeGlobals(); + g_wxAnyValueTypeGlobals->PreRegisterAnyToVariant(reg); +} + +bool wxConvertAnyToVariant(const wxAny& any, wxVariant* variant) +{ + if ( any.IsNull() ) + { + variant->MakeNull(); + return true; + } + + // (signed) integer is a special case, because there is only one type + // in wxAny, and two ("long" and "longlong") in wxVariant. For better + // backwards compatibility, convert all values that fit in "long", + // and others to "longlong". + if ( wxANY_CHECK_TYPE(any, signed int) ) + { +#ifdef wxLongLong_t + wxLongLong_t ll = 0; + if ( any.GetAs(&ll) ) + { + // NB: Do not use LONG_MAX here. Explicitly using 32-bit + // integer constraint yields more consistent behavior across + // builds. + if ( ll > wxINT32_MAX || ll < wxINT32_MIN ) + *variant = wxLongLong(ll); + else + *variant = (long) wxLongLong(ll).GetLo(); + } + else + { + return false; + } +#else + long l; + if ( any.GetAs(&l) ) + *variant = l; + else + return false; +#endif + return true; + } + + // Find matching factory function + wxVariantDataFactory f = + g_wxAnyValueTypeGlobals->FindVariantDataFactory(any.GetType()); + + wxVariantData* data = NULL; + + if ( f ) + { + data = f(any); + } + else + { + // Check if wxAny wrapped wxVariantData* + if ( !any.GetAs(&data) ) + { + // Ok, one last chance: while unlikely, it is possible that the + // wxAny actually contains wxVariant. + if ( wxANY_CHECK_TYPE(any, wxVariant) ) + *variant = wxANY_AS(any, wxVariant); + return false; + } + + // Wrapper's GetValue() does not increase reference + // count, se have to do it before the data gets passed + // to a new variant. + data->IncRef(); + } + + variant->SetData(data); + return true; +} + // // This class is to make sure that wxAnyValueType instances // etc. get freed correctly. We must use a separate wxAnyValueTypeGlobals @@ -84,26 +223,15 @@ public: } virtual void OnExit() { - delete g_wxAnyValueTypeGlobals; - g_wxAnyValueTypeGlobals = NULL; + wxDELETE(g_wxAnyValueTypeGlobals); } private: }; IMPLEMENT_DYNAMIC_CLASS(wxAnyValueTypeGlobalsManager, wxModule) +#endif // wxUSE_VARIANT -//------------------------------------------------------------------------- -// wxAnyValueType -//------------------------------------------------------------------------- - -wxAnyValueType::wxAnyValueType() -{ - if ( !g_wxAnyValueTypeGlobals ) - g_wxAnyValueTypeGlobals = new wxAnyValueTypeGlobals(); - - g_wxAnyValueTypeGlobals->RegisterValueType(this); -} //------------------------------------------------------------------------- // Dynamic conversion member functions @@ -112,27 +240,23 @@ wxAnyValueType::wxAnyValueType() // // Define integer minimum and maximum as helpers #ifdef wxLongLong_t -const wxAnyBaseIntType UseIntMin = wxINT64_MIN; -const wxAnyBaseUintType UseIntMax = wxINT64_MAX; -const wxAnyBaseUintType UseUintMax = wxUINT64_MAX; + #define UseIntMin (wxINT64_MIN) + #define UseIntMax (wxINT64_MAX) + #define UseUintMax (wxUINT64_MAX) #else -const wxAnyBaseIntType UseIntMin = LONG_MIN; -const wxAnyBaseUintType UseUintMax = ULONG_MAX; -const wxAnyBaseUintType UseIntMax = LONG_MAX; + #define UseIntMin (LONG_MIN) + #define UseIntMax (LONG_MAX) + #define UseUintMax (ULONG_MAX) #endif +namespace +{ + const double UseIntMinF = static_cast(UseIntMin); -#ifndef __VISUALC6__ const double UseIntMaxF = static_cast(UseIntMax); const double UseUintMaxF = static_cast(UseUintMax); -#else -// VC6 doesn't implement conversion from unsigned __int64 to double -const wxAnyBaseIntType UseIntMax0 = static_cast(UseIntMax); -const wxAnyBaseIntType UseUintMax0 = static_cast(UseUintMax); -const double UseIntMaxF = static_cast(UseIntMax0); -const double UseUintMaxF = static_cast(UseUintMax0); -#endif +} // anonymous namespace bool wxAnyValueTypeImplInt::ConvertValue(const wxAnyValueBuffer& src, wxAnyValueType* dstType, @@ -216,12 +340,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 @@ -253,14 +381,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; @@ -335,10 +464,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)