]> git.saurik.com Git - wxWidgets.git/blame - src/common/any.cpp
Improve wxAny<->wxVariant conversion 64-bit integer tests
[wxWidgets.git] / src / common / any.cpp
CommitLineData
39601a7f
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/any.cpp
3// Purpose: wxAny class, container for any type
4// Author: Jaakko Salli
5// Modified by:
6// Created: 07/05/2009
7// RCS-ID: $Id$
8// Copyright: (c) wxWidgets team
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx/wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16 #pragma hdrstop
17#endif
18
19#include "wx/any.h"
20
21#if wxUSE_ANY
22
23#ifndef WX_PRECOMP
24 #include "wx/math.h"
25 #include "wx/crt.h"
26#endif
27
28#include "wx/vector.h"
29#include "wx/module.h"
0bf14ab8 30#include "wx/hashmap.h"
39601a7f
VZ
31
32using namespace wxPrivate;
33
34//-------------------------------------------------------------------------
35// wxAnyValueTypeGlobals
36//-------------------------------------------------------------------------
37
0bf14ab8
JS
38#if wxUSE_VARIANT
39
40WX_DECLARE_HASH_MAP(wxAnyValueType*,
41 wxVariantDataFactory,
42 wxPointerHash,
43 wxPointerEqual,
44 wxAnyTypeToVariantDataFactoryMap);
45
46#endif
47
39601a7f 48//
0bf14ab8
JS
49// Helper class to manage wxAnyValueType instances and and other
50// related global variables (such as wxAny<->wxVariant type association).
39601a7f
VZ
51//
52// NB: We really need to have wxAnyValueType instances allocated
53// in heap. They are stored as static template member variables,
54// and with them we just can't be too careful (eg. not allocating
55// them in heap broke the type identification in GCC).
56//
57class wxAnyValueTypeGlobals
58{
59public:
60 wxAnyValueTypeGlobals()
61 {
62 }
63 ~wxAnyValueTypeGlobals()
64 {
0bf14ab8
JS
65 #if wxUSE_VARIANT
66 m_anyToVariant.clear();
67 #endif
39601a7f
VZ
68 for ( size_t i=0; i<m_valueTypes.size(); i++ )
69 delete m_valueTypes[i];
70 }
71
72 void RegisterValueType(wxAnyValueType* valueType)
73 {
74 m_valueTypes.push_back(valueType);
75 }
76
0bf14ab8
JS
77#if wxUSE_VARIANT
78 void PreRegisterAnyToVariant(wxAnyToVariantRegistration* reg)
79 {
80 m_anyToVariantRegs.push_back(reg);
81 }
82
83 // Find wxVariantData factory function for given value type,
84 // (or compatible, if possible)
549d99f0 85 wxVariantDataFactory FindVariantDataFactory(const wxAnyValueType* type_)
0bf14ab8 86 {
549d99f0 87 // Ideally we'd have the hash map of type 'const wxAnyValueType*',
dabf03b4
JS
88 // but WX_DECLARE_HASH_MAP() has some trouble with it.
89 wxAnyValueType* type = const_cast<wxAnyValueType*>(type_);
549d99f0 90
0bf14ab8
JS
91 wxAnyTypeToVariantDataFactoryMap& anyToVariant = m_anyToVariant;
92 wxAnyTypeToVariantDataFactoryMap::const_iterator it;
93 it = anyToVariant.find(type);
94 if ( it != anyToVariant.end() )
95 return it->second;
96
97 // Not found, handle pre-registrations
98 size_t i = m_anyToVariantRegs.size();
99 while ( i > 0 )
100 {
101 i--;
102 wxAnyToVariantRegistration* reg = m_anyToVariantRegs[i];
103 wxAnyValueType* assocType = reg->GetAssociatedType();
104 if ( assocType )
105 {
106 // Both variant data and wxAnyValueType have been
107 // now been properly initialized, so remove the
108 // pre-registration entry and move data to anyToVarian
109 // map.
110 anyToVariant[assocType] = reg->GetFactory();
111 m_anyToVariantRegs.erase( m_anyToVariantRegs.begin() + i );
112 }
113 }
114
115 // Then try again
116 it = anyToVariant.find(type);
117 if ( it != anyToVariant.end() )
118 return it->second;
119
120 // Finally, attempt to find a compatible type
121 for ( it = anyToVariant.begin(); it != anyToVariant.end(); it++ )
122 {
123 if ( type->IsSameType(it->first) )
124 {
125 wxVariantDataFactory f = it->second;
126 anyToVariant[type] = f;
127 return f;
128 }
129 }
130
131 // Nothing found
132 return NULL;
133 }
134#endif
135
39601a7f 136private:
0bf14ab8
JS
137 wxVector<wxAnyValueType*> m_valueTypes;
138#if wxUSE_VARIANT
139 wxAnyTypeToVariantDataFactoryMap m_anyToVariant;
140 wxVector<wxAnyToVariantRegistration*> m_anyToVariantRegs;
141#endif
39601a7f
VZ
142};
143
144static wxAnyValueTypeGlobals* g_wxAnyValueTypeGlobals = NULL;
145
0bf14ab8
JS
146#if wxUSE_VARIANT
147
148WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplVariantData)
149
150void wxPreRegisterAnyToVariant(wxAnyToVariantRegistration* reg)
151{
152 if ( !g_wxAnyValueTypeGlobals )
153 g_wxAnyValueTypeGlobals = new wxAnyValueTypeGlobals();
154 g_wxAnyValueTypeGlobals->PreRegisterAnyToVariant(reg);
155}
156
157bool wxConvertAnyToVariant(const wxAny& any, wxVariant* variant)
158{
159 if ( any.IsNull() )
160 {
161 variant->MakeNull();
162 return true;
163 }
164
165 // (signed) integer is a special case, because there is only one type
166 // in wxAny, and two ("long" and "longlong") in wxVariant. For better
167 // backwards compatibility, convert all values that fit in "long",
168 // and others to "longlong".
169 if ( wxANY_CHECK_TYPE(any, signed int) )
170 {
171#ifdef wxLongLong_t
5afecf60 172 wxLongLong_t ll = 0;
0bf14ab8
JS
173 if ( any.GetAs(&ll) )
174 {
175 if ( ll > LONG_MAX )
176 *variant = wxLongLong(ll);
177 else
178 *variant = (long) wxLongLong(ll).GetLo();
179 }
180 else
181 {
182 return false;
183 }
184#else
185 long l;
186 if ( any.GetAs(&l) )
187 *variant = l;
188 else
189 return false;
190#endif
191 return true;
192 }
193
194 // Find matching factory function
195 wxVariantDataFactory f =
196 g_wxAnyValueTypeGlobals->FindVariantDataFactory(any.GetType());
197
5afecf60
JS
198 wxVariantData* data = NULL;
199
0bf14ab8
JS
200 if ( f )
201 {
202 data = f(any);
203 }
204 else
205 {
206 // Check if wxAny wrapped wxVariantData*
207 if ( !any.GetAs(&data) )
0aaed451
JS
208 {
209 // Ok, one last chance: while unlikely, it is possible that the
210 // wxAny actually contains wxVariant.
211 if ( wxANY_CHECK_TYPE(any, wxVariant) )
212 *variant = wxANY_AS(any, wxVariant);
0bf14ab8 213 return false;
0aaed451 214 }
0bf14ab8
JS
215
216 // Wrapper's GetValue() does not increase reference
217 // count, se have to do it before the data gets passed
218 // to a new variant.
219 data->IncRef();
220 }
221
222 variant->SetData(data);
223 return true;
224}
225
226#endif // wxUSE_VARIANT
227
39601a7f
VZ
228//
229// This class is to make sure that wxAnyValueType instances
230// etc. get freed correctly. We must use a separate wxAnyValueTypeGlobals
231// because wxModule itself is instantiated too late.
232//
233class wxAnyValueTypeGlobalsManager : public wxModule
234{
235 DECLARE_DYNAMIC_CLASS(wxAnyValueTypeGlobalsManager)
236public:
237 wxAnyValueTypeGlobalsManager() : wxModule() { }
238 virtual ~wxAnyValueTypeGlobalsManager() { }
239
240 virtual bool OnInit()
241 {
242 return true;
243 }
244 virtual void OnExit()
245 {
246 delete g_wxAnyValueTypeGlobals;
247 g_wxAnyValueTypeGlobals = NULL;
248 }
249private:
250};
251
252IMPLEMENT_DYNAMIC_CLASS(wxAnyValueTypeGlobalsManager, wxModule)
253
254
255//-------------------------------------------------------------------------
256// wxAnyValueType
257//-------------------------------------------------------------------------
258
259wxAnyValueType::wxAnyValueType()
260{
261 if ( !g_wxAnyValueTypeGlobals )
262 g_wxAnyValueTypeGlobals = new wxAnyValueTypeGlobals();
263
264 g_wxAnyValueTypeGlobals->RegisterValueType(this);
265}
266
39601a7f
VZ
267//-------------------------------------------------------------------------
268// Dynamic conversion member functions
269//-------------------------------------------------------------------------
270
271//
272// Define integer minimum and maximum as helpers
273#ifdef wxLongLong_t
982d7f93
VZ
274 #define UseIntMin (wxINT64_MIN)
275 #define UseIntMax (wxINT64_MAX)
276 #define UseUintMax (wxUINT64_MAX)
39601a7f 277#else
982d7f93
VZ
278 #define UseIntMin (LONG_MIN)
279 #define UseIntMax (LONG_MAX)
280 #define UseUintMax (ULONG_MAX)
39601a7f
VZ
281#endif
282
982d7f93
VZ
283namespace
284{
285
39601a7f 286const double UseIntMinF = static_cast<double>(UseIntMin);
39601a7f
VZ
287const double UseIntMaxF = static_cast<double>(UseIntMax);
288const double UseUintMaxF = static_cast<double>(UseUintMax);
39601a7f 289
982d7f93 290} // anonymous namespace
39601a7f
VZ
291
292bool wxAnyValueTypeImplInt::ConvertValue(const wxAnyValueBuffer& src,
293 wxAnyValueType* dstType,
294 wxAnyValueBuffer& dst) const
295{
296 wxAnyBaseIntType value = GetValue(src);
297 if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) )
298 {
299#ifdef wxLongLong_t
300 wxLongLong ll(value);
301 wxString s = ll.ToString();
302#else
303 wxString s = wxString::Format(wxS("%ld"), (long)value);
304#endif
305 wxAnyValueTypeImpl<wxString>::SetValue(s, dst);
306 }
307 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseUintType) )
308 {
309 if ( value < 0 )
310 return false;
311 wxAnyBaseUintType ul = (wxAnyBaseUintType) value;
312 wxAnyValueTypeImplUint::SetValue(ul, dst);
313 }
314 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, double) )
315 {
316 double value2 = static_cast<double>(value);
317 wxAnyValueTypeImplDouble::SetValue(value2, dst);
318 }
319 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, bool) )
320 {
321 bool value2 = value ? true : false;
322 wxAnyValueTypeImpl<bool>::SetValue(value2, dst);
323 }
324 else
325 return false;
326
327 return true;
328}
329
330bool wxAnyValueTypeImplUint::ConvertValue(const wxAnyValueBuffer& src,
331 wxAnyValueType* dstType,
332 wxAnyValueBuffer& dst) const
333{
334 wxAnyBaseUintType value = GetValue(src);
335 if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) )
336 {
337#ifdef wxLongLong_t
338 wxULongLong ull(value);
339 wxString s = ull.ToString();
340#else
341 wxString s = wxString::Format(wxS("%lu"), (long)value);
342#endif
343 wxAnyValueTypeImpl<wxString>::SetValue(s, dst);
344 }
345 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) )
346 {
347 if ( value > UseIntMax )
348 return false;
349 wxAnyBaseIntType l = (wxAnyBaseIntType) value;
350 wxAnyValueTypeImplInt::SetValue(l, dst);
351 }
352 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, double) )
353 {
354#ifndef __VISUALC6__
355 double value2 = static_cast<double>(value);
356#else
357 // VC6 doesn't implement conversion from unsigned __int64 to double
358 wxAnyBaseIntType value0 = static_cast<wxAnyBaseIntType>(value);
359 double value2 = static_cast<double>(value0);
360#endif
361 wxAnyValueTypeImplDouble::SetValue(value2, dst);
362 }
363 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, bool) )
364 {
365 bool value2 = value ? true : false;
366 wxAnyValueTypeImpl<bool>::SetValue(value2, dst);
367 }
368 else
369 return false;
370
371 return true;
372}
373
374bool wxAnyValueTypeImplString::ConvertValue(const wxAnyValueBuffer& src,
375 wxAnyValueType* dstType,
376 wxAnyValueBuffer& dst) const
377{
378 wxString value = GetValue(src);
379 if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) )
380 {
381 wxAnyBaseIntType value2;
382#ifdef wxLongLong_t
383 if ( !value.ToLongLong(&value2) )
384#else
385 if ( !value.ToLong(&value2) )
386#endif
387 return false;
388 wxAnyValueTypeImplInt::SetValue(value2, dst);
389 }
390 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseUintType) )
391 {
392 wxAnyBaseUintType value2;
393#ifdef wxLongLong_t
394 if ( !value.ToULongLong(&value2) )
395#else
396 if ( !value.ToULong(&value2) )
397#endif
398 return false;
399 wxAnyValueTypeImplUint::SetValue(value2, dst);
400 }
401 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, double) )
402 {
403 double value2;
404 if ( !value.ToDouble(&value2) )
405 return false;
406 wxAnyValueTypeImplDouble::SetValue(value2, dst);
407 }
408 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, bool) )
409 {
410 bool value2;
411 value.MakeLower();
412 if ( value == wxS("true") ||
413 value == wxS("yes") ||
414 value == wxS('1') )
415 value2 = true;
416 else if ( value == wxS("false") ||
417 value == wxS("no") ||
418 value == wxS('0') )
419 value2 = false;
420 else
421 return false;
422
423 wxAnyValueTypeImpl<bool>::SetValue(value2, dst);
424 }
425 else
426 return false;
427
428 return true;
429}
430
431bool wxAnyValueTypeImpl<bool>::ConvertValue(const wxAnyValueBuffer& src,
432 wxAnyValueType* dstType,
433 wxAnyValueBuffer& dst) const
434{
435 bool value = GetValue(src);
436 if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) )
437 {
438 wxAnyBaseIntType value2 = static_cast<wxAnyBaseIntType>(value);
439 wxAnyValueTypeImplInt::SetValue(value2, dst);
440 }
441 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseUintType) )
442 {
443 wxAnyBaseIntType value2 = static_cast<wxAnyBaseUintType>(value);
444 wxAnyValueTypeImplUint::SetValue(value2, dst);
445 }
446 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) )
447 {
448 wxString s;
449 if ( value )
450 s = wxS("true");
451 else
452 s = wxS("false");
453 wxAnyValueTypeImpl<wxString>::SetValue(s, dst);
454 }
455 else
456 return false;
457
458 return true;
459}
460
461bool wxAnyValueTypeImplDouble::ConvertValue(const wxAnyValueBuffer& src,
462 wxAnyValueType* dstType,
463 wxAnyValueBuffer& dst) const
464{
465 double value = GetValue(src);
466 if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) )
467 {
468 if ( value < UseIntMinF || value > UseIntMaxF )
469 return false;
470 wxAnyBaseUintType ul = static_cast<wxAnyBaseUintType>(value);
471 wxAnyValueTypeImplUint::SetValue(ul, dst);
472 }
473 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseUintType) )
474 {
475 if ( value < 0.0 || value > UseUintMaxF )
476 return false;
477 wxAnyBaseUintType ul = static_cast<wxAnyBaseUintType>(value);
478 wxAnyValueTypeImplUint::SetValue(ul, dst);
479 }
480 else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) )
481 {
482 wxString s = wxString::Format(wxS("%.14g"), value);
483 wxAnyValueTypeImpl<wxString>::SetValue(s, dst);
484 }
485 else
486 return false;
487
488 return true;
489}
490
491WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplInt)
492WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplUint)
493WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplString)
494WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<bool>)
495WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplDouble)
496
c5fe6a5b
JS
497WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxDateTime>)
498//WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxObject*>)
499//WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxArrayString>)
500
39601a7f
VZ
501//-------------------------------------------------------------------------
502// wxAnyNullValueType implementation
503//-------------------------------------------------------------------------
504
505class wxAnyNullValue
506{
507private:
508 void* m_dummy;
509};
510
511template <>
512class wxAnyValueTypeImpl<wxAnyNullValue> : public wxAnyValueType
513{
514 WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxAnyNullValue>)
515public:
24985a9b 516 // Dummy implementations
39601a7f
VZ
517 virtual void DeleteValue(wxAnyValueBuffer& buf) const
518 {
24985a9b 519 wxUnusedVar(buf);
39601a7f
VZ
520 }
521
39601a7f
VZ
522 virtual void CopyBuffer(const wxAnyValueBuffer& src,
523 wxAnyValueBuffer& dst) const
524 {
525 wxUnusedVar(src);
526 wxUnusedVar(dst);
527 }
528
529 virtual bool ConvertValue(const wxAnyValueBuffer& src,
530 wxAnyValueType* dstType,
531 wxAnyValueBuffer& dst) const
532 {
533 wxUnusedVar(src);
534 wxUnusedVar(dstType);
535 wxUnusedVar(dst);
536 return false;
537 }
538
539private:
540};
541
542WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxAnyNullValue>)
543
544wxAnyValueType* wxAnyNullValueType =
545 wxAnyValueTypeImpl<wxAnyNullValue>::GetInstance();
546
547#endif // wxUSE_ANY