Sunshine0.0.5917
Sunshine 0.0.5917
Self-hosted game stream host for Moonlight.
Loading...
Searching...
No Matches
Go to the documentation of this file.
1
5#pragma once
6
7// standard includes
8#include <algorithm>
9#include <array>
10#include <bit>
11#include <condition_variable>
12#include <cstddef>
13#include <memory>
14#include <mutex>
15#include <optional>
16#include <ostream>
17#include <string>
18#include <string_view>
19#include <type_traits>
20#include <variant>
21#include <vector>
22
27#define KITTY_WHILE_LOOP(x, y, z) \
28 { \
29 x; \
30 while (y) z \
31 }
32
33template<typename T>
35
39template<typename T, typename U>
40struct argument_type<T(U)> {
44 using type = U;
45};
46
51#define KITTY_USING_MOVE_T(move_t, t, init_val, z) \
52 \
55 class move_t { \
56 public: \
57 \
60 using element_type = typename argument_type<void(t)>::type; \
61\
62 \
65 move_t(): \
66 el {init_val} { \
67 } \
68 \
73 template<class... Args> \
74 move_t(Args &&...args): \
75 el {std::forward<Args>(args)...} { \
76 } \
77 \
80 move_t(const move_t &) = delete; \
81\
82 \
87 move_t(move_t &&other) noexcept: \
88 el {std::move(other.el)} { \
89 other.el = element_type {init_val}; \
90 } \
91\
92 \
95 move_t &operator=(const move_t &) = delete; \
96\
97 \
103 move_t &operator=(move_t &&other) { \
104 std::swap(el, other.el); \
105 return *this; \
106 } \
107
111 */ \
112 element_type *operator->() { \
113 return &el; \
114 } \
115
118 \
120 const element_type *operator->() const { \
121 return &el; \
122 } \
124
128 \
129 inline element_type release() { \
130 element_type val = std::move(el); \
131 el = element_type {init_val}; \
132 return val; \
133 } \
134\
135 \
138 ~move_t() z \
139\
140 \
143 element_type el; \
144 }
150#define KITTY_DECL_CONSTR(x) \
151 \
154 x(x &&) noexcept = default; \
155
156 * @brief Defaulted move assignment for the generated type. \
157 * \
158 * @return This instance. \
159 */ \
160 x &operator=(x &&) noexcept = default; \
161 \
164 x();
169
170#define KITTY_DEFAULT_CONSTR_MOVE(x) \
171 \
174 x(x &&) noexcept = default; \
175
179 \
180 x &operator=(x &&) noexcept = default;
181
184 * @brief Declare defaulted move construction and assignment that may throw.
185 */
186#define KITTY_DEFAULT_CONSTR_MOVE_THROW(x) \
187
189 \
190 x(x &&) = default; \
191
194 * @return This instance. \
195 */ \
196 x &operator=(x &&) = default; \
197 \
200 x() = default;
201
202/**
203 * @def KITTY_DEFAULT_CONSTR(x)
204 * @brief Declare defaulted copy and move operations for a value type.
205 */
206#define KITTY_DEFAULT_CONSTR(x) \
207 KITTY_DEFAULT_CONSTR_MOVE(x) \
211 x(const x &) noexcept = default; \
212 \
217 x &operator=(const x &) = default;
218
223#define TUPLE_2D(a, b, expr) \
224 decltype(expr) a##_##b = expr; \
225 auto &a = std::get<0>(a##_##b); \
226 auto &b = std::get<1>(a##_##b)
229
232#define TUPLE_2D_REF(a, b, expr) \
233 auto &a##_##b = expr; \
234 auto &a = std::get<0>(a##_##b); \
235 auto &b = std::get<1>(a##_##b)
236
240
241#define TUPLE_3D(a, b, c, expr) \
242 decltype(expr) a##_##b##_##c = expr; \
243 auto &a = std::get<0>(a##_##b##_##c); \
244 auto &b = std::get<1>(a##_##b##_##c); \
245 auto &c = std::get<2>(a##_##b##_##c)
246
248 * @def TUPLE_3D_REF(a, b, c, expr)
249 * @brief Bind all elements of an existing 3-tuple expression to local references.
250 */
251#define TUPLE_3D_REF(a, b, c, expr) \
252 auto &a##_##b##_##c = expr; \
253 auto &a = std::get<0>(a##_##b##_##c); \
254 auto &b = std::get<1>(a##_##b##_##c); \
255 auto &c = std::get<2>(a##_##b##_##c)
256
261#define TUPLE_EL(a, b, expr) \
262 decltype(expr) a##_ = expr; \
263 auto &a = std::get<b>(a##_)
264
269#define TUPLE_EL_REF(a, b, expr) \
270 auto &a = std::get<b>(expr)
271
272namespace util {
273
274 template<template<typename...> class X, class... Y>
275 struct __instantiation_of: public std::false_type {};
276
277 template<template<typename...> class X, class... Y>
278 struct __instantiation_of<X, X<Y...>>: public std::true_type {};
280 template<template<typename...> class X, class T, class... Y>
281 static constexpr auto instantiation_of_v = __instantiation_of<X, T, Y...>::value;
282
283 template<bool V, class X, class Y>
284 struct __either;
285
289 template<class X, class Y>
290 struct __either<true, X, Y> {
294 using type = X;
295 };
296
299 */
300 template<class X, class Y>
301 struct __either<false, X, Y> {
302
305 using type = Y;
306 };
307
308
311 template<bool V, class X, class Y>
312 using either_t = typename __either<V, X, Y>::type;
313
314 template<class... Ts>
315 struct overloaded: Ts... {
316 using Ts::operator()...;
317 };
319
321 template<class... Ts>
322 overloaded(Ts...) -> overloaded<Ts...>;
323
327 template<class T>
328 class FailGuard {
329 public:
330 FailGuard() = delete;
331
337 explicit FailGuard(T &&f) noexcept:
338 _func {std::forward<T>(f)} {
339 }
340
344 * @param other Source object whose state is copied or moved into this object.
345 */
346 FailGuard(FailGuard &&other) noexcept:
347 failure {other.failure},
348 _func {std::move(other._func)} {
349 other.failure = false;
350 }
351
352 FailGuard(const FailGuard &) = delete;
353
354 FailGuard &operator=(const FailGuard &) = delete;
355 FailGuard &operator=(FailGuard &&other) = delete;
356
357 ~FailGuard() noexcept {
358 if (failure) {
359 _func();
360 }
361 }
362
366 void disable() {
367 failure = false;
368 }
369
370 bool failure {true};
371
372 private:
373 T _func;
374 };
375
379 * @param f Callable executed by the helper.
380 * @return Fail guard object that invokes the callable on scope exit.
381 */
382 template<class T>
383 [[nodiscard]] auto fail_guard(T &&f) {
384 return FailGuard<T> {std::forward<T>(f)};
385 }
386
393 template<class T>
394 void append_struct(std::vector<uint8_t> &buf, const T &_struct) {
395 constexpr size_t data_len = sizeof(_struct);
396
397 buf.reserve(data_len);
398
399 auto const *data = reinterpret_cast<std::byte const *>(&_struct);
401 for (size_t x = 0; x < data_len; ++x) {
402 buf.push_back(std::to_integer<uint8_t>(data[x]));
403 }
404 }
405
409 template<class T>
410 class Hex {
411 public:
412
415 using elem_type = T;
416
417 private:
418 const std::array<char, 16> _bits {
419 '0',
420 '1',
421 '2',
422 '3',
423 '4',
424 '5',
425 '6',
426 '7',
427 '8',
428 '9',
429 'A',
430 'B',
431 'C',
432 'D',
433 'E',
434 'F'
435 };
437 std::array<char, sizeof(elem_type) * 2> _hex;
438
439 public:
445 */
446 Hex(const elem_type &elem, bool rev) {
447 if (!rev) {
448 const auto *data = reinterpret_cast<const std::byte *>(&elem) + sizeof(elem_type) - 1;
449 for (auto it = begin(); it < cend();) {
450 *it++ = _bits[std::to_integer<unsigned>(*data) / 16];
451 *it++ = _bits[std::to_integer<unsigned>(*data--) % 16];
452 }
453 } else {
454 const auto *data = reinterpret_cast<const std::byte *>(&elem);
455 for (auto it = begin(); it < cend();) {
456 *it++ = _bits[std::to_integer<unsigned>(*data) / 16];
457 *it++ = _bits[std::to_integer<unsigned>(*data++) % 16];
458 }
459 }
460 }
461
463 * @brief Return an iterator to the first byte in the buffer view.
464 *
465 * @return Iterator to the first element.
466 */
467 char *begin() {
468 return _hex.data();
469 }
470
476 char *end() {
477 return _hex.data() + _hex.size();
478 }
479
485 const char *begin() const {
486 return _hex.data();
488
490
494 const char *end() const {
495 return _hex.data() + _hex.size();
496 }
497
501 * @return Pointer to the first formatted hexadecimal character.
502 */
503 const char *cbegin() const {
504 return _hex.data();
505 }
506
512 const char *cend() const {
513 return _hex.data() + _hex.size();
514 }
515
521 std::string to_string() const {
522 return {begin(), end()};
523 }
524
530 std::string_view to_string_view() const {
531 return {begin(), sizeof(elem_type) * 2};
532 }
533 };
534
542 template<class T>
543 Hex<T> hex(const T &elem, bool rev = false) {
544 return Hex<T>(elem, rev);
545 }
546
553 template<typename T>
554 std::string log_hex(const T &value) {
555 return "0x" + Hex<T>(value, false).to_string();
556 }
557
566 template<class It>
567 std::string hex_vec(It begin, It end, bool rev = false) {
568 auto str_size = 2 * std::distance(begin, end);
569
570 std::string hex;
571 hex.resize(str_size);
572
573 if (begin == end) {
574 return hex;
575 }
576
577 const std::array<char, 16> _bits {
578 '0',
579 '1',
580 '2',
581 '3',
582 '4',
583 '5',
584 '6',
585 '7',
586 '8',
587 '9',
588 'A',
589 'B',
590 'C',
591 'D',
592 'E',
593 'F'
594 };
595
596 if (rev) {
597 for (auto it = std::begin(hex); it < std::end(hex);) {
598 *it++ = _bits[((uint8_t) *begin) / 16];
599 *it++ = _bits[((uint8_t) *begin++) % 16];
600 }
601 } else {
602 --end;
603 for (auto it = std::begin(hex); it < std::end(hex);) {
604 *it++ = _bits[((uint8_t) *end) / 16];
605 *it++ = _bits[((uint8_t) *end--) % 16];
606 }
607 }
608
609 return hex;
610 }
611
614
619 template<class C>
620 std::string hex_vec(C &&c, bool rev = false) {
621 return hex_vec(std::begin(c), std::end(c), rev);
623
633 template<class T>
634 T from_hex(const std::string_view &hex, bool rev = false) {
635 std::array<std::byte, sizeof(T)> buf;
636
637 auto is_convertable = [](char ch) {
638 if (isdigit(ch)) {
639 return true;
640 }
641
642 return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z');
643 };
644
645 auto buf_size = std::min<std::size_t>(std::ranges::count_if(hex, is_convertable) / 2, sizeof(T));
646 auto padding = sizeof(T) - buf_size;
647
648 const char *data = hex.data() + hex.size() - 1;
649
650 auto convert = [](char ch) {
651 if (ch >= '0' && ch <= '9') {
652 return static_cast<std::byte>(ch - '0');
653 }
654
655 const auto lowercase = std::byte {static_cast<unsigned char>(ch)} | std::byte {'a' - 'A'};
656 return static_cast<std::byte>(std::to_integer<unsigned>(lowercase) - 'a' + 10);
657 };
658
659 std::fill_n(buf.begin() + buf_size, padding, std::byte {0});
660
661 std::for_each_n(buf.begin(), buf_size, [&](auto &el) {
662 while (!is_convertable(*data)) {
663 --data;
664 }
665 const auto ch_r = convert(*data--);
666
667 while (!is_convertable(*data)) {
668 --data;
669 }
670 const auto ch_l = convert(*data--);
671
672 el = (ch_l << 4) | ch_r;
673 });
674
675 if (rev) {
676 std::ranges::reverse(buf);
678
679 return std::bit_cast<T>(buf);
680 }
681
685 * @param hex Hexadecimal text to decode.
686 * @param rev Whether bytes should be emitted in reverse order.
687 * @return Value converted from hex vec.
688 */
689 inline std::string from_hex_vec(const std::string &hex, bool rev = false) {
690 std::string buf;
691
692 auto is_convertable = [](char ch) {
693 if (isdigit(ch)) {
694 return true;
695 }
696
697 return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z');
698 };
699
700 auto buf_size = std::ranges::count_if(hex, is_convertable) / 2;
701 buf.resize(buf_size);
702
703 const char *data = hex.data() + hex.size() - 1;
704
705 auto convert = [](char ch) {
706 if (ch >= '0' && ch <= '9') {
707 return static_cast<std::byte>(ch - '0');
708 }
710 const auto lowercase = std::byte {static_cast<unsigned char>(ch)} | std::byte {'a' - 'A'};
711 return static_cast<std::byte>(std::to_integer<unsigned>(lowercase) - 'a' + 10);
712 };
713
714 for (auto &el : buf) {
715 while (!is_convertable(*data)) {
716 --data;
717 }
718 const auto ch_r = convert(*data--);
719
720 while (!is_convertable(*data)) {
721 --data;
722 }
723 const auto ch_l = convert(*data--);
724
725 el = std::to_integer<char>((ch_l << 4) | ch_r);
726 }
727
728 if (rev) {
729 std::ranges::reverse(buf);
730 }
731
732 return buf;
733 }
734
735
738 template<class T>
739 class hash {
740 public:
742 * @brief Value type accepted by the hash functor.
743 */
744 using value_type = T;
745
750 * @return Hash value for the byte representation.
751 */
752 std::size_t operator()(const value_type &value) const {
753 const auto bytes = std::bit_cast<std::array<char, sizeof(value_type)>>(value);
754 return std::hash<std::string_view> {}(std::string_view {bytes.data(), bytes.size()});
755 }
756 };
757
759 * @brief Convert between enum values and their string names.
760 *
761 * @param val Value assigned to the synchronized object.
762 * @return Const reference to the enum's underlying integral storage.
763 */
764 template<class T>
765 auto enm(const T &val) -> const std::underlying_type_t<T> & {
766 return *reinterpret_cast<const std::underlying_type_t<T> *>(&val);
767 }
771
775 template<class T>
776 auto enm(T &val) -> std::underlying_type_t<T> & {
777 return *reinterpret_cast<std::underlying_type_t<T> *>(&val);
778 }
779
780
786 */
787 inline std::int64_t from_chars(const char *begin, const char *end) {
788 if (begin == end) {
789 return 0;
790 }
791
792 std::int64_t res {};
793 std::int64_t mul = 1;
794 while (begin != --end) {
795 res += (std::int64_t) (*end - '0') * mul;
796
797 mul *= 10;
798 }
799
800 return *begin != '-' ? res + (std::int64_t) (*begin - '0') * mul : -res;
801 }
802
804 * @brief Convert from view.
805 *
806 * @param number Integer value to serialize or convert.
807 * @return Value converted from view.
808 */
809 inline std::int64_t from_view(const std::string_view &number) {
810 return from_chars(std::begin(number), std::end(number));
811 }
812
814 * @brief Tagged storage for one of two possible value types.
815 */
816 template<class X, class Y>
817 class Either: public std::variant<std::monostate, X, Y> {
818 public:
819 using std::variant<std::monostate, X, Y>::variant;
820
826 constexpr bool has_left() const {
827 return std::holds_alternative<X>(*this);
828 }
829
835 constexpr bool has_right() const {
836 return std::holds_alternative<Y>(*this);
837 }
838
844 X &left() {
845 return std::get<X>(*this);
846 }
847
853 Y &right() {
854 return std::get<Y>(*this);
855 }
856
857 /**
858 * @brief Return the left-hand alternative held by the variant.
859 *
860 * @return Const reference to the left-hand alternative.
861 */
862 const X &left() const {
863 return std::get<X>(*this);
864 }
865
871 const Y &right() const {
872 return std::get<Y>(*this);
873 }
874 };
875
876 // Compared to std::unique_ptr, it adds the ability to get the address of the pointer itself
880 template<typename T, typename D = std::default_delete<T>>
881 class uniq_ptr {
882 public:
885 */
886 using element_type = T;
889
890 using pointer = element_type *; // NOSONAR(cpp:S5008): Native C handle instantiations must retain HANDLE, PSID, EGLDisplay and VADisplay pointer types.
894 using const_pointer = element_type const *; // NOSONAR(cpp:S5008): Native C handle instantiations must retain HANDLE, PSID, EGLDisplay and VADisplay pointer types.
897 */
898 using deleter_type = D;
899
903 constexpr uniq_ptr() noexcept = default;
904
908#ifndef DOXYGEN
909 explicit(false)
910#endif
911 constexpr uniq_ptr(std::nullptr_t) noexcept:
912 _p {nullptr} {
913 }
914
915 uniq_ptr(const uniq_ptr &other) noexcept = delete;
916 uniq_ptr &operator=(const uniq_ptr &other) noexcept = delete;
917
918
923 template<class V>
924 explicit uniq_ptr(V *p) noexcept:
925 _p {p} {
926 static_assert(std::is_same_v<element_type, void> || std::is_same_v<element_type, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
927 }
934 template<class V>
935#ifndef DOXYGEN
936 explicit(false)
937#endif
938 uniq_ptr(std::unique_ptr<V, deleter_type> &&uniq) noexcept:
939 _p {uniq.release()} {
940 static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
942
946
948 template<class V>
949#ifndef DOXYGEN
950 explicit(false)
951#endif
953 _p {other.release()} {
954 static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
955 }
956
961 * @return Reference returned by the operator overload.
962 */
963 template<class V>
964 uniq_ptr &operator=(uniq_ptr<V, deleter_type> &&other) noexcept {
965 static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
966 reset(other.release());
967
968 return *this;
969 }
973
977 template<class V>
978 uniq_ptr &operator=(std::unique_ptr<V, deleter_type> &&uniq) noexcept {
979 static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
980
981 reset(uniq.release());
982
983 return *this;
984 }
985
986 ~uniq_ptr() {
987 reset();
989
991
995 void reset(pointer p = pointer()) {
996 if (_p) {
998 }
999
1000 _p = p;
1001 }
1002
1006 * @return Reference count or status returned after releasing the object.
1007 */
1008 pointer release() {
1009 auto tmp = _p;
1010 _p = nullptr;
1011 return tmp;
1012 }
1013
1015 * @brief Return the currently wrapped value or handle.
1016 *
1017 * @return Underlying native handle or object pointer.
1018 */
1019 pointer get() {
1020 return _p;
1021 }
1022
1024 * @brief Return the currently wrapped value or handle.
1025 *
1026 * @return Underlying native handle or object pointer.
1027 */
1028 const_pointer get() const {
1029 return _p;
1030 }
1031
1033 * @brief Dereference the managed pointer.
1034 *
1035 * @return Const reference to the pointed-to object.
1036 */
1037 std::add_lvalue_reference_t<element_type const> operator*() const {
1038 return *_p;
1039 }
1043
1046 std::add_lvalue_reference_t<element_type> operator*() {
1047 return *_p;
1048 }
1049
1055 const_pointer operator->() const {
1056 return _p;
1058
1060
1064 pointer operator->() {
1065 return _p;
1066 }
1067
1069 * @brief Expose the stored pointer address for C APIs that write handles.
1070 *
1071 * @return Address of the stored pointer.
1072 */
1073 pointer *operator&() const {
1074 return &_p;
1075 }
1076
1082 pointer *operator&() {
1083 return &_p;
1084 }
1085
1091 deleter_type &get_deleter() {
1092 return _deleter;
1094
1096
1100 const deleter_type &get_deleter() const {
1101 return _deleter;
1102 }
1103
1105 * @brief Check whether the wrapper currently owns a non-null pointer.
1106 */
1107 explicit operator bool() const {
1108 return _p != nullptr;
1109 }
1110
1111 protected:
1112 pointer _p {nullptr};
1113 deleter_type _deleter;
1114 };
1115
1117 * @brief Compare two Sunshine unique pointers by their stored addresses.
1118 *
1119 * @param x Left-hand pointer or value being compared.
1120 * @param y Right-hand pointer or value being compared.
1121 * @return True when both wrappers store the same pointer address.
1122 */
1123 template<class T1, class D1, class T2, class D2>
1124 bool operator==(const uniq_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
1125 return x.get() == y.get();
1126 }
1127
1128 /**
1129 * @brief Compare two Sunshine unique pointers by their stored addresses.
1130 *
1131 * @param x Left-hand pointer or value being compared.
1132 * @param y Right-hand pointer or value being compared.
1133 * @return True when the wrappers store different pointer addresses.
1134 */
1135 template<class T1, class D1, class T2, class D2>
1136 bool operator!=(const uniq_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
1137 return x.get() != y.get();
1138 }
1142
1147 template<class T1, class D1, class T2, class D2>
1148 bool operator==(const std::unique_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
1149 return x.get() == y.get();
1151
1153
1159 template<class T1, class D1, class T2, class D2>
1160 bool operator!=(const std::unique_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
1161 return x.get() != y.get();
1162 }
1163
1164
1171 template<class T1, class D1, class T2, class D2>
1172 bool operator==(const uniq_ptr<T1, D1> &x, const std::unique_ptr<T1, D1> &y) {
1173 return x.get() == y.get();
1174 }
1175
1179 * @param x Left-hand pointer or value being compared.
1180 * @param y Right-hand pointer or value being compared.
1181 * @return True when the wrappers store different pointer addresses.
1182 */
1183 template<class T1, class D1, class T2, class D2>
1184 bool operator!=(const uniq_ptr<T1, D1> &x, const std::unique_ptr<T1, D1> &y) {
1185 return x.get() != y.get();
1187
1194 template<class T, class D>
1195 bool operator==(const uniq_ptr<T, D> &x, std::nullptr_t) {
1196 return !(bool) x;
1197 }
1198
1205 template<class T, class D>
1206 bool operator!=(const uniq_ptr<T, D> &x, std::nullptr_t) {
1207 return (bool) x;
1208 }
1209
1216 template<class T, class D>
1217 bool operator==(std::nullptr_t, const uniq_ptr<T, D> &y) {
1218 return !(bool) y;
1220
1223
1227 template<class T, class D>
1228 bool operator!=(std::nullptr_t, const uniq_ptr<T, D> &y) {
1229 return (bool) y;
1230 }
1231
1233
1235 template<class P>
1236 using shared_t = std::shared_ptr<typename P::element_type>;
1237
1239 * @brief Create a shared object or message.
1240 *
1241 * @param pointer Raw pointer adopted by the safe pointer wrapper.
1242 * @return Constructed shared object.
1243 */
1244 template<class P, class T>
1246 return shared_t<P>(reinterpret_cast<typename P::pointer>(pointer), typename P::deleter_type());
1247 }
1248
1252 template<class T>
1253 class wrap_ptr {
1254 public:
1258 using element_type = T;
1262 using pointer = element_type *;
1263
1266 using const_pointer = element_type const *;
1270 using reference = element_type &;
1271 /**
1272 * @brief Const reference type exposed by the pointer wrapper.
1273 */
1274 using const_reference = element_type const &;
1275
1276 wrap_ptr():
1277 _own_ptr {false},
1278 _p {nullptr} {
1279 }
1280
1286 explicit wrap_ptr(pointer p):
1287 _own_ptr {false},
1288 _p {p} {
1289 }
1290
1295
1296 explicit wrap_ptr(std::unique_ptr<element_type> &&uniq_p):
1297 _own_ptr {true},
1298 _p {uniq_p.release()} {
1299 }
1300
1306 wrap_ptr(wrap_ptr &&other):
1307 _own_ptr {other._own_ptr},
1308 _p {other._p} {
1309 other._own_ptr = false;
1310 }
1311
1312
1318 wrap_ptr &operator=(wrap_ptr &&other) noexcept {
1319 if (_own_ptr) {
1320 delete _p;
1321 }
1322
1323 _p = other._p;
1324
1325 _own_ptr = other._own_ptr;
1326 other._own_ptr = false;
1328 return *this;
1329 }
1330
1337 template<class V>
1338 wrap_ptr &operator=(std::unique_ptr<V> &&uniq_ptr) {
1339 static_assert(std::is_base_of_v<element_type, V>, "element_type must be base class of V");
1340 _own_ptr = true;
1341 _p = uniq_ptr.release();
1342
1343 return *this;
1344 }
1345
1352 wrap_ptr &operator=(pointer p) {
1353 if (_own_ptr) {
1354 delete _p;
1355 }
1357 _p = p;
1358 _own_ptr = false;
1359
1360 return *this;
1361 }
1364 if (_own_ptr) {
1365 delete _p;
1366 }
1367
1368 _own_ptr = false;
1369 }
1373
1376 const_reference operator*() const {
1377 return *_p;
1381
1385 reference operator*() {
1386 return *_p;
1387 }
1388
1394 const_pointer operator->() const {
1395 return _p;
1396 }
1397
1398 /**
1399 * @brief Access members of the wrapped pointer.
1400 *
1401 * @return Mutable pointer to the wrapped object.
1402 */
1403 pointer operator->() {
1404 return _p;
1405 }
1406
1407 private:
1408 bool _own_ptr;
1409 pointer _p;
1410 };
1411
1412 template<class T>
1413
1416 constexpr bool is_pointer_v =
1417 instantiation_of_v<std::unique_ptr, T> ||
1418 instantiation_of_v<std::shared_ptr, T> ||
1419 instantiation_of_v<uniq_ptr, T> ||
1420 std::is_pointer_v<T>;
1421
1422 template<class T, class V = void>
1423 struct __false_v;
1424
1428 template<class T>
1429 struct __false_v<T, std::enable_if_t<instantiation_of_v<std::optional, T>>> {
1430 static constexpr std::nullopt_t value = std::nullopt;
1432
1436 template<class T>
1437 struct __false_v<T, std::enable_if_t<is_pointer_v<T>>> {
1438 static constexpr std::nullptr_t value = nullptr;
1439 };
1440
1444 template<class T>
1445 struct __false_v<T, std::enable_if_t<std::is_same_v<T, bool>>> {
1446 static constexpr bool value = false;
1447 };
1448
1449 template<class T>
1450 static constexpr auto false_v = __false_v<T>::value;
1451
1455 template<class T>
1456 using optional_t = either_t<
1457 (std::is_same_v<T, bool> || is_pointer_v<T>),
1458 T,
1459 std::optional<T>>;
1460
1464 template<class T>
1465 class buffer_t {
1466 public:
1467 buffer_t():
1468 _els {0} {};
1469
1475 buffer_t(buffer_t &&o) noexcept:
1476 _els {o._els},
1477 _buf {std::move(o._buf)} {
1478 o._els = 0;
1479 }
1480
1486 buffer_t(const buffer_t &o):
1487 _els {o._els},
1488 _buf(_els) {
1489 std::ranges::copy(o, begin());
1490 }
1491
1495 * @param o Source object used for comparison or assignment.
1496 * @return Reference returned by the operator overload.
1497 */
1498 buffer_t &operator=(buffer_t &&o) noexcept {
1499 std::swap(_els, o._els);
1500 std::swap(_buf, o._buf);
1501
1502 return *this;
1504
1506
1510 explicit buffer_t(size_t elements):
1511 _els {elements},
1512 _buf(elements) {
1513 }
1514
1515
1521 explicit buffer_t(size_t elements, const T &t):
1522 _els {elements},
1523 _buf(elements) {
1524 std::fill_n(_buf.data(), elements, t);
1525 }
1526
1530 * @param el Zero-based element index.
1531 * @return Mutable reference to the requested element.
1532 */
1533 T &operator[](size_t el) {
1534 return _buf[el];
1535 }
1536
1538
1543 const T &operator[](size_t el) const {
1544 return _buf[el];
1545 }
1546
1547 /**
1548 * @brief Return the serialized size of the current object.
1549 *
1550 * @return Number of elements currently stored.
1551 */
1552 size_t size() const {
1553 return _els;
1554 }
1555
1559 * @param els Elements used to initialize the buffer.
1560 */
1561 void fake_resize(std::size_t els) {
1562 _els = els;
1564
1565
1570 T *begin() {
1571 return _buf.data();
1572 }
1573
1579 const T *begin() const {
1580 return _buf.data();
1582
1584
1585
1588 T *end() {
1589 return _buf.data() + _els;
1591
1597 const T *end() const {
1598 return _buf.data() + _els;
1599 }
1600
1601 private:
1602 size_t _els;
1603 std::vector<T> _buf;
1604 };
1608
1613 template<class T>
1614 T either(std::optional<T> &&l, T &&r) {
1615 if (l) {
1616 return std::move(*l);
1617 }
1618
1619 return std::forward<T>(r);
1620 }
1621
1625 template<class ReturnType, class... Args>
1626 struct Function {
1630 using type = ReturnType (*)(Args...);
1631 };
1632
1636 template<class T, class ReturnType, typename Function<ReturnType, T>::type function>
1637 struct Destroy {
1641 using pointer = T; // NOSONAR(cpp:S5008): Native C handle instantiations must retain HANDLE, PSID, EGLDisplay and VADisplay pointer types.
1642
1646 * @param p Pointer to release.
1647 */
1648 void operator()(pointer p) const {
1649 function(p);
1650 }
1651 };
1652
1656 template<class T, typename Function<void, T *>::type function>
1658
1659 // You cannot specialize an alias
1663 template<class T, class ReturnType, typename Function<ReturnType, T *>::type function>
1671 template<class T>
1672 void c_free(T *p) {
1673 free(p);
1674 }
1675
1681 template<class T, class ReturnType, ReturnType (**function)(T *)>
1682 void dynamic(T *p) {
1683 (*function)(p);
1684 }
1685
1689 template<class T, void (**function)(T *)>
1691
1695 template<class T, class ReturnType, ReturnType (**function)(T *)>
1701 template<class T>
1703
1704
1711 template<class It>
1712 std::string_view view(It begin, It end) {
1713 return std::string_view {(const char *) begin, (std::size_t) (end - begin)};
1714 }
1715
1719 * @param data Payload or state data to serialize, deserialize, or forward.
1720 * @return String view over the contiguous object's bytes.
1721 */
1722 template<class T>
1723 std::string_view view(const T &data) {
1724 return std::string_view((const char *) &data, sizeof(T));
1725 }
1726
1728
1730 struct point_t {
1731 double x;
1732 double y;
1733
1735 * @brief Operator.
1736 */
1737 friend std::ostream &operator<<(std::ostream &os, const point_t &p) {
1738 return (os << "Point(x: " << p.x << ", y: " << p.y << ")");
1739 }
1740 };
1741
1742 namespace endian {
1744
1745
1746 template<class T = void>
1747 struct endianness {
1748 enum : bool {
1749#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \
1750 defined(__BIG_ENDIAN__) || \
1751 defined(__ARMEB__) || \
1752 defined(__THUMBEB__) || \
1753 defined(__AARCH64EB__) || \
1754 defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
1755 // It's a big-endian target architecture
1756 little = false,
1757#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \
1758 defined(__LITTLE_ENDIAN__) || \
1759 defined(__ARMEL__) || \
1760 defined(__THUMBEL__) || \
1761 defined(__AARCH64EL__) || \
1762 defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
1763 defined(_WIN32)
1764 little = true,
1765#else
1766 #error "Unknown Endianness"
1767#endif
1768 big = !little
1769 };
1770 };
1771
1772 template<class T, class S = void>
1773 struct endian_helper {};
1774
1778 template<class T>
1779 struct endian_helper<T, std::enable_if_t<!(instantiation_of_v<std::optional, T>)>> {
1786 static inline T big(T x) {
1787 if constexpr (endianness<T>::little) {
1788 auto *data = reinterpret_cast<std::byte *>(&x);
1789
1790 std::reverse(data, data + sizeof(x));
1791 }
1792
1793 return x;
1794 }
1795
1799 * @param x Value to convert.
1800 * @return Value represented in little-endian byte order.
1801 */
1802 static inline T little(T x) {
1803 if constexpr (endianness<T>::big) {
1804 auto *data = reinterpret_cast<std::byte *>(&x);
1805
1806 std::reverse(data, data + sizeof(x));
1807 }
1808
1809 return x;
1811 };
1812
1813
1816 template<class T>
1817 struct endian_helper<T, std::enable_if_t<instantiation_of_v<std::optional, T>>> {
1824 static inline T little(T x) {
1825 if (!x) {
1826 return x;
1827 }
1828
1829 if constexpr (endianness<T>::big) {
1830 auto *data = reinterpret_cast<std::byte *>(&*x);
1831
1832 std::reverse(data, data + sizeof(*x));
1833 }
1834
1835 return x;
1836 }
1837
1844 static inline T big(T x) {
1845 if (!x) {
1846 return x;
1847 }
1848
1849 if constexpr (endianness<T>::little) {
1850 auto *data = reinterpret_cast<std::byte *>(&*x);
1851
1852 std::reverse(data, data + sizeof(*x));
1853 }
1854
1855 return x;
1856 }
1857 };
1858
1865 template<class T>
1866 inline auto little(T x) {
1867 return endian_helper<T>::little(x);
1868 }
1869
1876 template<class T>
1877 inline auto big(T x) {
1878 return endian_helper<T>::big(x);
1879 }
1880 } // namespace endian
1881} // namespace util
Tagged storage for one of two possible value types.
Definition utility.h:750
Scope guard that runs a cleanup action unless it is disabled.
Definition utility.h:261
void disable()
Disable the fail guard so destruction will not run the cleanup action.
Definition utility.h:299
bool failure
Whether the fail guard should run its cleanup action.
Definition utility.h:303
Formatter that exposes a value's bytes as hexadecimal text.
Definition utility.h:343
char * end()
Return an iterator one past the final byte in the buffer view.
Definition utility.h:409
std::string to_string() const
Convert to string.
Definition utility.h:454
const char * cend() const
Return a const iterator one past the last byte in the view.
Definition utility.h:445
char * begin()
Return an iterator to the first byte in the buffer view.
Definition utility.h:400
std::string_view to_string_view() const
Convert to string view.
Definition utility.h:463
const char * cbegin() const
Return a const iterator to the first byte in the view.
Definition utility.h:436
Hex(const elem_type &elem, bool rev)
Format the supplied object's byte representation as hexadecimal text.
Definition utility.h:379
T elem_type
Integral type used for one formatted hex element.
Definition utility.h:348
Owning contiguous buffer with an explicit logical element count.
Definition utility.h:1398
std::uint8_t & operator[](size_t el)
Definition utility.h:1466
buffer_t & operator=(buffer_t &&o) noexcept
Definition utility.h:1431
std::uint8_t * begin()
Definition utility.h:1503
Unique pointer wrapper with customizable pointer and deleter types.
Definition utility.h:814
element_type const * const_pointer
Definition utility.h:827
void reset(pointer p=pointer())
Definition utility.h:928
std::add_lvalue_reference_t< element_type const > operator*() const
Definition utility.h:970
safe_hlocal_deleter deleter_type
Definition utility.h:831
Pointer wrapper that may borrow or own the pointee.
Definition utility.h:1186
element_type const & const_reference
Const reference type exposed by the pointer wrapper.
Definition utility.h:1207
element_type & reference
Mutable reference type exposed by the pointer wrapper.
Definition utility.h:1203
element_type * pointer
Mutable pointer type exposed by the pointer wrapper.
Definition utility.h:1195
element_type const * const_pointer
Const pointer type exposed by the pointer wrapper.
Definition utility.h:1199
T element_type
Object type referenced by the pointer wrapper.
Definition utility.h:1191
wrap_ptr & operator=(wrap_ptr &&other) noexcept
Assign state from another instance while preserving ownership semantics.
Definition utility.h:1251
sha256_t hash(const std::string_view &plaintext)
Hashes the given plaintext using SHA-256.
Definition crypto.cpp:341
U type
Type extracted from the matched function signature.
Definition utility.h:44
Definition utility.h:34
Deleter adapter that destroys the wrapped pointer.
Definition utility.h:1570
Callable wrapper used by utility metaprogramming helpers.
Definition utility.h:1559
Definition utility.h:217
Definition utility.h:1356
Definition utility.h:208
static T big(T x)
Convert a value to or from big-endian byte order.
Definition utility.h:1777
static T little(T x)
Convert a value to or from little-endian byte order.
Definition utility.h:1757
Definition utility.h:1706
@ little
little-endian target architecture
Definition utility.h:1697
@ big
big-endian target architecture
Definition utility.h:1701
Definition utility.h:248
Two-dimensional integer point.
Definition utility.h:1663
double x
X.
Definition utility.h:1664
double y
Y.
Definition utility.h:1665
safe_ptr< T, dynamic< T, ReturnType, function > > dyn_safe_ptr_v2
Safe pointer wrapper for runtime-resolved release functions with status returns.
Definition utility.h:1629
std::shared_ptr< typename P::element_type > shared_t
Shared pointer type matching a safe pointer wrapper's element type.
Definition utility.h:1169
std::string hex_vec(It begin, It end, bool rev=false)
Convert a value to a vector of hexadecimal bytes.
Definition utility.h:500
bool operator!=(const uniq_ptr< T1, D1 > &x, const uniq_ptr< T2, D2 > &y)
Compare two Sunshine unique pointers by their stored addresses.
Definition utility.h:1069
uniq_ptr< T, Destroy< T *, ReturnType, function > > safe_ptr_v2
Safe pointer wrapper for APIs whose release function returns a status value.
Definition utility.h:1597
void c_free(T *p)
Release memory allocated by C APIs with free.
Definition utility.h:1605
typename __either< V, X, Y >::type either_t
Compile-time selector for one of two types.
Definition utility.h:245
uniq_ptr< T, Destroy< T *, void, function > > safe_ptr
Unique pointer using a compile-time C-style destroy function.
Definition utility.h:1590
bool operator==(const uniq_ptr< T1, D1 > &x, const uniq_ptr< T2, D2 > &y)
Compare two Sunshine unique pointers by their stored addresses.
Definition utility.h:1057
auto fail_guard(T &&f)
Create a scope guard that runs unless it is disabled.
Definition utility.h:316
void append_struct(std::vector< uint8_t > &buf, const T &_struct)
Append the raw bytes of a trivially-copyable structure to a byte buffer.
Definition utility.h:327
auto big(T x)
Convert a value to or from big-endian byte order.
Definition utility.h:1810
std::int64_t from_view(const std::string_view &number)
Convert from view.
Definition utility.h:742
std::string log_hex(const T &value)
Format a value as hexadecimal text for logging.
Definition utility.h:487
std::int64_t from_chars(const char *begin, const char *end)
Convert from chars.
Definition utility.h:720
auto little(T x)
Convert a value to or from little-endian byte order.
Definition utility.h:1799
std::string from_hex_vec(const std::string &hex, bool rev=false)
Decode hexadecimal text into a string containing the decoded bytes.
Definition utility.h:622
T either(std::optional< T > &&l, T &&r)
Build an either value from a left-hand value.
Definition utility.h:1547
auto enm(const T &val) -> const std::underlying_type_t< T > &
Convert between enum values and their string names.
Definition utility.h:698
constexpr bool is_pointer_v
Trait value indicating whether the template argument is a pointer.
Definition utility.h:1349
void dynamic(T *p)
Create a non-owning dynamic buffer view over contiguous memory.
Definition utility.h:1615
shared_t< P > make_shared(T *pointer)
Create a shared object or message.
Definition utility.h:1178
Hex< T > hex(const T &elem, bool rev=false)
Serialize an element as hexadecimal text.
Definition utility.h:476
either_t<(std::is_same_v< T, bool >||is_pointer_v< T >), T, std::optional< T > > optional_t
Optional trait value used by endian serialization helpers.
Definition utility.h:1389
safe_ptr< T, c_free< T > > c_ptr
Safe pointer wrapper for memory released by std::free.
Definition utility.h:1635
std::string_view view(It begin, It end)
Read the current value without removing it from the queue.
Definition utility.h:1645
safe_ptr< T, dynamic< T, void, function > > dyn_safe_ptr
Unique pointer using a runtime-provided destroy function.
Definition utility.h:1623