swap.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. // Copyright (c) 2012- PPSSPP Project / Dolphin Project.
  2. // This program is free software: you can redistribute it and/or modify
  3. // it under the terms of the GNU General Public License as published by
  4. // the Free Software Foundation, version 2.0 or later versions.
  5. // This program is distributed in the hope that it will be useful,
  6. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. // GNU General Public License 2.0 for more details.
  9. // A copy of the GPL 2.0 should have been included with the program.
  10. // If not, see http://www.gnu.org/licenses/
  11. // Official git repository and contact information can be found at
  12. // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
  13. #pragma once
  14. #include <type_traits>
  15. #if defined(_MSC_VER)
  16. #include <cstdlib>
  17. #elif defined(__linux__)
  18. #include <byteswap.h>
  19. #elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
  20. defined(__NetBSD__) || defined(__OpenBSD__)
  21. #include <sys/endian.h>
  22. #endif
  23. #include <cstring>
  24. #include "common/common_types.h"
  25. // GCC
  26. #ifdef __GNUC__
  27. #if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN)
  28. #define COMMON_LITTLE_ENDIAN 1
  29. #elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && !defined(COMMON_BIG_ENDIAN)
  30. #define COMMON_BIG_ENDIAN 1
  31. #endif
  32. // LLVM/clang
  33. #elif defined(__clang__)
  34. #if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN)
  35. #define COMMON_LITTLE_ENDIAN 1
  36. #elif __BIG_ENDIAN__ && !defined(COMMON_BIG_ENDIAN)
  37. #define COMMON_BIG_ENDIAN 1
  38. #endif
  39. // MSVC
  40. #elif defined(_MSC_VER) && !defined(COMMON_BIG_ENDIAN) && !defined(COMMON_LITTLE_ENDIAN)
  41. #define COMMON_LITTLE_ENDIAN 1
  42. #endif
  43. // Worst case, default to little endian.
  44. #if !COMMON_BIG_ENDIAN && !COMMON_LITTLE_ENDIAN
  45. #define COMMON_LITTLE_ENDIAN 1
  46. #endif
  47. namespace Common {
  48. #ifdef _MSC_VER
  49. inline u16 swap16(u16 _data) {
  50. return _byteswap_ushort(_data);
  51. }
  52. inline u32 swap32(u32 _data) {
  53. return _byteswap_ulong(_data);
  54. }
  55. inline u64 swap64(u64 _data) {
  56. return _byteswap_uint64(_data);
  57. }
  58. #elif defined(ARCHITECTURE_ARM) && (__ARM_ARCH >= 6)
  59. inline u16 swap16(u16 _data) {
  60. u32 data = _data;
  61. __asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data));
  62. return (u16)data;
  63. }
  64. inline u32 swap32(u32 _data) {
  65. __asm__("rev %0, %1\n" : "=l"(_data) : "l"(_data));
  66. return _data;
  67. }
  68. inline u64 swap64(u64 _data) {
  69. return ((u64)swap32(_data) << 32) | swap32(_data >> 32);
  70. }
  71. #elif __linux__
  72. inline u16 swap16(u16 _data) {
  73. return bswap_16(_data);
  74. }
  75. inline u32 swap32(u32 _data) {
  76. return bswap_32(_data);
  77. }
  78. inline u64 swap64(u64 _data) {
  79. return bswap_64(_data);
  80. }
  81. #elif __APPLE__
  82. inline __attribute__((always_inline)) u16 swap16(u16 _data) {
  83. return (_data >> 8) | (_data << 8);
  84. }
  85. inline __attribute__((always_inline)) u32 swap32(u32 _data) {
  86. return __builtin_bswap32(_data);
  87. }
  88. inline __attribute__((always_inline)) u64 swap64(u64 _data) {
  89. return __builtin_bswap64(_data);
  90. }
  91. #elif defined(__Bitrig__) || defined(__OpenBSD__)
  92. // redefine swap16, swap32, swap64 as inline functions
  93. #undef swap16
  94. #undef swap32
  95. #undef swap64
  96. inline u16 swap16(u16 _data) {
  97. return __swap16(_data);
  98. }
  99. inline u32 swap32(u32 _data) {
  100. return __swap32(_data);
  101. }
  102. inline u64 swap64(u64 _data) {
  103. return __swap64(_data);
  104. }
  105. #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
  106. inline u16 swap16(u16 _data) {
  107. return bswap16(_data);
  108. }
  109. inline u32 swap32(u32 _data) {
  110. return bswap32(_data);
  111. }
  112. inline u64 swap64(u64 _data) {
  113. return bswap64(_data);
  114. }
  115. #else
  116. // Slow generic implementation.
  117. inline u16 swap16(u16 data) {
  118. return (data >> 8) | (data << 8);
  119. }
  120. inline u32 swap32(u32 data) {
  121. return (swap16(data) << 16) | swap16(data >> 16);
  122. }
  123. inline u64 swap64(u64 data) {
  124. return ((u64)swap32(data) << 32) | swap32(data >> 32);
  125. }
  126. #endif
  127. inline float swapf(float f) {
  128. static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t.");
  129. u32 value;
  130. std::memcpy(&value, &f, sizeof(u32));
  131. value = swap32(value);
  132. std::memcpy(&f, &value, sizeof(u32));
  133. return f;
  134. }
  135. inline double swapd(double f) {
  136. static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t.");
  137. u64 value;
  138. std::memcpy(&value, &f, sizeof(u64));
  139. value = swap64(value);
  140. std::memcpy(&f, &value, sizeof(u64));
  141. return f;
  142. }
  143. } // Namespace Common
  144. template <typename T, typename F>
  145. struct swap_struct_t {
  146. using swapped_t = swap_struct_t;
  147. protected:
  148. T value;
  149. static T swap(T v) {
  150. return F::swap(v);
  151. }
  152. public:
  153. T swap() const {
  154. return swap(value);
  155. }
  156. swap_struct_t() = default;
  157. swap_struct_t(const T& v) : value(swap(v)) {}
  158. template <typename S>
  159. swapped_t& operator=(const S& source) {
  160. value = swap(static_cast<T>(source));
  161. return *this;
  162. }
  163. operator s8() const {
  164. return static_cast<s8>(swap());
  165. }
  166. operator u8() const {
  167. return static_cast<u8>(swap());
  168. }
  169. operator s16() const {
  170. return static_cast<s16>(swap());
  171. }
  172. operator u16() const {
  173. return static_cast<u16>(swap());
  174. }
  175. operator s32() const {
  176. return static_cast<s32>(swap());
  177. }
  178. operator u32() const {
  179. return static_cast<u32>(swap());
  180. }
  181. operator s64() const {
  182. return static_cast<s64>(swap());
  183. }
  184. operator u64() const {
  185. return static_cast<u64>(swap());
  186. }
  187. operator float() const {
  188. return static_cast<float>(swap());
  189. }
  190. operator double() const {
  191. return static_cast<double>(swap());
  192. }
  193. // +v
  194. swapped_t operator+() const {
  195. return +swap();
  196. }
  197. // -v
  198. swapped_t operator-() const {
  199. return -swap();
  200. }
  201. // v / 5
  202. swapped_t operator/(const swapped_t& i) const {
  203. return swap() / i.swap();
  204. }
  205. template <typename S>
  206. swapped_t operator/(const S& i) const {
  207. return swap() / i;
  208. }
  209. // v * 5
  210. swapped_t operator*(const swapped_t& i) const {
  211. return swap() * i.swap();
  212. }
  213. template <typename S>
  214. swapped_t operator*(const S& i) const {
  215. return swap() * i;
  216. }
  217. // v + 5
  218. swapped_t operator+(const swapped_t& i) const {
  219. return swap() + i.swap();
  220. }
  221. template <typename S>
  222. swapped_t operator+(const S& i) const {
  223. return swap() + static_cast<T>(i);
  224. }
  225. // v - 5
  226. swapped_t operator-(const swapped_t& i) const {
  227. return swap() - i.swap();
  228. }
  229. template <typename S>
  230. swapped_t operator-(const S& i) const {
  231. return swap() - static_cast<T>(i);
  232. }
  233. // v += 5
  234. swapped_t& operator+=(const swapped_t& i) {
  235. value = swap(swap() + i.swap());
  236. return *this;
  237. }
  238. template <typename S>
  239. swapped_t& operator+=(const S& i) {
  240. value = swap(swap() + static_cast<T>(i));
  241. return *this;
  242. }
  243. // v -= 5
  244. swapped_t& operator-=(const swapped_t& i) {
  245. value = swap(swap() - i.swap());
  246. return *this;
  247. }
  248. template <typename S>
  249. swapped_t& operator-=(const S& i) {
  250. value = swap(swap() - static_cast<T>(i));
  251. return *this;
  252. }
  253. // ++v
  254. swapped_t& operator++() {
  255. value = swap(swap() + 1);
  256. return *this;
  257. }
  258. // --v
  259. swapped_t& operator--() {
  260. value = swap(swap() - 1);
  261. return *this;
  262. }
  263. // v++
  264. swapped_t operator++(int) {
  265. swapped_t old = *this;
  266. value = swap(swap() + 1);
  267. return old;
  268. }
  269. // v--
  270. swapped_t operator--(int) {
  271. swapped_t old = *this;
  272. value = swap(swap() - 1);
  273. return old;
  274. }
  275. // Comparaison
  276. // v == i
  277. bool operator==(const swapped_t& i) const {
  278. return swap() == i.swap();
  279. }
  280. template <typename S>
  281. bool operator==(const S& i) const {
  282. return swap() == i;
  283. }
  284. // v != i
  285. bool operator!=(const swapped_t& i) const {
  286. return swap() != i.swap();
  287. }
  288. template <typename S>
  289. bool operator!=(const S& i) const {
  290. return swap() != i;
  291. }
  292. // v > i
  293. bool operator>(const swapped_t& i) const {
  294. return swap() > i.swap();
  295. }
  296. template <typename S>
  297. bool operator>(const S& i) const {
  298. return swap() > i;
  299. }
  300. // v < i
  301. bool operator<(const swapped_t& i) const {
  302. return swap() < i.swap();
  303. }
  304. template <typename S>
  305. bool operator<(const S& i) const {
  306. return swap() < i;
  307. }
  308. // v >= i
  309. bool operator>=(const swapped_t& i) const {
  310. return swap() >= i.swap();
  311. }
  312. template <typename S>
  313. bool operator>=(const S& i) const {
  314. return swap() >= i;
  315. }
  316. // v <= i
  317. bool operator<=(const swapped_t& i) const {
  318. return swap() <= i.swap();
  319. }
  320. template <typename S>
  321. bool operator<=(const S& i) const {
  322. return swap() <= i;
  323. }
  324. // logical
  325. swapped_t operator!() const {
  326. return !swap();
  327. }
  328. // bitmath
  329. swapped_t operator~() const {
  330. return ~swap();
  331. }
  332. swapped_t operator&(const swapped_t& b) const {
  333. return swap() & b.swap();
  334. }
  335. template <typename S>
  336. swapped_t operator&(const S& b) const {
  337. return swap() & b;
  338. }
  339. swapped_t& operator&=(const swapped_t& b) {
  340. value = swap(swap() & b.swap());
  341. return *this;
  342. }
  343. template <typename S>
  344. swapped_t& operator&=(const S b) {
  345. value = swap(swap() & b);
  346. return *this;
  347. }
  348. swapped_t operator|(const swapped_t& b) const {
  349. return swap() | b.swap();
  350. }
  351. template <typename S>
  352. swapped_t operator|(const S& b) const {
  353. return swap() | b;
  354. }
  355. swapped_t& operator|=(const swapped_t& b) {
  356. value = swap(swap() | b.swap());
  357. return *this;
  358. }
  359. template <typename S>
  360. swapped_t& operator|=(const S& b) {
  361. value = swap(swap() | b);
  362. return *this;
  363. }
  364. swapped_t operator^(const swapped_t& b) const {
  365. return swap() ^ b.swap();
  366. }
  367. template <typename S>
  368. swapped_t operator^(const S& b) const {
  369. return swap() ^ b;
  370. }
  371. swapped_t& operator^=(const swapped_t& b) {
  372. value = swap(swap() ^ b.swap());
  373. return *this;
  374. }
  375. template <typename S>
  376. swapped_t& operator^=(const S& b) {
  377. value = swap(swap() ^ b);
  378. return *this;
  379. }
  380. template <typename S>
  381. swapped_t operator<<(const S& b) const {
  382. return swap() << b;
  383. }
  384. template <typename S>
  385. swapped_t& operator<<=(const S& b) const {
  386. value = swap(swap() << b);
  387. return *this;
  388. }
  389. template <typename S>
  390. swapped_t operator>>(const S& b) const {
  391. return swap() >> b;
  392. }
  393. template <typename S>
  394. swapped_t& operator>>=(const S& b) const {
  395. value = swap(swap() >> b);
  396. return *this;
  397. }
  398. // Member
  399. /** todo **/
  400. // Arithmetics
  401. template <typename S, typename T2, typename F2>
  402. friend S operator+(const S& p, const swapped_t v);
  403. template <typename S, typename T2, typename F2>
  404. friend S operator-(const S& p, const swapped_t v);
  405. template <typename S, typename T2, typename F2>
  406. friend S operator/(const S& p, const swapped_t v);
  407. template <typename S, typename T2, typename F2>
  408. friend S operator*(const S& p, const swapped_t v);
  409. template <typename S, typename T2, typename F2>
  410. friend S operator%(const S& p, const swapped_t v);
  411. // Arithmetics + assignements
  412. template <typename S, typename T2, typename F2>
  413. friend S operator+=(const S& p, const swapped_t v);
  414. template <typename S, typename T2, typename F2>
  415. friend S operator-=(const S& p, const swapped_t v);
  416. // Bitmath
  417. template <typename S, typename T2, typename F2>
  418. friend S operator&(const S& p, const swapped_t v);
  419. // Comparison
  420. template <typename S, typename T2, typename F2>
  421. friend bool operator<(const S& p, const swapped_t v);
  422. template <typename S, typename T2, typename F2>
  423. friend bool operator>(const S& p, const swapped_t v);
  424. template <typename S, typename T2, typename F2>
  425. friend bool operator<=(const S& p, const swapped_t v);
  426. template <typename S, typename T2, typename F2>
  427. friend bool operator>=(const S& p, const swapped_t v);
  428. template <typename S, typename T2, typename F2>
  429. friend bool operator!=(const S& p, const swapped_t v);
  430. template <typename S, typename T2, typename F2>
  431. friend bool operator==(const S& p, const swapped_t v);
  432. };
  433. // Arithmetics
  434. template <typename S, typename T, typename F>
  435. S operator+(const S& i, const swap_struct_t<T, F> v) {
  436. return i + v.swap();
  437. }
  438. template <typename S, typename T, typename F>
  439. S operator-(const S& i, const swap_struct_t<T, F> v) {
  440. return i - v.swap();
  441. }
  442. template <typename S, typename T, typename F>
  443. S operator/(const S& i, const swap_struct_t<T, F> v) {
  444. return i / v.swap();
  445. }
  446. template <typename S, typename T, typename F>
  447. S operator*(const S& i, const swap_struct_t<T, F> v) {
  448. return i * v.swap();
  449. }
  450. template <typename S, typename T, typename F>
  451. S operator%(const S& i, const swap_struct_t<T, F> v) {
  452. return i % v.swap();
  453. }
  454. // Arithmetics + assignements
  455. template <typename S, typename T, typename F>
  456. S& operator+=(S& i, const swap_struct_t<T, F> v) {
  457. i += v.swap();
  458. return i;
  459. }
  460. template <typename S, typename T, typename F>
  461. S& operator-=(S& i, const swap_struct_t<T, F> v) {
  462. i -= v.swap();
  463. return i;
  464. }
  465. // Logical
  466. template <typename S, typename T, typename F>
  467. S operator&(const S& i, const swap_struct_t<T, F> v) {
  468. return i & v.swap();
  469. }
  470. template <typename S, typename T, typename F>
  471. S operator&(const swap_struct_t<T, F> v, const S& i) {
  472. return static_cast<S>(v.swap() & i);
  473. }
  474. // Comparaison
  475. template <typename S, typename T, typename F>
  476. bool operator<(const S& p, const swap_struct_t<T, F> v) {
  477. return p < v.swap();
  478. }
  479. template <typename S, typename T, typename F>
  480. bool operator>(const S& p, const swap_struct_t<T, F> v) {
  481. return p > v.swap();
  482. }
  483. template <typename S, typename T, typename F>
  484. bool operator<=(const S& p, const swap_struct_t<T, F> v) {
  485. return p <= v.swap();
  486. }
  487. template <typename S, typename T, typename F>
  488. bool operator>=(const S& p, const swap_struct_t<T, F> v) {
  489. return p >= v.swap();
  490. }
  491. template <typename S, typename T, typename F>
  492. bool operator!=(const S& p, const swap_struct_t<T, F> v) {
  493. return p != v.swap();
  494. }
  495. template <typename S, typename T, typename F>
  496. bool operator==(const S& p, const swap_struct_t<T, F> v) {
  497. return p == v.swap();
  498. }
  499. template <typename T>
  500. struct swap_64_t {
  501. static T swap(T x) {
  502. return static_cast<T>(Common::swap64(x));
  503. }
  504. };
  505. template <typename T>
  506. struct swap_32_t {
  507. static T swap(T x) {
  508. return static_cast<T>(Common::swap32(x));
  509. }
  510. };
  511. template <typename T>
  512. struct swap_16_t {
  513. static T swap(T x) {
  514. return static_cast<T>(Common::swap16(x));
  515. }
  516. };
  517. template <typename T>
  518. struct swap_float_t {
  519. static T swap(T x) {
  520. return static_cast<T>(Common::swapf(x));
  521. }
  522. };
  523. template <typename T>
  524. struct swap_double_t {
  525. static T swap(T x) {
  526. return static_cast<T>(Common::swapd(x));
  527. }
  528. };
  529. template <typename T>
  530. struct swap_enum_t {
  531. static_assert(std::is_enum_v<T>);
  532. using base = std::underlying_type_t<T>;
  533. public:
  534. swap_enum_t() = default;
  535. swap_enum_t(const T& v) : value(swap(v)) {}
  536. swap_enum_t& operator=(const T& v) {
  537. value = swap(v);
  538. return *this;
  539. }
  540. operator T() const {
  541. return swap(value);
  542. }
  543. explicit operator base() const {
  544. return static_cast<base>(swap(value));
  545. }
  546. protected:
  547. T value{};
  548. // clang-format off
  549. using swap_t = std::conditional_t<
  550. std::is_same_v<base, u16>, swap_16_t<u16>, std::conditional_t<
  551. std::is_same_v<base, s16>, swap_16_t<s16>, std::conditional_t<
  552. std::is_same_v<base, u32>, swap_32_t<u32>, std::conditional_t<
  553. std::is_same_v<base, s32>, swap_32_t<s32>, std::conditional_t<
  554. std::is_same_v<base, u64>, swap_64_t<u64>, std::conditional_t<
  555. std::is_same_v<base, s64>, swap_64_t<s64>, void>>>>>>;
  556. // clang-format on
  557. static T swap(T x) {
  558. return static_cast<T>(swap_t::swap(static_cast<base>(x)));
  559. }
  560. };
  561. struct SwapTag {}; // Use the different endianness from the system
  562. struct KeepTag {}; // Use the same endianness as the system
  563. template <typename T, typename Tag>
  564. struct AddEndian;
  565. // KeepTag specializations
  566. template <typename T>
  567. struct AddEndian<T, KeepTag> {
  568. using type = T;
  569. };
  570. // SwapTag specializations
  571. template <>
  572. struct AddEndian<u8, SwapTag> {
  573. using type = u8;
  574. };
  575. template <>
  576. struct AddEndian<u16, SwapTag> {
  577. using type = swap_struct_t<u16, swap_16_t<u16>>;
  578. };
  579. template <>
  580. struct AddEndian<u32, SwapTag> {
  581. using type = swap_struct_t<u32, swap_32_t<u32>>;
  582. };
  583. template <>
  584. struct AddEndian<u64, SwapTag> {
  585. using type = swap_struct_t<u64, swap_64_t<u64>>;
  586. };
  587. template <>
  588. struct AddEndian<s8, SwapTag> {
  589. using type = s8;
  590. };
  591. template <>
  592. struct AddEndian<s16, SwapTag> {
  593. using type = swap_struct_t<s16, swap_16_t<s16>>;
  594. };
  595. template <>
  596. struct AddEndian<s32, SwapTag> {
  597. using type = swap_struct_t<s32, swap_32_t<s32>>;
  598. };
  599. template <>
  600. struct AddEndian<s64, SwapTag> {
  601. using type = swap_struct_t<s64, swap_64_t<s64>>;
  602. };
  603. template <>
  604. struct AddEndian<float, SwapTag> {
  605. using type = swap_struct_t<float, swap_float_t<float>>;
  606. };
  607. template <>
  608. struct AddEndian<double, SwapTag> {
  609. using type = swap_struct_t<double, swap_double_t<double>>;
  610. };
  611. template <typename T>
  612. struct AddEndian<T, SwapTag> {
  613. static_assert(std::is_enum_v<T>);
  614. using type = swap_enum_t<T>;
  615. };
  616. // Alias LETag/BETag as KeepTag/SwapTag depending on the system
  617. #if COMMON_LITTLE_ENDIAN
  618. using LETag = KeepTag;
  619. using BETag = SwapTag;
  620. #else
  621. using BETag = KeepTag;
  622. using LETag = SwapTag;
  623. #endif
  624. // Aliases for LE types
  625. using u16_le = AddEndian<u16, LETag>::type;
  626. using u32_le = AddEndian<u32, LETag>::type;
  627. using u64_le = AddEndian<u64, LETag>::type;
  628. using s16_le = AddEndian<s16, LETag>::type;
  629. using s32_le = AddEndian<s32, LETag>::type;
  630. using s64_le = AddEndian<s64, LETag>::type;
  631. template <typename T>
  632. using enum_le = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, LETag>::type>;
  633. using float_le = AddEndian<float, LETag>::type;
  634. using double_le = AddEndian<double, LETag>::type;
  635. // Aliases for BE types
  636. using u16_be = AddEndian<u16, BETag>::type;
  637. using u32_be = AddEndian<u32, BETag>::type;
  638. using u64_be = AddEndian<u64, BETag>::type;
  639. using s16_be = AddEndian<s16, BETag>::type;
  640. using s32_be = AddEndian<s32, BETag>::type;
  641. using s64_be = AddEndian<s64, BETag>::type;
  642. template <typename T>
  643. using enum_be = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, BETag>::type>;
  644. using float_be = AddEndian<float, BETag>::type;
  645. using double_be = AddEndian<double, BETag>::type;