aboutsummaryrefslogblamecommitdiffstats
path: root/util/system/hi_lo.h
blob: f86870534fb4dccc09f85cd527264cf453245a22 (plain) (tree)
1
2
3
4
5
6
7
8


                          
                  
                       
                            









                                              




                                             
 

                                    




                          
                                               





                                         
                                                   

                         

                                                



























                                            
                                                     


                               
                                               














                                                                                  
                                                                          












































                                                                                                         
#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));
}

/** @} */