Program Listing for File crc.h#

Return to documentation for file (support\crc.h)

#ifndef SDV_CRC_H
#define SDV_CRC_H

#include <array>
#include <cstdint>
#include <stddef.h>

namespace sdv
{
    template <typename T>
    constexpr T reflect(T tValue)
    {
        static_assert(std::is_arithmetic_v<T> || std::is_same_v<T, bool>);

        T tMask = 1;
        T tReflection{0};
        for (size_t nBit = 0; nBit < sizeof(T) * 8; nBit++)
        {
            tReflection <<= 1;
            if (tValue & tMask)
                tReflection |= 0x1;
            tMask <<= 1;
        }
        return tReflection;
    }

    template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
    class crc
    {
    public:
        using TCRCType = TCRC;

        template <typename T>
        TCRCType calc_checksum(const T* pData, size_t nCount) noexcept;

        template <typename T>
        void add(T tValue) noexcept;

        TCRCType get_checksum() const noexcept;

        void set_checksum(TCRCType tCrcValue) noexcept;

        void reset() noexcept;

    private:
        static constexpr uint64_t m_nWidth = 8 * sizeof(TCRCType);

        static constexpr uint64_t m_nMsb = 1ull << (m_nWidth - 1);

        static constexpr auto m_arrTable = []
        {
            std::array<TCRCType, 256> arrTemp{};
            for (size_t tDividend = 0; tDividend < 256; ++tDividend)
            {
                TCRCType tRemainder = static_cast<TCRCType>(tDividend << (m_nWidth - 8));
                for (uint8_t bit = 8; bit > 0; --bit)
                {
                    if (tRemainder & m_nMsb)
                        tRemainder = (tRemainder << 1) ^ tPolynomial;
                    else
                        tRemainder = (tRemainder << 1);
                }
                arrTemp[tDividend] = tRemainder;
            }
            return arrTemp;
        }();

        TCRCType m_tCrcValue = tInitVal;
    };

    using crcSAE_J1850 = sdv::crc<uint8_t, 0x1du, 0xff, 0xff, false, false>;

    using crcAUTOSAR_8H2F = sdv::crc<uint8_t, 0x2fu, 0xff, 0xff, false, false>;

    using crcCCITT_FALSE = sdv::crc<uint16_t, 0x1021u, 0xffffu, 0, false, false> ;

    using crcARC = sdv::crc<uint16_t, 0x8005, 0, 0, true, true>;

    using crcIEEE_802_3 = sdv::crc<uint32_t, 0x04C11DB7u, 0xffffffffu, 0xffffffffu, true, true> ;

    using crcAUTOSAR_P4 = sdv::crc<uint32_t, 0xF4ACFB13u, 0xffffffffu, 0xffffffffu, true, true> ;

    using crcCRC32C = sdv::crc<uint32_t, 0x1EDC6F41, 0xffffffffu, 0xffffffffu, true, true> ;

    using crcECMA = sdv::crc<uint64_t, 0x42F0E1EBA9EA3693, 0xffffffffffffffffu, 0xffffffffffffffffu, true, true>;

    template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
    template <typename T>
    typename crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::TCRCType
        crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::calc_checksum(const T* pData, size_t nCount) noexcept
    {
        if (!pData || !nCount) return get_checksum();
        for (size_t nIndex = 0; nIndex < nCount; nIndex++)
            add(pData[nIndex]);
        return get_checksum();
    }

    template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
    template <typename T>
    inline void crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::add(T tValue) noexcept
    {
        if constexpr (bReflectIn)
        {
            for (size_t nIndex = 0; nIndex < sizeof(T); ++nIndex)
            {
                uint8_t data = static_cast<uint8_t>(reflect(reinterpret_cast<uint8_t*>(&tValue)[nIndex]) ^ (m_tCrcValue >> (m_nWidth - 8)));
                m_tCrcValue = m_arrTable[data] ^ (m_tCrcValue << 8);
            }
        }
        else
        {
            for (size_t nIndex = 0; nIndex < sizeof(T); ++nIndex)
            {
                uint8_t data = static_cast<uint8_t>((reinterpret_cast<uint8_t*>(&tValue)[nIndex]) ^ (m_tCrcValue >> (m_nWidth - 8)));
                m_tCrcValue = m_arrTable[data] ^ (m_tCrcValue << 8);
            }
        }
    }

    template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
    inline typename crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::TCRCType
        crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::get_checksum() const noexcept
    {
        if constexpr (bReflectOut)
            return static_cast<TCRCType>(reflect(m_tCrcValue) ^ tXorOut);
        else
            return static_cast<TCRCType>(m_tCrcValue ^ tXorOut);
    }

    template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
    inline void crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::set_checksum(TCRCType tCrcValue) noexcept
    {
        if constexpr (bReflectOut)
            m_tCrcValue = static_cast<TCRCType>(reflect(static_cast<TCRCType>(tCrcValue ^ tXorOut)));
        else
            m_tCrcValue = static_cast<TCRCType>(tCrcValue ^ tXorOut);
    }

    template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
    inline void crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::reset() noexcept
    {
        m_tCrcValue = tInitVal;
    }

} // namespace sdv

#endif // SDV_CRC_H