summaryrefslogtreecommitdiff
path: root/crc32.c
diff options
context:
space:
mode:
authorMark Adler <madler@alumni.caltech.edu>2018-11-04 10:31:46 -0800
committerHans Kristian Rosbach <hk-github@circlestorm.org>2018-12-08 12:36:30 +0100
commitcc36e352bafd42a2cddffdff926acdbe448da89f (patch)
tree8594d0af7b3385ac8bc1bc6318e4abd80fb864a4 /crc32.c
parent9a143bb48f514065438bd59c234fd4a868fa73c7 (diff)
Add crc32_combine_gen() and crc32_combine_op() for fast combines.
When the same len2 is used repeatedly, it is faster to use crc32_combine_gen() to generate an operator, that is then used to combine CRCs with crc32_combine_op().
Diffstat (limited to 'crc32.c')
-rw-r--r--crc32.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/crc32.c b/crc32.c
index fb64b91..95080b3 100644
--- a/crc32.c
+++ b/crc32.c
@@ -41,6 +41,7 @@
#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
static uint32_t gf2_matrix_times(const uint32_t *mat, uint32_t vec);
static uint32_t crc32_combine_(uint32_t crc1, uint32_t crc2, z_off64_t len2);
+static void crc32_combine_gen_(uint32_t *op, z_off64_t len2);
/* ========================================================================= */
static uint32_t gf2_matrix_times(const uint32_t *mat, uint32_t vec) {
@@ -410,3 +411,67 @@ ZLIB_INTERNAL void copy_with_crc(PREFIX3(stream) *strm, unsigned char *dst, unsi
}
#endif
+/* ========================================================================= */
+static void crc32_combine_gen_(uint32_t *op, z_off64_t len2)
+{
+ uint32_t row;
+ int j;
+ unsigned i;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+ /* if len2 is zero or negative, return the identity matrix */
+ if (len2 <= 0) {
+ row = 1;
+ for (j = 0; j < GF2_DIM; j++) {
+ op[j] = row;
+ row <<= 1;
+ }
+ return;
+ }
+
+ /* at least one bit in len2 is set -- find it, and copy the operator
+ corresponding to that position into op */
+ i = 0;
+ for (;;) {
+ if (len2 & 1) {
+ for (j = 0; j < GF2_DIM; j++)
+ op[j] = crc_comb[i][j];
+ break;
+ }
+ len2 >>= 1;
+ i = (i + 1) % GF2_DIM;
+ }
+
+ /* for each remaining bit set in len2 (if any), multiply op by the operator
+ corresponding to that position */
+ for (;;) {
+ len2 >>= 1;
+ i = (i + 1) % GF2_DIM;
+ if (len2 == 0)
+ break;
+ if (len2 & 1)
+ for (j = 0; j < GF2_DIM; j++)
+ op[j] = gf2_matrix_times(crc_comb[i], op[j]);
+ }
+}
+
+/* ========================================================================= */
+void ZEXPORT PREFIX(crc32_combine_gen)(uint32_t *op, z_off_t len2)
+{
+ crc32_combine_gen_(op, len2);
+}
+
+void ZEXPORT PREFIX(crc32_combine_gen64)(uint32_t *op, z_off64_t len2)
+{
+ crc32_combine_gen_(op, len2);
+}
+
+/* ========================================================================= */
+uint32_t ZEXPORT PREFIX(crc32_combine_op)(uint32_t crc1, uint32_t crc2, const uint32_t *op)
+{
+ return gf2_matrix_times(op, crc1) ^ crc2;
+}