Program Listing for File crc32.h
↰ Return to documentation for file (liberate/checksum/crc32.h
)
/*
* This file is part of liberate.
*
* Author(s): Jens Finkhaeuser <jens@finkhaeuser.de>
*
* Copyright (c) 2021 Jens Finkhaeuser.
* Copyright (c) 2022 Interpeer gUG (haftungsbeschränkt)
*
* SPDX-License-Identifier: GPL-3.0-only
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBERATE_CHECKSUM_CRC32_H
#define LIBERATE_CHECKSUM_CRC32_H
#ifndef __cplusplus
#error You are trying to include a C++ only header file
#endif
#include <liberate.h>
#include <numeric>
#include <array>
namespace liberate::checksum {
using crc32_checksum = std::uint_fast32_t;
using crc32_serialize = uint32_t; // For size estimation
constexpr crc32_checksum CRC32_MASK = ~crc32_checksum{0} & crc32_checksum{0xFFFFFFFFuL};
constexpr crc32_checksum CRC32_INITIALIZER = CRC32_MASK;
enum crc32_polynomials : crc32_checksum
{
CRC32 = crc32_checksum{0xEDB88320uL},
CRC32_ISO3309 = CRC32,
CRC32_IEEE802_3 = CRC32,
CRC32_GZIP = CRC32,
CRC32_BZIP2 = CRC32,
CRC32_POSIX = CRC32,
CRC32C = crc32_checksum{0x82F63B78uL},
CRC32_CASTAGNOLI = CRC32C,
CRC32C_SCTP = CRC32C,
CRC32C_SSE42 = CRC32C,
CRC32K = crc32_checksum{0xEB31D82EuL},
CRC32_KOOPMAN = CRC32K,
CRC32K2 = crc32_checksum{0x992C1A4CuL},
CRC32_KOOPMAN2 = CRC32K,
CRC32Q = crc32_checksum{0xD5828281uL},
CRC32_AIXM = CRC32Q,
};
namespace {
template <
crc32_checksum POLYNOMIAL,
size_t table_size = 256
>
struct crc32_table_generator
{
private:
// Calculate iteration value based on current value and LSB.
template <crc32_checksum VAL, bool flag>
struct iter_value;
template <crc32_checksum VAL>
struct iter_value<VAL, true>
{
static constexpr crc32_checksum value = (VAL >> 1) ^ POLYNOMIAL;
};
template <crc32_checksum VAL>
struct iter_value<VAL, false>
{
static constexpr crc32_checksum value = (VAL >> 1);
};
// Calculation for table elements; index is the table index, N is the
// iteration value.
template <uint8_t index, uint8_t N = 0>
struct table_element
{
static constexpr bool lsb =
static_cast<bool>(
table_element<index, N + 1>::value & 0x01u
);
static constexpr crc32_checksum value = iter_value<
table_element<index, N + 1>::value,
lsb
>::value;
};
template <uint8_t index>
struct table_element<index, 7>
{
static constexpr bool lsb =
static_cast<bool>(
index & 0x01u
);
static constexpr crc32_checksum value = iter_value<
index,
lsb
>::value;
};
// Calculation of table
template <
size_t N = table_size - 1,
crc32_checksum ...Indices
>
struct table
{
static constexpr auto value = table<
N - 1,
table_element<N>::value,
Indices...
>::value;
};
template <
crc32_checksum ...Indices
>
struct table<0, Indices...>
{
static constexpr std::array<crc32_checksum, sizeof...(Indices) + 1> value
= {{ table_element<0>::value, Indices... }};
};
public:
// Final array calculation
static constexpr std::array<crc32_checksum, table_size> value = table<>::value;
};
template <
typename tableT,
typename valueT
>
struct checksum_step
{
static constexpr auto table = tableT::value;
static crc32_checksum
step(crc32_checksum checksum, valueT value)
{
return checksum_step<tableT, std::uint_fast8_t>::step(checksum,
static_cast<std::uint_fast8_t>(value));
}
};
template <
typename tableT
>
struct checksum_step<tableT, std::uint_fast8_t>
{
static constexpr auto table = tableT::value;
static crc32_checksum
step(crc32_checksum checksum, std::uint_fast8_t value)
{
return table[(checksum ^ value) & 0xFFu] ^ (checksum >> 8);
}
};
} // anonymous namespace
template <
crc32_checksum POLYNOMIAL,
typename iterT
>
crc32_checksum
crc32(iterT begin, iterT end, crc32_checksum initial = CRC32_INITIALIZER)
{
auto init = initial == CRC32_INITIALIZER
? initial
: ~initial & CRC32_MASK;
// Calculate checksum
return CRC32_MASK &
~std::accumulate(begin, end, init,
checksum_step<
crc32_table_generator<POLYNOMIAL>,
typename std::iterator_traits<iterT>::value_type
>::step
);
}
} // namespace liberate::checksum
#endif // guard