/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_CRC_CRC_HPP #define MPT_CRC_CRC_HPP #include "mpt/base/array.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/memory.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { template class crc { public: using self_type = crc; using value_type = T; using byte_type = uint8; static constexpr std::size_t size_bytes = sizeof(value_type); static constexpr std::size_t size_bits = sizeof(value_type) * 8; static constexpr value_type top_bit = static_cast(1) << ((sizeof(value_type) * 8) - 1); private: template static constexpr Tint reverse(Tint value) noexcept { const std::size_t bits = sizeof(Tint) * 8; Tint result = 0; for (std::size_t i = 0; i < bits; ++i) { result <<= 1; result |= static_cast(value & 0x1); value >>= 1; } return result; } static constexpr value_type calculate_table_entry(byte_type pos) noexcept { value_type value = 0; value = (static_cast(reverseData ? reverse(pos) : pos) << (size_bits - 8)); for (std::size_t bit = 0; bit < 8; ++bit) { if (value & top_bit) { value = (value << 1) ^ polynomial; } else { value = (value << 1); } } value = (reverseData ? reverse(value) : value); return value; } private: static constexpr std::array calculate_table() noexcept { std::array t = mpt::init_array(value_type{}); for (std::size_t i = 0; i < 256; ++i) { t[i] = calculate_table_entry(static_cast(i)); } return t; } static constexpr std::array table = calculate_table(); private: constexpr value_type read_table(byte_type pos) const noexcept { return table[pos]; } private: value_type value; public: constexpr crc() noexcept : value(initial) { return; } constexpr void processByte(byte_type byte) noexcept { if constexpr (reverseData) { value = (value >> 8) ^ read_table(static_cast((value & 0xff) ^ byte)); } else { value = (value << 8) ^ read_table(static_cast(((value >> (size_bits - 8)) & 0xff) ^ byte)); } } constexpr value_type result() const noexcept { return (value ^ resultXOR); } public: constexpr operator value_type() const noexcept { return result(); } inline crc & process(char c) noexcept { processByte(mpt::byte_cast(c)); return *this; } inline crc & process(signed char c) noexcept { processByte(static_cast(c)); return *this; } inline crc & process(unsigned char c) noexcept { processByte(mpt::byte_cast(c)); return *this; } inline crc & process(std::byte c) noexcept { processByte(mpt::byte_cast(c)); return *this; } template inline crc & process(InputIt beg, InputIt end) { for (InputIt it = beg; it != end; ++it) { static_assert(sizeof(*it) == 1, "1 byte type required"); process(*it); } return *this; } template inline crc & process(const Container & data) { operator()(data.begin(), data.end()); return *this; } inline crc & operator()(char c) noexcept { processByte(mpt::byte_cast(c)); return *this; } inline crc & operator()(signed char c) noexcept { processByte(static_cast(c)); return *this; } inline crc & operator()(unsigned char c) noexcept { processByte(mpt::byte_cast(c)); return *this; } inline crc & operator()(std::byte c) noexcept { processByte(mpt::byte_cast(c)); return *this; } template crc & operator()(InputIt beg, InputIt end) { for (InputIt it = beg; it != end; ++it) { static_assert(sizeof(*it) == 1, "1 byte type required"); operator()(*it); } return *this; } template inline crc & operator()(const Container & data) { operator()(data.begin(), data.end()); return *this; } template crc(InputIt beg, InputIt end) : value(initial) { for (InputIt it = beg; it != end; ++it) { static_assert(sizeof(*it) == 1, "1 byte type required"); process(*it); } } template inline crc(const Container & data) : value(initial) { process(data.begin(), data.end()); } }; using crc16 = crc; using crc32 = crc; using crc32_ogg = crc; using crc32c = crc; using crc64_jones = crc; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_CRC_CRC_HPP