#pragma once #include "unaligned_mem.h" #include #ifndef _little_endian_ #error "Not implemented" #endif namespace NHiLoPrivate { template class TConstIntRef { public: explicit TConstIntRef(const char* ptr) : Ptr(ptr) { } TRepr Get() const { return ReadUnaligned(Ptr); } operator TRepr() const { return Get(); } const char* GetPtr() const { return Ptr; } protected: const char* Ptr; }; template class TIntRef: public TConstIntRef { public: explicit TIntRef(char* ptr) : TConstIntRef(ptr) { } TIntRef& operator=(TRepr value) { WriteUnaligned(GetPtr(), value); return *this; } char* GetPtr() const { return const_cast(this->Ptr); } }; template struct TReferenceType { using TType = T; }; template struct TReferenceType> { using TType = T; }; template struct TReferenceType> { using TType = T; }; template auto MakeIntRef(const char* ptr) { return TConstIntRef(ptr); } template auto MakeIntRef(char* ptr) { return TIntRef(ptr); } template const char* CharPtrOf(const T& value) { return reinterpret_cast(&value); } template char* CharPtrOf(T& value) { return reinterpret_cast(&value); } template const char* CharPtrOf(TConstIntRef value) { return value.GetPtr(); } template char* CharPtrOf(TIntRef value) { return value.GetPtr(); } template auto MakeIntRef(T&& value) { using TRef = typename TReferenceType::type>::TType; static_assert( std::is_scalar::value, "Hi* and Lo* functions can be applied only to scalar values"); static_assert(sizeof(TRef) >= sizeof(TRepr), "Requested bit range is not within provided value"); constexpr size_t offset = IsLow ? 0 : sizeof(TRef) - sizeof(TRepr); return MakeIntRef(CharPtrOf(std::forward(value)) + offset); } } // namespace NHiLoPrivate /** * Return manipulator object that allows to get and set lower or higher bits of the value. * * @param value Must be a scalar value of sufficient size or a manipulator object obtained by * calling any of the other Hi/Lo functions. * * @{ */ template auto Lo32(T&& value) { return NHiLoPrivate::MakeIntRef(std::forward(value)); } template auto Hi32(T&& value) { return NHiLoPrivate::MakeIntRef(std::forward(value)); } template auto Lo16(T&& value) { return NHiLoPrivate::MakeIntRef(std::forward(value)); } template auto Hi16(T&& value) { return NHiLoPrivate::MakeIntRef(std::forward(value)); } template auto Lo8(T&& value) { return NHiLoPrivate::MakeIntRef(std::forward(value)); } template auto Hi8(T&& value) { return NHiLoPrivate::MakeIntRef(std::forward(value)); } /** @} */