hi_lo.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #pragma once
  2. #include "unaligned_mem.h"
  3. #include <utility>
  4. #ifndef _little_endian_
  5. #error "Not implemented"
  6. #endif
  7. namespace NHiLoPrivate {
  8. template <class TRepr>
  9. class TConstIntRef {
  10. public:
  11. explicit TConstIntRef(const char* ptr)
  12. : Ptr(ptr)
  13. {
  14. }
  15. TRepr Get() const {
  16. return ReadUnaligned<TRepr>(Ptr);
  17. }
  18. operator TRepr() const {
  19. return Get();
  20. }
  21. const char* GetPtr() const {
  22. return Ptr;
  23. }
  24. protected:
  25. const char* Ptr;
  26. };
  27. template <class TRepr>
  28. class TIntRef: public TConstIntRef<TRepr> {
  29. public:
  30. explicit TIntRef(char* ptr)
  31. : TConstIntRef<TRepr>(ptr)
  32. {
  33. }
  34. TIntRef& operator=(TRepr value) {
  35. WriteUnaligned<TRepr>(GetPtr(), value);
  36. return *this;
  37. }
  38. char* GetPtr() const {
  39. return const_cast<char*>(this->Ptr);
  40. }
  41. };
  42. template <class T>
  43. struct TReferenceType {
  44. using TType = T;
  45. };
  46. template <class T>
  47. struct TReferenceType<TConstIntRef<T>> {
  48. using TType = T;
  49. };
  50. template <class T>
  51. struct TReferenceType<TIntRef<T>> {
  52. using TType = T;
  53. };
  54. template <class TRepr>
  55. auto MakeIntRef(const char* ptr) {
  56. return TConstIntRef<TRepr>(ptr);
  57. }
  58. template <class TRepr>
  59. auto MakeIntRef(char* ptr) {
  60. return TIntRef<TRepr>(ptr);
  61. }
  62. template <class T>
  63. const char* CharPtrOf(const T& value) {
  64. return reinterpret_cast<const char*>(&value);
  65. }
  66. template <class T>
  67. char* CharPtrOf(T& value) {
  68. return reinterpret_cast<char*>(&value);
  69. }
  70. template <class T>
  71. const char* CharPtrOf(TConstIntRef<T> value) {
  72. return value.GetPtr();
  73. }
  74. template <class T>
  75. char* CharPtrOf(TIntRef<T> value) {
  76. return value.GetPtr();
  77. }
  78. template <bool IsLow, class TRepr, class T>
  79. auto MakeIntRef(T&& value) {
  80. using TRef = typename TReferenceType<typename std::decay<T>::type>::TType;
  81. static_assert(
  82. std::is_scalar<TRef>::value,
  83. "Hi* and Lo* functions can be applied only to scalar values");
  84. static_assert(sizeof(TRef) >= sizeof(TRepr), "Requested bit range is not within provided value");
  85. constexpr size_t offset = IsLow ? 0 : sizeof(TRef) - sizeof(TRepr);
  86. return MakeIntRef<TRepr>(CharPtrOf(std::forward<T>(value)) + offset);
  87. }
  88. } // namespace NHiLoPrivate
  89. /**
  90. * Return manipulator object that allows to get and set lower or higher bits of the value.
  91. *
  92. * @param value Must be a scalar value of sufficient size or a manipulator object obtained by
  93. * calling any of the other Hi/Lo functions.
  94. *
  95. * @{
  96. */
  97. template <class T>
  98. auto Lo32(T&& value) {
  99. return NHiLoPrivate::MakeIntRef<true, ui32>(std::forward<T>(value));
  100. }
  101. template <class T>
  102. auto Hi32(T&& value) {
  103. return NHiLoPrivate::MakeIntRef<false, ui32>(std::forward<T>(value));
  104. }
  105. template <class T>
  106. auto Lo16(T&& value) {
  107. return NHiLoPrivate::MakeIntRef<true, ui16>(std::forward<T>(value));
  108. }
  109. template <class T>
  110. auto Hi16(T&& value) {
  111. return NHiLoPrivate::MakeIntRef<false, ui16>(std::forward<T>(value));
  112. }
  113. template <class T>
  114. auto Lo8(T&& value) {
  115. return NHiLoPrivate::MakeIntRef<true, ui8>(std::forward<T>(value));
  116. }
  117. template <class T>
  118. auto Hi8(T&& value) {
  119. return NHiLoPrivate::MakeIntRef<false, ui8>(std::forward<T>(value));
  120. }
  121. /** @} */