2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #define _LIBCPP_DISABLE_AVAILABILITY
22 #define strtoll _strtoi64
23 #define strtoull _strtoui64
24 #define wcstoll _wcstoi64
25 #define wcstoull _wcstoui64
26 #else // TARGET_WINDOWS
27 #if !defined(TARGET_DARWIN)
28 #define strtoll(str, endptr, base) (int64_t)strtod(str, endptr)
29 #define strtoull(str, endptr, base) (uint64_t)strtod(str, endptr)
30 #define wcstoll(str, endptr, base) (int64_t)wcstod(str, endptr)
31 #define wcstoull(str, endptr, base) (uint64_t)wcstod(str, endptr)
33 #endif // TARGET_WINDOWS
36 // helper type for the visitor
38 struct overloaded
: Ts
...
40 using Ts::operator()...;
42 // explicit deduction guide (not needed as of C++20)
44 overloaded(Ts
...) -> overloaded
<Ts
...>;
46 std::string_view
trim(std::string_view str
)
48 str
.remove_prefix(std::min(str
.find_first_not_of(" \n\r\t"), str
.size()));
49 str
.remove_suffix(str
.size() - std::min(str
.find_last_not_of(" \n\r\t") + 1, str
.size()));
53 std::wstring_view
trim(std::wstring_view str
)
55 str
.remove_prefix(std::min(str
.find_first_not_of(L
" \n\r\t"), str
.size()));
56 str
.remove_suffix(str
.size() - std::min(str
.find_last_not_of(L
" \n\r\t") + 1, str
.size()));
60 int64_t str2int64(std::string_view str
, int64_t fallback
/* = 0 */)
62 std::string_view tmp
= trim(str
);
64 const std::from_chars_result res
= std::from_chars(tmp
.data(), tmp
.data() + tmp
.size(), result
);
65 if (res
.ec
== std::errc())
71 int64_t str2int64(std::wstring_view str
, int64_t fallback
/* = 0 */)
74 std::wstring
tmp(trim(str
));
75 int64_t result
= wcstoll(tmp
.c_str(), &end
, 0);
76 if (end
== NULL
|| *end
== '\0')
82 uint64_t str2uint64(std::string_view str
, uint64_t fallback
/* = 0 */)
84 std::string_view tmp
= trim(str
);
86 const std::from_chars_result res
= std::from_chars(tmp
.data(), tmp
.data() + tmp
.size(), result
);
87 if (res
.ec
== std::errc())
93 uint64_t str2uint64(std::wstring_view str
, uint64_t fallback
/* = 0 */)
96 std::wstring
tmp(trim(str
));
97 uint64_t result
= wcstoull(tmp
.c_str(), &end
, 0);
98 if (end
== NULL
|| *end
== '\0')
104 double str2double(std::string_view str
, double fallback
/* = 0.0 */)
106 std::string_view trimmedStr
= trim(str
);
107 char cStr
[512]; // definitely big enough to hold any floating point number
108 const size_t copySize
= std::min(trimmedStr
.size(), sizeof(cStr
) - 1);
109 std::memcpy(cStr
, trimmedStr
.data(), copySize
);
110 cStr
[copySize
] = '\0';
112 double result
= strtod(cStr
, &end
);
113 if (end
== NULL
|| *end
== '\0')
116 // Use this once std::from_char with double is supported on all platform
117 //std::string_view tmp = trim(str);
119 //const std::from_chars_result res = std::from_chars(tmp.data(), tmp.data() + tmp.size(), result);
120 //if (res.ec == std::errc() && res.ptr == tmp.data() + tmp.size())
126 double str2double(std::wstring_view str
, double fallback
/* = 0.0 */)
128 std::wstring_view trimmedStr
= trim(str
);
129 wchar_t wcStr
[512]; // definitely big enough to hold any floating point number
130 const size_t copySize
= std::min(trimmedStr
.size(), (sizeof(wcStr
) / sizeof(wchar_t)) - 1);
131 std::memcpy(wcStr
, trimmedStr
.data(), copySize
* sizeof(wchar_t));
132 wcStr
[copySize
] = '\0';
133 wchar_t* end
= nullptr;
134 double result
= wcstod(wcStr
, &end
);
135 if (end
== NULL
|| *end
== '\0')
142 : CVariant(VariantTypeNull
)
146 CVariant
CVariant::ConstNullVariant
= CVariant::VariantTypeConstNull
;
147 CVariant::VariantArray
CVariant::EMPTY_ARRAY
;
148 CVariant::VariantMap
CVariant::EMPTY_MAP
;
150 CVariant::CVariant(VariantType type
)
154 case VariantTypeNull
:
157 case VariantTypeConstNull
:
158 m_data
= ConstNull
{};
160 case VariantTypeInteger
:
163 case VariantTypeUnsignedInteger
:
166 case VariantTypeBoolean
:
169 case VariantTypeDouble
:
172 case VariantTypeString
:
173 m_data
= std::string
{};
175 case VariantTypeWideString
:
176 m_data
= std::wstring
{};
178 case VariantTypeArray
:
179 m_data
= VariantArray
{};
181 case VariantTypeObject
:
182 m_data
= VariantMap
{};
187 CVariant::CVariant(int integer
) : m_data(static_cast<int64_t>(integer
))
191 CVariant::CVariant(int64_t integer
) : m_data(integer
)
195 CVariant::CVariant(unsigned int unsignedinteger
) : m_data(static_cast<uint64_t>(unsignedinteger
))
199 CVariant::CVariant(uint64_t unsignedinteger
) : m_data(unsignedinteger
)
203 CVariant::CVariant(double value
) : m_data(value
)
207 CVariant::CVariant(float value
) : m_data(static_cast<double>(value
))
211 CVariant::CVariant(bool boolean
) : m_data(boolean
)
215 CVariant::CVariant(const char* str
) : m_data(std::in_place_type
<std::string
>, str
)
219 CVariant::CVariant(const char* str
, unsigned int length
)
220 : m_data(std::in_place_type
<std::string
>, str
, length
)
224 CVariant::CVariant(const std::string
& str
) : m_data(std::in_place_type
<std::string
>, str
)
228 CVariant::CVariant(std::string
&& str
) : m_data(std::in_place_type
<std::string
>, std::move(str
))
232 CVariant::CVariant(const wchar_t* str
) : m_data(std::in_place_type
<std::wstring
>, str
)
236 CVariant::CVariant(const wchar_t* str
, unsigned int length
)
237 : m_data(std::in_place_type
<std::wstring
>, str
, length
)
241 CVariant::CVariant(const std::wstring
& str
) : m_data(std::in_place_type
<std::wstring
>, str
)
245 CVariant::CVariant(std::wstring
&& str
) : m_data(std::in_place_type
<std::wstring
>, std::move(str
))
249 CVariant::CVariant(const std::vector
<std::string
> &strArray
)
251 VariantArray tmpArray
;
252 tmpArray
.reserve(strArray
.size());
253 for (const auto& item
: strArray
)
254 tmpArray
.emplace_back(item
);
256 m_data
= std::move(tmpArray
);
259 CVariant::CVariant(std::vector
<std::string
>&& strArray
)
261 VariantArray tmpArray
;
262 tmpArray
.reserve(strArray
.size());
263 for (auto& item
: strArray
)
264 tmpArray
.emplace_back(std::move(item
));
266 m_data
= std::move(tmpArray
);
269 CVariant::CVariant(const std::map
<std::string
, std::string
> &strMap
)
272 for (const auto& elem
: strMap
)
273 tmpMap
.emplace(elem
.first
, CVariant(elem
.second
));
275 m_data
= std::move(tmpMap
);
278 CVariant::CVariant(std::map
<std::string
, std::string
>&& strMap
)
281 for (auto& elem
: strMap
)
282 tmpMap
.emplace(elem
.first
, CVariant(std::move(elem
.second
)));
284 m_data
= std::move(tmpMap
);
287 CVariant::CVariant(const std::map
<std::string
, CVariant
>& variantMap
)
288 : m_data(std::in_place_type
<VariantMap
>, variantMap
)
292 CVariant::CVariant(std::map
<std::string
, CVariant
>&& variantMap
)
293 : m_data(std::in_place_type
<VariantMap
>, std::move(variantMap
))
297 CVariant::CVariant(const CVariant
& variant
) : m_data(variant
.m_data
)
301 CVariant::CVariant(CVariant
&& rhs
) noexcept
: m_data(std::move(rhs
.m_data
))
305 CVariant::~CVariant()
310 void CVariant::cleanup()
315 bool CVariant::isInteger() const
317 return isSignedInteger() || isUnsignedInteger();
320 bool CVariant::isSignedInteger() const
322 return std::holds_alternative
<int64_t>(m_data
);
325 bool CVariant::isUnsignedInteger() const
327 return std::holds_alternative
<uint64_t>(m_data
);
330 bool CVariant::isBoolean() const
332 return std::holds_alternative
<bool>(m_data
);
335 bool CVariant::isDouble() const
337 return std::holds_alternative
<double>(m_data
);
340 bool CVariant::isString() const
342 return std::holds_alternative
<std::string
>(m_data
);
345 bool CVariant::isWideString() const
347 return std::holds_alternative
<std::wstring
>(m_data
);
350 bool CVariant::isArray() const
352 return std::holds_alternative
<VariantArray
>(m_data
);
355 bool CVariant::isObject() const
357 return std::holds_alternative
<VariantMap
>(m_data
);
360 bool CVariant::isNull() const
362 return std::holds_alternative
<Null
>(m_data
) || std::holds_alternative
<ConstNull
>(m_data
);
365 CVariant::VariantType
CVariant::type() const
367 return static_cast<VariantType
>(m_data
.index());
370 int64_t CVariant::asInteger(int64_t fallback
) const
372 return std::visit(overloaded
{[](int64_t i
) { return i
; },
373 [](uint64_t u
) { return static_cast<int64_t>(u
); },
374 [](double d
) { return static_cast<int64_t>(d
); },
375 [=](const std::string
& s
) { return str2int64(s
, fallback
); },
376 [=](const std::wstring
& ws
) { return str2int64(ws
, fallback
); },
377 [=](const auto&) { return fallback
; }},
381 int32_t CVariant::asInteger32(int32_t fallback
) const
383 return static_cast<int32_t>(asInteger(fallback
));
386 uint64_t CVariant::asUnsignedInteger(uint64_t fallback
) const
388 return std::visit(overloaded
{[](uint64_t u
) { return u
; },
389 [](int64_t i
) { return static_cast<uint64_t>(i
); },
390 [](double d
) { return static_cast<uint64_t>(d
); },
391 [=](const std::string
& s
) { return str2uint64(s
, fallback
); },
392 [=](const std::wstring
& ws
) { return str2uint64(ws
, fallback
); },
393 [=](const auto&) { return fallback
; }},
397 uint32_t CVariant::asUnsignedInteger32(uint32_t fallback
) const
399 return static_cast<uint32_t>(asUnsignedInteger(fallback
));
402 double CVariant::asDouble(double fallback
) const
406 [](double d
) { return d
; }, [](int64_t i
) { return static_cast<double>(i
); },
407 [](uint64_t u
) { return static_cast<double>(u
); },
408 [=](const std::string
& s
) { return static_cast<double>(str2uint64(s
, fallback
)); },
409 [=](const std::wstring
& ws
) { return static_cast<double>(str2uint64(ws
, fallback
)); },
410 [=](const auto&) { return fallback
; }},
414 float CVariant::asFloat(float fallback
) const
416 return static_cast<float>(asDouble(static_cast<double>(fallback
)));
419 bool CVariant::asBoolean(bool fallback
) const
423 [](bool b
) { return b
; }, [](int64_t i
) { return i
!= 0; },
424 [](uint64_t u
) { return u
!= 0; }, [](double d
) { return d
!= 0; },
425 [](const std::string
& s
) { return !(s
.empty() || s
== "0" || s
== "false"); },
426 [](const std::wstring
& ws
) { return !(ws
.empty() || ws
== L
"0" || ws
== L
"false"); },
427 [=](const auto&) { return fallback
; }},
431 std::string
CVariant::asString(std::string_view fallback
/* = "" */) const&
433 return std::visit(overloaded
{[](const std::string
& s
) { return s
; },
434 [](bool b
) { return std::string(b
? "true" : "false"); },
435 [](int64_t i
) { return std::to_string(i
); },
436 [](uint64_t u
) { return std::to_string(u
); },
437 [](double d
) { return std::to_string(d
); },
438 [=](const auto& a
) { return std::string(fallback
); }},
442 std::string
CVariant::asString(std::string_view fallback
/*= ""*/) &&
444 return std::visit(overloaded
{[](std::string
& s
) { return std::move(s
); },
445 [&](auto&) { return asString(fallback
); }},
449 std::wstring
CVariant::asWideString(std::wstring_view fallback
/* = L"" */) const&
451 return std::visit(overloaded
{[](const std::wstring
& ws
) { return ws
; },
452 [](bool b
) { return std::wstring(b
? L
"true" : L
"false"); },
453 [](int64_t i
) { return std::to_wstring(i
); },
454 [](uint64_t u
) { return std::to_wstring(u
); },
455 [](double d
) { return std::to_wstring(d
); },
456 [=](const auto&) { return std::wstring(fallback
); }},
460 std::wstring
CVariant::asWideString(std::wstring_view fallback
/*= L""*/) &&
462 return std::visit(overloaded
{[](std::wstring
& ws
) { return std::move(ws
); },
463 [&](auto&) { return asWideString(fallback
); }},
467 CVariant
& CVariant::operator[](const std::string
& key
) &
469 if (type() == VariantTypeNull
)
471 m_data
= VariantMap
{};
474 return std::visit(overloaded
{[&](VariantMap
& m
) -> CVariant
& { return m
[key
]; },
475 [](auto&) -> CVariant
& { return ConstNullVariant
; }},
479 const CVariant
& CVariant::operator[](const std::string
& key
) const&
481 return std::visit(overloaded
{[&](const VariantMap
& m
) -> const CVariant
& {
482 auto it
= m
.find(key
);
483 return it
!= m
.cend() ? it
->second
: ConstNullVariant
;
485 [](const auto&) -> const CVariant
& { return ConstNullVariant
; }},
489 CVariant
CVariant::operator[](const std::string
& key
) &&
491 return std::visit(overloaded
{[&](VariantMap
& m
) -> CVariant
{
492 auto it
= m
.find(key
);
493 return it
!= m
.cend() ? std::move(it
->second
) : ConstNullVariant
;
495 [](auto&) -> CVariant
{ return ConstNullVariant
; }},
499 CVariant
& CVariant::operator[](unsigned int position
) &
501 return std::visit(overloaded
{[&](VariantArray
& a
) -> CVariant
& {
502 return a
.size() > position
? a
[position
] : ConstNullVariant
;
504 [](auto&) -> CVariant
& { return ConstNullVariant
; }},
508 const CVariant
& CVariant::operator[](unsigned int position
) const&
510 return std::visit(overloaded
{[&](const VariantArray
& a
) -> const CVariant
& {
511 return a
.size() > position
? a
[position
] : ConstNullVariant
;
513 [](const auto&) -> const CVariant
& { return ConstNullVariant
; }},
517 CVariant
CVariant::operator[](unsigned int position
) &&
519 return std::visit(overloaded
{[&](VariantArray
& a
) -> CVariant
{
520 return a
.size() > position
? std::move(a
[position
])
523 [](auto&) -> CVariant
{ return ConstNullVariant
; }},
527 CVariant
&CVariant::operator=(const CVariant
&rhs
)
529 if (type() == VariantTypeConstNull
|| this == &rhs
)
537 CVariant
& CVariant::operator=(CVariant
&& rhs
) noexcept
539 if (type() == VariantTypeConstNull
|| this == &rhs
)
542 m_data
= std::move(rhs
.m_data
);
546 bool CVariant::operator==(const CVariant
&rhs
) const
548 return m_data
== rhs
.m_data
;
551 void CVariant::reserve(size_t length
)
553 if (type() == VariantTypeNull
)
555 m_data
= VariantArray
{};
557 if (type() == VariantTypeArray
)
558 std::get
<VariantArray
>(m_data
).reserve(length
);
561 void CVariant::push_back(const CVariant
&variant
)
563 if (type() == VariantTypeNull
)
565 m_data
= VariantArray
{};
568 if (type() == VariantTypeArray
)
569 std::get
<VariantArray
>(m_data
).emplace_back(variant
);
572 void CVariant::push_back(CVariant
&&variant
)
574 if (type() == VariantTypeNull
)
576 m_data
= VariantArray
{};
579 if (type() == VariantTypeArray
)
580 std::get
<VariantArray
>(m_data
).emplace_back(std::move(variant
));
583 void CVariant::append(const CVariant
&variant
)
588 void CVariant::append(CVariant
&& variant
)
590 push_back(std::move(variant
));
593 const char *CVariant::c_str() const
595 return std::visit(overloaded
{[](const std::string
& s
) { return s
.c_str(); },
596 [](const auto&) -> const char* { return nullptr; }},
600 void CVariant::swap(CVariant
& rhs
) noexcept
602 std::swap(m_data
, rhs
.m_data
);
605 CVariant::iterator_array
CVariant::begin_array()
607 return std::visit(overloaded
{[](VariantArray
& a
) { return a
.begin(); },
608 [](auto&) { return EMPTY_ARRAY
.begin(); }},
612 CVariant::const_iterator_array
CVariant::begin_array() const
614 return std::visit(overloaded
{[](const VariantArray
& a
) { return a
.cbegin(); },
615 [](const auto&) { return EMPTY_ARRAY
.cbegin(); }},
619 CVariant::iterator_array
CVariant::end_array()
622 overloaded
{[](VariantArray
& a
) { return a
.end(); }, [](auto&) { return EMPTY_ARRAY
.end(); }},
626 CVariant::const_iterator_array
CVariant::end_array() const
628 return std::visit(overloaded
{[](const VariantArray
& a
) { return a
.cend(); },
629 [](const auto&) { return EMPTY_ARRAY
.cend(); }},
633 CVariant::iterator_map
CVariant::begin_map()
636 overloaded
{[](VariantMap
& a
) { return a
.begin(); }, [](auto&) { return EMPTY_MAP
.begin(); }},
640 CVariant::const_iterator_map
CVariant::begin_map() const
642 return std::visit(overloaded
{[](const VariantMap
& a
) { return a
.cbegin(); },
643 [](const auto&) { return EMPTY_MAP
.cbegin(); }},
647 CVariant::iterator_map
CVariant::end_map()
650 overloaded
{[](VariantMap
& a
) { return a
.end(); }, [](auto&) { return EMPTY_MAP
.end(); }},
654 CVariant::const_iterator_map
CVariant::end_map() const
656 return std::visit(overloaded
{[](const VariantMap
& m
) { return m
.cend(); },
657 [](const auto&) { return EMPTY_MAP
.cend(); }},
661 unsigned int CVariant::size() const
663 return std::visit(overloaded
{[](const VariantMap
& m
) { return m
.size(); },
664 [](const VariantArray
& a
) { return a
.size(); },
665 [](const std::string
& s
) { return s
.size(); },
666 [](const std::wstring
& w
) { return w
.size(); },
667 [](const auto&) { return std::size_t(0); }},
671 bool CVariant::empty() const
673 return std::visit(overloaded
{[](const VariantMap
& m
) { return m
.empty(); },
674 [](const VariantArray
& a
) { return a
.empty(); },
675 [](const std::string
& s
) { return s
.empty(); },
676 [](const std::wstring
& w
) { return w
.empty(); },
677 [](const Null
& n
) { return true; },
678 [](const auto&) { return false; }},
682 void CVariant::clear()
684 std::visit(overloaded
{[](VariantMap
& m
) { m
.clear(); }, [](VariantArray
& a
) { a
.clear(); },
685 [](std::string
& s
) { s
.clear(); }, [](std::wstring
& w
) { w
.clear(); },
690 void CVariant::erase(const std::string
&key
)
692 std::visit(overloaded
{[&](Null
&) { m_data
= VariantMap
{}; }, [&](VariantMap
& m
) { m
.erase(key
); },
697 void CVariant::erase(unsigned int position
)
699 std::visit(overloaded
{[&](Null
&) { m_data
= VariantArray
{}; },
700 [=](VariantArray
& a
) { a
.erase(a
.begin() + position
); }, [](auto&) {}},
704 bool CVariant::isMember(const std::string
&key
) const
706 return std::visit(overloaded
{[&](const VariantMap
& m
) { return m
.find(key
) != m
.end(); },
707 [](const auto&) { return false; }},