diff --git a/include/Nazara/Core/Algorithm.hpp b/include/Nazara/Core/Algorithm.hpp index 844ec705d..69ef58f1f 100644 --- a/include/Nazara/Core/Algorithm.hpp +++ b/include/Nazara/Core/Algorithm.hpp @@ -32,6 +32,10 @@ namespace Nz template ByteArray ComputeHash(AbstractHash& hash, const T& v); template constexpr std::size_t CountOf(T(&name)[N]) noexcept; template std::size_t CountOf(const T& c); + constexpr UInt32 CRC32(const UInt8* data, std::size_t size) noexcept; + constexpr UInt32 CRC32(const char* str) noexcept; + constexpr UInt32 CRC32(const std::string_view& str) noexcept; + template constexpr std::size_t CountOf(const char(&str)[N]) noexcept; inline bool HashAppend(AbstractHash* hash, const std::string_view& v); template void HashCombine(std::size_t& seed, const T& v); template bool IsPowerOfTwo(T value); diff --git a/include/Nazara/Core/Algorithm.inl b/include/Nazara/Core/Algorithm.inl index 1198df701..04d42790c 100644 --- a/include/Nazara/Core/Algorithm.inl +++ b/include/Nazara/Core/Algorithm.inl @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,50 @@ namespace Nz } NAZARA_CORE_API extern const UInt8 BitReverseTable256[256]; + + // https://stackoverflow.com/questions/28675727/using-crc32-algorithm-to-hash-string-at-compile-time + // Generates CRC-32 table, algorithm based from this link: + // http://www.hackersdelight.org/hdcodetxt/crc.c.txt + constexpr auto GenerateCRC32Table(UInt32 polynomial = 0xEDB88320) + { +#ifdef NAZARA_COMPILER_MSVC +// Disable warning: unary minus operator applied to unsigned type, result still unsigned +#pragma warning(push) +#pragma warning(disable: 4146) +#endif + + constexpr UInt32 byteCount = 256; + constexpr UInt32 iterationCount = 8; + + std::array crc32Table{}; + for (UInt32 byte = 0u; byte < byteCount; ++byte) + { + UInt32 crc = byte; + + for (UInt32 i = 0; i < iterationCount; ++i) + { + UInt32 mask = static_cast(-(crc & 1)); + crc = (crc >> 1) ^ (polynomial & mask); + } + + crc32Table[byte] = crc; + } + + return crc32Table; + +#ifdef NAZARA_COMPILER_MSVC +#pragma warning(pop) +#endif + } + + // Stores CRC-32 table and softly validates it. + static constexpr auto crc32Table = GenerateCRC32Table(); + static_assert( + crc32Table.size() == 256 && + crc32Table[1] == 0x77073096 && + crc32Table[255] == 0x2D02EF8D, + "gen_crc32_table generated unexpected result." + ); } /*! @@ -204,6 +249,48 @@ namespace Nz return hash.End(); } + // From https://stackoverflow.com/questions/28675727/using-crc32-algorithm-to-hash-string-at-compile-time + constexpr UInt32 CRC32(const UInt8* input, std::size_t size) noexcept + { + UInt32 crc = 0xFFFFFFFFu; + + for (std::size_t i = 0u; i < size; ++i) + crc = Detail::crc32Table[(crc ^ input[i]) & 0xFF] ^ (crc >> 8); + + return ~crc; + } + + constexpr UInt32 CRC32(const char* str) noexcept + { + UInt32 crc = 0xFFFFFFFFu; + + for (std::size_t i = 0u; auto c = str[i]; ++i) + crc = Detail::crc32Table[(crc ^ str[i]) & 0xFF] ^ (crc >> 8); + + return ~crc; + } + + constexpr UInt32 CRC32(const std::string_view& str) noexcept + { + UInt32 crc = 0xFFFFFFFFu; + + for (std::size_t i = 0u; i < str.size(); ++i) + crc = Detail::crc32Table[(crc ^ str[i]) & 0xFF] ^ (crc >> 8); + + return ~crc; + } + + template + constexpr UInt32 CRC32(const char (&str)[N]) noexcept + { + UInt32 crc = 0xFFFFFFFFu; + + for (std::size_t i = 0u; i < N - 1; ++i) + crc = Detail::crc32Table[(crc ^ str[i]) & 0xFF] ^ (crc >> 8); + + return ~crc; + } + /*! * \ingroup core * \brief Returns the number of elements in a C-array diff --git a/tests/Engine/Core/AlgorithmCoreTest.cpp b/tests/Engine/Core/AlgorithmCoreTest.cpp index 4c08b4594..23b222aa7 100644 --- a/tests/Engine/Core/AlgorithmCoreTest.cpp +++ b/tests/Engine/Core/AlgorithmCoreTest.cpp @@ -45,6 +45,12 @@ TEST_CASE("ComputeHash", "[CORE][ALGORITHM]") const char* expectedOutput; }; + static_assert(Nz::CRC32("Nazara Engine") == 0x8A2F5235); + static_assert(Nz::CRC32("The quick brown fox jumps over the lazy dog") == 0x414FA339); + + CHECK(Nz::CRC32("Nazara Engine") == 0x8A2F5235); + CHECK(Nz::CRC32("The quick brown fox jumps over the lazy dog") == 0x414FA339); + // https://defuse.ca/checksums.htm // https://toolslick.com/programming/hashing/crc-calculator