diff --git a/Numeric/BitReverse.hpp b/Numeric/BitReverse.hpp index 897f058ef..d05459b48 100644 --- a/Numeric/BitReverse.hpp +++ b/Numeric/BitReverse.hpp @@ -8,53 +8,36 @@ #pragma once +#include "Sizes.hpp" + #include #include namespace Numeric { -namespace { - -constexpr auto reverse_map = [] { - std::array 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 constexpr IntT bit_reverse(IntT source); // The single-byte specialisation uses a lookup table. -template<> constexpr uint8_t bit_reverse(const uint8_t source) { - return reverse_map[source]; +template<> constexpr uint8_t bit_reverse(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 constexpr IntT bit_reverse(const IntT source) { static_assert(std::is_same_v || std::is_same_v || std::is_same_v); - using HalfIntT = - std::conditional_t, uint8_t, - std::conditional_t, uint16_t, - uint32_t>>; - constexpr auto HalfShift = sizeof(IntT) * 4; + + constexpr auto HalfSize = sizeof(IntT) * 4; + using HalfIntT = uint_t; 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 ); } diff --git a/Numeric/BitSpread.hpp b/Numeric/BitSpread.hpp index d7c0de92c..56553aff1 100644 --- a/Numeric/BitSpread.hpp +++ b/Numeric/BitSpread.hpp @@ -8,6 +8,8 @@ #pragma once +#include + namespace Numeric { /// @returns The bits of @c input with a 0 bit inserted between each and diff --git a/Numeric/CRC.hpp b/Numeric/CRC.hpp index 24a7b2cbd..5a0e5f7f2 100644 --- a/Numeric/CRC.hpp +++ b/Numeric/CRC.hpp @@ -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 IntType compute_crc(const Collection &data) { - return compute_crc(data.begin(), data.end()); + template + 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 IntType compute_crc(Iterator begin, const Iterator end) { - reset(); + template + 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: diff --git a/Numeric/Sizes.hpp b/Numeric/Sizes.hpp index c78cc70d9..aaec3039a 100644 --- a/Numeric/Sizes.hpp +++ b/Numeric/Sizes.hpp @@ -8,9 +8,19 @@ #pragma once +#include #include #include +template 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 using uint_t = typename uint_t_impl::type; + /*! Maps to the smallest integral type that can contain max_value, from the following options: diff --git a/OSBindings/Mac/Clock SignalTests/CRCTests.mm b/OSBindings/Mac/Clock SignalTests/CRCTests.mm index 938004326..bf4273803 100644 --- a/OSBindings/Mac/Clock SignalTests/CRCTests.mm +++ b/OSBindings/Mac/Clock SignalTests/CRCTests.mm @@ -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 diff --git a/Storage/Disk/DiskImage/Formats/WOZ.cpp b/Storage/Disk/DiskImage/Formats/WOZ.cpp index c8f1970b4..487e3e6b8 100644 --- a/Storage/Disk/DiskImage/Formats/WOZ.cpp +++ b/Storage/Disk/DiskImage/Formats/WOZ.cpp @@ -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> &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()); diff --git a/Storage/Disk/DiskImage/Formats/WOZ.hpp b/Storage/Disk/DiskImage/Formats/WOZ.hpp index fa482c3b7..05bfd8cb2 100644 --- a/Storage/Disk/DiskImage/Formats/WOZ.hpp +++ b/Storage/Disk/DiskImage/Formats/WOZ.hpp @@ -42,7 +42,6 @@ private: long tracks_offset_ = -1; std::vector post_crc_contents_; - CRC::CRC32 crc_generator; /*! Gets the in-file offset of a track.