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