Sunshine master
Self-hosted game stream host for Moonlight.
utility.h
Go to the documentation of this file.
1
5#pragma once
6
7// standard includes
8#include <algorithm>
9#include <condition_variable>
10#include <memory>
11#include <mutex>
12#include <optional>
13#include <ostream>
14#include <string>
15#include <string_view>
16#include <type_traits>
17#include <variant>
18#include <vector>
19
24#define KITTY_WHILE_LOOP(x, y, z) \
25 { \
26 x; \
27 while (y) z \
28 }
29
30template<typename T>
32
36template<typename T, typename U>
37struct argument_type<T(U)> {
41 typedef U type;
42};
43
48#define KITTY_USING_MOVE_T(move_t, t, init_val, z) \
49
51 \
52 class move_t { \
53 public: \
54
56 \
57 using element_type = typename argument_type<void(t)>::type; \
58\
59
61 \
62 move_t(): \
63 el {init_val} { \
64 } \
65
69 \
70 template<class... Args> \
71 move_t(Args &&...args): \
72 el {std::forward<Args>(args)...} { \
73 } \
74
76 \
77 move_t(const move_t &) = delete; \
78\
79
83 \
84 move_t(move_t &&other) noexcept: \
85 el {std::move(other.el)} { \
86 other.el = element_type {init_val}; \
87 } \
88\
89
91 \
92 move_t &operator=(const move_t &) = delete; \
93\
94
99 \
100 move_t &operator=(move_t &&other) { \
101 std::swap(el, other.el); \
102 return *this; \
103 } \
104
109 element_type *operator->() { \
110 return &el; \
111 } \
112
116 \
117 const element_type *operator->() const { \
118 return &el; \
119 } \
121
125 \
126 inline element_type release() { \
127 element_type val = std::move(el); \
128 el = element_type {init_val}; \
129 return val; \
130 } \
131\
132
134 \
135 ~move_t() z \
136\
137
139 \
140 element_type el; \
141 }
147#define KITTY_DECL_CONSTR(x) \
148
150 \
151 x(x &&) noexcept = default; \
152
156 \
157 x &operator=(x &&) noexcept = default; \
158
160 \
161 x();
167#define KITTY_DEFAULT_CONSTR_MOVE(x) \
168
170 \
171 x(x &&) noexcept = default; \
172
176 \
177 x &operator=(x &&) noexcept = default;
178
183#define KITTY_DEFAULT_CONSTR_MOVE_THROW(x) \
184
186 \
187 x(x &&) = default; \
188
192 \
193 x &operator=(x &&) = default; \
194
196 \
197 x() = default;
198
203#define KITTY_DEFAULT_CONSTR(x) \
204 KITTY_DEFAULT_CONSTR_MOVE(x) \
207 \
208 x(const x &) noexcept = default; \
209
213 \
214 x &operator=(const x &) = default;
215
220#define TUPLE_2D(a, b, expr) \
221 decltype(expr) a##_##b = expr; \
222 auto &a = std::get<0>(a##_##b); \
223 auto &b = std::get<1>(a##_##b)
229#define TUPLE_2D_REF(a, b, expr) \
230 auto &a##_##b = expr; \
231 auto &a = std::get<0>(a##_##b); \
232 auto &b = std::get<1>(a##_##b)
233
238#define TUPLE_3D(a, b, c, expr) \
239 decltype(expr) a##_##b##_##c = expr; \
240 auto &a = std::get<0>(a##_##b##_##c); \
241 auto &b = std::get<1>(a##_##b##_##c); \
242 auto &c = std::get<2>(a##_##b##_##c)
243
248#define TUPLE_3D_REF(a, b, c, expr) \
249 auto &a##_##b##_##c = expr; \
250 auto &a = std::get<0>(a##_##b##_##c); \
251 auto &b = std::get<1>(a##_##b##_##c); \
252 auto &c = std::get<2>(a##_##b##_##c)
253
258#define TUPLE_EL(a, b, expr) \
259 decltype(expr) a##_ = expr; \
260 auto &a = std::get<b>(a##_)
261
266#define TUPLE_EL_REF(a, b, expr) \
267 auto &a = std::get<b>(expr)
268
269namespace util {
270
271 template<template<typename...> class X, class... Y>
272 struct __instantiation_of: public std::false_type {};
273
274 template<template<typename...> class X, class... Y>
275 struct __instantiation_of<X, X<Y...>>: public std::true_type {};
277 template<template<typename...> class X, class T, class... Y>
278 static constexpr auto instantiation_of_v = __instantiation_of<X, T, Y...>::value;
279
280 template<bool V, class X, class Y>
281 struct __either;
282
286 template<class X, class Y>
287 struct __either<true, X, Y> {
291 using type = X;
292 };
293
297 template<class X, class Y>
298 struct __either<false, X, Y> {
302 using type = Y;
303 };
304
308 template<bool V, class X, class Y>
309 using either_t = typename __either<V, X, Y>::type;
310
311 template<class... Ts>
312 struct overloaded: Ts... {
313 using Ts::operator()...;
314 };
318 template<class... Ts>
319 overloaded(Ts...) -> overloaded<Ts...>;
320
324 template<class T>
325 class FailGuard {
326 public:
327 FailGuard() = delete;
328
334 FailGuard(T &&f) noexcept:
335 _func {std::forward<T>(f)} {
336 }
337
343 FailGuard(FailGuard &&other) noexcept:
344 _func {std::move(other._func)} {
345 this->failure = other.failure;
347 other.failure = false;
348 }
349
350 FailGuard(const FailGuard &) = delete;
351
352 FailGuard &operator=(const FailGuard &) = delete;
353 FailGuard &operator=(FailGuard &&other) = delete;
354
355 ~FailGuard() noexcept {
356 if (failure) {
357 _func();
358 }
359 }
360
364 void disable() {
365 failure = false;
366 }
367
368 bool failure {true};
369
370 private:
371 T _func;
372 };
373
380 template<class T>
381 [[nodiscard]] auto fail_guard(T &&f) {
382 return FailGuard<T> {std::forward<T>(f)};
383 }
384
391 template<class T>
392 void append_struct(std::vector<uint8_t> &buf, const T &_struct) {
393 constexpr size_t data_len = sizeof(_struct);
394
395 buf.reserve(data_len);
396
397 auto *data = (uint8_t *) &_struct;
399 for (size_t x = 0; x < data_len; ++x) {
400 buf.push_back(data[x]);
401 }
402 }
403
407 template<class T>
408 class Hex {
409 public:
413 typedef T elem_type;
414
415 private:
416 const char _bits[16] {
417 '0',
418 '1',
419 '2',
420 '3',
421 '4',
422 '5',
423 '6',
424 '7',
425 '8',
426 '9',
427 'A',
428 'B',
429 'C',
430 'D',
431 'E',
432 'F'
433 };
435 char _hex[sizeof(elem_type) * 2];
436
437 public:
444 Hex(const elem_type &elem, bool rev) {
445 if (!rev) {
446 const uint8_t *data = reinterpret_cast<const uint8_t *>(&elem) + sizeof(elem_type) - 1;
447 for (auto it = begin(); it < cend();) {
448 *it++ = _bits[*data / 16];
449 *it++ = _bits[*data-- % 16];
450 }
451 } else {
452 const uint8_t *data = reinterpret_cast<const uint8_t *>(&elem);
453 for (auto it = begin(); it < cend();) {
454 *it++ = _bits[*data / 16];
455 *it++ = _bits[*data++ % 16];
456 }
457 }
458 }
459
465 char *begin() {
466 return _hex;
467 }
468
474 char *end() {
475 return _hex + sizeof(elem_type) * 2;
476 }
477
483 const char *begin() const {
484 return _hex;
486
492 const char *end() const {
493 return _hex + sizeof(elem_type) * 2;
494 }
495
501 const char *cbegin() const {
502 return _hex;
503 }
504
510 const char *cend() const {
511 return _hex + sizeof(elem_type) * 2;
512 }
513
519 std::string to_string() const {
520 return {begin(), end()};
521 }
522
528 std::string_view to_string_view() const {
529 return {begin(), sizeof(elem_type) * 2};
530 }
531 };
532
540 template<class T>
541 Hex<T> hex(const T &elem, bool rev = false) {
542 return Hex<T>(elem, rev);
543 }
544
551 template<typename T>
552 std::string log_hex(const T &value) {
553 return "0x" + Hex<T>(value, false).to_string();
554 }
555
564 template<class It>
565 std::string hex_vec(It begin, It end, bool rev = false) {
566 auto str_size = 2 * std::distance(begin, end);
567
568 std::string hex;
569 hex.resize(str_size);
570
571 const char _bits[16] {
572 '0',
573 '1',
574 '2',
575 '3',
576 '4',
577 '5',
578 '6',
579 '7',
580 '8',
581 '9',
582 'A',
583 'B',
584 'C',
585 'D',
586 'E',
587 'F'
588 };
589
590 if (rev) {
591 for (auto it = std::begin(hex); it < std::end(hex);) {
592 *it++ = _bits[((uint8_t) *begin) / 16];
593 *it++ = _bits[((uint8_t) *begin++) % 16];
594 }
595 } else {
596 --end;
597 for (auto it = std::begin(hex); it < std::end(hex);) {
598 *it++ = _bits[((uint8_t) *end) / 16];
599 *it++ = _bits[((uint8_t) *end--) % 16];
600 }
601 }
602
603 return hex;
604 }
605
613 template<class C>
614 std::string hex_vec(C &&c, bool rev = false) {
615 return hex_vec(std::begin(c), std::end(c), rev);
616 }
617
625 template<class T>
626 T from_hex(const std::string_view &hex, bool rev = false) {
627 std::uint8_t buf[sizeof(T)];
628
629 static char constexpr shift_bit = 'a' - 'A';
630
631 auto is_convertable = [](char ch) -> bool {
632 if (isdigit(ch)) {
633 return true;
634 }
635
636 ch |= shift_bit;
637
638 if ('a' > ch || ch > 'z') {
639 return false;
640 }
641
642 return true;
643 };
644
645 auto buf_size = std::count_if(std::begin(hex), std::end(hex), is_convertable) / 2;
646 auto padding = sizeof(T) - buf_size;
647
648 const char *data = hex.data() + hex.size() - 1;
649
650 auto convert = [](char ch) -> std::uint8_t {
651 if (ch >= '0' && ch <= '9') {
652 return (std::uint8_t) ch - '0';
653 }
654
655 return (std::uint8_t) (ch | (char) 32) - 'a' + (char) 10;
656 };
657
658 std::fill_n(buf + buf_size, padding, 0);
659
660 std::for_each_n(buf, buf_size, [&](auto &el) {
661 while (!is_convertable(*data)) {
662 --data;
663 }
664 std::uint8_t ch_r = convert(*data--);
665
666 while (!is_convertable(*data)) {
667 --data;
668 }
669 std::uint8_t ch_l = convert(*data--);
670
671 el = (ch_l << 4) | ch_r;
672 });
673
674 if (rev) {
675 std::reverse(std::begin(buf), std::end(buf));
676 }
678 return *reinterpret_cast<T *>(buf);
679 }
680
688 inline std::string from_hex_vec(const std::string &hex, bool rev = false) {
689 std::string buf;
691 static char constexpr shift_bit = 'a' - 'A';
692 auto is_convertable = [](char ch) -> bool {
693 if (isdigit(ch)) {
694 return true;
695 }
696
697 ch |= shift_bit;
698
699 if ('a' > ch || ch > 'z') {
700 return false;
701 }
702
703 return true;
704 };
705
706 auto buf_size = std::count_if(std::begin(hex), std::end(hex), is_convertable) / 2;
707 buf.resize(buf_size);
708
709 const char *data = hex.data() + hex.size() - 1;
710
711 auto convert = [](char ch) -> std::uint8_t {
712 if (ch >= '0' && ch <= '9') {
713 return (std::uint8_t) ch - '0';
714 }
716 return (std::uint8_t) (ch | (char) 32) - 'a' + (char) 10;
717 };
718
719 for (auto &el : buf) {
720 while (!is_convertable(*data)) {
721 --data;
722 }
723 std::uint8_t ch_r = convert(*data--);
724
725 while (!is_convertable(*data)) {
726 --data;
727 }
728 std::uint8_t ch_l = convert(*data--);
729
730 el = (ch_l << 4) | ch_r;
731 }
732
733 if (rev) {
734 std::reverse(std::begin(buf), std::end(buf));
735 }
736
737 return buf;
738 }
739
743 template<class T>
744 class hash {
745 public:
749 using value_type = T;
750
757 std::size_t operator()(const value_type &value) const {
758 const auto *p = reinterpret_cast<const char *>(&value);
759
760 return std::hash<std::string_view> {}(std::string_view {p, sizeof(value_type)});
761 }
762 };
763
770 template<class T>
771 auto enm(const T &val) -> const std::underlying_type_t<T> & {
772 return *reinterpret_cast<const std::underlying_type_t<T> *>(&val);
773 }
781 template<class T>
782 auto enm(T &val) -> std::underlying_type_t<T> & {
783 return *reinterpret_cast<std::underlying_type_t<T> *>(&val);
784 }
785
793 inline std::int64_t from_chars(const char *begin, const char *end) {
794 if (begin == end) {
795 return 0;
796 }
797
798 std::int64_t res {};
799 std::int64_t mul = 1;
800 while (begin != --end) {
801 res += (std::int64_t) (*end - '0') * mul;
802
803 mul *= 10;
804 }
805
806 return *begin != '-' ? res + (std::int64_t) (*begin - '0') * mul : -res;
807 }
808
815 inline std::int64_t from_view(const std::string_view &number) {
816 return from_chars(std::begin(number), std::end(number));
817 }
818
822 template<class X, class Y>
823 class Either: public std::variant<std::monostate, X, Y> {
824 public:
825 using std::variant<std::monostate, X, Y>::variant;
826
832 constexpr bool has_left() const {
833 return std::holds_alternative<X>(*this);
834 }
835
841 constexpr bool has_right() const {
842 return std::holds_alternative<Y>(*this);
843 }
844
850 X &left() {
851 return std::get<X>(*this);
852 }
853
859 Y &right() {
860 return std::get<Y>(*this);
861 }
862
868 const X &left() const {
869 return std::get<X>(*this);
871
877 const Y &right() const {
878 return std::get<Y>(*this);
879 }
880 };
882 // Compared to std::unique_ptr, it adds the ability to get the address of the pointer itself
886 template<typename T, typename D = std::default_delete<T>>
887 class uniq_ptr {
888 public:
892 using element_type = T;
896 using pointer = element_type *;
900 using const_pointer = element_type const *;
904 using deleter_type = D;
905
906 constexpr uniq_ptr() noexcept:
907 _p {nullptr} {
908 }
909
913 constexpr uniq_ptr(std::nullptr_t) noexcept:
914 _p {nullptr} {
915 }
916
917 uniq_ptr(const uniq_ptr &other) noexcept = delete;
918 uniq_ptr &operator=(const uniq_ptr &other) noexcept = delete;
919
925 template<class V>
926 uniq_ptr(V *p) noexcept:
927 _p {p} {
928 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");
929 }
930
936 template<class V>
937 uniq_ptr(std::unique_ptr<V, deleter_type> &&uniq) noexcept:
938 _p {uniq.release()} {
939 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");
940 }
941
947 template<class V>
949 _p {other.release()} {
950 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");
951 }
952
959 template<class V>
960 uniq_ptr &operator=(uniq_ptr<V, deleter_type> &&other) noexcept {
961 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");
962 reset(other.release());
963
964 return *this;
965 }
973 template<class V>
974 uniq_ptr &operator=(std::unique_ptr<V, deleter_type> &&uniq) noexcept {
975 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");
976
977 reset(uniq.release());
978
979 return *this;
980 }
981
982 ~uniq_ptr() {
983 reset();
985
991 void reset(pointer p = pointer()) {
992 if (_p) {
994 }
995
996 _p = p;
997 }
998
1004 pointer release() {
1005 auto tmp = _p;
1006 _p = nullptr;
1007 return tmp;
1008 }
1009
1015 pointer get() {
1016 return _p;
1017 }
1018
1024 const_pointer get() const {
1025 return _p;
1026 }
1027
1033 std::add_lvalue_reference_t<element_type const> operator*() const {
1034 return *_p;
1035 }
1042 std::add_lvalue_reference_t<element_type> operator*() {
1043 return *_p;
1044 }
1045
1051 const_pointer operator->() const {
1052 return _p;
1054
1061 return _p;
1062 }
1063
1069 pointer *operator&() const {
1070 return &_p;
1071 }
1072
1078 pointer *operator&() {
1079 return &_p;
1080 }
1081
1088 return _deleter;
1090
1096 const deleter_type &get_deleter() const {
1097 return _deleter;
1098 }
1099
1103 explicit operator bool() const {
1104 return _p != nullptr;
1105 }
1106
1107 protected:
1108 pointer _p;
1110 };
1111
1119 template<class T1, class D1, class T2, class D2>
1120 bool operator==(const uniq_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
1121 return x.get() == y.get();
1122 }
1123
1131 template<class T1, class D1, class T2, class D2>
1132 bool operator!=(const uniq_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
1133 return x.get() != y.get();
1134 }
1143 template<class T1, class D1, class T2, class D2>
1144 bool operator==(const std::unique_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
1145 return x.get() == y.get();
1147
1155 template<class T1, class D1, class T2, class D2>
1156 bool operator!=(const std::unique_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
1157 return x.get() != y.get();
1158 }
1159
1167 template<class T1, class D1, class T2, class D2>
1168 bool operator==(const uniq_ptr<T1, D1> &x, const std::unique_ptr<T1, D1> &y) {
1169 return x.get() == y.get();
1170 }
1171
1179 template<class T1, class D1, class T2, class D2>
1180 bool operator!=(const uniq_ptr<T1, D1> &x, const std::unique_ptr<T1, D1> &y) {
1181 return x.get() != y.get();
1183
1190 template<class T, class D>
1191 bool operator==(const uniq_ptr<T, D> &x, std::nullptr_t) {
1192 return !(bool) x;
1193 }
1194
1201 template<class T, class D>
1202 bool operator!=(const uniq_ptr<T, D> &x, std::nullptr_t) {
1203 return (bool) x;
1204 }
1205
1212 template<class T, class D>
1213 bool operator==(std::nullptr_t, const uniq_ptr<T, D> &y) {
1214 return !(bool) y;
1216
1223 template<class T, class D>
1224 bool operator!=(std::nullptr_t, const uniq_ptr<T, D> &y) {
1225 return (bool) y;
1226 }
1227
1231 template<class P>
1232 using shared_t = std::shared_ptr<typename P::element_type>;
1233
1240 template<class P, class T>
1241 shared_t<P> make_shared(T *pointer) {
1242 return shared_t<P>(reinterpret_cast<typename P::pointer>(pointer), typename P::deleter_type());
1243 }
1244
1248 template<class T>
1249 class wrap_ptr {
1250 public:
1254 using element_type = T;
1258 using pointer = element_type *;
1262 using const_pointer = element_type const *;
1266 using reference = element_type &;
1270 using const_reference = element_type const &;
1271
1272 wrap_ptr():
1273 _own_ptr {false},
1274 _p {nullptr} {
1275 }
1276
1282 wrap_ptr(pointer p):
1283 _own_ptr {false},
1284 _p {p} {
1285 }
1286
1292 wrap_ptr(std::unique_ptr<element_type> &&uniq_p):
1293 _own_ptr {true},
1294 _p {uniq_p.release()} {
1295 }
1296
1302 wrap_ptr(wrap_ptr &&other):
1303 _own_ptr {other._own_ptr},
1304 _p {other._p} {
1305 other._own_ptr = false;
1306 }
1307
1314 wrap_ptr &operator=(wrap_ptr &&other) noexcept {
1315 if (_own_ptr) {
1316 delete _p;
1317 }
1318
1319 _p = other._p;
1320
1321 _own_ptr = other._own_ptr;
1322 other._own_ptr = false;
1324 return *this;
1325 }
1326
1333 template<class V>
1334 wrap_ptr &operator=(std::unique_ptr<V> &&uniq_ptr) {
1335 static_assert(std::is_base_of_v<element_type, V>, "element_type must be base class of V");
1336 _own_ptr = true;
1337 _p = uniq_ptr.release();
1338
1339 return *this;
1340 }
1341
1348 wrap_ptr &operator=(pointer p) {
1349 if (_own_ptr) {
1350 delete _p;
1351 }
1353 _p = p;
1354 _own_ptr = false;
1355
1356 return *this;
1357 }
1360 if (_own_ptr) {
1361 delete _p;
1362 }
1363
1364 _own_ptr = false;
1365 }
1372 const_reference operator*() const {
1373 return *_p;
1382 return *_p;
1383 }
1384
1390 const_pointer operator->() const {
1391 return _p;
1392 }
1393
1400 return _p;
1401 }
1402
1403 private:
1404 bool _own_ptr;
1405 pointer _p;
1406 };
1407
1408 template<class T>
1412 constexpr bool is_pointer_v =
1413 instantiation_of_v<std::unique_ptr, T> ||
1414 instantiation_of_v<std::shared_ptr, T> ||
1415 instantiation_of_v<uniq_ptr, T> ||
1416 std::is_pointer_v<T>;
1417
1418 template<class T, class V = void>
1419 struct __false_v;
1420
1424 template<class T>
1425 struct __false_v<T, std::enable_if_t<instantiation_of_v<std::optional, T>>> {
1426 static constexpr std::nullopt_t value = std::nullopt;
1428
1432 template<class T>
1433 struct __false_v<T, std::enable_if_t<is_pointer_v<T>>> {
1434 static constexpr std::nullptr_t value = nullptr;
1435 };
1436
1440 template<class T>
1441 struct __false_v<T, std::enable_if_t<std::is_same_v<T, bool>>> {
1442 static constexpr bool value = false;
1443 };
1444
1445 template<class T>
1446 static constexpr auto false_v = __false_v<T>::value;
1447
1451 template<class T>
1452 using optional_t = either_t<
1453 (std::is_same_v<T, bool> || is_pointer_v<T>),
1454 T,
1455 std::optional<T>>;
1456
1460 template<class T>
1461 class buffer_t {
1462 public:
1463 buffer_t():
1464 _els {0} {};
1465
1471 buffer_t(buffer_t &&o) noexcept:
1472 _els {o._els},
1473 _buf {std::move(o._buf)} {
1474 o._els = 0;
1475 }
1476
1482 buffer_t(const buffer_t &o):
1483 _els {o._els},
1484 _buf {std::make_unique<T[]>(_els)} {
1485 std::copy(o.begin(), o.end(), begin());
1486 }
1487
1494 buffer_t &operator=(buffer_t &&o) noexcept {
1495 std::swap(_els, o._els);
1496 std::swap(_buf, o._buf);
1497
1498 return *this;
1500
1506 explicit buffer_t(size_t elements):
1507 _els {elements},
1508 _buf {std::make_unique<T[]>(elements)} {
1509 }
1510
1517 explicit buffer_t(size_t elements, const T &t):
1518 _els {elements},
1519 _buf {std::make_unique<T[]>(elements)} {
1520 std::fill_n(_buf.get(), elements, t);
1521 }
1522
1529 T &operator[](size_t el) {
1530 return _buf[el];
1531 }
1532
1539 const T &operator[](size_t el) const {
1540 return _buf[el];
1541 }
1542
1548 size_t size() const {
1549 return _els;
1550 }
1551
1557 void fake_resize(std::size_t els) {
1558 _els = els;
1560
1566 T *begin() {
1567 return _buf.get();
1568 }
1569
1575 const T *begin() const {
1576 return _buf.get();
1578
1584 T *end() {
1585 return _buf.get() + _els;
1587
1593 const T *end() const {
1594 return _buf.get() + _els;
1595 }
1596
1597 private:
1598 size_t _els;
1599 std::unique_ptr<T[]> _buf;
1600 };
1609 template<class T>
1610 T either(std::optional<T> &&l, T &&r) {
1611 if (l) {
1612 return std::move(*l);
1613 }
1614
1615 return std::forward<T>(r);
1616 }
1617
1621 template<class ReturnType, class... Args>
1622 struct Function {
1626 typedef ReturnType (*type)(Args...);
1627 };
1628
1632 template<class T, class ReturnType, typename Function<ReturnType, T>::type function>
1633 struct Destroy {
1637 typedef T pointer;
1638
1644 void operator()(pointer p) {
1645 function(p);
1646 }
1647 };
1648
1652 template<class T, typename Function<void, T *>::type function>
1654
1655 // You cannot specialize an alias
1659 template<class T, class ReturnType, typename Function<ReturnType, T *>::type function>
1667 template<class T>
1668 void c_free(T *p) {
1669 free(p);
1670 }
1671
1677 template<class T, class ReturnType, ReturnType (**function)(T *)>
1678 void dynamic(T *p) {
1679 (*function)(p);
1680 }
1681
1685 template<class T, void (**function)(T *)>
1686 using dyn_safe_ptr = safe_ptr<T, dynamic<T, void, function>>;
1687
1691 template<class T, class ReturnType, ReturnType (**function)(T *)>
1692 using dyn_safe_ptr_v2 = safe_ptr<T, dynamic<T, ReturnType, function>>;
1697 template<class T>
1699
1707 template<class It>
1708 std::string_view view(It begin, It end) {
1709 return std::string_view {(const char *) begin, (std::size_t) (end - begin)};
1710 }
1711
1718 template<class T>
1719 std::string_view view(const T &data) {
1720 return std::string_view((const char *) &data, sizeof(T));
1721 }
1722
1726 struct point_t {
1727 double x;
1728 double y;
1729
1733 friend std::ostream &operator<<(std::ostream &os, const point_t &p) {
1734 return (os << "Point(x: " << p.x << ", y: " << p.y << ")");
1735 }
1736 };
1737
1738 namespace endian {
1742 template<class T = void>
1743 struct endianness {
1744 enum : bool {
1745#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \
1746 defined(__BIG_ENDIAN__) || \
1747 defined(__ARMEB__) || \
1748 defined(__THUMBEB__) || \
1749 defined(__AARCH64EB__) || \
1750 defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
1751 // It's a big-endian target architecture
1752 little = false,
1753#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \
1754 defined(__LITTLE_ENDIAN__) || \
1755 defined(__ARMEL__) || \
1756 defined(__THUMBEL__) || \
1757 defined(__AARCH64EL__) || \
1758 defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
1759 defined(_WIN32)
1760 little = true,
1761#else
1762 #error "Unknown Endianness"
1763#endif
1764 big = !little
1765 };
1766 };
1767
1768 template<class T, class S = void>
1769 struct endian_helper {};
1770
1774 template<class T>
1775 struct endian_helper<T, std::enable_if_t<!(instantiation_of_v<std::optional, T>)>> {
1782 static inline T big(T x) {
1783 if constexpr (endianness<T>::little) {
1784 uint8_t *data = reinterpret_cast<uint8_t *>(&x);
1785
1786 std::reverse(data, data + sizeof(x));
1787 }
1788
1789 return x;
1790 }
1791
1798 static inline T little(T x) {
1799 if constexpr (endianness<T>::big) {
1800 uint8_t *data = reinterpret_cast<uint8_t *>(&x);
1801
1802 std::reverse(data, data + sizeof(x));
1803 }
1804
1805 return x;
1807 };
1808
1812 template<class T>
1813 struct endian_helper<T, std::enable_if_t<instantiation_of_v<std::optional, T>>> {
1820 static inline T little(T x) {
1821 if (!x) {
1822 return x;
1823 }
1824
1825 if constexpr (endianness<T>::big) {
1826 auto *data = reinterpret_cast<uint8_t *>(&*x);
1827
1828 std::reverse(data, data + sizeof(*x));
1829 }
1830
1831 return x;
1832 }
1833
1840 static inline T big(T x) {
1841 if (!x) {
1842 return x;
1843 }
1844
1845 if constexpr (endianness<T>::little) {
1846 auto *data = reinterpret_cast<uint8_t *>(&*x);
1847
1848 std::reverse(data, data + sizeof(*x));
1849 }
1850
1851 return x;
1852 }
1853 };
1854
1861 template<class T>
1862 inline auto little(T x) {
1863 return endian_helper<T>::little(x);
1864 }
1865
1872 template<class T>
1873 inline auto big(T x) {
1874 return endian_helper<T>::big(x);
1875 }
1876 } // namespace endian
1877} // namespace util
util::buffer_t< std::uint8_t > buffer_t
Byte buffer used for encoded audio packet payloads.
Definition audio.h:92
X & left()
Return the left-hand alternative held by the variant.
Definition utility.h:783
constexpr bool has_right() const
Check whether right.
Definition utility.h:774
constexpr bool has_left() const
Check whether left.
Definition utility.h:765
Y & right()
Return the right-hand alternative held by the variant.
Definition utility.h:792
Scope guard that runs a cleanup action unless it is disabled.
Definition utility.h:258
void disable()
Disable the fail guard so destruction will not run the cleanup action.
Definition utility.h:297
bool failure
Whether the fail guard should run its cleanup action.
Definition utility.h:301
Formatter that exposes a value's bytes as hexadecimal text.
Definition utility.h:341
char * end()
Return an iterator one past the final byte in the buffer view.
Definition utility.h:407
std::string to_string() const
Convert to string.
Definition utility.h:452
T elem_type
Integral type used for one formatted hex element.
Definition utility.h:346
const char * cend() const
Return a const iterator one past the last byte in the view.
Definition utility.h:443
char * begin()
Return an iterator to the first byte in the buffer view.
Definition utility.h:398
std::string_view to_string_view() const
Convert to string view.
Definition utility.h:461
const char * cbegin() const
Return a const iterator to the first byte in the view.
Definition utility.h:434
Hex(const elem_type &elem, bool rev)
Construct a hexadecimal byte view for the supplied value.
Definition utility.h:377
Owning contiguous buffer with an explicit logical element count.
Definition utility.h:1394
T & operator[](size_t el)
Access an element in the owning buffer.
Definition utility.h:1462
size_t size() const
Return the serialized size of the current object.
Definition utility.h:1481
T * end()
Return an iterator one past the final byte in the buffer view.
Definition utility.h:1517
buffer_t & operator=(buffer_t &&o) noexcept
Assign state from another instance while preserving ownership semantics.
Definition utility.h:1427
T * begin()
Return an iterator to the first byte in the buffer view.
Definition utility.h:1499
void fake_resize(std::size_t els)
Update the logical element count without reallocating storage.
Definition utility.h:1490
T value_type
Value type accepted by the hash functor.
Definition utility.h:682
std::size_t operator()(const value_type &value) const
Hash a value by viewing its object representation as bytes.
Definition utility.h:690
Unique pointer wrapper with customizable pointer and deleter types.
Definition utility.h:820
element_type const * const_pointer
Const pointer type exposed by the unique pointer wrapper.
Definition utility.h:833
element_type * pointer
Pointer type stored by the unique pointer wrapper.
Definition utility.h:829
const_pointer operator->() const
Access members of the managed pointer.
Definition utility.h:984
deleter_type & get_deleter()
Return the deleter used when resetting the wrapped pointer.
Definition utility.h:1020
void reset(pointer p=pointer())
Reset the object to its initial empty state.
Definition utility.h:924
pointer release()
Release the COM or platform reference owned by the pointer.
Definition utility.h:937
std::add_lvalue_reference_t< element_type const > operator*() const
Dereference the managed pointer.
Definition utility.h:966
deleter_type _deleter
Callable used to release _p.
Definition utility.h:1042
D deleter_type
Callable type used to release the managed pointer.
Definition utility.h:837
T element_type
Object type managed by the unique pointer wrapper.
Definition utility.h:825
pointer _p
Pointer currently owned by the wrapper.
Definition utility.h:1041
pointer * operator&() const
Expose the stored pointer address for C APIs that write handles.
Definition utility.h:1002
pointer get()
Return the currently wrapped value or handle.
Definition utility.h:948
Pointer wrapper that may borrow or own the pointee.
Definition utility.h:1182
element_type const & const_reference
Const reference type exposed by the pointer wrapper.
Definition utility.h:1203
const_pointer operator->() const
Access members of the wrapped pointer.
Definition utility.h:1323
element_type & reference
Mutable reference type exposed by the pointer wrapper.
Definition utility.h:1199
element_type * pointer
Mutable pointer type exposed by the pointer wrapper.
Definition utility.h:1191
const_reference operator*() const
Dereference the wrapped pointer.
Definition utility.h:1305
element_type const * const_pointer
Const pointer type exposed by the pointer wrapper.
Definition utility.h:1195
T element_type
Object type referenced by the pointer wrapper.
Definition utility.h:1187
wrap_ptr & operator=(wrap_ptr &&other) noexcept
Assign state from another instance while preserving ownership semantics.
Definition utility.h:1247
sha256_t hash(const std::string_view &plaintext)
Hashes the given plaintext using SHA-256.
Definition crypto.cpp:350
U type
Type extracted from the matched function signature.
Definition utility.h:41
Definition utility.h:31
T pointer
Pointer type accepted by this deleter.
Definition utility.h:1570
void operator()(pointer p)
Invoke the configured destroy function on a pointer.
Definition utility.h:1577
ReturnType(*) type(Args...)
Type extracted from the matched function signature.
Definition utility.h:1559
Definition utility.h:214
Definition utility.h:1352
Definition utility.h:205
@ little
little-endian target architecture
Definition utility.h:1693
@ big
big-endian target architecture
Definition utility.h:1697
Definition utility.h:245
Two-dimensional integer point.
Definition utility.h:1659
double x
X.
Definition utility.h:1660
friend std::ostream & operator<<(std::ostream &os, const point_t &p)
Operator.
Definition utility.h:1666
double y
Y.
Definition utility.h:1661
std::shared_ptr< typename P::element_type > shared_t
Shared pointer type matching a safe pointer wrapper's element type.
Definition utility.h:1165
std::string hex_vec(It begin, It end, bool rev=false)
Convert a value to a vector of hexadecimal bytes.
Definition utility.h:498
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:1065
void c_free(T *p)
Release memory allocated by C APIs with free.
Definition utility.h:1601
typename __either< V, X, Y >::type either_t
Compile-time selector for one of two types.
Definition utility.h:242
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:1053
auto fail_guard(T &&f)
Create a scope guard that runs unless it is disabled.
Definition utility.h:314
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:325
auto big(T x)
Convert a value to or from big-endian byte order.
Definition utility.h:1806
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:1385
std::string log_hex(const T &value)
Format a value as hexadecimal text for logging.
Definition utility.h:485
std::int64_t from_chars(const char *begin, const char *end)
Convert from chars.
Definition utility.h:726
auto little(T x)
Convert a value to or from little-endian byte order.
Definition utility.h:1795
std::string from_hex_vec(const std::string &hex, bool rev=false)
Convert from hex vec.
Definition utility.h:621
T either(std::optional< T > &&l, T &&r)
Build an either value from a left-hand value.
Definition utility.h:1543
auto enm(const T &val) -> const std::underlying_type_t< T > &
Convert between enum values and their string names.
Definition utility.h:704
constexpr bool is_pointer_v
Trait value indicating whether the template argument is a pointer.
Definition utility.h:1345
T from_hex(const std::string_view &hex, bool rev=false)
Convert from hex.
Definition utility.h:559
void dynamic(T *p)
Create a non-owning dynamic buffer view over contiguous memory.
Definition utility.h:1611
Hex< T > hex(const T &elem, bool rev=false)
Serialize an element as hexadecimal text.
Definition utility.h:474
std::string_view view(It begin, It end)
Read the current value without removing it from the queue.
Definition utility.h:1641