summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/Variant.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/utils/Variant.cpp')
-rw-r--r--xbmc/utils/Variant.cpp885
1 files changed, 885 insertions, 0 deletions
diff --git a/xbmc/utils/Variant.cpp b/xbmc/utils/Variant.cpp
new file mode 100644
index 0000000..97676f6
--- /dev/null
+++ b/xbmc/utils/Variant.cpp
@@ -0,0 +1,885 @@
1/*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9#include "Variant.h"
10
11#include <stdlib.h>
12#include <string.h>
13#include <utility>
14
15#ifndef strtoll
16#ifdef TARGET_WINDOWS
17#define strtoll _strtoi64
18#define strtoull _strtoui64
19#define wcstoll _wcstoi64
20#define wcstoull _wcstoui64
21#else // TARGET_WINDOWS
22#if !defined(TARGET_DARWIN)
23#define strtoll(str, endptr, base) (int64_t)strtod(str, endptr)
24#define strtoull(str, endptr, base) (uint64_t)strtod(str, endptr)
25#define wcstoll(str, endptr, base) (int64_t)wcstod(str, endptr)
26#define wcstoull(str, endptr, base) (uint64_t)wcstod(str, endptr)
27#endif
28#endif // TARGET_WINDOWS
29#endif // strtoll
30
31std::string trimRight(const std::string &str)
32{
33 std::string tmp = str;
34 // find_last_not_of will return string::npos (which is defined as -1)
35 // or a value between 0 and size() - 1 => find_last_not_of() + 1 will
36 // always result in a valid index between 0 and size()
37 tmp.erase(tmp.find_last_not_of(" \n\r\t") + 1);
38
39 return tmp;
40}
41
42std::wstring trimRight(const std::wstring &str)
43{
44 std::wstring tmp = str;
45 // find_last_not_of will return string::npos (which is defined as -1)
46 // or a value between 0 and size() - 1 => find_last_not_of() + 1 will
47 // always result in a valid index between 0 and size()
48 tmp.erase(tmp.find_last_not_of(L" \n\r\t") + 1);
49
50 return tmp;
51}
52
53int64_t str2int64(const std::string &str, int64_t fallback /* = 0 */)
54{
55 char *end = NULL;
56 std::string tmp = trimRight(str);
57 int64_t result = strtoll(tmp.c_str(), &end, 0);
58 if (end == NULL || *end == '\0')
59 return result;
60
61 return fallback;
62}
63
64int64_t str2int64(const std::wstring &str, int64_t fallback /* = 0 */)
65{
66 wchar_t *end = NULL;
67 std::wstring tmp = trimRight(str);
68 int64_t result = wcstoll(tmp.c_str(), &end, 0);
69 if (end == NULL || *end == '\0')
70 return result;
71
72 return fallback;
73}
74
75uint64_t str2uint64(const std::string &str, uint64_t fallback /* = 0 */)
76{
77 char *end = NULL;
78 std::string tmp = trimRight(str);
79 uint64_t result = strtoull(tmp.c_str(), &end, 0);
80 if (end == NULL || *end == '\0')
81 return result;
82
83 return fallback;
84}
85
86uint64_t str2uint64(const std::wstring &str, uint64_t fallback /* = 0 */)
87{
88 wchar_t *end = NULL;
89 std::wstring tmp = trimRight(str);
90 uint64_t result = wcstoull(tmp.c_str(), &end, 0);
91 if (end == NULL || *end == '\0')
92 return result;
93
94 return fallback;
95}
96
97double str2double(const std::string &str, double fallback /* = 0.0 */)
98{
99 char *end = NULL;
100 std::string tmp = trimRight(str);
101 double result = strtod(tmp.c_str(), &end);
102 if (end == NULL || *end == '\0')
103 return result;
104
105 return fallback;
106}
107
108double str2double(const std::wstring &str, double fallback /* = 0.0 */)
109{
110 wchar_t *end = NULL;
111 std::wstring tmp = trimRight(str);
112 double result = wcstod(tmp.c_str(), &end);
113 if (end == NULL || *end == '\0')
114 return result;
115
116 return fallback;
117}
118
119CVariant::CVariant()
120 : CVariant(VariantTypeNull)
121{
122}
123
124CVariant CVariant::ConstNullVariant = CVariant::VariantTypeConstNull;
125CVariant::VariantArray CVariant::EMPTY_ARRAY;
126CVariant::VariantMap CVariant::EMPTY_MAP;
127
128CVariant::CVariant(VariantType type)
129{
130 m_type = type;
131
132 switch (type)
133 {
134 case VariantTypeInteger:
135 m_data.integer = 0;
136 break;
137 case VariantTypeUnsignedInteger:
138 m_data.unsignedinteger = 0;
139 break;
140 case VariantTypeBoolean:
141 m_data.boolean = false;
142 break;
143 case VariantTypeDouble:
144 m_data.dvalue = 0.0;
145 break;
146 case VariantTypeString:
147 m_data.string = new std::string();
148 break;
149 case VariantTypeWideString:
150 m_data.wstring = new std::wstring();
151 break;
152 case VariantTypeArray:
153 m_data.array = new VariantArray();
154 break;
155 case VariantTypeObject:
156 m_data.map = new VariantMap();
157 break;
158 default:
159#ifndef TARGET_WINDOWS_STORE // this corrupts the heap in Win10 UWP version
160 memset(&m_data, 0, sizeof(m_data));
161#endif
162 break;
163 }
164}
165
166CVariant::CVariant(int integer)
167{
168 m_type = VariantTypeInteger;
169 m_data.integer = integer;
170}
171
172CVariant::CVariant(int64_t integer)
173{
174 m_type = VariantTypeInteger;
175 m_data.integer = integer;
176}
177
178CVariant::CVariant(unsigned int unsignedinteger)
179{
180 m_type = VariantTypeUnsignedInteger;
181 m_data.unsignedinteger = unsignedinteger;
182}
183
184CVariant::CVariant(uint64_t unsignedinteger)
185{
186 m_type = VariantTypeUnsignedInteger;
187 m_data.unsignedinteger = unsignedinteger;
188}
189
190CVariant::CVariant(double value)
191{
192 m_type = VariantTypeDouble;
193 m_data.dvalue = value;
194}
195
196CVariant::CVariant(float value)
197{
198 m_type = VariantTypeDouble;
199 m_data.dvalue = (double)value;
200}
201
202CVariant::CVariant(bool boolean)
203{
204 m_type = VariantTypeBoolean;
205 m_data.boolean = boolean;
206}
207
208CVariant::CVariant(const char *str)
209{
210 m_type = VariantTypeString;
211 m_data.string = new std::string(str);
212}
213
214CVariant::CVariant(const char *str, unsigned int length)
215{
216 m_type = VariantTypeString;
217 m_data.string = new std::string(str, length);
218}
219
220CVariant::CVariant(const std::string &str)
221{
222 m_type = VariantTypeString;
223 m_data.string = new std::string(str);
224}
225
226CVariant::CVariant(std::string &&str)
227{
228 m_type = VariantTypeString;
229 m_data.string = new std::string(std::move(str));
230}
231
232CVariant::CVariant(const wchar_t *str)
233{
234 m_type = VariantTypeWideString;
235 m_data.wstring = new std::wstring(str);
236}
237
238CVariant::CVariant(const wchar_t *str, unsigned int length)
239{
240 m_type = VariantTypeWideString;
241 m_data.wstring = new std::wstring(str, length);
242}
243
244CVariant::CVariant(const std::wstring &str)
245{
246 m_type = VariantTypeWideString;
247 m_data.wstring = new std::wstring(str);
248}
249
250CVariant::CVariant(std::wstring &&str)
251{
252 m_type = VariantTypeWideString;
253 m_data.wstring = new std::wstring(std::move(str));
254}
255
256CVariant::CVariant(const std::vector<std::string> &strArray)
257{
258 m_type = VariantTypeArray;
259 m_data.array = new VariantArray;
260 m_data.array->reserve(strArray.size());
261 for (const auto& item : strArray)
262 m_data.array->push_back(CVariant(item));
263}
264
265CVariant::CVariant(const std::map<std::string, std::string> &strMap)
266{
267 m_type = VariantTypeObject;
268 m_data.map = new VariantMap;
269 for (std::map<std::string, std::string>::const_iterator it = strMap.begin(); it != strMap.end(); ++it)
270 m_data.map->insert(make_pair(it->first, CVariant(it->second)));
271}
272
273CVariant::CVariant(const std::map<std::string, CVariant> &variantMap)
274{
275 m_type = VariantTypeObject;
276 m_data.map = new VariantMap(variantMap.begin(), variantMap.end());
277}
278
279CVariant::CVariant(const CVariant &variant)
280{
281 m_type = VariantTypeNull;
282 *this = variant;
283}
284
285CVariant::CVariant(CVariant&& rhs)
286{
287 //Set this so that operator= don't try and run cleanup
288 //when we're not initialized.
289 m_type = VariantTypeNull;
290
291 *this = std::move(rhs);
292}
293
294CVariant::~CVariant()
295{
296 cleanup();
297}
298
299void CVariant::cleanup()
300{
301 switch (m_type)
302 {
303 case VariantTypeString:
304 delete m_data.string;
305 m_data.string = nullptr;
306 break;
307
308 case VariantTypeWideString:
309 delete m_data.wstring;
310 m_data.wstring = nullptr;
311 break;
312
313 case VariantTypeArray:
314 delete m_data.array;
315 m_data.array = nullptr;
316 break;
317
318 case VariantTypeObject:
319 delete m_data.map;
320 m_data.map = nullptr;
321 break;
322 default:
323 break;
324 }
325 m_type = VariantTypeNull;
326}
327
328bool CVariant::isInteger() const
329{
330 return isSignedInteger() || isUnsignedInteger();
331}
332
333bool CVariant::isSignedInteger() const
334{
335 return m_type == VariantTypeInteger;
336}
337
338bool CVariant::isUnsignedInteger() const
339{
340 return m_type == VariantTypeUnsignedInteger;
341}
342
343bool CVariant::isBoolean() const
344{
345 return m_type == VariantTypeBoolean;
346}
347
348bool CVariant::isDouble() const
349{
350 return m_type == VariantTypeDouble;
351}
352
353bool CVariant::isString() const
354{
355 return m_type == VariantTypeString;
356}
357
358bool CVariant::isWideString() const
359{
360 return m_type == VariantTypeWideString;
361}
362
363bool CVariant::isArray() const
364{
365 return m_type == VariantTypeArray;
366}
367
368bool CVariant::isObject() const
369{
370 return m_type == VariantTypeObject;
371}
372
373bool CVariant::isNull() const
374{
375 return m_type == VariantTypeNull || m_type == VariantTypeConstNull;
376}
377
378CVariant::VariantType CVariant::type() const
379{
380 return m_type;
381}
382
383int64_t CVariant::asInteger(int64_t fallback) const
384{
385 switch (m_type)
386 {
387 case VariantTypeInteger:
388 return m_data.integer;
389 case VariantTypeUnsignedInteger:
390 return (int64_t)m_data.unsignedinteger;
391 case VariantTypeDouble:
392 return (int64_t)m_data.dvalue;
393 case VariantTypeString:
394 return str2int64(*m_data.string, fallback);
395 case VariantTypeWideString:
396 return str2int64(*m_data.wstring, fallback);
397 default:
398 return fallback;
399 }
400
401 return fallback;
402}
403
404int32_t CVariant::asInteger32(int32_t fallback) const
405{
406 return static_cast<int32_t>(asInteger(fallback));
407}
408
409uint64_t CVariant::asUnsignedInteger(uint64_t fallback) const
410{
411 switch (m_type)
412 {
413 case VariantTypeUnsignedInteger:
414 return m_data.unsignedinteger;
415 case VariantTypeInteger:
416 return (uint64_t)m_data.integer;
417 case VariantTypeDouble:
418 return (uint64_t)m_data.dvalue;
419 case VariantTypeString:
420 return str2uint64(*m_data.string, fallback);
421 case VariantTypeWideString:
422 return str2uint64(*m_data.wstring, fallback);
423 default:
424 return fallback;
425 }
426
427 return fallback;
428}
429
430uint32_t CVariant::asUnsignedInteger32(uint32_t fallback) const
431{
432 return static_cast<uint32_t>(asUnsignedInteger(fallback));
433}
434
435double CVariant::asDouble(double fallback) const
436{
437 switch (m_type)
438 {
439 case VariantTypeDouble:
440 return m_data.dvalue;
441 case VariantTypeInteger:
442 return (double)m_data.integer;
443 case VariantTypeUnsignedInteger:
444 return (double)m_data.unsignedinteger;
445 case VariantTypeString:
446 return str2double(*m_data.string, fallback);
447 case VariantTypeWideString:
448 return str2double(*m_data.wstring, fallback);
449 default:
450 return fallback;
451 }
452
453 return fallback;
454}
455
456float CVariant::asFloat(float fallback) const
457{
458 switch (m_type)
459 {
460 case VariantTypeDouble:
461 return (float)m_data.dvalue;
462 case VariantTypeInteger:
463 return (float)m_data.integer;
464 case VariantTypeUnsignedInteger:
465 return (float)m_data.unsignedinteger;
466 case VariantTypeString:
467 return (float)str2double(*m_data.string, fallback);
468 case VariantTypeWideString:
469 return (float)str2double(*m_data.wstring, fallback);
470 default:
471 return fallback;
472 }
473
474 return fallback;
475}
476
477bool CVariant::asBoolean(bool fallback) const
478{
479 switch (m_type)
480 {
481 case VariantTypeBoolean:
482 return m_data.boolean;
483 case VariantTypeInteger:
484 return (m_data.integer != 0);
485 case VariantTypeUnsignedInteger:
486 return (m_data.unsignedinteger != 0);
487 case VariantTypeDouble:
488 return (m_data.dvalue != 0);
489 case VariantTypeString:
490 if (m_data.string->empty() || m_data.string->compare("0") == 0 || m_data.string->compare("false") == 0)
491 return false;
492 return true;
493 case VariantTypeWideString:
494 if (m_data.wstring->empty() || m_data.wstring->compare(L"0") == 0 || m_data.wstring->compare(L"false") == 0)
495 return false;
496 return true;
497 default:
498 return fallback;
499 }
500
501 return fallback;
502}
503
504std::string CVariant::asString(const std::string &fallback /* = "" */) const
505{
506 switch (m_type)
507 {
508 case VariantTypeString:
509 return *m_data.string;
510 case VariantTypeBoolean:
511 return m_data.boolean ? "true" : "false";
512 case VariantTypeInteger:
513 return std::to_string(m_data.integer);
514 case VariantTypeUnsignedInteger:
515 return std::to_string(m_data.unsignedinteger);
516 case VariantTypeDouble:
517 return std::to_string(m_data.dvalue);
518 default:
519 return fallback;
520 }
521
522 return fallback;
523}
524
525std::wstring CVariant::asWideString(const std::wstring &fallback /* = L"" */) const
526{
527 switch (m_type)
528 {
529 case VariantTypeWideString:
530 return *m_data.wstring;
531 case VariantTypeBoolean:
532 return m_data.boolean ? L"true" : L"false";
533 case VariantTypeInteger:
534 return std::to_wstring(m_data.integer);
535 case VariantTypeUnsignedInteger:
536 return std::to_wstring(m_data.unsignedinteger);
537 case VariantTypeDouble:
538 return std::to_wstring(m_data.dvalue);
539 default:
540 return fallback;
541 }
542
543 return fallback;
544}
545
546CVariant &CVariant::operator[](const std::string &key)
547{
548 if (m_type == VariantTypeNull)
549 {
550 m_type = VariantTypeObject;
551 m_data.map = new VariantMap;
552 }
553
554 if (m_type == VariantTypeObject)
555 return (*m_data.map)[key];
556 else
557 return ConstNullVariant;
558}
559
560const CVariant &CVariant::operator[](const std::string &key) const
561{
562 VariantMap::const_iterator it;
563 if (m_type == VariantTypeObject && (it = m_data.map->find(key)) != m_data.map->end())
564 return it->second;
565 else
566 return ConstNullVariant;
567}
568
569CVariant &CVariant::operator[](unsigned int position)
570{
571 if (m_type == VariantTypeArray && size() > position)
572 return m_data.array->at(position);
573 else
574 return ConstNullVariant;
575}
576
577const CVariant &CVariant::operator[](unsigned int position) const
578{
579 if (m_type == VariantTypeArray && size() > position)
580 return m_data.array->at(position);
581 else
582 return ConstNullVariant;
583}
584
585CVariant &CVariant::operator=(const CVariant &rhs)
586{
587 if (m_type == VariantTypeConstNull || this == &rhs)
588 return *this;
589
590 cleanup();
591
592 m_type = rhs.m_type;
593
594 switch (m_type)
595 {
596 case VariantTypeInteger:
597 m_data.integer = rhs.m_data.integer;
598 break;
599 case VariantTypeUnsignedInteger:
600 m_data.unsignedinteger = rhs.m_data.unsignedinteger;
601 break;
602 case VariantTypeBoolean:
603 m_data.boolean = rhs.m_data.boolean;
604 break;
605 case VariantTypeDouble:
606 m_data.dvalue = rhs.m_data.dvalue;
607 break;
608 case VariantTypeString:
609 m_data.string = new std::string(*rhs.m_data.string);
610 break;
611 case VariantTypeWideString:
612 m_data.wstring = new std::wstring(*rhs.m_data.wstring);
613 break;
614 case VariantTypeArray:
615 m_data.array = new VariantArray(rhs.m_data.array->begin(), rhs.m_data.array->end());
616 break;
617 case VariantTypeObject:
618 m_data.map = new VariantMap(rhs.m_data.map->begin(), rhs.m_data.map->end());
619 break;
620 default:
621 break;
622 }
623
624 return *this;
625}
626
627CVariant& CVariant::operator=(CVariant&& rhs)
628{
629 if (m_type == VariantTypeConstNull || this == &rhs)
630 return *this;
631
632 //Make sure that if we're moved into we don't leak any pointers
633 if (m_type != VariantTypeNull)
634 cleanup();
635
636 m_type = rhs.m_type;
637 m_data = std::move(rhs.m_data);
638
639 //Should be enough to just set m_type here
640 //but better safe than sorry, could probably lead to coverity warnings
641 if (rhs.m_type == VariantTypeString)
642 rhs.m_data.string = nullptr;
643 else if (rhs.m_type == VariantTypeWideString)
644 rhs.m_data.wstring = nullptr;
645 else if (rhs.m_type == VariantTypeArray)
646 rhs.m_data.array = nullptr;
647 else if (rhs.m_type == VariantTypeObject)
648 rhs.m_data.map = nullptr;
649
650 rhs.m_type = VariantTypeNull;
651
652 return *this;
653}
654
655bool CVariant::operator==(const CVariant &rhs) const
656{
657 if (m_type == rhs.m_type)
658 {
659 switch (m_type)
660 {
661 case VariantTypeInteger:
662 return m_data.integer == rhs.m_data.integer;
663 case VariantTypeUnsignedInteger:
664 return m_data.unsignedinteger == rhs.m_data.unsignedinteger;
665 case VariantTypeBoolean:
666 return m_data.boolean == rhs.m_data.boolean;
667 case VariantTypeDouble:
668 return m_data.dvalue == rhs.m_data.dvalue;
669 case VariantTypeString:
670 return *m_data.string == *rhs.m_data.string;
671 case VariantTypeWideString:
672 return *m_data.wstring == *rhs.m_data.wstring;
673 case VariantTypeArray:
674 return *m_data.array == *rhs.m_data.array;
675 case VariantTypeObject:
676 return *m_data.map == *rhs.m_data.map;
677 default:
678 break;
679 }
680 }
681
682 return false;
683}
684
685void CVariant::reserve(size_t length)
686{
687 if (m_type == VariantTypeNull)
688 {
689 m_type = VariantTypeArray;
690 m_data.array = new VariantArray;
691 }
692 if (m_type == VariantTypeArray)
693 m_data.array->reserve(length);
694}
695
696void CVariant::push_back(const CVariant &variant)
697{
698 if (m_type == VariantTypeNull)
699 {
700 m_type = VariantTypeArray;
701 m_data.array = new VariantArray;
702 }
703
704 if (m_type == VariantTypeArray)
705 m_data.array->push_back(variant);
706}
707
708void CVariant::push_back(CVariant &&variant)
709{
710 if (m_type == VariantTypeNull)
711 {
712 m_type = VariantTypeArray;
713 m_data.array = new VariantArray;
714 }
715
716 if (m_type == VariantTypeArray)
717 m_data.array->push_back(std::move(variant));
718}
719
720void CVariant::append(const CVariant &variant)
721{
722 push_back(variant);
723}
724
725void CVariant::append(CVariant&& variant)
726{
727 push_back(std::move(variant));
728}
729
730const char *CVariant::c_str() const
731{
732 if (m_type == VariantTypeString)
733 return m_data.string->c_str();
734 else
735 return NULL;
736}
737
738void CVariant::swap(CVariant &rhs)
739{
740 VariantType temp_type = m_type;
741 VariantUnion temp_data = m_data;
742
743 m_type = rhs.m_type;
744 m_data = rhs.m_data;
745
746 rhs.m_type = temp_type;
747 rhs.m_data = temp_data;
748}
749
750CVariant::iterator_array CVariant::begin_array()
751{
752 if (m_type == VariantTypeArray)
753 return m_data.array->begin();
754 else
755 return EMPTY_ARRAY.begin();
756}
757
758CVariant::const_iterator_array CVariant::begin_array() const
759{
760 if (m_type == VariantTypeArray)
761 return m_data.array->begin();
762 else
763 return EMPTY_ARRAY.begin();
764}
765
766CVariant::iterator_array CVariant::end_array()
767{
768 if (m_type == VariantTypeArray)
769 return m_data.array->end();
770 else
771 return EMPTY_ARRAY.end();
772}
773
774CVariant::const_iterator_array CVariant::end_array() const
775{
776 if (m_type == VariantTypeArray)
777 return m_data.array->end();
778 else
779 return EMPTY_ARRAY.end();
780}
781
782CVariant::iterator_map CVariant::begin_map()
783{
784 if (m_type == VariantTypeObject)
785 return m_data.map->begin();
786 else
787 return EMPTY_MAP.begin();
788}
789
790CVariant::const_iterator_map CVariant::begin_map() const
791{
792 if (m_type == VariantTypeObject)
793 return m_data.map->begin();
794 else
795 return EMPTY_MAP.begin();
796}
797
798CVariant::iterator_map CVariant::end_map()
799{
800 if (m_type == VariantTypeObject)
801 return m_data.map->end();
802 else
803 return EMPTY_MAP.end();
804}
805
806CVariant::const_iterator_map CVariant::end_map() const
807{
808 if (m_type == VariantTypeObject)
809 return m_data.map->end();
810 else
811 return EMPTY_MAP.end();
812}
813
814unsigned int CVariant::size() const
815{
816 if (m_type == VariantTypeObject)
817 return m_data.map->size();
818 else if (m_type == VariantTypeArray)
819 return m_data.array->size();
820 else if (m_type == VariantTypeString)
821 return m_data.string->size();
822 else if (m_type == VariantTypeWideString)
823 return m_data.wstring->size();
824 else
825 return 0;
826}
827
828bool CVariant::empty() const
829{
830 if (m_type == VariantTypeObject)
831 return m_data.map->empty();
832 else if (m_type == VariantTypeArray)
833 return m_data.array->empty();
834 else if (m_type == VariantTypeString)
835 return m_data.string->empty();
836 else if (m_type == VariantTypeWideString)
837 return m_data.wstring->empty();
838 else if (m_type == VariantTypeNull)
839 return true;
840
841 return false;
842}
843
844void CVariant::clear()
845{
846 if (m_type == VariantTypeObject)
847 m_data.map->clear();
848 else if (m_type == VariantTypeArray)
849 m_data.array->clear();
850 else if (m_type == VariantTypeString)
851 m_data.string->clear();
852 else if (m_type == VariantTypeWideString)
853 m_data.wstring->clear();
854}
855
856void CVariant::erase(const std::string &key)
857{
858 if (m_type == VariantTypeNull)
859 {
860 m_type = VariantTypeObject;
861 m_data.map = new VariantMap;
862 }
863 else if (m_type == VariantTypeObject)
864 m_data.map->erase(key);
865}
866
867void CVariant::erase(unsigned int position)
868{
869 if (m_type == VariantTypeNull)
870 {
871 m_type = VariantTypeArray;
872 m_data.array = new VariantArray;
873 }
874
875 if (m_type == VariantTypeArray && position < size())
876 m_data.array->erase(m_data.array->begin() + position);
877}
878
879bool CVariant::isMember(const std::string &key) const
880{
881 if (m_type == VariantTypeObject)
882 return m_data.map->find(key) != m_data.map->end();
883
884 return false;
885}