Sunshine v2025.118.151840
Self-hosted game stream host for Moonlight.
utility.h
Go to the documentation of this file.
1
5#pragma once
6
7#include <algorithm>
8#include <condition_variable>
9#include <memory>
10#include <mutex>
11#include <optional>
12#include <ostream>
13#include <string>
14#include <string_view>
15#include <type_traits>
16#include <variant>
17#include <vector>
18
19#define KITTY_WHILE_LOOP(x, y, z) \
20 { \
21 x; \
22 while (y) z \
23 }
24
25template <typename T>
27
28template <typename T, typename U>
29struct argument_type<T(U)> {
30 typedef U type;
31};
32
33#define KITTY_USING_MOVE_T(move_t, t, init_val, z) \
34 class move_t { \
35 public: \
36 using element_type = typename argument_type<void(t)>::type; \
37 \
38 move_t(): el { init_val } {} \
39 template <class... Args> \
40 move_t(Args &&...args): el { std::forward<Args>(args)... } {} \
41 move_t(const move_t &) = delete; \
42 \
43 move_t(move_t &&other) noexcept: el { std::move(other.el) } { \
44 other.el = element_type { init_val }; \
45 } \
46 \
47 move_t & \
48 operator=(const move_t &) = delete; \
49 \
50 move_t & \
51 operator=(move_t &&other) { \
52 std::swap(el, other.el); \
53 return *this; \
54 } \
55 element_type * \
56 operator->() { return &el; } \
57 const element_type * \
58 operator->() const { return &el; } \
59 \
60 inline element_type \
61 release() { \
62 element_type val = std::move(el); \
63 el = element_type { init_val }; \
64 return val; \
65 } \
66 \
67 ~move_t() z \
68 \
69 element_type el; \
70 }
71
72#define KITTY_DECL_CONSTR(x) \
73 x(x &&) noexcept = default; \
74 x &operator=(x &&) noexcept = default; \
75 x();
76
77#define KITTY_DEFAULT_CONSTR_MOVE(x) \
78 x(x &&) noexcept = default; \
79 x &operator=(x &&) noexcept = default;
80
81#define KITTY_DEFAULT_CONSTR_MOVE_THROW(x) \
82 x(x &&) = default; \
83 x &operator=(x &&) = default; \
84 x() = default;
85
86#define KITTY_DEFAULT_CONSTR(x) \
87 KITTY_DEFAULT_CONSTR_MOVE(x) \
88 x(const x &) noexcept = default; \
89 x &operator=(const x &) = default;
90
91#define TUPLE_2D(a, b, expr) \
92 decltype(expr) a##_##b = expr; \
93 auto &a = std::get<0>(a##_##b); \
94 auto &b = std::get<1>(a##_##b)
95
96#define TUPLE_2D_REF(a, b, expr) \
97 auto &a##_##b = expr; \
98 auto &a = std::get<0>(a##_##b); \
99 auto &b = std::get<1>(a##_##b)
100
101#define TUPLE_3D(a, b, c, expr) \
102 decltype(expr) a##_##b##_##c = expr; \
103 auto &a = std::get<0>(a##_##b##_##c); \
104 auto &b = std::get<1>(a##_##b##_##c); \
105 auto &c = std::get<2>(a##_##b##_##c)
106
107#define TUPLE_3D_REF(a, b, c, expr) \
108 auto &a##_##b##_##c = expr; \
109 auto &a = std::get<0>(a##_##b##_##c); \
110 auto &b = std::get<1>(a##_##b##_##c); \
111 auto &c = std::get<2>(a##_##b##_##c)
112
113#define TUPLE_EL(a, b, expr) \
114 decltype(expr) a##_ = expr; \
115 auto &a = std::get<b>(a##_)
116
117#define TUPLE_EL_REF(a, b, expr) \
118 auto &a = std::get<b>(expr)
119
120namespace util {
121
122 template <template <typename...> class X, class... Y>
123 struct __instantiation_of: public std::false_type {};
124
125 template <template <typename...> class X, class... Y>
126 struct __instantiation_of<X, X<Y...>>: public std::true_type {};
127
128 template <template <typename...> class X, class T, class... Y>
129 static constexpr auto instantiation_of_v = __instantiation_of<X, T, Y...>::value;
130
131 template <bool V, class X, class Y>
132 struct __either;
133
134 template <class X, class Y>
135 struct __either<true, X, Y> {
136 using type = X;
137 };
138
139 template <class X, class Y>
140 struct __either<false, X, Y> {
141 using type = Y;
142 };
143
144 template <bool V, class X, class Y>
145 using either_t = typename __either<V, X, Y>::type;
146
147 template <class... Ts>
148 struct overloaded: Ts... {
149 using Ts::operator()...;
150 };
151 template <class... Ts>
152 overloaded(Ts...) -> overloaded<Ts...>;
153
154 template <class T>
155 class FailGuard {
156 public:
157 FailGuard() = delete;
158 FailGuard(T &&f) noexcept:
159 _func { std::forward<T>(f) } {}
160 FailGuard(FailGuard &&other) noexcept:
161 _func { std::move(other._func) } {
162 this->failure = other.failure;
163
164 other.failure = false;
165 }
166
167 FailGuard(const FailGuard &) = delete;
168
169 FailGuard &
170 operator=(const FailGuard &) = delete;
171 FailGuard &
172 operator=(FailGuard &&other) = delete;
173
174 ~FailGuard() noexcept {
175 if (failure) {
176 _func();
177 }
178 }
179
180 void
181 disable() { failure = false; }
182 bool failure { true };
183
184 private:
185 T _func;
186 };
187
188 template <class T>
189 [[nodiscard]] auto
190 fail_guard(T &&f) {
191 return FailGuard<T> { std::forward<T>(f) };
192 }
193
194 template <class T>
195 void
196 append_struct(std::vector<uint8_t> &buf, const T &_struct) {
197 constexpr size_t data_len = sizeof(_struct);
198
199 buf.reserve(data_len);
200
201 auto *data = (uint8_t *) &_struct;
202
203 for (size_t x = 0; x < data_len; ++x) {
204 buf.push_back(data[x]);
205 }
206 }
207
208 template <class T>
209 class Hex {
210 public:
211 typedef T elem_type;
212
213 private:
214 const char _bits[16] {
215 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
216 };
217
218 char _hex[sizeof(elem_type) * 2];
219
220 public:
221 Hex(const elem_type &elem, bool rev) {
222 if (!rev) {
223 const uint8_t *data = reinterpret_cast<const uint8_t *>(&elem) + sizeof(elem_type) - 1;
224 for (auto it = begin(); it < cend();) {
225 *it++ = _bits[*data / 16];
226 *it++ = _bits[*data-- % 16];
227 }
228 }
229 else {
230 const uint8_t *data = reinterpret_cast<const uint8_t *>(&elem);
231 for (auto it = begin(); it < cend();) {
232 *it++ = _bits[*data / 16];
233 *it++ = _bits[*data++ % 16];
234 }
235 }
236 }
237
238 char *
239 begin() { return _hex; }
240 char *
241 end() { return _hex + sizeof(elem_type) * 2; }
242
243 const char *
244 begin() const { return _hex; }
245 const char *
246 end() const { return _hex + sizeof(elem_type) * 2; }
247
248 const char *
249 cbegin() const { return _hex; }
250 const char *
251 cend() const { return _hex + sizeof(elem_type) * 2; }
252
253 std::string
254 to_string() const {
255 return { begin(), end() };
256 }
257
258 std::string_view
259 to_string_view() const {
260 return { begin(), sizeof(elem_type) * 2 };
261 }
262 };
263
264 template <class T>
265 Hex<T>
266 hex(const T &elem, bool rev = false) {
267 return Hex<T>(elem, rev);
268 }
269
270 template <typename T>
271 std::string
272 log_hex(const T &value) {
273 return "0x" + Hex<T>(value, false).to_string();
274 }
275
276 template <class It>
277 std::string
278 hex_vec(It begin, It end, bool rev = false) {
279 auto str_size = 2 * std::distance(begin, end);
280
281 std::string hex;
282 hex.resize(str_size);
283
284 const char _bits[16] {
285 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
286 };
287
288 if (rev) {
289 for (auto it = std::begin(hex); it < std::end(hex);) {
290 *it++ = _bits[((uint8_t) *begin) / 16];
291 *it++ = _bits[((uint8_t) *begin++) % 16];
292 }
293 }
294 else {
295 --end;
296 for (auto it = std::begin(hex); it < std::end(hex);) {
297 *it++ = _bits[((uint8_t) *end) / 16];
298 *it++ = _bits[((uint8_t) *end--) % 16];
299 }
300 }
301
302 return hex;
303 }
304
305 template <class C>
306 std::string
307 hex_vec(C &&c, bool rev = false) {
308 return hex_vec(std::begin(c), std::end(c), rev);
309 }
310
311 template <class T>
312 T
313 from_hex(const std::string_view &hex, bool rev = false) {
314 std::uint8_t buf[sizeof(T)];
315
316 static char constexpr shift_bit = 'a' - 'A';
317
318 auto is_convertable = [](char ch) -> bool {
319 if (isdigit(ch)) {
320 return true;
321 }
322
323 ch |= shift_bit;
324
325 if ('a' > ch || ch > 'z') {
326 return false;
327 }
328
329 return true;
330 };
331
332 auto buf_size = std::count_if(std::begin(hex), std::end(hex), is_convertable) / 2;
333 auto padding = sizeof(T) - buf_size;
334
335 const char *data = hex.data() + hex.size() - 1;
336
337 auto convert = [](char ch) -> std::uint8_t {
338 if (ch >= '0' && ch <= '9') {
339 return (std::uint8_t) ch - '0';
340 }
341
342 return (std::uint8_t)(ch | (char) 32) - 'a' + (char) 10;
343 };
344
345 std::fill_n(buf + buf_size, padding, 0);
346
347 std::for_each_n(buf, buf_size, [&](auto &el) {
348 while (!is_convertable(*data)) { --data; }
349 std::uint8_t ch_r = convert(*data--);
350
351 while (!is_convertable(*data)) { --data; }
352 std::uint8_t ch_l = convert(*data--);
353
354 el = (ch_l << 4) | ch_r;
355 });
356
357 if (rev) {
358 std::reverse(std::begin(buf), std::end(buf));
359 }
360
361 return *reinterpret_cast<T *>(buf);
362 }
363
364 inline std::string
365 from_hex_vec(const std::string &hex, bool rev = false) {
366 std::string buf;
367
368 static char constexpr shift_bit = 'a' - 'A';
369 auto is_convertable = [](char ch) -> bool {
370 if (isdigit(ch)) {
371 return true;
372 }
373
374 ch |= shift_bit;
375
376 if ('a' > ch || ch > 'z') {
377 return false;
378 }
379
380 return true;
381 };
382
383 auto buf_size = std::count_if(std::begin(hex), std::end(hex), is_convertable) / 2;
384 buf.resize(buf_size);
385
386 const char *data = hex.data() + hex.size() - 1;
387
388 auto convert = [](char ch) -> std::uint8_t {
389 if (ch >= '0' && ch <= '9') {
390 return (std::uint8_t) ch - '0';
391 }
392
393 return (std::uint8_t)(ch | (char) 32) - 'a' + (char) 10;
394 };
395
396 for (auto &el : buf) {
397 while (!is_convertable(*data)) { --data; }
398 std::uint8_t ch_r = convert(*data--);
399
400 while (!is_convertable(*data)) { --data; }
401 std::uint8_t ch_l = convert(*data--);
402
403 el = (ch_l << 4) | ch_r;
404 }
405
406 if (rev) {
407 std::reverse(std::begin(buf), std::end(buf));
408 }
409
410 return buf;
411 }
412
413 template <class T>
414 class hash {
415 public:
416 using value_type = T;
417 std::size_t
418 operator()(const value_type &value) const {
419 const auto *p = reinterpret_cast<const char *>(&value);
420
421 return std::hash<std::string_view> {}(std::string_view { p, sizeof(value_type) });
422 }
423 };
424
425 template <class T>
426 auto
427 enm(const T &val) -> const std::underlying_type_t<T> & {
428 return *reinterpret_cast<const std::underlying_type_t<T> *>(&val);
429 }
430
431 template <class T>
432 auto
433 enm(T &val) -> std::underlying_type_t<T> & {
434 return *reinterpret_cast<std::underlying_type_t<T> *>(&val);
435 }
436
437 inline std::int64_t
438 from_chars(const char *begin, const char *end) {
439 if (begin == end) {
440 return 0;
441 }
442
443 std::int64_t res {};
444 std::int64_t mul = 1;
445 while (begin != --end) {
446 res += (std::int64_t)(*end - '0') * mul;
447
448 mul *= 10;
449 }
450
451 return *begin != '-' ? res + (std::int64_t)(*begin - '0') * mul : -res;
452 }
453
454 inline std::int64_t
455 from_view(const std::string_view &number) {
456 return from_chars(std::begin(number), std::end(number));
457 }
458
459 template <class X, class Y>
460 class Either: public std::variant<std::monostate, X, Y> {
461 public:
462 using std::variant<std::monostate, X, Y>::variant;
463
464 constexpr bool
465 has_left() const {
466 return std::holds_alternative<X>(*this);
467 }
468 constexpr bool
469 has_right() const {
470 return std::holds_alternative<Y>(*this);
471 }
472
473 X &
474 left() {
475 return std::get<X>(*this);
476 }
477
478 Y &
479 right() {
480 return std::get<Y>(*this);
481 }
482
483 const X &
484 left() const {
485 return std::get<X>(*this);
486 }
487
488 const Y &
489 right() const {
490 return std::get<Y>(*this);
491 }
492 };
493
494 // Compared to std::unique_ptr, it adds the ability to get the address of the pointer itself
495 template <typename T, typename D = std::default_delete<T>>
496 class uniq_ptr {
497 public:
498 using element_type = T;
499 using pointer = element_type *;
500 using const_pointer = element_type const *;
501 using deleter_type = D;
502
503 constexpr uniq_ptr() noexcept:
504 _p { nullptr } {}
505 constexpr uniq_ptr(std::nullptr_t) noexcept:
506 _p { nullptr } {}
507
508 uniq_ptr(const uniq_ptr &other) noexcept = delete;
509 uniq_ptr &
510 operator=(const uniq_ptr &other) noexcept = delete;
511
512 template <class V>
513 uniq_ptr(V *p) noexcept:
514 _p { p } {
515 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");
516 }
517
518 template <class V>
519 uniq_ptr(std::unique_ptr<V, deleter_type> &&uniq) noexcept:
520 _p { uniq.release() } {
521 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");
522 }
523
524 template <class V>
525 uniq_ptr(uniq_ptr<V, deleter_type> &&other) noexcept:
526 _p { other.release() } {
527 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");
528 }
529
530 template <class V>
531 uniq_ptr &
532 operator=(uniq_ptr<V, deleter_type> &&other) noexcept {
533 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");
534 reset(other.release());
535
536 return *this;
537 }
538
539 template <class V>
540 uniq_ptr &
541 operator=(std::unique_ptr<V, deleter_type> &&uniq) noexcept {
542 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");
543
544 reset(uniq.release());
545
546 return *this;
547 }
548
549 ~uniq_ptr() {
550 reset();
551 }
552
553 void
554 reset(pointer p = pointer()) {
555 if (_p) {
556 _deleter(_p);
557 }
558
559 _p = p;
560 }
561
562 pointer
563 release() {
564 auto tmp = _p;
565 _p = nullptr;
566 return tmp;
567 }
568
569 pointer
570 get() {
571 return _p;
572 }
573
574 const_pointer
575 get() const {
576 return _p;
577 }
578
579 std::add_lvalue_reference_t<element_type const>
580 operator*() const {
581 return *_p;
582 }
583 std::add_lvalue_reference_t<element_type>
584 operator*() {
585 return *_p;
586 }
587 const_pointer
588 operator->() const {
589 return _p;
590 }
591 pointer
592 operator->() {
593 return _p;
594 }
595 pointer *
596 operator&() const {
597 return &_p;
598 }
599
600 pointer *
601 operator&() {
602 return &_p;
603 }
604
605 deleter_type &
606 get_deleter() {
607 return _deleter;
608 }
609
610 const deleter_type &
611 get_deleter() const {
612 return _deleter;
613 }
614
615 explicit
616 operator bool() const {
617 return _p != nullptr;
618 }
619
620 protected:
621 pointer _p;
622 deleter_type _deleter;
623 };
624
625 template <class T1, class D1, class T2, class D2>
626 bool
627 operator==(const uniq_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
628 return x.get() == y.get();
629 }
630
631 template <class T1, class D1, class T2, class D2>
632 bool
633 operator!=(const uniq_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
634 return x.get() != y.get();
635 }
636
637 template <class T1, class D1, class T2, class D2>
638 bool
639 operator==(const std::unique_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
640 return x.get() == y.get();
641 }
642
643 template <class T1, class D1, class T2, class D2>
644 bool
645 operator!=(const std::unique_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
646 return x.get() != y.get();
647 }
648
649 template <class T1, class D1, class T2, class D2>
650 bool
651 operator==(const uniq_ptr<T1, D1> &x, const std::unique_ptr<T1, D1> &y) {
652 return x.get() == y.get();
653 }
654
655 template <class T1, class D1, class T2, class D2>
656 bool
657 operator!=(const uniq_ptr<T1, D1> &x, const std::unique_ptr<T1, D1> &y) {
658 return x.get() != y.get();
659 }
660
661 template <class T, class D>
662 bool
663 operator==(const uniq_ptr<T, D> &x, std::nullptr_t) {
664 return !(bool) x;
665 }
666
667 template <class T, class D>
668 bool
669 operator!=(const uniq_ptr<T, D> &x, std::nullptr_t) {
670 return (bool) x;
671 }
672
673 template <class T, class D>
674 bool
675 operator==(std::nullptr_t, const uniq_ptr<T, D> &y) {
676 return !(bool) y;
677 }
678
679 template <class T, class D>
680 bool
681 operator!=(std::nullptr_t, const uniq_ptr<T, D> &y) {
682 return (bool) y;
683 }
684
685 template <class P>
686 using shared_t = std::shared_ptr<typename P::element_type>;
687
688 template <class P, class T>
689 shared_t<P>
690 make_shared(T *pointer) {
691 return shared_t<P>(reinterpret_cast<typename P::pointer>(pointer), typename P::deleter_type());
692 }
693
694 template <class T>
695 class wrap_ptr {
696 public:
697 using element_type = T;
698 using pointer = element_type *;
699 using const_pointer = element_type const *;
700 using reference = element_type &;
701 using const_reference = element_type const &;
702
703 wrap_ptr():
704 _own_ptr { false }, _p { nullptr } {}
705 wrap_ptr(pointer p):
706 _own_ptr { false }, _p { p } {}
707 wrap_ptr(std::unique_ptr<element_type> &&uniq_p):
708 _own_ptr { true }, _p { uniq_p.release() } {}
709 wrap_ptr(wrap_ptr &&other):
710 _own_ptr { other._own_ptr }, _p { other._p } {
711 other._own_ptr = false;
712 }
713
714 wrap_ptr &
715 operator=(wrap_ptr &&other) noexcept {
716 if (_own_ptr) {
717 delete _p;
718 }
719
720 _p = other._p;
721
722 _own_ptr = other._own_ptr;
723 other._own_ptr = false;
724
725 return *this;
726 }
727
728 template <class V>
729 wrap_ptr &
730 operator=(std::unique_ptr<V> &&uniq_ptr) {
731 static_assert(std::is_base_of_v<element_type, V>, "element_type must be base class of V");
732 _own_ptr = true;
733 _p = uniq_ptr.release();
734
735 return *this;
736 }
737
738 wrap_ptr &
739 operator=(pointer p) {
740 if (_own_ptr) {
741 delete _p;
742 }
743
744 _p = p;
745 _own_ptr = false;
746
747 return *this;
748 }
749
750 ~wrap_ptr() {
751 if (_own_ptr) {
752 delete _p;
753 }
754
755 _own_ptr = false;
756 }
757
758 const_reference
759 operator*() const {
760 return *_p;
761 }
762 reference
763 operator*() {
764 return *_p;
765 }
766 const_pointer
767 operator->() const {
768 return _p;
769 }
770 pointer
771 operator->() {
772 return _p;
773 }
774
775 private:
776 bool _own_ptr;
777 pointer _p;
778 };
779
780 template <class T>
781 constexpr bool is_pointer_v =
782 instantiation_of_v<std::unique_ptr, T> ||
783 instantiation_of_v<std::shared_ptr, T> ||
784 instantiation_of_v<uniq_ptr, T> ||
785 std::is_pointer_v<T>;
786
787 template <class T, class V = void>
788 struct __false_v;
789
790 template <class T>
791 struct __false_v<T, std::enable_if_t<instantiation_of_v<std::optional, T>>> {
792 static constexpr std::nullopt_t value = std::nullopt;
793 };
794
795 template <class T>
796 struct __false_v<T, std::enable_if_t<is_pointer_v<T>>> {
797 static constexpr std::nullptr_t value = nullptr;
798 };
799
800 template <class T>
801 struct __false_v<T, std::enable_if_t<std::is_same_v<T, bool>>> {
802 static constexpr bool value = false;
803 };
804
805 template <class T>
806 static constexpr auto false_v = __false_v<T>::value;
807
808 template <class T>
809 using optional_t = either_t<
810 (std::is_same_v<T, bool> || is_pointer_v<T>),
811 T, std::optional<T>>;
812
813 template <class T>
814 class buffer_t {
815 public:
816 buffer_t():
817 _els { 0 } {};
818 buffer_t(buffer_t &&o) noexcept:
819 _els { o._els }, _buf { std::move(o._buf) } {
820 o._els = 0;
821 }
822 buffer_t(const buffer_t &o):
823 _els { o._els }, _buf { std::make_unique<T[]>(_els) } {
824 std::copy(o.begin(), o.end(), begin());
825 }
826 buffer_t &
827 operator=(buffer_t &&o) noexcept {
828 std::swap(_els, o._els);
829 std::swap(_buf, o._buf);
830
831 return *this;
832 };
833
834 explicit buffer_t(size_t elements):
835 _els { elements }, _buf { std::make_unique<T[]>(elements) } {}
836 explicit buffer_t(size_t elements, const T &t):
837 _els { elements }, _buf { std::make_unique<T[]>(elements) } {
838 std::fill_n(_buf.get(), elements, t);
839 }
840
841 T &
842 operator[](size_t el) {
843 return _buf[el];
844 }
845
846 const T &
847 operator[](size_t el) const {
848 return _buf[el];
849 }
850
851 size_t
852 size() const {
853 return _els;
854 }
855
856 void
857 fake_resize(std::size_t els) {
858 _els = els;
859 }
860
861 T *
862 begin() {
863 return _buf.get();
864 }
865
866 const T *
867 begin() const {
868 return _buf.get();
869 }
870
871 T *
872 end() {
873 return _buf.get() + _els;
874 }
875
876 const T *
877 end() const {
878 return _buf.get() + _els;
879 }
880
881 private:
882 size_t _els;
883 std::unique_ptr<T[]> _buf;
884 };
885
886 template <class T>
887 T
888 either(std::optional<T> &&l, T &&r) {
889 if (l) {
890 return std::move(*l);
891 }
892
893 return std::forward<T>(r);
894 }
895
896 template <class ReturnType, class... Args>
897 struct Function {
898 typedef ReturnType (*type)(Args...);
899 };
900
901 template <class T, class ReturnType, typename Function<ReturnType, T>::type function>
902 struct Destroy {
903 typedef T pointer;
904
905 void
906 operator()(pointer p) {
907 function(p);
908 }
909 };
910
911 template <class T, typename Function<void, T *>::type function>
913
914 // You cannot specialize an alias
915 template <class T, class ReturnType, typename Function<ReturnType, T *>::type function>
917
918 template <class T>
919 void
920 c_free(T *p) {
921 free(p);
922 }
923
924 template <class T, class ReturnType, ReturnType (**function)(T *)>
925 void
926 dynamic(T *p) {
927 (*function)(p);
928 }
929
930 template <class T, void (**function)(T *)>
931 using dyn_safe_ptr = safe_ptr<T, dynamic<T, void, function>>;
932
933 template <class T, class ReturnType, ReturnType (**function)(T *)>
934 using dyn_safe_ptr_v2 = safe_ptr<T, dynamic<T, ReturnType, function>>;
935
936 template <class T>
937 using c_ptr = safe_ptr<T, c_free<T>>;
938
939 template <class It>
940 std::string_view
941 view(It begin, It end) {
942 return std::string_view { (const char *) begin, (std::size_t)(end - begin) };
943 }
944
945 template <class T>
946 std::string_view
947 view(const T &data) {
948 return std::string_view((const char *) &data, sizeof(T));
949 }
950
951 struct point_t {
952 double x;
953 double y;
954
955 friend std::ostream &
956 operator<<(std::ostream &os, const point_t &p) {
957 return (os << "Point(x: " << p.x << ", y: " << p.y << ")");
958 }
959 };
960
961 namespace endian {
962 template <class T = void>
963 struct endianness {
964 enum : bool {
965#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \
966 defined(__BIG_ENDIAN__) || \
967 defined(__ARMEB__) || \
968 defined(__THUMBEB__) || \
969 defined(__AARCH64EB__) || \
970 defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
971 // It's a big-endian target architecture
972 little = false,
973#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \
974 defined(__LITTLE_ENDIAN__) || \
975 defined(__ARMEL__) || \
976 defined(__THUMBEL__) || \
977 defined(__AARCH64EL__) || \
978 defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
979 defined(_WIN32)
980 little = true,
981#else
982 #error "Unknown Endianness"
983#endif
984 big = !little
985 };
986 };
987
988 template <class T, class S = void>
989 struct endian_helper {};
990
991 template <class T>
992 struct endian_helper<T, std::enable_if_t<
993 !(instantiation_of_v<std::optional, T>)>> {
994 static inline T
995 big(T x) {
996 if constexpr (endianness<T>::little) {
997 uint8_t *data = reinterpret_cast<uint8_t *>(&x);
998
999 std::reverse(data, data + sizeof(x));
1000 }
1001
1002 return x;
1003 }
1004
1005 static inline T
1006 little(T x) {
1007 if constexpr (endianness<T>::big) {
1008 uint8_t *data = reinterpret_cast<uint8_t *>(&x);
1009
1010 std::reverse(data, data + sizeof(x));
1011 }
1012
1013 return x;
1014 }
1015 };
1016
1017 template <class T>
1018 struct endian_helper<T, std::enable_if_t<
1019 instantiation_of_v<std::optional, T>>> {
1020 static inline T
1021 little(T x) {
1022 if (!x) return x;
1023
1024 if constexpr (endianness<T>::big) {
1025 auto *data = reinterpret_cast<uint8_t *>(&*x);
1026
1027 std::reverse(data, data + sizeof(*x));
1028 }
1029
1030 return x;
1031 }
1032
1033 static inline T
1034 big(T x) {
1035 if (!x) return x;
1036
1037 if constexpr (endianness<T>::little) {
1038 auto *data = reinterpret_cast<uint8_t *>(&*x);
1039
1040 std::reverse(data, data + sizeof(*x));
1041 }
1042
1043 return x;
1044 }
1045 };
1046
1047 template <class T>
1048 inline auto
1049 little(T x) { return endian_helper<T>::little(x); }
1050
1051 template <class T>
1052 inline auto
1053 big(T x) { return endian_helper<T>::big(x); }
1054 } // namespace endian
1055} // namespace util
Definition utility.h:460
Definition utility.h:155
Definition utility.h:209
Definition utility.h:814
Definition utility.h:414
Definition utility.h:496
Definition utility.h:695
Definition utility.h:26
Definition utility.h:902
Definition utility.h:897
Definition utility.h:132
Definition utility.h:788
Definition utility.h:123
Definition utility.h:989
Definition utility.h:963
@ little
little-endian target architecture
Definition utility.h:980
@ big
big-endian target architecture
Definition utility.h:984
Definition utility.h:148
Definition utility.h:951