aboutsummaryrefslogtreecommitdiffstats
path: root/util/system/hi_lo.h
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/hi_lo.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/hi_lo.h')
-rw-r--r--util/system/hi_lo.h149
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));
+}
+
+/** @} */