diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/bit_field.h | 14 | ||||
| -rw-r--r-- | src/common/swap.h | 174 |
2 files changed, 150 insertions, 38 deletions
diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 7433c39ba..8e35c463f 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <limits> | 34 | #include <limits> |
| 35 | #include <type_traits> | 35 | #include <type_traits> |
| 36 | #include "common/common_funcs.h" | 36 | #include "common/common_funcs.h" |
| 37 | #include "common/swap.h" | ||
| 37 | 38 | ||
| 38 | /* | 39 | /* |
| 39 | * Abstract bitfield class | 40 | * Abstract bitfield class |
| @@ -108,7 +109,7 @@ | |||
| 108 | * symptoms. | 109 | * symptoms. |
| 109 | */ | 110 | */ |
| 110 | #pragma pack(1) | 111 | #pragma pack(1) |
| 111 | template <std::size_t Position, std::size_t Bits, typename T> | 112 | template <std::size_t Position, std::size_t Bits, typename T, typename EndianTag = LETag> |
| 112 | struct BitField { | 113 | struct BitField { |
| 113 | private: | 114 | private: |
| 114 | // UnderlyingType is T for non-enum types and the underlying type of T if | 115 | // UnderlyingType is T for non-enum types and the underlying type of T if |
| @@ -121,7 +122,11 @@ private: | |||
| 121 | // We store the value as the unsigned type to avoid undefined behaviour on value shifting | 122 | // We store the value as the unsigned type to avoid undefined behaviour on value shifting |
| 122 | using StorageType = std::make_unsigned_t<UnderlyingType>; | 123 | using StorageType = std::make_unsigned_t<UnderlyingType>; |
| 123 | 124 | ||
| 125 | using StorageTypeWithEndian = typename AddEndian<StorageType, EndianTag>::type; | ||
| 126 | |||
| 124 | public: | 127 | public: |
| 128 | BitField& operator=(const BitField&) = default; | ||
| 129 | |||
| 125 | /// Constants to allow limited introspection of fields if needed | 130 | /// Constants to allow limited introspection of fields if needed |
| 126 | static constexpr std::size_t position = Position; | 131 | static constexpr std::size_t position = Position; |
| 127 | static constexpr std::size_t bits = Bits; | 132 | static constexpr std::size_t bits = Bits; |
| @@ -170,7 +175,7 @@ public: | |||
| 170 | } | 175 | } |
| 171 | 176 | ||
| 172 | constexpr FORCE_INLINE void Assign(const T& value) { | 177 | constexpr FORCE_INLINE void Assign(const T& value) { |
| 173 | storage = (storage & ~mask) | FormatValue(value); | 178 | storage = (static_cast<StorageType>(storage) & ~mask) | FormatValue(value); |
| 174 | } | 179 | } |
| 175 | 180 | ||
| 176 | constexpr T Value() const { | 181 | constexpr T Value() const { |
| @@ -182,7 +187,7 @@ public: | |||
| 182 | } | 187 | } |
| 183 | 188 | ||
| 184 | private: | 189 | private: |
| 185 | StorageType storage; | 190 | StorageTypeWithEndian storage; |
| 186 | 191 | ||
| 187 | static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); | 192 | static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); |
| 188 | 193 | ||
| @@ -193,3 +198,6 @@ private: | |||
| 193 | static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField"); | 198 | static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField"); |
| 194 | }; | 199 | }; |
| 195 | #pragma pack() | 200 | #pragma pack() |
| 201 | |||
| 202 | template <std::size_t Position, std::size_t Bits, typename T> | ||
| 203 | using BitFieldBE = BitField<Position, Bits, T, BETag>; | ||
diff --git a/src/common/swap.h b/src/common/swap.h index 0e219747f..b3eab1324 100644 --- a/src/common/swap.h +++ b/src/common/swap.h | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | 17 | ||
| 18 | #pragma once | 18 | #pragma once |
| 19 | 19 | ||
| 20 | #include <type_traits> | ||
| 21 | |||
| 20 | #if defined(_MSC_VER) | 22 | #if defined(_MSC_VER) |
| 21 | #include <cstdlib> | 23 | #include <cstdlib> |
| 22 | #elif defined(__linux__) | 24 | #elif defined(__linux__) |
| @@ -170,7 +172,7 @@ struct swap_struct_t { | |||
| 170 | using swapped_t = swap_struct_t; | 172 | using swapped_t = swap_struct_t; |
| 171 | 173 | ||
| 172 | protected: | 174 | protected: |
| 173 | T value = T(); | 175 | T value; |
| 174 | 176 | ||
| 175 | static T swap(T v) { | 177 | static T swap(T v) { |
| 176 | return F::swap(v); | 178 | return F::swap(v); |
| @@ -605,52 +607,154 @@ struct swap_double_t { | |||
| 605 | } | 607 | } |
| 606 | }; | 608 | }; |
| 607 | 609 | ||
| 608 | #if COMMON_LITTLE_ENDIAN | 610 | template <typename T> |
| 609 | using u16_le = u16; | 611 | struct swap_enum_t { |
| 610 | using u32_le = u32; | 612 | static_assert(std::is_enum_v<T>); |
| 611 | using u64_le = u64; | 613 | using base = std::underlying_type_t<T>; |
| 614 | |||
| 615 | public: | ||
| 616 | swap_enum_t() = default; | ||
| 617 | swap_enum_t(const T& v) : value(swap(v)) {} | ||
| 618 | |||
| 619 | swap_enum_t& operator=(const T& v) { | ||
| 620 | value = swap(v); | ||
| 621 | return *this; | ||
| 622 | } | ||
| 623 | |||
| 624 | operator T() const { | ||
| 625 | return swap(value); | ||
| 626 | } | ||
| 627 | |||
| 628 | explicit operator base() const { | ||
| 629 | return static_cast<base>(swap(value)); | ||
| 630 | } | ||
| 612 | 631 | ||
| 613 | using s16_le = s16; | 632 | protected: |
| 614 | using s32_le = s32; | 633 | T value{}; |
| 615 | using s64_le = s64; | 634 | // clang-format off |
| 635 | using swap_t = std::conditional_t< | ||
| 636 | std::is_same_v<base, u16>, swap_16_t<u16>, std::conditional_t< | ||
| 637 | std::is_same_v<base, s16>, swap_16_t<s16>, std::conditional_t< | ||
| 638 | std::is_same_v<base, u32>, swap_32_t<u32>, std::conditional_t< | ||
| 639 | std::is_same_v<base, s32>, swap_32_t<s32>, std::conditional_t< | ||
| 640 | std::is_same_v<base, u64>, swap_64_t<u64>, std::conditional_t< | ||
| 641 | std::is_same_v<base, s64>, swap_64_t<s64>, void>>>>>>; | ||
| 642 | // clang-format on | ||
| 643 | static T swap(T x) { | ||
| 644 | return static_cast<T>(swap_t::swap(static_cast<base>(x))); | ||
| 645 | } | ||
| 646 | }; | ||
| 616 | 647 | ||
| 617 | using float_le = float; | 648 | struct SwapTag {}; // Use the different endianness from the system |
| 618 | using double_le = double; | 649 | struct KeepTag {}; // Use the same endianness as the system |
| 619 | 650 | ||
| 620 | using u64_be = swap_struct_t<u64, swap_64_t<u64>>; | 651 | template <typename T, typename Tag> |
| 621 | using s64_be = swap_struct_t<s64, swap_64_t<s64>>; | 652 | struct AddEndian; |
| 622 | 653 | ||
| 623 | using u32_be = swap_struct_t<u32, swap_32_t<u32>>; | 654 | // KeepTag specializations |
| 624 | using s32_be = swap_struct_t<s32, swap_32_t<s32>>; | ||
| 625 | 655 | ||
| 626 | using u16_be = swap_struct_t<u16, swap_16_t<u16>>; | 656 | template <typename T> |
| 627 | using s16_be = swap_struct_t<s16, swap_16_t<s16>>; | 657 | struct AddEndian<T, KeepTag> { |
| 658 | using type = T; | ||
| 659 | }; | ||
| 628 | 660 | ||
| 629 | using float_be = swap_struct_t<float, swap_float_t<float>>; | 661 | // SwapTag specializations |
| 630 | using double_be = swap_struct_t<double, swap_double_t<double>>; | 662 | |
| 631 | #else | 663 | template <> |
| 664 | struct AddEndian<u8, SwapTag> { | ||
| 665 | using type = u8; | ||
| 666 | }; | ||
| 667 | |||
| 668 | template <> | ||
| 669 | struct AddEndian<u16, SwapTag> { | ||
| 670 | using type = swap_struct_t<u16, swap_16_t<u16>>; | ||
| 671 | }; | ||
| 672 | |||
| 673 | template <> | ||
| 674 | struct AddEndian<u32, SwapTag> { | ||
| 675 | using type = swap_struct_t<u32, swap_32_t<u32>>; | ||
| 676 | }; | ||
| 632 | 677 | ||
| 633 | using u64_le = swap_struct_t<u64, swap_64_t<u64>>; | 678 | template <> |
| 634 | using s64_le = swap_struct_t<s64, swap_64_t<s64>>; | 679 | struct AddEndian<u64, SwapTag> { |
| 680 | using type = swap_struct_t<u64, swap_64_t<u64>>; | ||
| 681 | }; | ||
| 682 | |||
| 683 | template <> | ||
| 684 | struct AddEndian<s8, SwapTag> { | ||
| 685 | using type = s8; | ||
| 686 | }; | ||
| 635 | 687 | ||
| 636 | using u32_le = swap_struct_t<u32, swap_32_t<u32>>; | 688 | template <> |
| 637 | using s32_le = swap_struct_t<s32, swap_32_t<s32>>; | 689 | struct AddEndian<s16, SwapTag> { |
| 690 | using type = swap_struct_t<s16, swap_16_t<s16>>; | ||
| 691 | }; | ||
| 638 | 692 | ||
| 639 | using u16_le = swap_struct_t<u16, swap_16_t<u16>>; | 693 | template <> |
| 640 | using s16_le = swap_struct_t<s16, swap_16_t<s16>>; | 694 | struct AddEndian<s32, SwapTag> { |
| 695 | using type = swap_struct_t<s32, swap_32_t<s32>>; | ||
| 696 | }; | ||
| 697 | |||
| 698 | template <> | ||
| 699 | struct AddEndian<s64, SwapTag> { | ||
| 700 | using type = swap_struct_t<s64, swap_64_t<s64>>; | ||
| 701 | }; | ||
| 702 | |||
| 703 | template <> | ||
| 704 | struct AddEndian<float, SwapTag> { | ||
| 705 | using type = swap_struct_t<float, swap_float_t<float>>; | ||
| 706 | }; | ||
| 707 | |||
| 708 | template <> | ||
| 709 | struct AddEndian<double, SwapTag> { | ||
| 710 | using type = swap_struct_t<double, swap_double_t<double>>; | ||
| 711 | }; | ||
| 712 | |||
| 713 | template <typename T> | ||
| 714 | struct AddEndian<T, SwapTag> { | ||
| 715 | static_assert(std::is_enum_v<T>); | ||
| 716 | using type = swap_enum_t<T>; | ||
| 717 | }; | ||
| 641 | 718 | ||
| 642 | using float_le = swap_struct_t<float, swap_float_t<float>>; | 719 | // Alias LETag/BETag as KeepTag/SwapTag depending on the system |
| 643 | using double_le = swap_struct_t<double, swap_double_t<double>>; | 720 | #if COMMON_LITTLE_ENDIAN |
| 644 | 721 | ||
| 645 | using u16_be = u16; | 722 | using LETag = KeepTag; |
| 646 | using u32_be = u32; | 723 | using BETag = SwapTag; |
| 647 | using u64_be = u64; | ||
| 648 | 724 | ||
| 649 | using s16_be = s16; | 725 | #else |
| 650 | using s32_be = s32; | ||
| 651 | using s64_be = s64; | ||
| 652 | 726 | ||
| 653 | using float_be = float; | 727 | using BETag = KeepTag; |
| 654 | using double_be = double; | 728 | using LETag = SwapTag; |
| 655 | 729 | ||
| 656 | #endif | 730 | #endif |
| 731 | |||
| 732 | // Aliases for LE types | ||
| 733 | using u16_le = AddEndian<u16, LETag>::type; | ||
| 734 | using u32_le = AddEndian<u32, LETag>::type; | ||
| 735 | using u64_le = AddEndian<u64, LETag>::type; | ||
| 736 | |||
| 737 | using s16_le = AddEndian<s16, LETag>::type; | ||
| 738 | using s32_le = AddEndian<s32, LETag>::type; | ||
| 739 | using s64_le = AddEndian<s64, LETag>::type; | ||
| 740 | |||
| 741 | template <typename T> | ||
| 742 | using enum_le = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, LETag>::type>; | ||
| 743 | |||
| 744 | using float_le = AddEndian<float, LETag>::type; | ||
| 745 | using double_le = AddEndian<double, LETag>::type; | ||
| 746 | |||
| 747 | // Aliases for BE types | ||
| 748 | using u16_be = AddEndian<u16, BETag>::type; | ||
| 749 | using u32_be = AddEndian<u32, BETag>::type; | ||
| 750 | using u64_be = AddEndian<u64, BETag>::type; | ||
| 751 | |||
| 752 | using s16_be = AddEndian<s16, BETag>::type; | ||
| 753 | using s32_be = AddEndian<s32, BETag>::type; | ||
| 754 | using s64_be = AddEndian<s64, BETag>::type; | ||
| 755 | |||
| 756 | template <typename T> | ||
| 757 | using enum_be = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, BETag>::type>; | ||
| 758 | |||
| 759 | using float_be = AddEndian<float, BETag>::type; | ||
| 760 | using double_be = AddEndian<double, BETag>::type; | ||