1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-03-27 19:33:26 +00:00

Remove need for a CRC generator instance.

This commit is contained in:
Thomas Harte 2025-02-04 22:54:39 -05:00
parent 0310db5f24
commit 07493a6b18
7 changed files with 48 additions and 71 deletions

View File

@ -8,53 +8,36 @@
#pragma once
#include "Sizes.hpp"
#include <array>
#include <cstdint>
namespace Numeric {
namespace {
constexpr auto reverse_map = [] {
std::array<uint8_t, 256> table{};
for(std::size_t c = 0; c < 256; ++c) {
table[c] = uint8_t(
((c & 0x80) >> 7) |
((c & 0x40) >> 5) |
((c & 0x20) >> 3) |
((c & 0x10) >> 1) |
((c & 0x08) << 1) |
((c & 0x04) << 3) |
((c & 0x02) << 5) |
((c & 0x01) << 7)
);
}
return table;
} ();
}
/// @returns @c source with the order of its bits reversed. E.g. if @c IntT is @c uint8_t then
/// the reverse of bit pattern abcd efgh is hgfd dcba.
template <typename IntT> constexpr IntT bit_reverse(IntT source);
// The single-byte specialisation uses a lookup table.
template<> constexpr uint8_t bit_reverse<uint8_t>(const uint8_t source) {
return reverse_map[source];
template<> constexpr uint8_t bit_reverse<uint8_t>(uint8_t source) {
source = uint8_t(((source & 0b1111'0000) >> 4) | ((source & 0b0000'1111) << 4));
source = uint8_t(((source & 0b1100'1100) >> 2) | ((source & 0b0011'0011) << 2));
source = uint8_t(((source & 0b1010'1010) >> 1) | ((source & 0b0101'0101) << 1));
return source;
}
// All other versions recursively subdivide.
template <typename IntT>
constexpr IntT bit_reverse(const IntT source) {
static_assert(std::is_same_v<IntT, uint16_t> || std::is_same_v<IntT, uint32_t> || std::is_same_v<IntT, uint64_t>);
using HalfIntT =
std::conditional_t<std::is_same_v<IntT, uint16_t>, uint8_t,
std::conditional_t<std::is_same_v<IntT, uint32_t>, uint16_t,
uint32_t>>;
constexpr auto HalfShift = sizeof(IntT) * 4;
constexpr auto HalfSize = sizeof(IntT) * 4;
using HalfIntT = uint_t<HalfSize>;
return IntT(
IntT(bit_reverse(HalfIntT(source))) << HalfShift) |
IntT(bit_reverse(HalfIntT(source >> HalfShift))
IntT(bit_reverse(HalfIntT(source >> HalfSize))) |
IntT(bit_reverse(HalfIntT(source))) << HalfSize
);
}

View File

@ -8,6 +8,8 @@
#pragma once
#include <cstdint>
namespace Numeric {
/// @returns The bits of @c input with a 0 bit inserted between each and

View File

@ -71,30 +71,24 @@ public:
void set_value(const IntType value) { value_ = value; }
/*!
A compound for:
reset()
[add all data from @c data]
get_value()
Calculates the CRC of the provided collection, assuming that it contains `uint8_t`s.
*/
template <typename Collection> IntType compute_crc(const Collection &data) {
return compute_crc(data.begin(), data.end());
template <typename Collection>
static IntType crc_of(const Collection &data) {
return crc_of(data.begin(), data.end());
}
/*!
A compound for:
reset()
[add all data from @c begin to @c end]
get_value()
Calculates the CRC of all `uint8_t`s in the range defined by @c begin and @c end.
*/
template <typename Iterator> IntType compute_crc(Iterator begin, const Iterator end) {
reset();
template <typename Iterator>
static IntType crc_of(Iterator begin, const Iterator end) {
Generator generator;
while(begin != end) {
add(*begin);
generator.add(*begin);
++begin;
}
return get_value();
return generator.get_value();
}
private:

View File

@ -8,9 +8,19 @@
#pragma once
#include <cstdint>
#include <limits>
#include <type_traits>
template <int size> struct uint_t_impl;
template <> struct uint_t_impl<8> { using type = uint8_t; };
template <> struct uint_t_impl<16> { using type = uint16_t; };
template <> struct uint_t_impl<32> { using type = uint32_t; };
template <> struct uint_t_impl<64> { using type = uint64_t; };
/// Unsigned integer types templated on size; `uint_t<8> = uint8_t`; `uint_t<16> = uint16_t`, etc.
template <int size> using uint_t = typename uint_t_impl<size>::type;
/*!
Maps to the smallest integral type that can contain max_value, from the following options:

View File

@ -15,26 +15,22 @@
@implementation CRCTests
- (uint16_t)crcOfData:(uint8_t *)data length:(size_t)length generator:(CRC::CCITT &)generator {
generator.reset();
for(size_t c = 0; c < length; c++)
generator.add(data[c]);
return generator.get_value();
- (uint16_t)crcOfData:(const uint8_t *)data length:(size_t)length generator:(CRC::CCITT &)generator {
return generator.crc_of(data, data+length);
}
- (void)testIDMark {
uint8_t IDMark[] = {
constexpr uint8_t IDMark[] = {
0xa1, 0xa1, 0xa1, 0xfe, 0x00, 0x00, 0x01, 0x01
};
uint16_t crc = 0xfa0c;
CRC::CCITT crcGenerator;
constexpr uint16_t crc = 0xfa0c;
const uint16_t computedCRC = CRC::CCITT::crc_of(std::begin(IDMark), std::end(IDMark));
uint16_t computedCRC = [self crcOfData:IDMark length:sizeof(IDMark) generator:crcGenerator];
XCTAssert(computedCRC == crc, @"Calculated CRC should have been %04x, was %04x", crc, computedCRC);
}
- (void)testData {
uint8_t sectorData[] = {
constexpr uint8_t sectorData[] = {
0xa1, 0xa1, 0xa1, 0xfb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x53, 0x45, 0x44, 0x4f,
0x52, 0x49, 0x43, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
@ -53,27 +49,20 @@
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20
};
uint16_t crc = 0x4de7;
CRC::CCITT crcGenerator;
constexpr uint16_t crc = 0x4de7;
uint16_t computedCRC = CRC::CCITT::crc_of(std::begin(sectorData), std::end(sectorData));
uint16_t computedCRC = [self crcOfData:sectorData length:sizeof(sectorData) generator:crcGenerator];
XCTAssert(computedCRC == crc, @"Calculated CRC should have been %04x, was %04x", crc, computedCRC);
}
- (void)testCCITTCheck {
CRC::CCITT crcGenerator;
for(auto c: std::string("123456789")) {
crcGenerator.add(c);
}
XCTAssertEqual(crcGenerator.get_value(), 0x29b1);
constexpr char testString[] = "123456789";
XCTAssertEqual(CRC::CCITT::crc_of(std::begin(testString), std::end(testString) - 1), 0x29b1);
}
- (void)testCRC32Check {
CRC::CRC32 crcGenerator;
for(auto c: std::string("123456789")) {
crcGenerator.add(c);
}
XCTAssertEqual(crcGenerator.get_value(), 0xcbf43926);
constexpr char testString[] = "123456789";
XCTAssertEqual(CRC::CRC32::crc_of(std::begin(testString), std::end(testString) - 1), 0xcbf43926);
}
@end

View File

@ -47,7 +47,7 @@ WOZ::WOZ(const std::string &file_name) :
post_crc_contents_ = file_.read(size_t(file_.stats().st_size - 12));
// Test the CRC.
const uint32_t computed_crc = crc_generator.compute_crc(post_crc_contents_);
const uint32_t computed_crc = CRC::CRC32::crc_of(post_crc_contents_);
if(crc != computed_crc) {
throw Error::InvalidFormat;
}
@ -209,7 +209,7 @@ void WOZ::set_tracks(const std::map<Track::Address, std::unique_ptr<Track>> &tra
}
// Calculate the new CRC.
const uint32_t crc = crc_generator.compute_crc(post_crc_contents_);
const uint32_t crc = CRC::CRC32::crc_of(post_crc_contents_);
// Grab the file lock, then write the CRC, then just dump the entire file buffer.
std::lock_guard lock_guard(file_.get_file_access_mutex());

View File

@ -42,7 +42,6 @@ private:
long tracks_offset_ = -1;
std::vector<uint8_t> post_crc_contents_;
CRC::CRC32 crc_generator;
/*!
Gets the in-file offset of a track.