swap.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. // SPDX-FileCopyrightText: 2012 PPSSPP Project
  2. // SPDX-FileCopyrightText: 2012 Dolphin Emulator Project
  3. // SPDX-License-Identifier: GPL-2.0-or-later
  4. // Official git repository and contact information can be found at
  5. // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
  6. #pragma once
  7. #if defined(_MSC_VER)
  8. #include <cstdlib>
  9. #endif
  10. #include <bit>
  11. #include <cstring>
  12. #include <type_traits>
  13. #include "common/common_types.h"
  14. namespace Common {
  15. #ifdef _MSC_VER
  16. [[nodiscard]] inline u16 swap16(u16 data) noexcept {
  17. return _byteswap_ushort(data);
  18. }
  19. [[nodiscard]] inline u32 swap32(u32 data) noexcept {
  20. return _byteswap_ulong(data);
  21. }
  22. [[nodiscard]] inline u64 swap64(u64 data) noexcept {
  23. return _byteswap_uint64(data);
  24. }
  25. #elif defined(__clang__) || defined(__GNUC__)
  26. #if defined(__Bitrig__) || defined(__OpenBSD__)
  27. // redefine swap16, swap32, swap64 as inline functions
  28. #undef swap16
  29. #undef swap32
  30. #undef swap64
  31. #endif
  32. [[nodiscard]] inline u16 swap16(u16 data) noexcept {
  33. return __builtin_bswap16(data);
  34. }
  35. [[nodiscard]] inline u32 swap32(u32 data) noexcept {
  36. return __builtin_bswap32(data);
  37. }
  38. [[nodiscard]] inline u64 swap64(u64 data) noexcept {
  39. return __builtin_bswap64(data);
  40. }
  41. #else
  42. // Generic implementation.
  43. [[nodiscard]] inline u16 swap16(u16 data) noexcept {
  44. return (data >> 8) | (data << 8);
  45. }
  46. [[nodiscard]] inline u32 swap32(u32 data) noexcept {
  47. return ((data & 0xFF000000U) >> 24) | ((data & 0x00FF0000U) >> 8) |
  48. ((data & 0x0000FF00U) << 8) | ((data & 0x000000FFU) << 24);
  49. }
  50. [[nodiscard]] inline u64 swap64(u64 data) noexcept {
  51. return ((data & 0xFF00000000000000ULL) >> 56) | ((data & 0x00FF000000000000ULL) >> 40) |
  52. ((data & 0x0000FF0000000000ULL) >> 24) | ((data & 0x000000FF00000000ULL) >> 8) |
  53. ((data & 0x00000000FF000000ULL) << 8) | ((data & 0x0000000000FF0000ULL) << 24) |
  54. ((data & 0x000000000000FF00ULL) << 40) | ((data & 0x00000000000000FFULL) << 56);
  55. }
  56. #endif
  57. [[nodiscard]] inline float swapf(float f) noexcept {
  58. static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t.");
  59. u32 value;
  60. std::memcpy(&value, &f, sizeof(u32));
  61. value = swap32(value);
  62. std::memcpy(&f, &value, sizeof(u32));
  63. return f;
  64. }
  65. [[nodiscard]] inline double swapd(double f) noexcept {
  66. static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t.");
  67. u64 value;
  68. std::memcpy(&value, &f, sizeof(u64));
  69. value = swap64(value);
  70. std::memcpy(&f, &value, sizeof(u64));
  71. return f;
  72. }
  73. } // Namespace Common
  74. template <typename T, typename F>
  75. struct swap_struct_t {
  76. using swapped_t = swap_struct_t;
  77. protected:
  78. T value;
  79. static T swap(T v) {
  80. return F::swap(v);
  81. }
  82. public:
  83. T swap() const {
  84. return swap(value);
  85. }
  86. swap_struct_t() = default;
  87. swap_struct_t(const T& v) : value(swap(v)) {}
  88. template <typename S>
  89. swapped_t& operator=(const S& source) {
  90. value = swap(static_cast<T>(source));
  91. return *this;
  92. }
  93. operator s8() const {
  94. return static_cast<s8>(swap());
  95. }
  96. operator u8() const {
  97. return static_cast<u8>(swap());
  98. }
  99. operator s16() const {
  100. return static_cast<s16>(swap());
  101. }
  102. operator u16() const {
  103. return static_cast<u16>(swap());
  104. }
  105. operator s32() const {
  106. return static_cast<s32>(swap());
  107. }
  108. operator u32() const {
  109. return static_cast<u32>(swap());
  110. }
  111. operator s64() const {
  112. return static_cast<s64>(swap());
  113. }
  114. operator u64() const {
  115. return static_cast<u64>(swap());
  116. }
  117. operator float() const {
  118. return static_cast<float>(swap());
  119. }
  120. operator double() const {
  121. return static_cast<double>(swap());
  122. }
  123. // +v
  124. swapped_t operator+() const {
  125. return +swap();
  126. }
  127. // -v
  128. swapped_t operator-() const {
  129. return -swap();
  130. }
  131. // v / 5
  132. swapped_t operator/(const swapped_t& i) const {
  133. return swap() / i.swap();
  134. }
  135. template <typename S>
  136. swapped_t operator/(const S& i) const {
  137. return swap() / i;
  138. }
  139. // v * 5
  140. swapped_t operator*(const swapped_t& i) const {
  141. return swap() * i.swap();
  142. }
  143. template <typename S>
  144. swapped_t operator*(const S& i) const {
  145. return swap() * i;
  146. }
  147. // v + 5
  148. swapped_t operator+(const swapped_t& i) const {
  149. return swap() + i.swap();
  150. }
  151. template <typename S>
  152. swapped_t operator+(const S& i) const {
  153. return swap() + static_cast<T>(i);
  154. }
  155. // v - 5
  156. swapped_t operator-(const swapped_t& i) const {
  157. return swap() - i.swap();
  158. }
  159. template <typename S>
  160. swapped_t operator-(const S& i) const {
  161. return swap() - static_cast<T>(i);
  162. }
  163. // v += 5
  164. swapped_t& operator+=(const swapped_t& i) {
  165. value = swap(swap() + i.swap());
  166. return *this;
  167. }
  168. template <typename S>
  169. swapped_t& operator+=(const S& i) {
  170. value = swap(swap() + static_cast<T>(i));
  171. return *this;
  172. }
  173. // v -= 5
  174. swapped_t& operator-=(const swapped_t& i) {
  175. value = swap(swap() - i.swap());
  176. return *this;
  177. }
  178. template <typename S>
  179. swapped_t& operator-=(const S& i) {
  180. value = swap(swap() - static_cast<T>(i));
  181. return *this;
  182. }
  183. // ++v
  184. swapped_t& operator++() {
  185. value = swap(swap() + 1);
  186. return *this;
  187. }
  188. // --v
  189. swapped_t& operator--() {
  190. value = swap(swap() - 1);
  191. return *this;
  192. }
  193. // v++
  194. swapped_t operator++(int) {
  195. swapped_t old = *this;
  196. value = swap(swap() + 1);
  197. return old;
  198. }
  199. // v--
  200. swapped_t operator--(int) {
  201. swapped_t old = *this;
  202. value = swap(swap() - 1);
  203. return old;
  204. }
  205. // Comparaison
  206. // v == i
  207. bool operator==(const swapped_t& i) const {
  208. return swap() == i.swap();
  209. }
  210. template <typename S>
  211. bool operator==(const S& i) const {
  212. return swap() == i;
  213. }
  214. // v != i
  215. bool operator!=(const swapped_t& i) const {
  216. return swap() != i.swap();
  217. }
  218. template <typename S>
  219. bool operator!=(const S& i) const {
  220. return swap() != i;
  221. }
  222. // v > i
  223. bool operator>(const swapped_t& i) const {
  224. return swap() > i.swap();
  225. }
  226. template <typename S>
  227. bool operator>(const S& i) const {
  228. return swap() > i;
  229. }
  230. // v < i
  231. bool operator<(const swapped_t& i) const {
  232. return swap() < i.swap();
  233. }
  234. template <typename S>
  235. bool operator<(const S& i) const {
  236. return swap() < i;
  237. }
  238. // v >= i
  239. bool operator>=(const swapped_t& i) const {
  240. return swap() >= i.swap();
  241. }
  242. template <typename S>
  243. bool operator>=(const S& i) const {
  244. return swap() >= i;
  245. }
  246. // v <= i
  247. bool operator<=(const swapped_t& i) const {
  248. return swap() <= i.swap();
  249. }
  250. template <typename S>
  251. bool operator<=(const S& i) const {
  252. return swap() <= i;
  253. }
  254. // logical
  255. swapped_t operator!() const {
  256. return !swap();
  257. }
  258. // bitmath
  259. swapped_t operator~() const {
  260. return ~swap();
  261. }
  262. swapped_t operator&(const swapped_t& b) const {
  263. return swap() & b.swap();
  264. }
  265. template <typename S>
  266. swapped_t operator&(const S& b) const {
  267. return swap() & b;
  268. }
  269. swapped_t& operator&=(const swapped_t& b) {
  270. value = swap(swap() & b.swap());
  271. return *this;
  272. }
  273. template <typename S>
  274. swapped_t& operator&=(const S b) {
  275. value = swap(swap() & b);
  276. return *this;
  277. }
  278. swapped_t operator|(const swapped_t& b) const {
  279. return swap() | b.swap();
  280. }
  281. template <typename S>
  282. swapped_t operator|(const S& b) const {
  283. return swap() | b;
  284. }
  285. swapped_t& operator|=(const swapped_t& b) {
  286. value = swap(swap() | b.swap());
  287. return *this;
  288. }
  289. template <typename S>
  290. swapped_t& operator|=(const S& b) {
  291. value = swap(swap() | b);
  292. return *this;
  293. }
  294. swapped_t operator^(const swapped_t& b) const {
  295. return swap() ^ b.swap();
  296. }
  297. template <typename S>
  298. swapped_t operator^(const S& b) const {
  299. return swap() ^ b;
  300. }
  301. swapped_t& operator^=(const swapped_t& b) {
  302. value = swap(swap() ^ b.swap());
  303. return *this;
  304. }
  305. template <typename S>
  306. swapped_t& operator^=(const S& b) {
  307. value = swap(swap() ^ b);
  308. return *this;
  309. }
  310. template <typename S>
  311. swapped_t operator<<(const S& b) const {
  312. return swap() << b;
  313. }
  314. template <typename S>
  315. swapped_t& operator<<=(const S& b) const {
  316. value = swap(swap() << b);
  317. return *this;
  318. }
  319. template <typename S>
  320. swapped_t operator>>(const S& b) const {
  321. return swap() >> b;
  322. }
  323. template <typename S>
  324. swapped_t& operator>>=(const S& b) const {
  325. value = swap(swap() >> b);
  326. return *this;
  327. }
  328. // Member
  329. /** todo **/
  330. // Arithmetics
  331. template <typename S, typename T2, typename F2>
  332. friend S operator+(const S& p, const swapped_t v);
  333. template <typename S, typename T2, typename F2>
  334. friend S operator-(const S& p, const swapped_t v);
  335. template <typename S, typename T2, typename F2>
  336. friend S operator/(const S& p, const swapped_t v);
  337. template <typename S, typename T2, typename F2>
  338. friend S operator*(const S& p, const swapped_t v);
  339. template <typename S, typename T2, typename F2>
  340. friend S operator%(const S& p, const swapped_t v);
  341. // Arithmetics + assignments
  342. template <typename S, typename T2, typename F2>
  343. friend S operator+=(const S& p, const swapped_t v);
  344. template <typename S, typename T2, typename F2>
  345. friend S operator-=(const S& p, const swapped_t v);
  346. // Bitmath
  347. template <typename S, typename T2, typename F2>
  348. friend S operator&(const S& p, const swapped_t v);
  349. // Comparison
  350. template <typename S, typename T2, typename F2>
  351. friend bool operator<(const S& p, const swapped_t v);
  352. template <typename S, typename T2, typename F2>
  353. friend bool operator>(const S& p, const swapped_t v);
  354. template <typename S, typename T2, typename F2>
  355. friend bool operator<=(const S& p, const swapped_t v);
  356. template <typename S, typename T2, typename F2>
  357. friend bool operator>=(const S& p, const swapped_t v);
  358. template <typename S, typename T2, typename F2>
  359. friend bool operator!=(const S& p, const swapped_t v);
  360. template <typename S, typename T2, typename F2>
  361. friend bool operator==(const S& p, const swapped_t v);
  362. };
  363. // Arithmetics
  364. template <typename S, typename T, typename F>
  365. S operator+(const S& i, const swap_struct_t<T, F> v) {
  366. return i + v.swap();
  367. }
  368. template <typename S, typename T, typename F>
  369. S operator-(const S& i, const swap_struct_t<T, F> v) {
  370. return i - v.swap();
  371. }
  372. template <typename S, typename T, typename F>
  373. S operator/(const S& i, const swap_struct_t<T, F> v) {
  374. return i / v.swap();
  375. }
  376. template <typename S, typename T, typename F>
  377. S operator*(const S& i, const swap_struct_t<T, F> v) {
  378. return i * v.swap();
  379. }
  380. template <typename S, typename T, typename F>
  381. S operator%(const S& i, const swap_struct_t<T, F> v) {
  382. return i % v.swap();
  383. }
  384. // Arithmetics + assignments
  385. template <typename S, typename T, typename F>
  386. S& operator+=(S& i, const swap_struct_t<T, F> v) {
  387. i += v.swap();
  388. return i;
  389. }
  390. template <typename S, typename T, typename F>
  391. S& operator-=(S& i, const swap_struct_t<T, F> v) {
  392. i -= v.swap();
  393. return i;
  394. }
  395. // Logical
  396. template <typename S, typename T, typename F>
  397. S operator&(const S& i, const swap_struct_t<T, F> v) {
  398. return i & v.swap();
  399. }
  400. template <typename S, typename T, typename F>
  401. S operator&(const swap_struct_t<T, F> v, const S& i) {
  402. return static_cast<S>(v.swap() & i);
  403. }
  404. // Comparaison
  405. template <typename S, typename T, typename F>
  406. bool operator<(const S& p, const swap_struct_t<T, F> v) {
  407. return p < v.swap();
  408. }
  409. template <typename S, typename T, typename F>
  410. bool operator>(const S& p, const swap_struct_t<T, F> v) {
  411. return p > v.swap();
  412. }
  413. template <typename S, typename T, typename F>
  414. bool operator<=(const S& p, const swap_struct_t<T, F> v) {
  415. return p <= v.swap();
  416. }
  417. template <typename S, typename T, typename F>
  418. bool operator>=(const S& p, const swap_struct_t<T, F> v) {
  419. return p >= v.swap();
  420. }
  421. template <typename S, typename T, typename F>
  422. bool operator!=(const S& p, const swap_struct_t<T, F> v) {
  423. return p != v.swap();
  424. }
  425. template <typename S, typename T, typename F>
  426. bool operator==(const S& p, const swap_struct_t<T, F> v) {
  427. return p == v.swap();
  428. }
  429. template <typename T>
  430. struct swap_64_t {
  431. static T swap(T x) {
  432. return static_cast<T>(Common::swap64(x));
  433. }
  434. };
  435. template <typename T>
  436. struct swap_32_t {
  437. static T swap(T x) {
  438. return static_cast<T>(Common::swap32(x));
  439. }
  440. };
  441. template <typename T>
  442. struct swap_16_t {
  443. static T swap(T x) {
  444. return static_cast<T>(Common::swap16(x));
  445. }
  446. };
  447. template <typename T>
  448. struct swap_float_t {
  449. static T swap(T x) {
  450. return static_cast<T>(Common::swapf(x));
  451. }
  452. };
  453. template <typename T>
  454. struct swap_double_t {
  455. static T swap(T x) {
  456. return static_cast<T>(Common::swapd(x));
  457. }
  458. };
  459. template <typename T>
  460. struct swap_enum_t {
  461. static_assert(std::is_enum_v<T>);
  462. using base = std::underlying_type_t<T>;
  463. public:
  464. swap_enum_t() = default;
  465. swap_enum_t(const T& v) : value(swap(v)) {}
  466. swap_enum_t& operator=(const T& v) {
  467. value = swap(v);
  468. return *this;
  469. }
  470. operator T() const {
  471. return swap(value);
  472. }
  473. explicit operator base() const {
  474. return static_cast<base>(swap(value));
  475. }
  476. protected:
  477. T value{};
  478. // clang-format off
  479. using swap_t = std::conditional_t<
  480. std::is_same_v<base, u16>, swap_16_t<u16>, std::conditional_t<
  481. std::is_same_v<base, s16>, swap_16_t<s16>, std::conditional_t<
  482. std::is_same_v<base, u32>, swap_32_t<u32>, std::conditional_t<
  483. std::is_same_v<base, s32>, swap_32_t<s32>, std::conditional_t<
  484. std::is_same_v<base, u64>, swap_64_t<u64>, std::conditional_t<
  485. std::is_same_v<base, s64>, swap_64_t<s64>, void>>>>>>;
  486. // clang-format on
  487. static T swap(T x) {
  488. return static_cast<T>(swap_t::swap(static_cast<base>(x)));
  489. }
  490. };
  491. struct SwapTag {}; // Use the different endianness from the system
  492. struct KeepTag {}; // Use the same endianness as the system
  493. template <typename T, typename Tag>
  494. struct AddEndian;
  495. // KeepTag specializations
  496. template <typename T>
  497. struct AddEndian<T, KeepTag> {
  498. using type = T;
  499. };
  500. // SwapTag specializations
  501. template <>
  502. struct AddEndian<u8, SwapTag> {
  503. using type = u8;
  504. };
  505. template <>
  506. struct AddEndian<u16, SwapTag> {
  507. using type = swap_struct_t<u16, swap_16_t<u16>>;
  508. };
  509. template <>
  510. struct AddEndian<u32, SwapTag> {
  511. using type = swap_struct_t<u32, swap_32_t<u32>>;
  512. };
  513. template <>
  514. struct AddEndian<u64, SwapTag> {
  515. using type = swap_struct_t<u64, swap_64_t<u64>>;
  516. };
  517. template <>
  518. struct AddEndian<s8, SwapTag> {
  519. using type = s8;
  520. };
  521. template <>
  522. struct AddEndian<s16, SwapTag> {
  523. using type = swap_struct_t<s16, swap_16_t<s16>>;
  524. };
  525. template <>
  526. struct AddEndian<s32, SwapTag> {
  527. using type = swap_struct_t<s32, swap_32_t<s32>>;
  528. };
  529. template <>
  530. struct AddEndian<s64, SwapTag> {
  531. using type = swap_struct_t<s64, swap_64_t<s64>>;
  532. };
  533. template <>
  534. struct AddEndian<float, SwapTag> {
  535. using type = swap_struct_t<float, swap_float_t<float>>;
  536. };
  537. template <>
  538. struct AddEndian<double, SwapTag> {
  539. using type = swap_struct_t<double, swap_double_t<double>>;
  540. };
  541. template <typename T>
  542. struct AddEndian<T, SwapTag> {
  543. static_assert(std::is_enum_v<T>);
  544. using type = swap_enum_t<T>;
  545. };
  546. // Alias LETag/BETag as KeepTag/SwapTag depending on the system
  547. using LETag = std::conditional_t<std::endian::native == std::endian::little, KeepTag, SwapTag>;
  548. using BETag = std::conditional_t<std::endian::native == std::endian::big, KeepTag, SwapTag>;
  549. // Aliases for LE types
  550. using u16_le = AddEndian<u16, LETag>::type;
  551. using u32_le = AddEndian<u32, LETag>::type;
  552. using u64_le = AddEndian<u64, LETag>::type;
  553. using s16_le = AddEndian<s16, LETag>::type;
  554. using s32_le = AddEndian<s32, LETag>::type;
  555. using s64_le = AddEndian<s64, LETag>::type;
  556. template <typename T>
  557. using enum_le = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, LETag>::type>;
  558. using float_le = AddEndian<float, LETag>::type;
  559. using double_le = AddEndian<double, LETag>::type;
  560. // Aliases for BE types
  561. using u16_be = AddEndian<u16, BETag>::type;
  562. using u32_be = AddEndian<u32, BETag>::type;
  563. using u64_be = AddEndian<u64, BETag>::type;
  564. using s16_be = AddEndian<s16, BETag>::type;
  565. using s32_be = AddEndian<s32, BETag>::type;
  566. using s64_be = AddEndian<s64, BETag>::type;
  567. template <typename T>
  568. using enum_be = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, BETag>::type>;
  569. using float_be = AddEndian<float, BETag>::type;
  570. using double_be = AddEndian<double, BETag>::type;