swap.h 17 KB

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