diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/hi_lo.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/hi_lo.h')
-rw-r--r-- | util/system/hi_lo.h | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/util/system/hi_lo.h b/util/system/hi_lo.h new file mode 100644 index 0000000000..f86870534f --- /dev/null +++ b/util/system/hi_lo.h @@ -0,0 +1,149 @@ +#pragma once + +#include "unaligned_mem.h" + +#include <utility> + +#ifndef _little_endian_ + #error "Not implemented" +#endif + +namespace NHiLoPrivate { + template <class TRepr> + class TConstIntRef { + public: + explicit TConstIntRef(const char* ptr) + : Ptr(ptr) + { + } + + TRepr Get() const { + return ReadUnaligned<TRepr>(Ptr); + } + operator TRepr() const { + return Get(); + } + + const char* GetPtr() const { + return Ptr; + } + + protected: + const char* Ptr; + }; + + template <class TRepr> + class TIntRef: public TConstIntRef<TRepr> { + public: + explicit TIntRef(char* ptr) + : TConstIntRef<TRepr>(ptr) + { + } + + TIntRef& operator=(TRepr value) { + WriteUnaligned<TRepr>(GetPtr(), value); + return *this; + } + + char* GetPtr() const { + return const_cast<char*>(this->Ptr); + } + }; + + template <class T> + struct TReferenceType { + using TType = T; + }; + + template <class T> + struct TReferenceType<TConstIntRef<T>> { + using TType = T; + }; + + template <class T> + struct TReferenceType<TIntRef<T>> { + using TType = T; + }; + + template <class TRepr> + auto MakeIntRef(const char* ptr) { + return TConstIntRef<TRepr>(ptr); + } + + template <class TRepr> + auto MakeIntRef(char* ptr) { + return TIntRef<TRepr>(ptr); + } + + template <class T> + const char* CharPtrOf(const T& value) { + return reinterpret_cast<const char*>(&value); + } + + template <class T> + char* CharPtrOf(T& value) { + return reinterpret_cast<char*>(&value); + } + + template <class T> + const char* CharPtrOf(TConstIntRef<T> value) { + return value.GetPtr(); + } + + template <class T> + char* CharPtrOf(TIntRef<T> value) { + return value.GetPtr(); + } + + template <bool IsLow, class TRepr, class T> + auto MakeIntRef(T&& value) { + using TRef = typename TReferenceType<typename std::decay<T>::type>::TType; + static_assert( + std::is_scalar<TRef>::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<TRepr>(CharPtrOf(std::forward<T>(value)) + offset); + } +} + +/** + * 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 <class T> +auto Lo32(T&& value) { + return NHiLoPrivate::MakeIntRef<true, ui32>(std::forward<T>(value)); +} + +template <class T> +auto Hi32(T&& value) { + return NHiLoPrivate::MakeIntRef<false, ui32>(std::forward<T>(value)); +} + +template <class T> +auto Lo16(T&& value) { + return NHiLoPrivate::MakeIntRef<true, ui16>(std::forward<T>(value)); +} + +template <class T> +auto Hi16(T&& value) { + return NHiLoPrivate::MakeIntRef<false, ui16>(std::forward<T>(value)); +} + +template <class T> +auto Lo8(T&& value) { + return NHiLoPrivate::MakeIntRef<true, ui8>(std::forward<T>(value)); +} + +template <class T> +auto Hi8(T&& value) { + return NHiLoPrivate::MakeIntRef<false, ui8>(std::forward<T>(value)); +} + +/** @} */ |