Merge pull request #26148 from ksooo/fix-secondstotimestring-warning
[xbmc.git] / xbmc / utils / Variant.cpp
blob45ab7e19d78365cf4cdd67c5d6f5f1991b37dc69
1 /*
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.
7 */
9 #define _LIBCPP_DISABLE_AVAILABILITY
11 #include "Variant.h"
13 #include <charconv>
14 #include <cstdlib>
15 #include <cstring>
16 #include <string>
17 #include <utility>
18 #include <variant>
20 #ifndef strtoll
21 #ifdef TARGET_WINDOWS
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)
32 #endif
33 #endif // TARGET_WINDOWS
34 #endif // strtoll
36 // helper type for the visitor
37 template<class... Ts>
38 struct overloaded : Ts...
40 using Ts::operator()...;
42 // explicit deduction guide (not needed as of C++20)
43 template<class... Ts>
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()));
50 return str;
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()));
57 return str;
60 int64_t str2int64(std::string_view str, int64_t fallback /* = 0 */)
62 std::string_view tmp = trim(str);
63 int64_t result{};
64 const std::from_chars_result res = std::from_chars(tmp.data(), tmp.data() + tmp.size(), result);
65 if (res.ec == std::errc())
66 return result;
68 return fallback;
71 int64_t str2int64(std::wstring_view str, int64_t fallback /* = 0 */)
73 wchar_t *end = NULL;
74 std::wstring tmp(trim(str));
75 int64_t result = wcstoll(tmp.c_str(), &end, 0);
76 if (end == NULL || *end == '\0')
77 return result;
79 return fallback;
82 uint64_t str2uint64(std::string_view str, uint64_t fallback /* = 0 */)
84 std::string_view tmp = trim(str);
85 uint64_t result{};
86 const std::from_chars_result res = std::from_chars(tmp.data(), tmp.data() + tmp.size(), result);
87 if (res.ec == std::errc())
88 return result;
90 return fallback;
93 uint64_t str2uint64(std::wstring_view str, uint64_t fallback /* = 0 */)
95 wchar_t *end = NULL;
96 std::wstring tmp(trim(str));
97 uint64_t result = wcstoull(tmp.c_str(), &end, 0);
98 if (end == NULL || *end == '\0')
99 return result;
101 return fallback;
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';
111 char* end = nullptr;
112 double result = strtod(cStr, &end);
113 if (end == NULL || *end == '\0')
114 return result;
116 // Use this once std::from_char with double is supported on all platform
117 //std::string_view tmp = trim(str);
118 //double result{};
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())
121 // return result;
123 return fallback;
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')
136 return result;
138 return fallback;
141 CVariant::CVariant()
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)
152 switch (type)
154 case VariantTypeNull:
155 m_data = Null{};
156 break;
157 case VariantTypeConstNull:
158 m_data = ConstNull{};
159 break;
160 case VariantTypeInteger:
161 m_data = int64_t{};
162 break;
163 case VariantTypeUnsignedInteger:
164 m_data = uint64_t{};
165 break;
166 case VariantTypeBoolean:
167 m_data = bool{};
168 break;
169 case VariantTypeDouble:
170 m_data = double{};
171 break;
172 case VariantTypeString:
173 m_data = std::string{};
174 break;
175 case VariantTypeWideString:
176 m_data = std::wstring{};
177 break;
178 case VariantTypeArray:
179 m_data = VariantArray{};
180 break;
181 case VariantTypeObject:
182 m_data = VariantMap{};
183 break;
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)
271 VariantMap tmpMap;
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)
280 VariantMap tmpMap;
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()
307 cleanup();
310 void CVariant::cleanup()
312 m_data = Null{};
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; }},
378 m_data);
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; }},
394 m_data);
397 uint32_t CVariant::asUnsignedInteger32(uint32_t fallback) const
399 return static_cast<uint32_t>(asUnsignedInteger(fallback));
402 double CVariant::asDouble(double fallback) const
404 return std::visit(
405 overloaded{
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; }},
411 m_data);
414 float CVariant::asFloat(float fallback) const
416 return static_cast<float>(asDouble(static_cast<double>(fallback)));
419 bool CVariant::asBoolean(bool fallback) const
421 return std::visit(
422 overloaded{
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; }},
428 m_data);
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); }},
439 m_data);
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); }},
446 m_data);
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); }},
457 m_data);
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); }},
464 m_data);
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; }},
476 m_data);
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; }},
486 m_data);
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; }},
496 m_data);
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; }},
505 m_data);
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; }},
514 m_data);
517 CVariant CVariant::operator[](unsigned int position) &&
519 return std::visit(overloaded{[&](VariantArray& a) -> CVariant {
520 return a.size() > position ? std::move(a[position])
521 : ConstNullVariant;
523 [](auto&) -> CVariant { return ConstNullVariant; }},
524 m_data);
527 CVariant &CVariant::operator=(const CVariant &rhs)
529 if (type() == VariantTypeConstNull || this == &rhs)
530 return *this;
532 cleanup();
533 m_data = rhs.m_data;
534 return *this;
537 CVariant& CVariant::operator=(CVariant&& rhs) noexcept
539 if (type() == VariantTypeConstNull || this == &rhs)
540 return *this;
542 m_data = std::move(rhs.m_data);
543 return *this;
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)
585 push_back(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; }},
597 m_data);
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(); }},
609 m_data);
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(); }},
616 m_data);
619 CVariant::iterator_array CVariant::end_array()
621 return std::visit(
622 overloaded{[](VariantArray& a) { return a.end(); }, [](auto&) { return EMPTY_ARRAY.end(); }},
623 m_data);
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(); }},
630 m_data);
633 CVariant::iterator_map CVariant::begin_map()
635 return std::visit(
636 overloaded{[](VariantMap& a) { return a.begin(); }, [](auto&) { return EMPTY_MAP.begin(); }},
637 m_data);
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(); }},
644 m_data);
647 CVariant::iterator_map CVariant::end_map()
649 return std::visit(
650 overloaded{[](VariantMap& a) { return a.end(); }, [](auto&) { return EMPTY_MAP.end(); }},
651 m_data);
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(); }},
658 m_data);
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); }},
668 m_data);
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; }},
679 m_data);
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(); },
686 [](auto&) {}},
687 m_data);
690 void CVariant::erase(const std::string &key)
692 std::visit(overloaded{[&](Null&) { m_data = VariantMap{}; }, [&](VariantMap& m) { m.erase(key); },
693 [](const auto&) {}},
694 m_data);
697 void CVariant::erase(unsigned int position)
699 std::visit(overloaded{[&](Null&) { m_data = VariantArray{}; },
700 [=](VariantArray& a) { a.erase(a.begin() + position); }, [](auto&) {}},
701 m_data);
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; }},
708 m_data);