You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bookkeeper.apache.org by si...@apache.org on 2018/01/07 05:45:59 UTC
[bookkeeper] branch master updated: ISSUE #915: Part 1 - Copy
pulsar-checksum module as circe-checksum
This is an automated email from the ASF dual-hosted git repository.
sijie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git
The following commit(s) were added to refs/heads/master by this push:
new a0b05c5 ISSUE #915: Part 1 - Copy pulsar-checksum module as circe-checksum
a0b05c5 is described below
commit a0b05c519b34dd1f4bcd1f440378aeb601c92c90
Author: Sijie Guo <si...@apache.org>
AuthorDate: Sat Jan 6 21:45:53 2018 -0800
ISSUE #915: Part 1 - Copy pulsar-checksum module as circe-checksum
Descriptions of the changes in this PR:
- this change copies the files under `com.scurrilous.circe` in pulsar-checksum module into bookkeeper as `circe-checksum`.
- this change doesn't copy files under `org.apache.pulsar` except NativeUtils. will have a subsequent change to add it.
- Move NativeUtils to `com.scurrilous.circe.utils`.
- Update notice files to respect to Trevor Robinson's change
Author: Sijie Guo <si...@apache.org>
Reviewers: Matteo Merli <mm...@apache.org>
This closes #916 from sijie/copy_pulsar_checksum, closes #915
---
NOTICE | 5 +
.../src/main/resources/NOTICE-all.bin.txt | 6 +
.../src/main/resources/NOTICE-server.bin.txt | 6 +
.../src/main/resources/bookkeeper/suppressions.xml | 3 +
circe-checksum/pom.xml | 206 +++++++++++++++++++
circe-checksum/src/main/assembly/assembly.xml | 71 +++++++
circe-checksum/src/main/circe/cpp/crc32c_sse42.cpp | 217 +++++++++++++++++++++
.../src/main/circe/cpp/crc32c_sse42_jni.cpp | 78 ++++++++
circe-checksum/src/main/circe/cpp/gf2.hpp | 174 +++++++++++++++++
.../src/main/circe/include/crc32c_sse42.hpp | 40 ++++
circe-checksum/src/main/circe/include/int_types.h | 43 ++++
.../java/com/scurrilous/circe/CommonHashes.java | 188 ++++++++++++++++++
.../src/main/java/com/scurrilous/circe/Hash.java | 53 +++++
.../java/com/scurrilous/circe/HashParameters.java | 30 +++
.../java/com/scurrilous/circe/HashProvider.java | 101 ++++++++++
.../java/com/scurrilous/circe/HashProviders.java | 125 ++++++++++++
.../java/com/scurrilous/circe/HashSupport.java | 179 +++++++++++++++++
.../src/main/java/com/scurrilous/circe/Hashes.java | 123 ++++++++++++
.../com/scurrilous/circe/IncrementalIntHash.java | 88 +++++++++
.../com/scurrilous/circe/IncrementalLongHash.java | 88 +++++++++
.../java/com/scurrilous/circe/StatefulHash.java | 171 ++++++++++++++++
.../java/com/scurrilous/circe/StatefulIntHash.java | 31 +++
.../com/scurrilous/circe/StatefulLongHash.java | 30 +++
.../java/com/scurrilous/circe/StatelessHash.java | 31 +++
.../com/scurrilous/circe/StatelessIntHash.java | 77 ++++++++
.../com/scurrilous/circe/StatelessLongHash.java | 77 ++++++++
.../com/scurrilous/circe/crc/AbstractIntCrc.java | 64 ++++++
.../com/scurrilous/circe/crc/AbstractLongCrc.java | 64 ++++++
.../java/com/scurrilous/circe/crc/JavaCrc32.java | 103 ++++++++++
.../com/scurrilous/circe/crc/NormalByteCrc.java | 46 +++++
.../com/scurrilous/circe/crc/NormalIntCrc.java | 48 +++++
.../com/scurrilous/circe/crc/NormalLongCrc.java | 48 +++++
.../com/scurrilous/circe/crc/ReflectedIntCrc.java | 49 +++++
.../com/scurrilous/circe/crc/ReflectedLongCrc.java | 45 +++++
.../java/com/scurrilous/circe/crc/Sse42Crc32C.java | 130 ++++++++++++
.../scurrilous/circe/crc/StandardCrcProvider.java | 82 ++++++++
.../com/scurrilous/circe/crc/package-info.java | 25 +++
.../circe/impl/AbstractHashProvider.java | 193 ++++++++++++++++++
.../circe/impl/AbstractIncrementalIntHash.java | 114 +++++++++++
.../circe/impl/AbstractIncrementalLongHash.java | 114 +++++++++++
.../circe/impl/AbstractStatefulHash.java | 132 +++++++++++++
.../circe/impl/AbstractStatelessIntHash.java | 79 ++++++++
.../circe/impl/AbstractStatelessLongHash.java | 79 ++++++++
.../circe/impl/DirectByteBufferAccess.java | 34 ++++
.../circe/impl/DirectByteBufferAccessLoader.java | 49 +++++
.../java/com/scurrilous/circe/impl/HashCache.java | 44 +++++
.../com/scurrilous/circe/impl/HashCacheLoader.java | 58 ++++++
.../circe/impl/IncrementalIntStatefulHash.java | 92 +++++++++
.../circe/impl/IncrementalLongStatefulHash.java | 92 +++++++++
.../scurrilous/circe/impl/IntStatefulLongHash.java | 109 +++++++++++
.../circe/impl/IntStatelessLongHash.java | 80 ++++++++
.../com/scurrilous/circe/impl/package-info.java | 22 +++
.../java/com/scurrilous/circe/package-info.java | 22 +++
.../com/scurrilous/circe/params/CrcParameters.java | 205 +++++++++++++++++++
.../circe/params/MurmurHash3Parameters.java | 73 +++++++
.../circe/params/MurmurHash3Variant.java | 52 +++++
.../circe/params/SimpleHashParameters.java | 85 ++++++++
.../circe/params/SipHash24Parameters.java | 69 +++++++
.../com/scurrilous/circe/params/package-info.java | 21 ++
.../com/scurrilous/circe/utils/NativeUtils.java | 104 ++++++++++
.../services/com.scurrilous.circe.HashProvider | 1 +
.../com/scurrilous/circe/CommonHashesTest.java | 45 +++++
.../com/scurrilous/circe/crc/CRCProvidersTest.java | 88 +++++++++
.../java/com/scurrilous/circe/crc/CRCTest.java | 180 +++++++++++++++++
.../circe/impl/AbstractIncrementalIntHashTest.java | 142 ++++++++++++++
.../impl/AbstractIncrementalLongHashTest.java | 147 ++++++++++++++
.../circe/impl/AbstractStatefulHashTest.java | 193 ++++++++++++++++++
.../circe/impl/AbstractStatelessIntHashTest.java | 84 ++++++++
.../circe/impl/AbstractStatelessLongHashTest.java | 84 ++++++++
.../scurrilous/circe/utils/NativeUtilsTests.java | 49 +++++
pom.xml | 3 +-
71 files changed, 5882 insertions(+), 1 deletion(-)
diff --git a/NOTICE b/NOTICE
index 1102436..52de65b 100644
--- a/NOTICE
+++ b/NOTICE
@@ -4,3 +4,8 @@ Copyright 2011-2017 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
+This product contains a modified version of 'Circe', a high-performance
+hash algorithm framework & library from Trevor Robinson:
+
+ * LICENSE: Apache License 2.0
+ * HOMEPAGE: https://github.com/trevorr/circe
diff --git a/bookkeeper-dist/src/main/resources/NOTICE-all.bin.txt b/bookkeeper-dist/src/main/resources/NOTICE-all.bin.txt
index ba657cc..ac64c97 100644
--- a/bookkeeper-dist/src/main/resources/NOTICE-all.bin.txt
+++ b/bookkeeper-dist/src/main/resources/NOTICE-all.bin.txt
@@ -47,3 +47,9 @@ This project includes:
Twitter Util under The Apache Software License, Version 2.0
Vertx under The Apache Software License, Version 2.0
ZooKeeper under The Apache Software License, Version 2.0
+
+This product contains a modified version of 'Circe', a high-performance
+hash algorithm framework & library from Trevor Robinson:
+
+ * LICENSE: Apache License 2.0
+ * HOMEPAGE: https://github.com/trevorr/circe
diff --git a/bookkeeper-dist/src/main/resources/NOTICE-server.bin.txt b/bookkeeper-dist/src/main/resources/NOTICE-server.bin.txt
index 73e7fdb..bd0ec23 100644
--- a/bookkeeper-dist/src/main/resources/NOTICE-server.bin.txt
+++ b/bookkeeper-dist/src/main/resources/NOTICE-server.bin.txt
@@ -35,3 +35,9 @@ This project includes:
The Netty Project under The Apache Software License, Version 2.0
Vertx under The Apache Software License, Version 2.0
ZooKeeper under Apache License, Version 2.0
+
+This product contains a modified version of 'Circe', a high-performance
+hash algorithm framework & library from Trevor Robinson:
+
+ * LICENSE: Apache License 2.0
+ * HOMEPAGE: https://github.com/trevorr/circe
diff --git a/buildtools/src/main/resources/bookkeeper/suppressions.xml b/buildtools/src/main/resources/bookkeeper/suppressions.xml
index e28dd40..c45e2fa 100644
--- a/buildtools/src/main/resources/bookkeeper/suppressions.xml
+++ b/buildtools/src/main/resources/bookkeeper/suppressions.xml
@@ -25,4 +25,7 @@
<suppress checks=".*" files=".+[\\/]generated[\\/].+\.java" />
<suppress checks=".*" files=".+[\\/]generated-sources[\\/].+\.java" />
<suppress checks=".*" files=".+[\\/]generated-test-sources[\\/].+\.java" />
+
+ <!-- suppress all checks in the copied code -->
+ <suppress checks=".*" files=".+[\\/]com[\\/]scurrilous[\\/]circe[\\/].+\.java" />
</suppressions>
diff --git a/circe-checksum/pom.xml b/circe-checksum/pom.xml
new file mode 100644
index 0000000..001fd7c
--- /dev/null
+++ b/circe-checksum/pom.xml
@@ -0,0 +1,206 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.bookkeeper</groupId>
+ <artifactId>bookkeeper</artifactId>
+ <version>4.7.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <artifactId>circe-checksum</artifactId>
+ <packaging>nar</packaging>
+ <name>Apache BookKeeper :: Circe Checksum Library</name>
+ <description>Circe Checksum Library</description>
+
+ <properties>
+ <nar.runtime>dynamic</nar.runtime>
+ <nar.cpp.optionSet>-msse4.2 -mpclmul</nar.cpp.optionSet>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>${guava.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>6.8.5</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.googlecode.jmockit</groupId>
+ <artifactId>jmockit</artifactId>
+ <version>1.7</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>${maven-checkstyle-plugin.version}</version>
+ <dependencies>
+ <dependency>
+ <groupId>com.puppycrawl.tools</groupId>
+ <artifactId>checkstyle</artifactId>
+ <version>${puppycrawl.checkstyle.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.bookkeeper</groupId>
+ <artifactId>buildtools</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <configLocation>bookkeeper/checkstyle.xml</configLocation>
+ <suppressionsLocation>bookkeeper/suppressions.xml</suppressionsLocation>
+ <consoleOutput>true</consoleOutput>
+ <failOnViolation>true</failOnViolation>
+ <includeResources>false</includeResources>
+ <includeTestSourceDirectory>true</includeTestSourceDirectory>
+ </configuration>
+ <executions>
+ <execution>
+ <id>checkstyle</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>com.github.maven-nar</groupId>
+ <artifactId>nar-maven-plugin</artifactId>
+ <version>3.1.0</version>
+ <extensions>true</extensions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4.1</version>
+ <configuration>
+ <descriptors>
+ <descriptor>src/main/assembly/assembly.xml</descriptor>
+ </descriptors>
+ <appendAssemblyId>false</appendAssemblyId>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>mac</id>
+ <activation>
+ <os>
+ <name>Mac OS X</name>
+ </os>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.github.maven-nar</groupId>
+ <artifactId>nar-maven-plugin</artifactId>
+ <version>3.1.0</version>
+ <extensions>true</extensions>
+ <configuration>
+ <runtime>${nar.runtime}</runtime>
+ <output>circe-checksum</output>
+ <libraries>
+ <library>
+ <type>jni</type>
+ <narSystemPackage>com.scurrilous.circe.checksum</narSystemPackage>
+ </library>
+ </libraries>
+ <cpp>
+ <optionSet>${nar.cpp.optionSet}</optionSet>
+ <exceptions>false</exceptions>
+ <rtti>false</rtti>
+ <optimize>full</optimize>
+ </cpp>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>Linux</id>
+ <activation>
+ <os>
+ <name>Linux</name>
+ </os>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.github.maven-nar</groupId>
+ <artifactId>nar-maven-plugin</artifactId>
+ <version>3.1.0</version>
+ <extensions>true</extensions>
+ <configuration>
+ <runtime>${nar.runtime}</runtime>
+ <output>circe-checksum</output>
+ <libraries>
+ <library>
+ <type>jni</type>
+ <narSystemPackage>com.scurrilous.circe.checksum</narSystemPackage>
+ </library>
+ </libraries>
+ <cpp>
+ <optionSet>${nar.cpp.optionSet}</optionSet>
+ <exceptions>false</exceptions>
+ <rtti>false</rtti>
+ <optimize>full</optimize>
+ </cpp>
+ <linker>
+ <libSet>rt</libSet>
+ </linker>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/circe-checksum/src/main/assembly/assembly.xml b/circe-checksum/src/main/assembly/assembly.xml
new file mode 100644
index 0000000..bded0ca
--- /dev/null
+++ b/circe-checksum/src/main/assembly/assembly.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<assembly>
+ <id>all</id>
+ <formats>
+ <format>jar</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <dependencySets>
+ <dependencySet>
+ <excludes>
+ <exclude>org.slf4j:slf4j-api</exclude>
+ <exclude>io.netty</exclude>
+ <exclude>*:nar:*</exclude>
+ </excludes>
+ </dependencySet>
+ </dependencySets>
+ <fileSets>
+ <fileSet>
+ <directory>${project.build.directory}/nar/${project.artifactId}-${project.version}-${os.arch}-MacOSX-gpp-jni/lib/${os.arch}-MacOSX-gpp/jni
+ </directory>
+ <outputDirectory>lib</outputDirectory>
+ <includes>
+ <include>lib*</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.build.directory}/nar/${project.artifactId}-${project.version}-${os.arch}-Linux-gpp-jni/lib/${os.arch}-Linux-gpp/jni
+ </directory>
+ <outputDirectory>lib</outputDirectory>
+ <includes>
+ <include>lib*</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.build.directory}/nar/${project.artifactId}-${project.version}-${os.arch}-${os.name}-gpp-jni/lib/${os.arch}-${os.name}-gpp/jni
+ </directory>
+ <outputDirectory>lib</outputDirectory>
+ <includes>
+ <include>lib*</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.build.directory}/classes</directory>
+ <outputDirectory></outputDirectory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/circe-checksum/src/main/circe/cpp/crc32c_sse42.cpp b/circe-checksum/src/main/circe/cpp/crc32c_sse42.cpp
new file mode 100644
index 0000000..904d437
--- /dev/null
+++ b/circe-checksum/src/main/circe/cpp/crc32c_sse42.cpp
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+#include "../include/crc32c_sse42.hpp"
+
+#include <assert.h>
+#include <nmmintrin.h> // SSE4.2
+#include <wmmintrin.h> // PCLMUL
+
+#ifdef _MSC_VER
+# include <intrin.h>
+#else
+# include <cpuid.h>
+#endif
+
+//#define CRC32C_DEBUG
+#define CRC32C_PCLMULQDQ
+
+#ifdef CRC32C_DEBUG
+# include <stdio.h>
+# define DEBUG_PRINTF1(fmt, v1) printf(fmt, v1)
+# define DEBUG_PRINTF2(fmt, v1, v2) printf(fmt, v1, v2)
+# define DEBUG_PRINTF3(fmt, v1, v2, v3) printf(fmt, v1, v2, v3)
+# define DEBUG_PRINTF4(fmt, v1, v2, v3, v4) printf(fmt, v1, v2, v3, v4)
+#else
+# define DEBUG_PRINTF1(fmt, v1)
+# define DEBUG_PRINTF2(fmt, v1, v2)
+# define DEBUG_PRINTF3(fmt, v1, v2, v3)
+# define DEBUG_PRINTF4(fmt, v1, v2, v3, v4)
+#endif
+
+static bool initialized = false;
+static bool has_sse42 = false;
+static bool has_pclmulqdq = false;
+
+bool crc32c_initialize() {
+ if (!initialized) {
+ const uint32_t cpuid_ecx_sse42 = (1 << 20);
+ const uint32_t cpuid_ecx_pclmulqdq = (1 << 1);
+
+#ifdef _MSC_VER
+ int CPUInfo[4] = {};
+ __cpuid(CPUInfo, 1);
+ has_sse42 = (CPUInfo[2] & cpuid_ecx_sse42) != 0;
+ has_pclmulqdq = (CPUInfo[2] & cpuid_ecx_pclmulqdq) != 0;
+#else
+ unsigned int eax, ebx, ecx, edx;
+ if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
+ has_sse42 = (ecx & cpuid_ecx_sse42) != 0;
+ has_pclmulqdq = (ecx & cpuid_ecx_pclmulqdq) != 0;
+ }
+#endif
+ DEBUG_PRINTF1("has_sse42 = %d\n", has_sse42);
+ DEBUG_PRINTF1("has_pclmulqdq = %d\n", has_pclmulqdq);
+ initialized = true;
+ }
+ return has_sse42;
+}
+
+#include "gf2.hpp"
+
+chunk_config::chunk_config(size_t words, const chunk_config* next) : words(words), next(next) {
+ assert(words > 0);
+ assert(!next || next->words < words);
+ const size_t loop_bytes = loops() * 8;
+ make_shift_table(loop_bytes, shift1);
+ make_shift_table(loop_bytes * 2, shift2);
+}
+
+void chunk_config::make_shift_table(size_t bytes, uint32_t table[256]) {
+ bitmatrix<32, 32> op;
+ op.lower_shift();
+ op[0] = 0x82f63b78; // reversed CRC-32C polynomial
+ bitmatrix<32, 32> m;
+ pow(m, op, bytes * 8);
+ for (unsigned int i = 0; i < 256; ++i)
+ table[i] = (const bitvector<32>) mul(m, bitvector<32>(i));
+}
+
+static uint32_t crc32c_chunk(uint32_t crc, const void *buf, const chunk_config& config) {
+ DEBUG_PRINTF3(" crc32c_chunk(crc = 0x%08x, buf = %p, config.words = " SIZE_T_FORMAT ")", crc, buf, config.words);
+
+ const uint64_t *pq = (const uint64_t*) buf;
+ uint64_t crc0 = config.extra() > 1 ? _mm_crc32_u64(crc, *pq++) : crc;
+ uint64_t crc1 = 0;
+ uint64_t crc2 = 0;
+ const size_t loops = config.loops();
+ for (unsigned int i = 0; i < loops; ++i, ++pq) {
+ crc1 = _mm_crc32_u64(crc1, pq[1 * loops]);
+ crc2 = _mm_crc32_u64(crc2, pq[2 * loops]);
+ crc0 = _mm_crc32_u64(crc0, pq[0 * loops]);
+ }
+ pq += 2 * loops;
+ uint64_t tmp = *pq++;
+# ifdef CRC32C_PCLMULQDQ
+ if (has_pclmulqdq) {
+ __m128i k = _mm_set_epi64x(config.shift1[1], config.shift2[1]);
+ __m128i mul1 = _mm_clmulepi64_si128(_mm_cvtsi64_si128((int64_t) crc1), k, 0x10);
+ __m128i mul0 = _mm_clmulepi64_si128(_mm_cvtsi64_si128((int64_t) crc0), k, 0x00);
+ tmp ^= (uint64_t) _mm_cvtsi128_si64(mul1);
+ tmp ^= (uint64_t) _mm_cvtsi128_si64(mul0);
+ } else
+# endif
+ {
+ tmp ^= config.shift1[crc1 & 0xff];
+ tmp ^= ((uint64_t) config.shift1[(crc1 >> 8) & 0xff]) << 8;
+ tmp ^= ((uint64_t) config.shift1[(crc1 >> 16) & 0xff]) << 16;
+ tmp ^= ((uint64_t) config.shift1[(crc1 >> 24) & 0xff]) << 24;
+
+ tmp ^= config.shift2[crc0 & 0xff];
+ tmp ^= ((uint64_t) config.shift2[(crc0 >> 8) & 0xff]) << 8;
+ tmp ^= ((uint64_t) config.shift2[(crc0 >> 16) & 0xff]) << 16;
+ tmp ^= ((uint64_t) config.shift2[(crc0 >> 24) & 0xff]) << 24;
+ }
+ crc2 = _mm_crc32_u64(crc2, tmp);
+ if (config.extra() > 2) // only if words is divisible by 3
+ crc2 = _mm_crc32_u64(crc2, *pq);
+ crc = (uint32_t) crc2;
+
+ DEBUG_PRINTF1(" = 0x%08x\n", crc);
+ return crc;
+}
+
+static uint32_t crc32c_words(uint32_t crc, const void *buf, size_t count) {
+ DEBUG_PRINTF3(" crc32c_words(crc = 0x%08x, buf = %p, count = " SIZE_T_FORMAT ")", crc, buf, count);
+
+ const uint64_t *pq = (const uint64_t*) buf;
+ size_t loops = (count + 7) / 8;
+ assert(loops > 0);
+ switch (count & 7) {
+ case 0:
+ do {
+ crc = (uint32_t) _mm_crc32_u64(crc, *pq++);
+ case 7: crc = (uint32_t) _mm_crc32_u64(crc, *pq++);
+ case 6: crc = (uint32_t) _mm_crc32_u64(crc, *pq++);
+ case 5: crc = (uint32_t) _mm_crc32_u64(crc, *pq++);
+ case 4: crc = (uint32_t) _mm_crc32_u64(crc, *pq++);
+ case 3: crc = (uint32_t) _mm_crc32_u64(crc, *pq++);
+ case 2: crc = (uint32_t) _mm_crc32_u64(crc, *pq++);
+ case 1: crc = (uint32_t) _mm_crc32_u64(crc, *pq++);
+ } while (--loops > 0);
+ }
+
+ DEBUG_PRINTF1(" = 0x%08x\n", crc);
+ return crc;
+}
+
+static uint32_t crc32c_bytes(uint32_t crc, const void *buf, size_t count) {
+ DEBUG_PRINTF3(" crc32c_bytes(crc = 0x%08x, buf = %p, count = " SIZE_T_FORMAT ")", crc, buf, count);
+
+ const uint8_t *pc = (const uint8_t*) buf;
+ size_t loops = (count + 7) / 8;
+ assert(loops > 0);
+ switch (count & 7) {
+ case 0:
+ do {
+ crc = (uint32_t) _mm_crc32_u8(crc, *pc++);
+ case 7: crc = (uint32_t) _mm_crc32_u8(crc, *pc++);
+ case 6: crc = (uint32_t) _mm_crc32_u8(crc, *pc++);
+ case 5: crc = (uint32_t) _mm_crc32_u8(crc, *pc++);
+ case 4: crc = (uint32_t) _mm_crc32_u8(crc, *pc++);
+ case 3: crc = (uint32_t) _mm_crc32_u8(crc, *pc++);
+ case 2: crc = (uint32_t) _mm_crc32_u8(crc, *pc++);
+ case 1: crc = (uint32_t) _mm_crc32_u8(crc, *pc++);
+ } while (--loops > 0);
+ }
+
+ DEBUG_PRINTF1(" = 0x%08x\n", crc);
+ return crc;
+}
+
+uint32_t crc32c(uint32_t init, const void *buf, size_t len, const chunk_config* config) {
+ DEBUG_PRINTF3("crc32c(init = 0x%08x, buf = %p, len = " SIZE_T_FORMAT ")\n", init, buf, len);
+
+ uint32_t crc = ~init;
+ const char *pc = (const char*) buf;
+ if (len >= 24) {
+ if ((uintptr_t) pc & 7) {
+ size_t unaligned = 8 - ((uintptr_t) pc & 7);
+ crc = crc32c_bytes(crc, pc, unaligned);
+ pc += unaligned;
+ len -= unaligned;
+ }
+ size_t words = len / 8;
+ while (config) {
+ while (words >= config->words) {
+ crc = crc32c_chunk(crc, pc, *config);
+ pc += config->words * 8;
+ words -= config->words;
+ }
+ config = config->next;
+ }
+ if (words > 0) {
+ crc = crc32c_words(crc, pc, words);
+ pc += words * 8;
+ }
+ len &= 7;
+ }
+ if (len)
+ crc = crc32c_bytes(crc, pc, len);
+ crc = ~crc;
+
+ DEBUG_PRINTF1("crc = 0x%08x\n", crc);
+ return crc;
+}
diff --git a/circe-checksum/src/main/circe/cpp/crc32c_sse42_jni.cpp b/circe-checksum/src/main/circe/cpp/crc32c_sse42_jni.cpp
new file mode 100644
index 0000000..4a8b116
--- /dev/null
+++ b/circe-checksum/src/main/circe/cpp/crc32c_sse42_jni.cpp
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+#include "com_scurrilous_circe_crc_Sse42Crc32C.h"
+#include "../include/crc32c_sse42.hpp"
+#include <new>
+
+extern "C"
+JNIEXPORT jboolean JNICALL Java_com_scurrilous_circe_crc_Sse42Crc32C_nativeSupported
+(JNIEnv *, jclass) {
+ return crc32c_initialize();
+}
+
+extern "C"
+JNIEXPORT jint JNICALL Java_com_scurrilous_circe_crc_Sse42Crc32C_nativeArray
+(JNIEnv *env, jclass, jint current, jbyteArray input, jint index, jint length, jlong config) {
+ const char *buf = (const char *) env->GetPrimitiveArrayCritical(input, 0);
+ jint crc = (jint) crc32c((uint32_t) current, buf + index, (size_t) length, (const chunk_config*) config);
+ env->ReleasePrimitiveArrayCritical(input, (void*) buf, 0);
+ return crc;
+}
+
+extern "C"
+JNIEXPORT jint JNICALL Java_com_scurrilous_circe_crc_Sse42Crc32C_nativeDirectBuffer
+(JNIEnv *env, jclass, jint current, jobject input, jint offset, jint length, jlong config) {
+ const char *address = (const char *) env->GetDirectBufferAddress(input);
+ if (!address)
+ return 0;
+ return (jint) crc32c((uint32_t) current, address + offset, (size_t) length, (const chunk_config*) config);
+}
+
+extern "C"
+JNIEXPORT jint JNICALL Java_com_scurrilous_circe_crc_Sse42Crc32C_nativeUnsafe
+(JNIEnv *, jclass, jint current, jlong address, jlong length, jlong config) {
+ return (jint) crc32c((uint32_t) current, (const void *) address, (size_t) length, (const chunk_config*) config);
+}
+
+extern "C"
+JNIEXPORT jlong JNICALL Java_com_scurrilous_circe_crc_Sse42Crc32C_allocConfig
+ (JNIEnv *env, jclass, jintArray chunkWords) {
+ chunk_config* configs = 0;
+ jsize len = env->GetArrayLength(chunkWords);
+ const jint *arr = (const jint *) env->GetPrimitiveArrayCritical(chunkWords, 0);
+ if (len < 1 || arr[0] < chunk_config::min_words)
+ goto fail;
+ for (jsize i = 1; i < len; ++i) {
+ if (arr[i] < chunk_config::min_words
+ || arr[i] >= arr[i - 1]) // chunk words must be strictly decreasing
+ goto fail;
+ }
+ configs = (chunk_config*) ::operator new[](sizeof(chunk_config) * (size_t) len, std::nothrow);
+ if (configs) {
+ for (jsize i = len; i > 0; --i) {
+ new(&configs[i - 1]) chunk_config((size_t) arr[i - 1], i < len ? &configs[i] : 0);
+ }
+ }
+fail:
+ env->ReleasePrimitiveArrayCritical(chunkWords, (void*) arr, 0);
+ return (jlong) configs;
+}
+
+extern "C"
+JNIEXPORT void JNICALL Java_com_scurrilous_circe_crc_Sse42Crc32C_freeConfig
+ (JNIEnv *, jclass, jlong config) {
+ delete[] (const chunk_config*) config;
+}
diff --git a/circe-checksum/src/main/circe/cpp/gf2.hpp b/circe-checksum/src/main/circe/cpp/gf2.hpp
new file mode 100644
index 0000000..ef963d3
--- /dev/null
+++ b/circe-checksum/src/main/circe/cpp/gf2.hpp
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+#include "../include/int_types.h"
+#include <algorithm> // std::swap
+
+#ifdef _MSC_VER
+#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned
+#endif
+
+// Type trait for unsigned integers of at least N bytes
+template <unsigned int N>
+struct uint_bytes {
+ enum { is_defined = 0 };
+};
+
+template <class T>
+struct defined_uint_bytes {
+ enum { is_defined = 1 };
+ typedef T type;
+};
+
+template <> struct uint_bytes<1> : defined_uint_bytes<uint8_t> {};
+template <> struct uint_bytes<2> : defined_uint_bytes<uint16_t> {};
+template <> struct uint_bytes<3> : defined_uint_bytes<uint32_t> {};
+template <> struct uint_bytes<4> : defined_uint_bytes<uint32_t> {};
+template <> struct uint_bytes<5> : defined_uint_bytes<uint64_t> {};
+template <> struct uint_bytes<6> : defined_uint_bytes<uint64_t> {};
+template <> struct uint_bytes<7> : defined_uint_bytes<uint64_t> {};
+template <> struct uint_bytes<8> : defined_uint_bytes<uint64_t> {};
+
+// Type trait for unsigned integers of at least N bits
+template <unsigned int N>
+struct uint_bits : uint_bytes<(N + 7) / 8> {
+ enum { bits = 8 * sizeof(typename uint_bits::type) };
+};
+
+// Bit vector of N bits; currently just exposes an unsigned integer
+template <unsigned int N>
+class bitvector {
+ typedef typename uint_bits<N>::type type;
+ type value;
+public:
+ bitvector() {}
+ bitvector(type value) : value(value) {}
+ operator type&() { return value; }
+ operator type() const { return value; }
+};
+
+// Bit matrix of M columns by N rows
+template <unsigned int M, unsigned int N = M>
+class bitmatrix {
+ typedef bitvector<M> row;
+ row value[N];
+public:
+ bitmatrix() {
+ }
+ explicit bitmatrix(bool b) {
+ if (b)
+ identity();
+ else
+ null();
+ }
+ void null() {
+ for (unsigned int i = 0; i < N; ++i)
+ value[i] = 0;
+ }
+ void identity() {
+ for (unsigned int i = 0; i < N; ++i)
+ value[i] = i < M ? (const row) 1 << i : 0;
+ }
+ void lower_shift() {
+ for (unsigned int i = 0; i < N; ++i)
+ value[i] = i > 0 && i <= M ? (const row) 1 << (i - 1) : 0;
+ }
+ void upper_shift() {
+ for (unsigned int i = 0; i < N; ++i)
+ value[i] = i + 1 < M ? (const row) 1 << (i + 1) : 0;
+ }
+ operator bitvector<M>*() { return value; }
+ operator const bitvector<M>*() const { return value; }
+};
+
+/*
+ * Multiplies MxN matrix A by N-row vector B in GF(2).
+ *
+ * For M,N = 3:
+ *
+ * | a b c | | x | | ax + by + cz |
+ * A = | d e f |, B = | y |, AB = | dx + ey + fz |
+ * | g h i | | z | | gx + hy + iz |
+ *
+ * In GF(2), addition corresponds to XOR and multiplication to AND:
+ *
+ * | (a & x) ^ (b & y) ^ (c & z) |
+ * AB = | (d & x) ^ (e & y) ^ (f & z) |
+ * | (g & x) ^ (h & y) ^ (i & z) |
+ *
+ * Trading variable names for [row,column] indices:
+ *
+ * AB = (A[,0] & B[0]) ^ (A[,1] & B[1]) ^ (A[,2] & B[2]) ^ ...
+ *
+ * Assuming columns are represented as words and rows as bit offsets,
+ * all rows of AB can be calculated in parallel:
+ *
+ * AB = (A[0] & -((B >> 0) & 1) ^ (A[1] & -((B >> 1) & 1) ^ ...
+ */
+template <unsigned int M, unsigned int N>
+bitvector<M> mul(const bitmatrix<M, N>& a, const bitvector<N> b) {
+ bitvector<M> result(0);
+ for (unsigned int i = 0; i < N; ++i)
+ result ^= a[i] & -((b >> i) & 1);
+ return result;
+}
+
+/*
+ * Multiplies MxN matrix A by NxP matrix B in GF(2).
+ *
+ * For M,N,P = 3:
+ *
+ * | a b c | | j k l | | (aj + bm + cp) (ak + bn + cq) (al + bo + cr) |
+ * A = | d e f |, B = | m n o |, AB = | (dj + em + fp) (dk + en + fq) (dl + eo + fr) |
+ * | g h i | | p q r | | (gj + hm + ip) (gk + hn + iq) (gl + ho + ir) |
+ */
+template <unsigned int M, unsigned int N, unsigned int P>
+void mul(bitmatrix<M, P>& result, const bitmatrix<M, N>& a, const bitmatrix<N, P>& b) {
+ for (unsigned int i = 0; i < P; i++)
+ result[i] = mul(a, b[i]);
+}
+
+/*
+ * Squares an NxN matrix in GF(2).
+ */
+template <unsigned int N>
+void sqr(bitmatrix<N, N>& result, const bitmatrix<N, N>& a) {
+ mul(result, a, a);
+}
+
+/*
+ * Raises an NxN matrix to the power n in GF(2) by squaring.
+ */
+template <unsigned int N>
+void pow(bitmatrix<N, N>& result, const bitmatrix<N, N>& a, uint64_t n) {
+ result.identity();
+ if (n > 0) {
+ bitmatrix<N, N> square = a;
+ bitmatrix<N, N> temp;
+ bitmatrix<N, N> *ptemp = &temp, *psquare = &square, *presult = &result;
+ for (;;) {
+ if (n & 1) {
+ mul(*ptemp, *presult, *psquare);
+ std::swap(ptemp, presult);
+ }
+ if (!(n >>= 1))
+ break;
+ sqr(*ptemp, *psquare);
+ std::swap(ptemp, psquare);
+ }
+ if (presult != &result)
+ result = *presult;
+ }
+}
diff --git a/circe-checksum/src/main/circe/include/crc32c_sse42.hpp b/circe-checksum/src/main/circe/include/crc32c_sse42.hpp
new file mode 100644
index 0000000..629f35e
--- /dev/null
+++ b/circe-checksum/src/main/circe/include/crc32c_sse42.hpp
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+#include "int_types.h"
+
+bool crc32c_initialize();
+
+class chunk_config {
+public:
+ enum { min_words = 4 };
+
+ const size_t words;
+ const chunk_config* const next;
+ uint32_t shift1[256];
+ uint32_t shift2[256];
+
+ chunk_config(size_t words, const chunk_config* next = 0);
+
+ size_t loops() const { return (words - 1) / 3; }
+ size_t extra() const { return (words - 1) % 3 + 1; }
+
+private:
+ chunk_config& operator=(const chunk_config&);
+
+ static void make_shift_table(size_t bytes, uint32_t table[256]);
+};
+
+uint32_t crc32c(uint32_t init, const void *buf, size_t len, const chunk_config* config);
diff --git a/circe-checksum/src/main/circe/include/int_types.h b/circe-checksum/src/main/circe/include/int_types.h
new file mode 100644
index 0000000..16c5c85
--- /dev/null
+++ b/circe-checksum/src/main/circe/include/int_types.h
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+#include <stddef.h> // size_t
+
+#if defined(_MSC_VER) && _MSC_VER < 1600 // stdint.h added in MSVC 2010
+
+typedef __int8 int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+
+#else
+
+# include <stdint.h>
+
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900 // MSVC 2015
+
+# define SIZE_T_FORMAT "%Iu"
+
+#else
+
+# define SIZE_T_FORMAT "%zu"
+
+#endif
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/CommonHashes.java b/circe-checksum/src/main/java/com/scurrilous/circe/CommonHashes.java
new file mode 100644
index 0000000..cb6ef66
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/CommonHashes.java
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+import com.scurrilous.circe.params.CrcParameters;
+import com.scurrilous.circe.params.MurmurHash3Parameters;
+import com.scurrilous.circe.params.MurmurHash3Variant;
+import com.scurrilous.circe.params.SimpleHashParameters;
+import com.scurrilous.circe.params.SipHash24Parameters;
+
+/**
+ * Static methods to obtain commonly-used hash functions. Note that a suitable
+ * provider JAR must be made available on the class path. This class does not
+ * have direct access to specific implementations; it simply constructs the hash
+ * parameters and uses the {@link Hashes} class to search for a provider.
+ */
+public final class CommonHashes {
+
+ private CommonHashes() {
+ }
+
+ /**
+ * Returns an incremental stateless hash function implementing the
+ * {@linkplain CrcParameters#CRC32 CRC-32} checksum algorithm.
+ *
+ * @return a CRC-32 stateless incremental integer hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static IncrementalIntHash crc32() {
+ return Hashes.getIncrementalInt(CrcParameters.CRC32);
+ }
+
+ /**
+ * Returns an incremental stateless hash function implementing the
+ * {@linkplain CrcParameters#CRC32C CRC-32C} checksum algorithm.
+ *
+ * @return a CRC-32C stateless incremental integer hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static IncrementalIntHash crc32c() {
+ return Hashes.getIncrementalInt(CrcParameters.CRC32C);
+ }
+
+ /**
+ * Returns an incremental stateless hash function implementing the
+ * {@linkplain CrcParameters#CRC64 CRC-64} checksum algorithm.
+ *
+ * @return a CRC-64 stateless incremental long integer hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static IncrementalLongHash crc64() {
+ return Hashes.getIncrementalLong(CrcParameters.CRC64);
+ }
+
+ /**
+ * Returns a hash function implementing the MurmurHash3 algorithm, 32-bit
+ * x86 variant, with a seed of 0.
+ *
+ * @return a MurmurHash3 32-bit/x86 stateless integer hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static StatelessIntHash murmur3_32() {
+ return Hashes.getStatelessInt(new MurmurHash3Parameters(MurmurHash3Variant.X86_32));
+ }
+
+ /**
+ * Returns a hash function implementing the MurmurHash3 algorithm, 32-bit
+ * x86 variant, with the given seed value
+ *
+ * @param seed the 32-bit seed value
+ * @return a MurmurHash3 32-bit/x86 stateless integer hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static StatelessIntHash murmur3_32(int seed) {
+ return Hashes.getStatelessInt(new MurmurHash3Parameters(MurmurHash3Variant.X86_32, seed));
+ }
+
+ /**
+ * Returns a hash function implementing the MurmurHash3 algorithm, 128-bit
+ * x64 variant, with a seed of 0.
+ *
+ * @return a MurmurHash3 128-bit/x64 stateful hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static StatefulHash murmur3_128() {
+ return Hashes.createStateful(new MurmurHash3Parameters(MurmurHash3Variant.X64_128));
+ }
+
+ /**
+ * Returns a hash function implementing the MurmurHash3 algorithm, 128-bit
+ * x64 variant, with the given seed value.
+ *
+ * @param seed the 32-bit seed value
+ * @return a MurmurHash3 128-bit/x64 stateful hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static StatefulHash murmur3_128(int seed) {
+ return Hashes.createStateful(new MurmurHash3Parameters(MurmurHash3Variant.X64_128, seed));
+ }
+
+ /**
+ * Returns a hash function implementing the SipHash-2-4 algorithm (64 bits)
+ * with the default seed,
+ * {@code 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F}.
+ *
+ * @return a SipHash-2-4 stateless long integer hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static StatelessLongHash sipHash24() {
+ return Hashes.getStatelessLong(new SipHash24Parameters());
+ }
+
+ /**
+ * Returns a hash function implementing the SipHash-2-4 algorithm (64 bits)
+ * with the given seed value.
+ *
+ * @param seedLow the low-order 64 bits of the seed
+ * @param seedHigh the high-order 64 bits of the seed
+ * @return a SipHash-2-4 stateless long integer hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static StatelessLongHash sipHash24(long seedLow, long seedHigh) {
+ return Hashes.getStatelessLong(new SipHash24Parameters(seedLow, seedHigh));
+ }
+
+ /**
+ * Returns a hash function implementing the MD5 algorithm (128 bits).
+ *
+ * @return an MD5 stateful hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static StatefulHash md5() {
+ return Hashes.createStateful(SimpleHashParameters.MD5);
+ }
+
+ /**
+ * Returns a hash function implementing the SHA-1 algorithm (160 bits).
+ *
+ * @return a SHA-1 stateful hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static StatefulHash sha1() {
+ return Hashes.createStateful(SimpleHashParameters.SHA1);
+ }
+
+ /**
+ * Returns a hash function implementing the SHA-256 algorithm (256 bits).
+ *
+ * @return a SHA-256 stateful hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static StatefulHash sha256() {
+ return Hashes.createStateful(SimpleHashParameters.SHA256);
+ }
+
+ /**
+ * Returns a hash function implementing the SHA-384 algorithm (384 bits).
+ *
+ * @return a SHA-384 stateful hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static StatefulHash sha384() {
+ return Hashes.createStateful(SimpleHashParameters.SHA384);
+ }
+
+ /**
+ * Returns a hash function implementing the SHA-512 algorithm (512 bits).
+ *
+ * @return a SHA-512 stateful hash
+ * @throws UnsupportedOperationException if no provider is available
+ */
+ public static StatefulHash sha512() {
+ return Hashes.createStateful(SimpleHashParameters.SHA512);
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/Hash.java b/circe-checksum/src/main/java/com/scurrilous/circe/Hash.java
new file mode 100644
index 0000000..1072e2d
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/Hash.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+/**
+ * Abstract hash function. Each actual hash function is provided using a
+ * {@linkplain StatefulHash stateful} derived interface. Hash functions with an
+ * output length that fits within an {@code int} or a {@code long} are also
+ * generally provided using a {@linkplain StatelessHash stateless} derived
+ * interface. Given a stateless hash object, a method is provided for obtaining
+ * a new corresponding stateful object.
+ */
+public interface Hash {
+
+ /**
+ * Returns the canonical name of this hash algorithm.
+ *
+ * @return the name of this hash algorithm
+ */
+ String algorithm();
+
+ /**
+ * Returns the length in bytes of the output of this hash function.
+ *
+ * @return the hash length in bytes
+ */
+ int length();
+
+ /**
+ * Returns whether this hash function supports unsafe access to arbitrary
+ * memory addresses using methods such as
+ * {@link StatefulHash#update(long, long)},
+ * {@link StatelessIntHash#calculate(long, long)}, or
+ * {@link IncrementalIntHash#resume(int, long, long)}. Such functions are
+ * generally implemented in native code.
+ *
+ * @return true if unsafe access is supported, false if not
+ */
+ boolean supportsUnsafe();
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/HashParameters.java b/circe-checksum/src/main/java/com/scurrilous/circe/HashParameters.java
new file mode 100644
index 0000000..5e6a444
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/HashParameters.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+/**
+ * Base interface implemented by classes describing parameters for a particular
+ * family of hash algorithms.
+ */
+public interface HashParameters {
+
+ /**
+ * Returns the canonical name of the hash algorithm.
+ *
+ * @return the name of the hash algorithm
+ */
+ String algorithm();
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/HashProvider.java b/circe-checksum/src/main/java/com/scurrilous/circe/HashProvider.java
new file mode 100644
index 0000000..219006e
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/HashProvider.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+import java.util.EnumSet;
+
+/**
+ * Interface used to obtain instances of various kinds of hash algorithms.
+ */
+public interface HashProvider {
+
+ /**
+ * Returns information about the available implementations corresponding to
+ * the given hash algorithm parameters.
+ *
+ * @param params the hash algorithm parameters
+ * @return a set of flags indicating the level of support
+ */
+ EnumSet<HashSupport> querySupport(HashParameters params);
+
+ /**
+ * Creates a stateful hash function using the given parameters.
+ *
+ * @param params the hash algorithm parameters
+ * @return a stateful hash function
+ * @throws UnsupportedOperationException if this provider cannot support the
+ * given parameters
+ */
+ StatefulHash createStateful(HashParameters params);
+
+ /**
+ * Requests a stateless, int-width hash function with the given parameters.
+ * Because not all stateless hash functions are incremental, this method may
+ * be able to return implementations not supported by or more optimized than
+ * {@link #getIncrementalInt}.
+ *
+ * @param params the hash algorithm parameters
+ * @return a stateless int-width hash function
+ * @throws UnsupportedOperationException if this provider cannot support the
+ * given parameters
+ */
+ StatelessIntHash getStatelessInt(HashParameters params);
+
+ /**
+ * Requests a stateless, long-width hash function with the given parameters.
+ * Because not all stateless hash functions are incremental, this method may
+ * be able to return implementations not supported by or more optimized than
+ * {@link #getIncrementalLong}.
+ * <p>
+ * Note that this method may return a less efficient hash function than
+ * {@link #getStatelessInt} for hashes of 32 bits or less.
+ *
+ * @param params the hash algorithm parameters
+ * @return a stateless long-width hash function
+ * @throws UnsupportedOperationException if this provider cannot support the
+ * given parameters
+ */
+ StatelessLongHash getStatelessLong(HashParameters params);
+
+ /**
+ * Requests an incremental, stateless, int-width hash function with the
+ * given parameters. Note that although an algorithm may be available in
+ * incremental form, some potentially more optimized implementations may not
+ * support that form, and therefore cannot be provided be this method.
+ *
+ * @param params the hash algorithm parameters
+ * @return a stateful int-width hash function
+ * @throws UnsupportedOperationException if this provider cannot support the
+ * given parameters
+ */
+ IncrementalIntHash getIncrementalInt(HashParameters params);
+
+ /**
+ * Requests an incremental, stateless, long-width hash function with the
+ * given parameters. Note that although an algorithm may be available in
+ * incremental form, some potentially more optimized implementations may not
+ * support that form, and therefore cannot be provided be this method.
+ * <p>
+ * Also note that this method may return a less efficient hash function than
+ * {@link #getIncrementalInt} for hashes of 32 bits or less.
+ *
+ * @param params the hash algorithm parameters
+ * @return a stateful long-width hash function
+ * @throws UnsupportedOperationException if this provider cannot support the
+ * given parameters
+ */
+ IncrementalLongHash getIncrementalLong(HashParameters params);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/HashProviders.java b/circe-checksum/src/main/java/com/scurrilous/circe/HashProviders.java
new file mode 100644
index 0000000..7196af5
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/HashProviders.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.ServiceLoader;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * Static utility methods for discovering {@link HashProvider} instances.
+ */
+public final class HashProviders {
+
+ static final Collection<HashProvider> ALL_PROVIDERS = getAllProviders();
+
+ private static Collection<HashProvider> getAllProviders() {
+ final ServiceLoader<HashProvider> loader = ServiceLoader.load(HashProvider.class);
+ final LinkedList<HashProvider> providers = new LinkedList<>();
+ for (final HashProvider provider : loader)
+ providers.add(provider);
+ return Collections.unmodifiableList(new ArrayList<>(providers));
+ }
+
+ private HashProviders() {
+ }
+
+ /**
+ * Returns an iterator over all known {@link HashProvider} instances.
+ *
+ * @return an iterator over all HashProviders
+ */
+ public static Iterator<HashProvider> iterator() {
+ return ALL_PROVIDERS.iterator();
+ }
+
+ /**
+ * Returns the best hash provider supporting at least a stateful
+ * implementation of a hash function with the given parameters.
+ *
+ * @param params the parameters defining the hash function
+ * @return the best hash provider for the given parameters
+ * @throws UnsupportedOperationException if no provider supports the
+ * parameters
+ */
+ public static HashProvider best(HashParameters params) {
+ return best(params, EnumSet.of(HashSupport.STATEFUL));
+ }
+
+ /**
+ * Returns the best hash provider supporting at least the given flags for a
+ * hash function with the given parameters.
+ *
+ * @param params the parameters defining the hash function
+ * @param required the required support flags for a provider to be
+ * considered
+ * @return the best hash provider for the given parameters
+ * @throws UnsupportedOperationException if no provider supports the
+ * parameters
+ */
+ public static HashProvider best(HashParameters params, EnumSet<HashSupport> required) {
+ HashProvider result = null;
+ EnumSet<HashSupport> resultSupport = null;
+ for (final HashProvider provider : ALL_PROVIDERS) {
+ final EnumSet<HashSupport> support = provider.querySupport(params);
+ if (support.containsAll(required) &&
+ (result == null || HashSupport.compare(support, resultSupport) < 0)) {
+ result = provider;
+ resultSupport = support;
+ }
+ }
+ if (result == null)
+ throw new UnsupportedOperationException();
+ return result;
+ }
+
+ /**
+ * Returns a map of hash providers supporting at least a stateful
+ * implementation of a hash function with the given parameters.
+ *
+ * @param params the parameters defining the hash function
+ * @return a sorted map of hash support flags to hash providers
+ */
+ public static SortedMap<EnumSet<HashSupport>, HashProvider> search(HashParameters params) {
+ return search(params, EnumSet.of(HashSupport.STATEFUL));
+ }
+
+ /**
+ * Returns a map of hash providers supporting at least the given flags for a
+ * hash function with the given parameters.
+ *
+ * @param params the parameters defining the hash function
+ * @param required the required support flags for a provider to be included
+ * @return a sorted map of hash support flags to hash providers
+ */
+ public static SortedMap<EnumSet<HashSupport>, HashProvider> search(HashParameters params,
+ EnumSet<HashSupport> required) {
+ final SortedMap<EnumSet<HashSupport>, HashProvider> result = new TreeMap<>(
+ new HashSupport.SetComparator());
+ for (final HashProvider provider : ALL_PROVIDERS) {
+ final EnumSet<HashSupport> support = provider.querySupport(params);
+ if (support.containsAll(required))
+ result.put(support, provider);
+ }
+ return result;
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/HashSupport.java b/circe-checksum/src/main/java/com/scurrilous/circe/HashSupport.java
new file mode 100644
index 0000000..34a203c
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/HashSupport.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.Iterator;
+
+/**
+ * Flags indicating the support available for some set of hash algorithm.
+ */
+public enum HashSupport {
+ /**
+ * Indicates that the hash algorithm is available in hardware-accelerated
+ * native code as an {@link IncrementalIntHash} or
+ * {@link IncrementalLongHash}, depending on which of {@link #INT_SIZED} or
+ * {@link #LONG_SIZED} is set.
+ */
+ HARDWARE_INCREMENTAL(10),
+ /**
+ * Indicates that the hash algorithm is available in hardware-accelerated
+ * native code.
+ */
+ HARDWARE(20),
+ /**
+ * Indicates that the hash algorithm is available in native code as a
+ * {@link IncrementalIntHash} or {@link IncrementalLongHash}, depending on
+ * which of {@link #INT_SIZED} or {@link #LONG_SIZED} is set.
+ */
+ NATIVE_INCREMENTAL(30),
+ /**
+ * Indicates that the hash algorithm is available in native code.
+ */
+ NATIVE(40),
+ /**
+ * Indicates that the incremental hash algorithm supports unsafe memory
+ * access via {@link IncrementalIntHash#resume(int, long, long)} or
+ * {@link IncrementalLongHash#resume(long, long, long)}, depending on which
+ * of {@link #INT_SIZED} or {@link #LONG_SIZED} is set.
+ */
+ UNSAFE_INCREMENTAL(50),
+ /**
+ * Indicates that the stateful hash algorithm unsafe memory access via
+ * {@link StatefulHash#update(long, long)}. If {@link #INT_SIZED} is also
+ * set, the function returned by {@link StatefulIntHash#asStateless()} also
+ * supports {@link StatelessIntHash#calculate(long, long)}. Similarly, if
+ * {@link #LONG_SIZED} is also set, the function returned by
+ * {@link StatefulLongHash#asStateless()} also supports
+ * {@link StatelessLongHash#calculate(long, long)}.
+ */
+ UNSAFE(60),
+ /**
+ * Indicates that the hash algorithm is available as a
+ * {@link IncrementalIntHash} or {@link IncrementalLongHash}, depending on
+ * which of {@link #INT_SIZED} or {@link #LONG_SIZED} is set.
+ */
+ STATELESS_INCREMENTAL(70),
+ /**
+ * Indicates that the hash algorithm is available as an incremental stateful
+ * hash function, for which {@link StatefulHash#supportsIncremental()}
+ * returns {@code true}. This flag is implied by
+ * {@link #STATELESS_INCREMENTAL}.
+ */
+ INCREMENTAL(80),
+ /**
+ * Indicates that the hash algorithm is available as a
+ * {@link StatefulIntHash} and {@link StatelessIntHash}.
+ */
+ INT_SIZED(90),
+ /**
+ * Indicates that the hash algorithm is available as a
+ * {@link StatefulLongHash} and {@link StatelessLongHash}.
+ */
+ LONG_SIZED(90),
+ /**
+ * Indicates that the hash algorithm is available as a {@link StatefulHash}.
+ * If this flag is not set, the algorithm is not supported at all.
+ */
+ STATEFUL(100);
+
+ /**
+ * The minimum priority value, indicating the highest priority. All flags
+ * have a priority value greater than this.
+ */
+ public static final int MIN_PRIORITY = 0;
+
+ /**
+ * The maximum priority value, indicating the lowest priority. All flags
+ * have a priority value less than this.
+ */
+ public static final int MAX_PRIORITY = 110;
+
+ private final int priority;
+
+ private HashSupport(int priority) {
+ this.priority = priority;
+ }
+
+ /**
+ * Returns the relative priority of a hash algorithm support flag, which is
+ * an indicator of its performance and flexibility. Lower values indicate
+ * higher priority.
+ *
+ * @return the priority of this flag (currently between 10 and 90)
+ */
+ public int getPriority() {
+ return priority;
+ }
+
+ /**
+ * Returns the {@linkplain #getPriority() priority} of the highest-priority
+ * hash algorithm support flag in the given set of flags. If the set is
+ * empty, {@link #MAX_PRIORITY} is returned.
+ *
+ * @param set a set of hash algorithm support flags
+ * @return the highest priority (lowest value) in the set, or
+ * {@link #MAX_PRIORITY} if empty
+ */
+ public static int getMaxPriority(EnumSet<HashSupport> set) {
+ if (set.isEmpty())
+ return MAX_PRIORITY;
+ return set.iterator().next().getPriority();
+ }
+
+ /**
+ * Compares the given sets of hash algorithm support flags for priority
+ * order. The set with the highest priority flag without a flag of matching
+ * priority in the other set has higher priority.
+ *
+ * @param set1 the first set to be compared
+ * @param set2 the second set to be compared
+ * @return a negative integer, zero, or a positive integer if the first set
+ * has priority higher than, equal to, or lower than the second
+ */
+ public static int compare(EnumSet<HashSupport> set1, EnumSet<HashSupport> set2) {
+ // assumes iterators return flags in priority order
+ final Iterator<HashSupport> i1 = set1.iterator();
+ final Iterator<HashSupport> i2 = set2.iterator();
+ int floor = MIN_PRIORITY;
+ while (i1.hasNext() || i2.hasNext()) {
+ int p1, p2;
+ do {
+ p1 = i1.hasNext() ? i1.next().getPriority() : MAX_PRIORITY;
+ } while (p1 == floor);
+ do {
+ p2 = i2.hasNext() ? i2.next().getPriority() : MAX_PRIORITY;
+ } while (p2 == floor);
+ if (p1 < p2)
+ return -1;
+ if (p1 > p2)
+ return 1;
+ floor = p1;
+ }
+ return 0;
+ }
+
+ /**
+ * {@link Comparator} for {@link EnumSet EnumSets} for hash support flags.
+ */
+ static final class SetComparator implements Comparator<EnumSet<HashSupport>> {
+ @Override
+ public int compare(EnumSet<HashSupport> o1, EnumSet<HashSupport> o2) {
+ return HashSupport.compare(o1, o2);
+ }
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/Hashes.java b/circe-checksum/src/main/java/com/scurrilous/circe/Hashes.java
new file mode 100644
index 0000000..786ead5
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/Hashes.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+import java.util.EnumSet;
+
+import com.scurrilous.circe.HashParameters;
+import com.scurrilous.circe.HashProviders;
+import com.scurrilous.circe.HashSupport;
+import com.scurrilous.circe.IncrementalIntHash;
+import com.scurrilous.circe.IncrementalLongHash;
+import com.scurrilous.circe.StatefulHash;
+import com.scurrilous.circe.StatelessIntHash;
+import com.scurrilous.circe.StatelessLongHash;
+
+/**
+ * Static methods to obtain various forms of abstract hash functions. Each
+ * method uses {@link HashProviders#best} to find the best provider for the
+ * given parameters and hash interface, and then calls the corresponding method
+ * on that provider.
+ */
+public final class Hashes {
+
+ private Hashes() {
+ }
+
+ /**
+ * Creates a stateful hash function using the given parameters.
+ *
+ * @param params the hash algorithm parameters
+ * @return a stateful hash function
+ * @throws UnsupportedOperationException if no provider supports the
+ * parameters
+ */
+ public static StatefulHash createStateful(HashParameters params) {
+ return HashProviders.best(params).createStateful(params);
+ }
+
+ /**
+ * Requests a stateless, int-width hash function with the given parameters.
+ * Because not all stateless hash functions are incremental, this method may
+ * be able to return implementations not supported by or more optimized than
+ * {@link #getIncrementalInt}.
+ *
+ * @param params the hash algorithm parameters
+ * @return a stateless int-width hash function
+ * @throws UnsupportedOperationException if no provider supports the
+ * parameters as a {@link StatelessIntHash}
+ */
+ public static StatelessIntHash getStatelessInt(HashParameters params) {
+ return HashProviders.best(params, EnumSet.of(HashSupport.INT_SIZED))
+ .getStatelessInt(params);
+ }
+
+ /**
+ * Requests a stateless, long-width hash function with the given parameters.
+ * Because not all stateless hash functions are incremental, this method may
+ * be able to return implementations not supported by or more optimized than
+ * {@link #getIncrementalLong}.
+ * <p>
+ * Note that this method may return a less efficient hash function than
+ * {@link #getStatelessInt} for hashes of 32 bits or less.
+ *
+ * @param params the hash algorithm parameters
+ * @return a stateless long-width hash function
+ * @throws UnsupportedOperationException if no provider supports the
+ * parameters as a {@link StatelessLongHash}
+ */
+ public static StatelessLongHash getStatelessLong(HashParameters params) {
+ return HashProviders.best(params, EnumSet.of(HashSupport.LONG_SIZED)).getStatelessLong(
+ params);
+ }
+
+ /**
+ * Requests an incremental, stateless, int-width hash function with the
+ * given parameters. Note that although an algorithm may be available in
+ * incremental form, some potentially more optimized implementations may not
+ * support that form, and therefore cannot be provided be this method.
+ *
+ * @param params the hash algorithm parameters
+ * @return a stateful int-width hash function
+ * @throws UnsupportedOperationException if no provider supports the
+ * parameters as an {@link IncrementalIntHash}
+ */
+ public static IncrementalIntHash getIncrementalInt(HashParameters params) {
+ return HashProviders.best(params,
+ EnumSet.of(HashSupport.INT_SIZED, HashSupport.STATELESS_INCREMENTAL))
+ .getIncrementalInt(params);
+ }
+
+ /**
+ * Requests an incremental, stateless, long-width hash function with the
+ * given parameters. Note that although an algorithm may be available in
+ * incremental form, some potentially more optimized implementations may not
+ * support that form, and therefore cannot be provided be this method.
+ * <p>
+ * Also note that this method may return a less efficient hash function than
+ * {@link #getIncrementalInt} for hashes of 32 bits or less.
+ *
+ * @param params the hash algorithm parameters
+ * @return a stateful long-width hash function
+ * @throws UnsupportedOperationException if no provider supports the
+ * parameters as an {@link IncrementalLongHash}
+ */
+ public static IncrementalLongHash getIncrementalLong(HashParameters params) {
+ return HashProviders.best(params,
+ EnumSet.of(HashSupport.LONG_SIZED, HashSupport.STATELESS_INCREMENTAL))
+ .getIncrementalLong(params);
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/IncrementalIntHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/IncrementalIntHash.java
new file mode 100644
index 0000000..46320c7
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/IncrementalIntHash.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Incremental stateless integer hash function, which has the property that its
+ * output is the same as (or easily derivable from) its state. Specifically, for
+ * any sequence M partitioned arbitrarily into two subsequences M<sub>1</sub>
+ * M<sub>2</sub>:
+ *
+ * <pre>
+ * h(M) = h'(h(M<sub>1</sub>), M<sub>2</sub>)
+ * </pre>
+ *
+ * where h corresponds to the {@link StatelessIntHash#calculate calculate}
+ * function and h' corresponds to the {@link #resume} function.
+ * <p>
+ * Note that stateful hash functions obtained from incremental stateless hash
+ * functions are also {@linkplain StatefulHash#supportsIncremental incremental}.
+ */
+public interface IncrementalIntHash extends StatelessIntHash {
+
+ /**
+ * Evaluates this hash function as if the entire given input array were
+ * appended to the previously hashed input.
+ *
+ * @param current the hash output for input hashed so far
+ * @param input the input array
+ * @return the output of the hash function for the concatenated input
+ */
+ int resume(int current, byte[] input);
+
+ /**
+ * Evaluates this hash function as if the given range of the given input
+ * array were appended to the previously hashed input.
+ *
+ * @param current the hash output for input hashed so far
+ * @param input the input array
+ * @param index the starting index of the first input byte
+ * @param length the length of the input range
+ * @return the output of the hash function for the concatenated input
+ * @throws IndexOutOfBoundsException if index is negative or
+ * {@code index + length} is greater than the array length
+ */
+ int resume(int current, byte[] input, int index, int length);
+
+ /**
+ * Evaluates this hash function as if the remaining contents of the given
+ * input buffer were appended to the previously hashed input. This method
+ * leaves the buffer position at the limit.
+ *
+ * @param current the hash output for input hashed so far
+ * @param input the input buffer
+ * @return the output of the hash function for the concatenated input
+ */
+ int resume(int current, ByteBuffer input);
+
+ /**
+ * Evaluates this hash function as if the memory with the given address and
+ * length were appended to the previously hashed input. The arguments are
+ * generally not checked in any way and will likely lead to a VM crash or
+ * undefined results if invalid.
+ *
+ * @param current the hash output for input hashed so far
+ * @param address the base address of the input
+ * @param length the length of the input
+ * @return the output of the hash function for the concatenated input
+ * @throws UnsupportedOperationException if this function does not support
+ * unsafe memory access
+ * @see #supportsUnsafe()
+ */
+ int resume(int current, long address, long length);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/IncrementalLongHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/IncrementalLongHash.java
new file mode 100644
index 0000000..382346d
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/IncrementalLongHash.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Incremental stateless long integer hash function, which has the property that
+ * its output is the same as (or easily derivable from) its state. Specifically,
+ * for any sequence M partitioned arbitrarily into two subsequences
+ * M<sub>1</sub> M<sub>2</sub>:
+ *
+ * <pre>
+ * h(M) = h'(h(M<sub>1</sub>), M<sub>2</sub>)
+ * </pre>
+ *
+ * where h corresponds to the {@link StatelessLongHash#calculate calculate}
+ * function and h' corresponds to the {@link #resume} function.
+ * <p>
+ * Note that stateful hash functions obtained from incremental stateless hash
+ * functions are also {@linkplain StatefulHash#supportsIncremental incremental}.
+ */
+public interface IncrementalLongHash extends StatelessLongHash {
+
+ /**
+ * Evaluates this hash function as if the entire given input array were
+ * appended to the previously hashed input.
+ *
+ * @param current the hash output for input hashed so far
+ * @param input the input array
+ * @return the output of the hash function for the concatenated input
+ */
+ long resume(long current, byte[] input);
+
+ /**
+ * Evaluates this hash function as if the given range of the given input
+ * array were appended to the previously hashed input.
+ *
+ * @param current the hash output for input hashed so far
+ * @param input the input array
+ * @param index the starting index of the first input byte
+ * @param length the length of the input range
+ * @return the output of the hash function for the concatenated input
+ * @throws IndexOutOfBoundsException if index is negative or
+ * {@code index + length} is greater than the array length
+ */
+ long resume(long current, byte[] input, int index, int length);
+
+ /**
+ * Evaluates this hash function as if the remaining contents of the given
+ * input buffer were appended to the previously hashed input. This method
+ * leaves the buffer position at the limit.
+ *
+ * @param current the hash output for input hashed so far
+ * @param input the input buffer
+ * @return the output of the hash function for the concatenated input
+ */
+ long resume(long current, ByteBuffer input);
+
+ /**
+ * Evaluates this hash function as if the memory with the given address and
+ * length were appended to the previously hashed input. The arguments are
+ * generally not checked in any way and will likely lead to a VM crash or
+ * undefined results if invalid.
+ *
+ * @param current the hash output for input hashed so far
+ * @param address the base address of the input
+ * @param length the length of the input
+ * @return the output of the hash function for the concatenated input
+ * @throws UnsupportedOperationException if this function does not support
+ * unsafe memory access
+ * @see #supportsUnsafe()
+ */
+ long resume(long current, long address, long length);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/StatefulHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/StatefulHash.java
new file mode 100644
index 0000000..94d355a
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/StatefulHash.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Represents a stateful hash function, which can accumulate input from multiple
+ * method calls and provide output in various forms. Stateful hash functions
+ * should not be used concurrently from multiple threads.
+ * <p>
+ * Stateful hash functions can be incremental or non-incremental. Incremental
+ * hashing allows calling the {@link #update} methods to continue hashing using
+ * accumulated state after calling any of the output methods (such as
+ * {@link #getBytes}). Non-incremental hash functions <i>require</i> calling
+ * {@link #reset} to reinitialize the state between calling an output method and
+ * an update method.
+ */
+public interface StatefulHash extends Hash {
+
+ /**
+ * Returns a new instance of this stateful hash function reset to the
+ * initial state.
+ *
+ * @return a new instance of this hash in the initial state
+ */
+ StatefulHash createNew();
+
+ /**
+ * Returns whether this hash function supports incremental hashing.
+ * Incremental hashing allows calling the {@link #update} methods to
+ * continue hashing using accumulated state after calling any of the output
+ * methods (such as {@link #getBytes}). Non-incremental hash functions
+ * require calling {@link #reset} to reinitialize the state between calling
+ * an output method and an update method.
+ *
+ * @return true if incremental hashing is supported, false if not
+ */
+ boolean supportsIncremental();
+
+ /**
+ * Resets this hash function to its initial state. Resetting the state is
+ * required for non-incremental hash functions after any output methods have
+ * been called.
+ */
+ void reset();
+
+ /**
+ * Updates the state of this hash function with the entire given input
+ * array.
+ *
+ * @param input the input array
+ * @throws IllegalStateException if this hash function is not incremental
+ * but an output method has been called without an intervening
+ * call to {@link #reset}
+ */
+ void update(byte[] input);
+
+ /**
+ * Updates the state of this hash function with the given range of the given
+ * input array.
+ *
+ * @param input the input array
+ * @param index the starting index of the first input byte
+ * @param length the length of the input range
+ * @throws IllegalArgumentException if length is negative
+ * @throws IndexOutOfBoundsException if index is negative or
+ * {@code index + length} is greater than the array length
+ * @throws IllegalStateException if this hash function is not incremental
+ * but an output method has been called without an intervening
+ * call to {@link #reset}
+ */
+ void update(byte[] input, int index, int length);
+
+ /**
+ * Updates the state of this hash function with the remaining contents of
+ * the given input buffer. This method leaves the buffer position at the
+ * limit.
+ *
+ * @param input the input buffer
+ * @throws IllegalStateException if this hash function is not incremental
+ * but an output method has been called without an intervening
+ * call to {@link #reset}
+ */
+ void update(ByteBuffer input);
+
+ /**
+ * Updates the state of this hash function with memory with the given
+ * address and length. The arguments are generally not checked in any way
+ * and will likely lead to a VM crash or undefined results if invalid.
+ *
+ * @param address the base address of the input
+ * @param length the length of the input
+ * @throws UnsupportedOperationException if this function does not support
+ * unsafe memory access
+ * @throws IllegalStateException if this hash function is not incremental
+ * but an output method has been called without an intervening
+ * call to {@link #reset}
+ * @see #supportsUnsafe()
+ */
+ void update(long address, long length);
+
+ /**
+ * Returns a new byte array containing the output of this hash function. The
+ * caller may freely modify the contents of the array.
+ *
+ * @return a new byte array containing the hash output
+ */
+ byte[] getBytes();
+
+ /**
+ * Writes the output of this hash function into the given byte array at the
+ * given offset.
+ *
+ * @param output the destination array for the output
+ * @param index the starting index of the first output byte
+ * @param maxLength the maximum number of bytes to write
+ * @return the number of bytes written
+ * @throws IllegalArgumentException if {@code maxLength} is negative
+ * @throws IndexOutOfBoundsException if {@code index} is negative or if
+ * {@code index + maxLength} is greater than the array length
+ */
+ int getBytes(byte[] output, int index, int maxLength);
+
+ /**
+ * Returns the first byte of the output of this hash function.
+ *
+ * @return the first output byte
+ */
+ byte getByte();
+
+ /**
+ * Returns the first two bytes of the output of this hash function as a
+ * little-endian {@code short}. If the output is less than two bytes, the
+ * remaining bytes are set to 0.
+ *
+ * @return the first two output bytes as a short
+ */
+ short getShort();
+
+ /**
+ * Returns the first four bytes of the output of this hash function as a
+ * little-endian {@code int}. If the output is less than four bytes, the
+ * remaining bytes are set to 0.
+ *
+ * @return the first four output bytes as an int
+ */
+ int getInt();
+
+ /**
+ * Returns the first eight bytes of the output of this hash function as a
+ * little-endian {@code long}. If the output is less than eight bytes, the
+ * remaining bytes are set to 0.
+ *
+ * @return the first eight output bytes as a long
+ */
+ long getLong();
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/StatefulIntHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/StatefulIntHash.java
new file mode 100644
index 0000000..ba6bcf1
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/StatefulIntHash.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+/**
+ * Interface implemented by stateful hash functions with an output length of 4
+ * bytes or less. Such functions can provide a corresponding stateless
+ * implementation.
+ */
+public interface StatefulIntHash extends StatefulHash {
+
+ /**
+ * Returns an instance of stateless version of this hash function.
+ *
+ * @return the stateless version of this hash function
+ */
+ StatelessIntHash asStateless();
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/StatefulLongHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/StatefulLongHash.java
new file mode 100644
index 0000000..076401b
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/StatefulLongHash.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+/**
+ * Interface implemented by stateless hash functions with an output length
+ * greater than 4 bytes and less than or equal to 8 bytes.
+ */
+public interface StatefulLongHash extends StatefulHash {
+
+ /**
+ * Returns an instance of stateless version of this hash function.
+ *
+ * @return the stateless version of this hash function
+ */
+ StatelessLongHash asStateless();
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/StatelessHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/StatelessHash.java
new file mode 100644
index 0000000..8d85347
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/StatelessHash.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+/**
+ * Base interface for stateless hash functions that immediately return the hash
+ * value corresponding to a given input. Stateless hash functions may be used
+ * concurrently by multiple threads without any synchronization overhead.
+ */
+public interface StatelessHash extends Hash {
+
+ /**
+ * Returns a new instance of stateful version of this hash function.
+ *
+ * @return the stateful version of this hash function
+ */
+ StatefulHash createStateful();
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/StatelessIntHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/StatelessIntHash.java
new file mode 100644
index 0000000..3ddb7c4
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/StatelessIntHash.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Interface implemented by stateless hash functions with an output length of 4
+ * bytes or less.
+ */
+public interface StatelessIntHash extends StatelessHash {
+
+ /**
+ * Returns a new instance of stateful version of this hash function.
+ *
+ * @return the stateful version of this hash function
+ */
+ @Override
+ StatefulIntHash createStateful();
+
+ /**
+ * Evaluates this hash function for the entire given input array.
+ *
+ * @param input the input array
+ * @return the output of the hash function
+ */
+ int calculate(byte[] input);
+
+ /**
+ * Evaluates this hash function for the given range of the given input
+ * array.
+ *
+ * @param input the input array
+ * @param index the starting index of the first input byte
+ * @param length the length of the input range
+ * @return the output of the hash function
+ * @throws IndexOutOfBoundsException if index is negative or
+ * {@code index + length} is greater than the array length
+ */
+ int calculate(byte[] input, int index, int length);
+
+ /**
+ * Evaluates this hash function with the remaining contents of the given
+ * input buffer. This method leaves the buffer position at the limit.
+ *
+ * @param input the input buffer
+ * @return the output of the hash function
+ */
+ int calculate(ByteBuffer input);
+
+ /**
+ * Evaluates this hash function for the memory with the given address and
+ * length. The arguments are generally not checked in any way and will
+ * likely lead to a VM crash or undefined results if invalid.
+ *
+ * @param address the base address of the input
+ * @param length the length of the input
+ * @return the output of the hash function
+ * @throws UnsupportedOperationException if this function does not support
+ * unsafe memory access
+ * @see #supportsUnsafe()
+ */
+ int calculate(long address, long length);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/StatelessLongHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/StatelessLongHash.java
new file mode 100644
index 0000000..ddaef38
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/StatelessLongHash.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Interface implemented by stateless hash functions with an output length
+ * greater than 4 bytes and less than or equal to 8 bytes.
+ */
+public interface StatelessLongHash extends StatelessHash {
+
+ /**
+ * Returns a new instance of stateful version of this hash function.
+ *
+ * @return the stateful version of this hash function
+ */
+ @Override
+ StatefulLongHash createStateful();
+
+ /**
+ * Evaluates this hash function for the entire given input array.
+ *
+ * @param input the input array
+ * @return the output of the hash function
+ */
+ long calculate(byte[] input);
+
+ /**
+ * Evaluates this hash function for the given range of the given input
+ * array.
+ *
+ * @param input the input array
+ * @param index the starting index of the first input byte
+ * @param length the length of the input range
+ * @return the output of the hash function
+ * @throws IndexOutOfBoundsException if index is negative or
+ * {@code index + length} is greater than the array length
+ */
+ long calculate(byte[] input, int index, int length);
+
+ /**
+ * Evaluates this hash function with the remaining contents of the given
+ * input buffer. This method leaves the buffer position at the limit.
+ *
+ * @param input the input buffer
+ * @return the output of the hash function
+ */
+ long calculate(ByteBuffer input);
+
+ /**
+ * Evaluates this hash function for the memory with the given address and
+ * length. The arguments are generally not checked in any way and will
+ * likely lead to a VM crash or undefined results if invalid.
+ *
+ * @param address the base address of the input
+ * @param length the length of the input
+ * @return the output of the hash function
+ * @throws UnsupportedOperationException if this function does not support
+ * unsafe memory access
+ * @see #supportsUnsafe()
+ */
+ long calculate(long address, long length);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/crc/AbstractIntCrc.java b/circe-checksum/src/main/java/com/scurrilous/circe/crc/AbstractIntCrc.java
new file mode 100644
index 0000000..f7fafbe
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/crc/AbstractIntCrc.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+import com.scurrilous.circe.impl.AbstractIncrementalIntHash;
+
+/**
+ * Base implementation of int-width CRC functions.
+ */
+abstract class AbstractIntCrc extends AbstractIncrementalIntHash {
+
+ private final String algorithm;
+ protected final int bitWidth;
+ private final int initial;
+ private final int xorOut;
+
+ AbstractIntCrc(String algorithm, int bitWidth, int initial, int xorOut) {
+ if (bitWidth < 1 || bitWidth > 32)
+ throw new IllegalArgumentException("invalid CRC width");
+ this.algorithm = algorithm;
+ this.bitWidth = bitWidth;
+ this.initial = initial;
+ this.xorOut = xorOut;
+ }
+
+ @Override
+ public String algorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public int length() {
+ return (bitWidth + 7) / 8;
+ }
+
+ @Override
+ protected int initial() {
+ return initial ^ xorOut;
+ }
+
+ @Override
+ protected int resumeUnchecked(int current, byte[] input, int index, int length) {
+ return resumeRaw(current ^ xorOut, input, index, length) ^ xorOut;
+ }
+
+ protected abstract int resumeRaw(int crc, byte[] input, int index, int length);
+
+ protected final int reflect(int value) {
+ return Integer.reverse(value) >>> (32 - bitWidth);
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/crc/AbstractLongCrc.java b/circe-checksum/src/main/java/com/scurrilous/circe/crc/AbstractLongCrc.java
new file mode 100644
index 0000000..e7c5e4b
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/crc/AbstractLongCrc.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+import com.scurrilous.circe.impl.AbstractIncrementalLongHash;
+
+/**
+ * Base implementation of long-width CRC functions.
+ */
+abstract class AbstractLongCrc extends AbstractIncrementalLongHash {
+
+ private final String algorithm;
+ protected final int bitWidth;
+ private final long initial;
+ private final long xorOut;
+
+ AbstractLongCrc(String algorithm, int bitWidth, long initial, long xorOut) {
+ if (bitWidth < 1 || bitWidth > 64)
+ throw new IllegalArgumentException("invalid CRC width");
+ this.algorithm = algorithm;
+ this.bitWidth = bitWidth;
+ this.initial = initial;
+ this.xorOut = xorOut;
+ }
+
+ @Override
+ public String algorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public int length() {
+ return (bitWidth + 7) / 8;
+ }
+
+ @Override
+ protected long initial() {
+ return initial ^ xorOut;
+ }
+
+ @Override
+ protected long resumeUnchecked(long current, byte[] input, int index, int length) {
+ return resumeRaw(current ^ xorOut, input, index, length) ^ xorOut;
+ }
+
+ protected abstract long resumeRaw(long crc, byte[] input, int index, int length);
+
+ protected final long reflect(long value) {
+ return Long.reverse(value) >>> (64 - bitWidth);
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/crc/JavaCrc32.java b/circe-checksum/src/main/java/com/scurrilous/circe/crc/JavaCrc32.java
new file mode 100644
index 0000000..afe22ef
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/crc/JavaCrc32.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+import java.util.zip.CRC32;
+
+import com.scurrilous.circe.StatefulHash;
+import com.scurrilous.circe.StatefulIntHash;
+import com.scurrilous.circe.StatelessIntHash;
+import com.scurrilous.circe.impl.AbstractStatefulHash;
+import com.scurrilous.circe.impl.AbstractStatelessIntHash;
+import com.scurrilous.circe.params.CrcParameters;
+
+/**
+ * Wraps {@link CRC32} in a {@link StatefulIntHash}.
+ */
+final class JavaCrc32 extends AbstractStatefulHash implements StatefulIntHash {
+
+ private static final String ALGORITHM = CrcParameters.CRC32.algorithm();
+ private static final int LENGTH = 4;
+
+ private final CRC32 impl = new CRC32();
+
+ @Override
+ public String algorithm() {
+ return ALGORITHM;
+ }
+
+ @Override
+ public int length() {
+ return LENGTH;
+ }
+
+ @Override
+ public StatefulHash createNew() {
+ return new JavaCrc32();
+ }
+
+ @Override
+ public boolean supportsIncremental() {
+ return true;
+ }
+
+ @Override
+ public void reset() {
+ impl.reset();
+ }
+
+ @Override
+ protected void updateUnchecked(byte[] input, int index, int length) {
+ impl.update(input, index, length);
+ }
+
+ @Override
+ public int getInt() {
+ return (int) impl.getValue();
+ }
+
+ @Override
+ public long getLong() {
+ return impl.getValue();
+ }
+
+ @Override
+ public StatelessIntHash asStateless() {
+ return new AbstractStatelessIntHash() {
+ @Override
+ public String algorithm() {
+ return ALGORITHM;
+ }
+
+ @Override
+ public int length() {
+ return LENGTH;
+ }
+
+ @Override
+ public StatefulIntHash createStateful() {
+ return new JavaCrc32();
+ }
+
+ @Override
+ protected int calculateUnchecked(byte[] input, int index, int length) {
+ final CRC32 crc32 = new CRC32();
+ crc32.update(input, index, length);
+ return (int) crc32.getValue();
+ }
+ };
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/crc/NormalByteCrc.java b/circe-checksum/src/main/java/com/scurrilous/circe/crc/NormalByteCrc.java
new file mode 100644
index 0000000..88706d6
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/crc/NormalByteCrc.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+/**
+ * Implements a "normal" MSB-first byte-width CRC function using a lookup table.
+ */
+final class NormalByteCrc extends AbstractIntCrc {
+
+ private final byte[] table = new byte[256];
+
+ NormalByteCrc(String algorithm, int bitWidth, int poly, int init, int xorOut) {
+ super(algorithm, bitWidth, init, xorOut);
+ if (bitWidth > 8)
+ throw new IllegalArgumentException("invalid CRC width");
+
+ final int widthMask = (1 << bitWidth) - 1;
+ final int shpoly = poly << (8 - bitWidth);
+ for (int i = 0; i < 256; ++i) {
+ int crc = i;
+ for (int j = 0; j < 8; ++j)
+ crc = (crc & 0x80) != 0 ? (crc << 1) ^ shpoly : crc << 1;
+ table[i] = (byte) ((crc >> (8 - bitWidth)) & widthMask);
+ }
+ }
+
+ @Override
+ protected int resumeRaw(int crc, byte[] input, int index, int length) {
+ for (int i = 0; i < length; ++i)
+ crc = table[(crc << (8 - bitWidth)) ^ (input[index + i] & 0xff)] & 0xff;
+ return crc;
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/crc/NormalIntCrc.java b/circe-checksum/src/main/java/com/scurrilous/circe/crc/NormalIntCrc.java
new file mode 100644
index 0000000..5636220
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/crc/NormalIntCrc.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+/**
+ * Implements a "normal" MSB-first int-width CRC function using a lookup table.
+ * Does not support bit-widths less than 8.
+ */
+final class NormalIntCrc extends AbstractIntCrc {
+
+ private final int widthMask;
+ private final int[] table = new int[256];
+
+ NormalIntCrc(String algorithm, int bitWidth, int poly, int init, int xorOut) {
+ super(algorithm, bitWidth, init, xorOut);
+ if (bitWidth < 8)
+ throw new IllegalArgumentException("invalid CRC width");
+
+ widthMask = bitWidth < 32 ? ((1 << bitWidth) - 1) : ~0;
+ final int top = 1 << (bitWidth - 1);
+ for (int i = 0; i < 256; ++i) {
+ int crc = i << (bitWidth - 8);
+ for (int j = 0; j < 8; ++j)
+ crc = (crc & top) != 0 ? (crc << 1) ^ poly : crc << 1;
+ table[i] = crc & widthMask;
+ }
+ }
+
+ @Override
+ protected int resumeRaw(int crc, byte[] input, int index, int length) {
+ for (int i = 0; i < length; ++i)
+ crc = table[((crc >>> (bitWidth - 8)) ^ input[index + i]) & 0xff] ^ (crc << 8);
+ return crc & widthMask;
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/crc/NormalLongCrc.java b/circe-checksum/src/main/java/com/scurrilous/circe/crc/NormalLongCrc.java
new file mode 100644
index 0000000..4a72847
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/crc/NormalLongCrc.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+/**
+ * Implements a "normal" MSB-first long-width CRC function using a lookup table.
+ * Does not support bit-widths less than 8.
+ */
+final class NormalLongCrc extends AbstractLongCrc {
+
+ private final long widthMask;
+ private final long[] table = new long[256];
+
+ NormalLongCrc(String algorithm, int bitWidth, long poly, long init, long xorOut) {
+ super(algorithm, bitWidth, init, xorOut);
+ if (bitWidth < 8)
+ throw new IllegalArgumentException("invalid CRC width");
+
+ widthMask = bitWidth < 64 ? ((1L << bitWidth) - 1) : ~0L;
+ final long top = 1L << (bitWidth - 1);
+ for (int i = 0; i < 256; ++i) {
+ long crc = (long) i << (bitWidth - 8);
+ for (int j = 0; j < 8; ++j)
+ crc = (crc & top) != 0 ? (crc << 1) ^ poly : crc << 1;
+ table[i] = crc & widthMask;
+ }
+ }
+
+ @Override
+ protected long resumeRaw(long crc, byte[] input, int index, int length) {
+ for (int i = 0; i < length; ++i)
+ crc = table[(int) ((crc >>> (bitWidth - 8)) ^ input[index + i]) & 0xff] ^ (crc << 8);
+ return crc & widthMask;
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/crc/ReflectedIntCrc.java b/circe-checksum/src/main/java/com/scurrilous/circe/crc/ReflectedIntCrc.java
new file mode 100644
index 0000000..0b190fa
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/crc/ReflectedIntCrc.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+/**
+ * Implements a "reflected" LSB-first int-width CRC function using a lookup
+ * table.
+ */
+final class ReflectedIntCrc extends AbstractIntCrc {
+
+ private final int[] table = new int[256];
+
+ ReflectedIntCrc(String algorithm, int width, int poly, int init, int xorOut) {
+ super(algorithm, width, init, xorOut);
+
+ poly = reflect(poly);
+ for (int i = 0; i < 256; ++i) {
+ int crc = i;
+ for (int j = 0; j < 8; ++j)
+ crc = (crc & 1) != 0 ? (crc >>> 1) ^ poly : crc >>> 1;
+ table[i] = crc;
+ }
+ }
+
+ @Override
+ protected int initial() {
+ return reflect(super.initial());
+ }
+
+ @Override
+ protected int resumeRaw(int crc, byte[] input, int index, int length) {
+ for (int i = 0; i < length; ++i)
+ crc = table[(crc ^ input[index + i]) & 0xff] ^ (crc >>> 8);
+ return crc;
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/crc/ReflectedLongCrc.java b/circe-checksum/src/main/java/com/scurrilous/circe/crc/ReflectedLongCrc.java
new file mode 100644
index 0000000..951fbec
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/crc/ReflectedLongCrc.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+/**
+ * Implements a "reflected" LSB-first long-width CRC function using a lookup
+ * table.
+ */
+final class ReflectedLongCrc extends AbstractLongCrc {
+
+ private final long[] table = new long[256];
+
+ ReflectedLongCrc(String algorithm, int width, long poly, long init, long xorOut) {
+ super(algorithm, width, init, xorOut);
+
+ poly = reflect(poly);
+ for (int i = 0; i < 256; ++i) {
+ long crc = i;
+ for (int j = 0; j < 8; ++j)
+ crc = (crc & 1) != 0 ? (crc >>> 1) ^ poly : crc >>> 1;
+ table[i] = crc;
+ }
+ }
+
+ @Override
+ protected long resumeRaw(long crc, byte[] input, int index, int length) {
+ crc = reflect(crc);
+ for (int i = 0; i < length; ++i)
+ crc = table[(int) (crc ^ input[index + i]) & 0xff] ^ (crc >>> 8);
+ return crc;
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/crc/Sse42Crc32C.java b/circe-checksum/src/main/java/com/scurrilous/circe/crc/Sse42Crc32C.java
new file mode 100644
index 0000000..28a989d
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/crc/Sse42Crc32C.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+import static com.scurrilous.circe.utils.NativeUtils.loadLibraryFromJar;
+import static com.scurrilous.circe.utils.NativeUtils.libType;
+
+import java.nio.ByteBuffer;
+import com.scurrilous.circe.IncrementalIntHash;
+import com.scurrilous.circe.impl.AbstractIncrementalIntHash;
+import com.scurrilous.circe.params.CrcParameters;
+
+/**
+ * Implementation of CRC-32C using the SSE 4.2 CRC instruction.
+ */
+public final class Sse42Crc32C extends AbstractIncrementalIntHash implements IncrementalIntHash {
+
+ private static final boolean SUPPORTED = checkSupported();
+
+ private static boolean checkSupported() {
+ try {
+ loadLibraryFromJar("/lib/libcirce-checksum." + libType());
+ return nativeSupported();
+ } catch (final Exception | UnsatisfiedLinkError e) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns whether SSE 4.2 CRC-32C is supported on this system.
+ *
+ * @return true if this class is supported, false if not
+ */
+ public static boolean isSupported() {
+ return SUPPORTED;
+ }
+
+ private final long config;
+
+ Sse42Crc32C() {
+ config = 0;
+ }
+
+ public Sse42Crc32C(int chunkWords[]) {
+ if (chunkWords.length == 0) {
+ config = 0;
+ } else {
+ config = allocConfig(chunkWords);
+ if (config == 0)
+ throw new RuntimeException("CRC32C configuration allocation failed");
+ }
+ }
+
+ @Override
+ protected void finalize() {
+ if (config != 0)
+ freeConfig(config);
+ }
+
+ @Override
+ public String algorithm() {
+ return CrcParameters.CRC32C.algorithm();
+ }
+
+ @Override
+ public int length() {
+ return 4;
+ }
+
+ @Override
+ public boolean supportsUnsafe() {
+ return true;
+ }
+
+ @Override
+ public int calculate(long address, long length) {
+ return nativeUnsafe(initial(), address, length, config);
+ }
+
+ @Override
+ public int resume(int current, ByteBuffer input) {
+ if (input.isDirect()) {
+ final int result = nativeDirectBuffer(current, input, input.position(), input.remaining(), config);
+ input.position(input.limit());
+ return result;
+ }
+
+ return super.resume(current, input);
+ }
+
+ @Override
+ public int resume(int current, long address, long length) {
+ return nativeUnsafe(current, address, length, config);
+ }
+
+ @Override
+ protected int initial() {
+ return 0;
+ }
+
+ @Override
+ protected int resumeUnchecked(int current, byte[] input, int index, int length) {
+ return nativeArray(current, input, index, length, config);
+ }
+
+ private static native boolean nativeSupported();
+
+ private static native int nativeArray(int current, byte[] input, int index, int length, long config);
+
+ private static native int nativeDirectBuffer(int current, ByteBuffer input, int offset, int length, long config);
+
+ private static native int nativeUnsafe(int current, long address, long length, long config);
+
+ private static native long allocConfig(int[] chunkWords);
+
+ private static native void freeConfig(long config);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/crc/StandardCrcProvider.java b/circe-checksum/src/main/java/com/scurrilous/circe/crc/StandardCrcProvider.java
new file mode 100644
index 0000000..b54fad6
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/crc/StandardCrcProvider.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+import java.util.EnumSet;
+
+import com.scurrilous.circe.Hash;
+import com.scurrilous.circe.HashSupport;
+import com.scurrilous.circe.StatelessHash;
+import com.scurrilous.circe.impl.AbstractHashProvider;
+import com.scurrilous.circe.params.CrcParameters;
+
+/**
+ * Provides pure Java and JDK-supplied CRC implementations.
+ */
+public final class StandardCrcProvider extends AbstractHashProvider<CrcParameters> {
+
+ /**
+ * Constructs a new {@link StandardCrcProvider}.
+ */
+ public StandardCrcProvider() {
+ super(CrcParameters.class);
+ }
+
+ @Override
+ protected EnumSet<HashSupport> querySupportTyped(CrcParameters params) {
+ final EnumSet<HashSupport> result = EnumSet.of(HashSupport.STATEFUL,
+ HashSupport.INCREMENTAL, HashSupport.STATELESS_INCREMENTAL, HashSupport.LONG_SIZED);
+ if (params.bitWidth() <= 32)
+ result.add(HashSupport.INT_SIZED);
+ if (params.equals(CrcParameters.CRC32))
+ result.add(HashSupport.NATIVE);
+ return result;
+ }
+
+ @Override
+ protected Hash get(CrcParameters params, EnumSet<HashSupport> required) {
+ if (!required.contains(HashSupport.STATELESS_INCREMENTAL) &&
+ params.equals(CrcParameters.CRC32))
+ return new JavaCrc32();
+ if (required.contains(HashSupport.NATIVE))
+ throw new UnsupportedOperationException();
+ return getCacheable(params, required);
+ }
+
+ @Override
+ protected StatelessHash createCacheable(CrcParameters params, EnumSet<HashSupport> required) {
+ final int bitWidth = params.bitWidth();
+ if (bitWidth > 32 || (required.contains(HashSupport.LONG_SIZED) && bitWidth >= 8)) {
+ if (required.contains(HashSupport.INT_SIZED))
+ throw new UnsupportedOperationException();
+ if (params.reflected())
+ return new ReflectedLongCrc(params.algorithm(), bitWidth, params.polynomial(),
+ params.initial(), params.xorOut());
+ else
+ return new NormalLongCrc(params.algorithm(), bitWidth, params.polynomial(),
+ params.initial(), params.xorOut());
+ } else {
+ if (params.reflected())
+ return new ReflectedIntCrc(params.algorithm(), bitWidth, (int) params.polynomial(),
+ (int) params.initial(), (int) params.xorOut());
+ else if (bitWidth > 8)
+ return new NormalIntCrc(params.algorithm(), bitWidth, (int) params.polynomial(),
+ (int) params.initial(), (int) params.xorOut());
+ return new NormalByteCrc(params.algorithm(), bitWidth, (int) params.polynomial(),
+ (int) params.initial(), (int) params.xorOut());
+ }
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/crc/package-info.java b/circe-checksum/src/main/java/com/scurrilous/circe/crc/package-info.java
new file mode 100644
index 0000000..4e4f0fe
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/crc/package-info.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+/**
+ * Provides various implementations of <a
+ * href="http://en.wikipedia.org/wiki/Cyclic_redundancy_check">cyclic redundancy
+ * check</a> (CRC) error-detecting codes. CRC values are based on the remainder
+ * of a polynomial division of the input data. They are particularly well-suited
+ * to detecting burst errors in data sent over telecommunications channels or
+ * retrieved from storage media.
+ */
+package com.scurrilous.circe.crc;
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractHashProvider.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractHashProvider.java
new file mode 100644
index 0000000..fb09624
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractHashProvider.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.util.EnumSet;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+
+import com.scurrilous.circe.Hash;
+import com.scurrilous.circe.HashParameters;
+import com.scurrilous.circe.HashProvider;
+import com.scurrilous.circe.HashSupport;
+import com.scurrilous.circe.IncrementalIntHash;
+import com.scurrilous.circe.IncrementalLongHash;
+import com.scurrilous.circe.StatefulHash;
+import com.scurrilous.circe.StatefulIntHash;
+import com.scurrilous.circe.StatefulLongHash;
+import com.scurrilous.circe.StatelessHash;
+import com.scurrilous.circe.StatelessIntHash;
+import com.scurrilous.circe.StatelessLongHash;
+
+/**
+ * Base implementation for hash function providers.
+ *
+ * @param <P> base supported hash parameters type
+ */
+public abstract class AbstractHashProvider<P extends HashParameters> implements HashProvider {
+
+ private final Class<P> parametersClass;
+
+ /**
+ * Constructs a new {@link AbstractHashProvider} with the given base
+ * parameters class.
+ *
+ * @param parametersClass the base hash parameters class supported
+ */
+ protected AbstractHashProvider(Class<P> parametersClass) {
+ this.parametersClass = parametersClass;
+ }
+
+ @Override
+ public final EnumSet<HashSupport> querySupport(HashParameters params) {
+ if (!parametersClass.isAssignableFrom(params.getClass()))
+ return EnumSet.noneOf(HashSupport.class);
+ return querySupportTyped(parametersClass.cast(params));
+ }
+
+ /**
+ * Implemented by subclasses to provide information about the available
+ * implementations corresponding to the given hash algorithm parameters.
+ * Called by {@link #querySupport} if the hash parameters match the base
+ * type supported by this provider.
+ *
+ * @param params the hash algorithm parameters
+ * @return a set of flags indicating the level of support
+ */
+ protected abstract EnumSet<HashSupport> querySupportTyped(P params);
+
+ /**
+ * Requests a hash function using the given parameters and support flags.
+ * This method is only responsible for checking support flags returned by
+ * {@link #querySupportTyped}.
+ * <p>
+ * To support caching of stateless hash functions, call
+ * {@link #getCacheable} from this method and implement
+ * {@link #createCacheable}.
+ *
+ * @param params the hash algorithm parameters
+ * @param required the required hash support flags
+ * @return a hash function
+ * @throws UnsupportedOperationException if this provider cannot support the
+ * given parameters
+ */
+ protected abstract Hash get(P params, EnumSet<HashSupport> required);
+
+ /**
+ * Called by implementations that support caching of stateless hash
+ * functions when a cached instance is desired. If a cached instance is not
+ * available, this method calls {@link #createCacheable} to create one,
+ * which is then cached (if caching is available).
+ *
+ * @param params the hash algorithm parameters
+ * @param required the required hash support flags
+ * @return a hash function
+ * @throws UnsupportedOperationException if this provider cannot support the
+ * given parameters
+ */
+ protected final Hash getCacheable(final P params, final EnumSet<HashSupport> required) {
+ if (HashCacheLoader.hasCache()) {
+ final HashCache cache = HashCacheLoader.getCache();
+ try {
+ return cache.get(params, required, new Callable<Hash>() {
+ @Override
+ public Hash call() throws Exception {
+ return createCacheable(params, required);
+ }
+ });
+ } catch (ExecutionException e) {
+ final Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException)
+ throw (RuntimeException) cause;
+ throw new UnsupportedOperationException(e);
+ }
+ }
+ return createCacheable(params, required);
+ }
+
+ /**
+ * Called by {@link #getCacheable} to create new cacheable stateless hash
+ * functions. The default implementation simply throws
+ * {@link UnsupportedOperationException}.
+ *
+ * @param params the hash algorithm parameters
+ * @param required the required hash support flags
+ * @return a stateless hash function
+ * @throws UnsupportedOperationException if this provider cannot support the
+ * given parameters
+ */
+ protected StatelessHash createCacheable(P params, EnumSet<HashSupport> required) {
+ throw new UnsupportedOperationException();
+ }
+
+ private Hash castAndGet(HashParameters params, EnumSet<HashSupport> required) {
+ if (!parametersClass.isAssignableFrom(params.getClass()))
+ throw new UnsupportedOperationException();
+ return get(parametersClass.cast(params), required);
+ }
+
+ @Override
+ public StatefulHash createStateful(HashParameters params) {
+ final Hash hash = castAndGet(params, EnumSet.of(HashSupport.STATEFUL));
+ if (hash instanceof StatefulHash)
+ return (StatefulHash) hash;
+ if (hash instanceof StatelessHash)
+ return ((StatelessHash) hash).createStateful();
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public StatelessIntHash getStatelessInt(HashParameters params) {
+ final Hash hash = castAndGet(params, EnumSet.of(HashSupport.INT_SIZED));
+ if (hash instanceof StatelessIntHash)
+ return (StatelessIntHash) hash;
+ if (hash instanceof StatefulIntHash)
+ return ((StatefulIntHash) hash).asStateless();
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public StatelessLongHash getStatelessLong(HashParameters params) {
+ final Hash hash = castAndGet(params, EnumSet.of(HashSupport.LONG_SIZED));
+ if (hash instanceof StatelessLongHash)
+ return (StatelessLongHash) hash;
+ if (hash instanceof StatefulLongHash)
+ return ((StatefulLongHash) hash).asStateless();
+ if (hash instanceof StatelessIntHash)
+ return new IntStatelessLongHash((StatelessIntHash) hash);
+ if (hash instanceof StatefulIntHash)
+ return new IntStatelessLongHash(((StatefulIntHash) hash).asStateless());
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public IncrementalIntHash getIncrementalInt(HashParameters params) {
+ final Hash hash = castAndGet(params,
+ EnumSet.of(HashSupport.INT_SIZED, HashSupport.STATELESS_INCREMENTAL));
+ if (hash instanceof IncrementalIntHash)
+ return (IncrementalIntHash) hash;
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public IncrementalLongHash getIncrementalLong(HashParameters params) {
+ final Hash hash = castAndGet(params,
+ EnumSet.of(HashSupport.LONG_SIZED, HashSupport.STATELESS_INCREMENTAL));
+ if (hash instanceof IncrementalLongHash)
+ return (IncrementalLongHash) hash;
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractIncrementalIntHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractIncrementalIntHash.java
new file mode 100644
index 0000000..094cf22
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractIncrementalIntHash.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.nio.ByteBuffer;
+
+import com.scurrilous.circe.IncrementalIntHash;
+import com.scurrilous.circe.StatefulIntHash;
+
+/**
+ * Base implementation for incremental stateless integer hash functions.
+ */
+public abstract class AbstractIncrementalIntHash implements IncrementalIntHash {
+
+ @Override
+ public boolean supportsUnsafe() {
+ return false;
+ }
+
+ @Override
+ public StatefulIntHash createStateful() {
+ return new IncrementalIntStatefulHash(this);
+ }
+
+ @Override
+ public int calculate(byte[] input) {
+ return resume(initial(), input);
+ }
+
+ @Override
+ public int calculate(byte[] input, int index, int length) {
+ return resume(initial(), input, index, length);
+ }
+
+ @Override
+ public int calculate(ByteBuffer input) {
+ return resume(initial(), input);
+ }
+
+ @Override
+ public int calculate(long address, long length) {
+ return resume(initial(), address, length);
+ }
+
+ @Override
+ public int resume(int current, byte[] input) {
+ return resumeUnchecked(current, input, 0, input.length);
+ }
+
+ @Override
+ public int resume(int current, byte[] input, int index, int length) {
+ if (length < 0)
+ throw new IllegalArgumentException();
+ if (index < 0 || index + length > input.length)
+ throw new IndexOutOfBoundsException();
+ return resumeUnchecked(current, input, index, length);
+ }
+
+ @Override
+ public int resume(int current, ByteBuffer input) {
+ final byte[] array;
+ final int index;
+ final int length = input.remaining();
+ if (input.hasArray()) {
+ array = input.array();
+ index = input.arrayOffset() + input.position();
+ input.position(input.limit());
+ } else {
+ array = new byte[length];
+ index = 0;
+ input.get(array);
+ }
+ return resumeUnchecked(current, array, index, length);
+ }
+
+ @Override
+ public int resume(int current, long address, long length) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * The initial state of the hash function, which is the same as the output
+ * value for an empty input sequence.
+ *
+ * @return the initial hash state/output
+ */
+ protected abstract int initial();
+
+ /**
+ * Evaluates this hash function as if the given range of the given input
+ * array were appended to the previously hashed input. The index and length
+ * parameters have already been validated.
+ *
+ * @param current the hash output for input hashed so far
+ * @param input the input array
+ * @param index the starting index of the first input byte
+ * @param length the length of the input range
+ * @return the output of the hash function for the concatenated input
+ */
+ protected abstract int resumeUnchecked(int current, byte[] input, int index, int length);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractIncrementalLongHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractIncrementalLongHash.java
new file mode 100644
index 0000000..9996f8e
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractIncrementalLongHash.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.nio.ByteBuffer;
+
+import com.scurrilous.circe.IncrementalLongHash;
+import com.scurrilous.circe.StatefulLongHash;
+
+/**
+ * Base implementation for incremental stateless long integer hash functions.
+ */
+public abstract class AbstractIncrementalLongHash implements IncrementalLongHash {
+
+ @Override
+ public boolean supportsUnsafe() {
+ return false;
+ }
+
+ @Override
+ public StatefulLongHash createStateful() {
+ return new IncrementalLongStatefulHash(this);
+ }
+
+ @Override
+ public long calculate(byte[] input) {
+ return resume(initial(), input);
+ }
+
+ @Override
+ public long calculate(byte[] input, int index, int length) {
+ return resume(initial(), input, index, length);
+ }
+
+ @Override
+ public long calculate(ByteBuffer input) {
+ return resume(initial(), input);
+ }
+
+ @Override
+ public long calculate(long address, long length) {
+ return resume(initial(), address, length);
+ }
+
+ @Override
+ public long resume(long current, byte[] input) {
+ return resumeUnchecked(current, input, 0, input.length);
+ }
+
+ @Override
+ public long resume(long current, byte[] input, int index, int length) {
+ if (length < 0)
+ throw new IllegalArgumentException();
+ if (index < 0 || index + length > input.length)
+ throw new IndexOutOfBoundsException();
+ return resumeUnchecked(current, input, index, length);
+ }
+
+ @Override
+ public long resume(long current, ByteBuffer input) {
+ final byte[] array;
+ final int index;
+ final int length = input.remaining();
+ if (input.hasArray()) {
+ array = input.array();
+ index = input.arrayOffset() + input.position();
+ input.position(input.limit());
+ } else {
+ array = new byte[length];
+ index = 0;
+ input.get(array);
+ }
+ return resumeUnchecked(current, array, index, length);
+ }
+
+ @Override
+ public long resume(long current, long address, long length) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * The initial state of the hash function, which is the same as the output
+ * value for an empty input sequence.
+ *
+ * @return the initial hash state/output
+ */
+ protected abstract long initial();
+
+ /**
+ * Evaluates this hash function as if the given range of the given input
+ * array were appended to the previously hashed input. The index and length
+ * parameters have already been validated.
+ *
+ * @param current the hash output for input hashed so far
+ * @param input the input array
+ * @param index the starting index of the first input byte
+ * @param length the length of the input range
+ * @return the output of the hash function for the concatenated input
+ */
+ protected abstract long resumeUnchecked(long current, byte[] input, int index, int length);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractStatefulHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractStatefulHash.java
new file mode 100644
index 0000000..e3edcec
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractStatefulHash.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.nio.ByteBuffer;
+
+import com.scurrilous.circe.StatefulHash;
+
+/**
+ * Base implementation for stateful hash functions.
+ */
+public abstract class AbstractStatefulHash implements StatefulHash {
+
+ @Override
+ public boolean supportsUnsafe() {
+ return false;
+ }
+
+ @Override
+ public void update(byte[] input) {
+ updateUnchecked(input, 0, input.length);
+ }
+
+ @Override
+ public void update(byte[] input, int index, int length) {
+ if (length < 0)
+ throw new IllegalArgumentException();
+ if (index < 0 || index + length > input.length)
+ throw new IndexOutOfBoundsException();
+ updateUnchecked(input, index, length);
+ }
+
+ @Override
+ public void update(ByteBuffer input) {
+ final byte[] array;
+ final int index;
+ final int length = input.remaining();
+ if (input.hasArray()) {
+ array = input.array();
+ index = input.arrayOffset() + input.position();
+ input.position(input.limit());
+ } else {
+ // convert to unsafe access if possible
+ if (input.isDirect() && supportsUnsafe()) {
+ long address = DirectByteBufferAccessLoader.getAddress(input);
+ if (address != 0) {
+ address += input.position();
+ input.position(input.limit());
+ update(address, length);
+ return;
+ }
+ }
+
+ array = new byte[length];
+ index = 0;
+ input.get(array);
+ }
+ updateUnchecked(array, index, length);
+ }
+
+ @Override
+ public void update(long address, long length) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Updates the state of this hash function with the given range of the given
+ * input array. The index and length parameters have already been validated.
+ *
+ * @param input the input array
+ * @param index the starting index of the first input byte
+ * @param length the length of the input range
+ */
+ protected abstract void updateUnchecked(byte[] input, int index, int length);
+
+ @Override
+ public byte[] getBytes() {
+ final byte[] array = new byte[length()];
+ writeBytes(array, 0, array.length);
+ return array;
+ }
+
+ @Override
+ public int getBytes(byte[] output, int index, int maxLength) {
+ if (maxLength < 0)
+ throw new IllegalArgumentException();
+ if (index < 0 || index + maxLength > output.length)
+ throw new IndexOutOfBoundsException();
+ final int length = Math.min(maxLength, length());
+ writeBytes(output, index, length);
+ return length;
+ }
+
+ /**
+ * Writes the output of this hash function into the given range of the given
+ * byte array. The inputs have already been validated.
+ *
+ * @param output the destination array for the output
+ * @param index the starting index of the first output byte
+ * @param length the number of bytes to write
+ */
+ protected void writeBytes(byte[] output, int index, int length) {
+ long temp = getLong();
+ for (int i = 0; i < length; ++i) {
+ output[index + i] = (byte) temp;
+ temp >>>= 8;
+ }
+ }
+
+ @Override
+ public byte getByte() {
+ return (byte) getInt();
+ }
+
+ @Override
+ public short getShort() {
+ return (short) getInt();
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractStatelessIntHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractStatelessIntHash.java
new file mode 100644
index 0000000..2228697
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractStatelessIntHash.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.nio.ByteBuffer;
+
+import com.scurrilous.circe.StatelessIntHash;
+
+/**
+ * Base implementation for stateless (but not incremental) integer hash
+ * functions.
+ */
+public abstract class AbstractStatelessIntHash implements StatelessIntHash {
+
+ @Override
+ public boolean supportsUnsafe() {
+ return false;
+ }
+
+ @Override
+ public int calculate(byte[] input) {
+ return calculateUnchecked(input, 0, input.length);
+ }
+
+ @Override
+ public int calculate(byte[] input, int index, int length) {
+ if (length < 0)
+ throw new IllegalArgumentException();
+ if (index < 0 || index + length > input.length)
+ throw new IndexOutOfBoundsException();
+ return calculateUnchecked(input, index, length);
+ }
+
+ @Override
+ public int calculate(ByteBuffer input) {
+ final byte[] array;
+ final int index;
+ final int length = input.remaining();
+ if (input.hasArray()) {
+ array = input.array();
+ index = input.arrayOffset() + input.position();
+ input.position(input.limit());
+ } else {
+ array = new byte[length];
+ index = 0;
+ input.get(array);
+ }
+ return calculateUnchecked(array, index, length);
+ }
+
+ @Override
+ public int calculate(long address, long length) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Evaluates this hash function for the given range of the given input
+ * array. The index and length parameters have already been validated.
+ *
+ * @param input the input array
+ * @param index the starting index of the first input byte
+ * @param length the length of the input range
+ * @return the output of the hash function
+ */
+ protected abstract int calculateUnchecked(byte[] input, int index, int length);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractStatelessLongHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractStatelessLongHash.java
new file mode 100644
index 0000000..8688b99
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/AbstractStatelessLongHash.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.nio.ByteBuffer;
+
+import com.scurrilous.circe.StatelessLongHash;
+
+/**
+ * Base implementation for stateless (but not incremental) long integer hash
+ * functions.
+ */
+public abstract class AbstractStatelessLongHash implements StatelessLongHash {
+
+ @Override
+ public boolean supportsUnsafe() {
+ return false;
+ }
+
+ @Override
+ public long calculate(byte[] input) {
+ return calculateUnchecked(input, 0, input.length);
+ }
+
+ @Override
+ public long calculate(byte[] input, int index, int length) {
+ if (length < 0)
+ throw new IllegalArgumentException();
+ if (index < 0 || index + length > input.length)
+ throw new IndexOutOfBoundsException();
+ return calculateUnchecked(input, index, length);
+ }
+
+ @Override
+ public long calculate(ByteBuffer input) {
+ final byte[] array;
+ final int index;
+ final int length = input.remaining();
+ if (input.hasArray()) {
+ array = input.array();
+ index = input.arrayOffset() + input.position();
+ input.position(input.limit());
+ } else {
+ array = new byte[length];
+ index = 0;
+ input.get(array);
+ }
+ return calculateUnchecked(array, index, length);
+ }
+
+ @Override
+ public long calculate(long address, long length) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Evaluates this hash function for the given range of the given input
+ * array. The index and length parameters have already been validated.
+ *
+ * @param input the input array
+ * @param index the starting index of the first input byte
+ * @param length the length of the input range
+ * @return the output of the hash function
+ */
+ protected abstract long calculateUnchecked(byte[] input, int index, int length);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/DirectByteBufferAccess.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/DirectByteBufferAccess.java
new file mode 100644
index 0000000..fdc5e5e
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/DirectByteBufferAccess.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+package com.scurrilous.circe.impl;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Service used to provide the native memory address of direct byte buffers.
+ */
+public interface DirectByteBufferAccess {
+
+ /**
+ * Returns the native memory address of the given direct byte buffer, or 0
+ * if the buffer is not direct or if obtaining the address is not supported.
+ *
+ * @param buffer the direct byte buffer for which to obtain the address
+ * @return the native memory address or 0
+ */
+ long getAddress(ByteBuffer buffer);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/DirectByteBufferAccessLoader.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/DirectByteBufferAccessLoader.java
new file mode 100644
index 0000000..5f457d8
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/DirectByteBufferAccessLoader.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+/**
+ * Provides access to a singleton {@link DirectByteBufferAccess} implementation,
+ * if one is available.
+ */
+public final class DirectByteBufferAccessLoader {
+
+ private static final DirectByteBufferAccess INSTANCE;
+
+ static {
+ final Iterator<DirectByteBufferAccess> iterator = ServiceLoader.load(
+ DirectByteBufferAccess.class).iterator();
+ INSTANCE = iterator.hasNext() ? iterator.next() : null;
+ }
+
+ /**
+ * Returns the native memory address of the given direct byte buffer, or 0
+ * if the buffer is not direct or if obtaining the address is not supported.
+ *
+ * @param buffer the direct byte buffer for which to obtain the address
+ * @return the native memory address or 0
+ */
+ public static long getAddress(ByteBuffer buffer) {
+ return INSTANCE != null ? INSTANCE.getAddress(buffer) : 0;
+ }
+
+ private DirectByteBufferAccessLoader() {
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/HashCache.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/HashCache.java
new file mode 100644
index 0000000..e8d367e
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/HashCache.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.util.EnumSet;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+
+import com.scurrilous.circe.Hash;
+import com.scurrilous.circe.HashParameters;
+import com.scurrilous.circe.HashSupport;
+
+/**
+ * Interface implemented by hash function caches.
+ */
+public interface HashCache {
+
+ /**
+ * Requests a cached hash function with the given parameters and required
+ * support flags. If no matching function is cached, the given loader is
+ * called to obtain one to cache.
+ *
+ * @param params the hash algorithm parameters
+ * @param required the required hash support flags
+ * @param loader a cache loader that creates the function if not cached
+ * @return a hash with the given parameters and support flags
+ * @throws ExecutionException if the loader throws an exception
+ */
+ Hash get(HashParameters params, EnumSet<HashSupport> required, Callable<Hash> loader)
+ throws ExecutionException;
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/HashCacheLoader.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/HashCacheLoader.java
new file mode 100644
index 0000000..55c7db4
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/HashCacheLoader.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+/**
+ * Provides access to a singleton hash function cache, if an implementation is
+ * available.
+ */
+public final class HashCacheLoader {
+
+ private static final HashCache HASH_CACHE;
+
+ static {
+ final Iterator<HashCache> iterator = ServiceLoader.load(HashCache.class).iterator();
+ HASH_CACHE = iterator.hasNext() ? iterator.next() : null;
+ }
+
+ /**
+ * Returns whether a hash function cache is available.
+ *
+ * @return true if a cache is available, false if {@link #getCache} will
+ * throw an exception
+ */
+ public static boolean hasCache() {
+ return HASH_CACHE != null;
+ }
+
+ /**
+ * Returns the single hash function cache.
+ *
+ * @return the single hash cache
+ * @throws UnsupportedOperationException if no hash cache is available
+ */
+ public static HashCache getCache() {
+ if (HASH_CACHE == null)
+ throw new UnsupportedOperationException();
+ return HASH_CACHE;
+ }
+
+ private HashCacheLoader() {
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/IncrementalIntStatefulHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/IncrementalIntStatefulHash.java
new file mode 100644
index 0000000..22f57b7
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/IncrementalIntStatefulHash.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.nio.ByteBuffer;
+
+import com.scurrilous.circe.StatefulHash;
+import com.scurrilous.circe.StatefulIntHash;
+import com.scurrilous.circe.StatelessIntHash;
+
+class IncrementalIntStatefulHash extends AbstractStatefulHash implements StatefulIntHash {
+
+ final AbstractIncrementalIntHash stateless;
+ int current;
+
+ IncrementalIntStatefulHash(AbstractIncrementalIntHash stateless) {
+ this.stateless = stateless;
+ }
+
+ @Override
+ public StatelessIntHash asStateless() {
+ return stateless;
+ }
+
+ @Override
+ public String algorithm() {
+ return stateless.algorithm();
+ }
+
+ @Override
+ public int length() {
+ return stateless.length();
+ }
+
+ @Override
+ public boolean supportsUnsafe() {
+ return stateless.supportsUnsafe();
+ }
+
+ @Override
+ public StatefulHash createNew() {
+ return new IncrementalIntStatefulHash(stateless);
+ }
+
+ @Override
+ public boolean supportsIncremental() {
+ return true;
+ }
+
+ @Override
+ public void reset() {
+ current = stateless.initial();
+ }
+
+ @Override
+ public void update(ByteBuffer input) {
+ current = stateless.resume(current, input);
+ }
+
+ @Override
+ public void update(long address, long length) {
+ current = stateless.resume(current, address, length);
+ }
+
+ @Override
+ protected void updateUnchecked(byte[] input, int index, int length) {
+ current = stateless.resumeUnchecked(current, input, index, length);
+ }
+
+ @Override
+ public int getInt() {
+ return current;
+ }
+
+ @Override
+ public long getLong() {
+ return current;
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/IncrementalLongStatefulHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/IncrementalLongStatefulHash.java
new file mode 100644
index 0000000..9d7f7f8
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/IncrementalLongStatefulHash.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.nio.ByteBuffer;
+
+import com.scurrilous.circe.StatefulHash;
+import com.scurrilous.circe.StatefulLongHash;
+import com.scurrilous.circe.StatelessLongHash;
+
+class IncrementalLongStatefulHash extends AbstractStatefulHash implements StatefulLongHash {
+
+ final AbstractIncrementalLongHash stateless;
+ long current;
+
+ IncrementalLongStatefulHash(AbstractIncrementalLongHash stateless) {
+ this.stateless = stateless;
+ }
+
+ @Override
+ public StatelessLongHash asStateless() {
+ return stateless;
+ }
+
+ @Override
+ public String algorithm() {
+ return stateless.algorithm();
+ }
+
+ @Override
+ public int length() {
+ return stateless.length();
+ }
+
+ @Override
+ public boolean supportsUnsafe() {
+ return stateless.supportsUnsafe();
+ }
+
+ @Override
+ public StatefulHash createNew() {
+ return new IncrementalLongStatefulHash(stateless);
+ }
+
+ @Override
+ public boolean supportsIncremental() {
+ return true;
+ }
+
+ @Override
+ public void reset() {
+ current = stateless.initial();
+ }
+
+ @Override
+ public void update(ByteBuffer input) {
+ current = stateless.resume(current, input);
+ }
+
+ @Override
+ public void update(long address, long length) {
+ current = stateless.resume(current, address, length);
+ }
+
+ @Override
+ protected void updateUnchecked(byte[] input, int index, int length) {
+ current = stateless.resumeUnchecked(current, input, index, length);
+ }
+
+ @Override
+ public int getInt() {
+ return (int) current;
+ }
+
+ @Override
+ public long getLong() {
+ return current;
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/IntStatefulLongHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/IntStatefulLongHash.java
new file mode 100644
index 0000000..3b9a3ac
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/IntStatefulLongHash.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.nio.ByteBuffer;
+
+import com.scurrilous.circe.StatefulHash;
+import com.scurrilous.circe.StatefulIntHash;
+import com.scurrilous.circe.StatefulLongHash;
+import com.scurrilous.circe.StatelessLongHash;
+
+/**
+ * Promotes a {@link StatefulIntHash} to a {@link StatefulLongHash}.
+ */
+public final class IntStatefulLongHash implements StatefulLongHash {
+
+ private final StatefulIntHash intHash;
+
+ /**
+ * Constructs a new {@link IntStatefulLongHash} that delegates to the given
+ * {@link StatefulIntHash}.
+ *
+ * @param intHash the underlying int-width hash
+ */
+ public IntStatefulLongHash(StatefulIntHash intHash) {
+ this.intHash = intHash;
+ }
+
+ public StatelessLongHash asStateless() {
+ return new IntStatelessLongHash(intHash.asStateless());
+ }
+
+ public String algorithm() {
+ return intHash.algorithm();
+ }
+
+ public int length() {
+ return intHash.length();
+ }
+
+ public StatefulHash createNew() {
+ return intHash.createNew();
+ }
+
+ public boolean supportsUnsafe() {
+ return intHash.supportsUnsafe();
+ }
+
+ public boolean supportsIncremental() {
+ return intHash.supportsIncremental();
+ }
+
+ public void reset() {
+ intHash.reset();
+ }
+
+ public void update(byte[] input) {
+ intHash.update(input);
+ }
+
+ public void update(byte[] input, int index, int length) {
+ intHash.update(input, index, length);
+ }
+
+ public void update(ByteBuffer input) {
+ intHash.update(input);
+ }
+
+ public void update(long address, long length) {
+ intHash.update(address, length);
+ }
+
+ public byte[] getBytes() {
+ return intHash.getBytes();
+ }
+
+ public int getBytes(byte[] output, int index, int maxLength) {
+ return intHash.getBytes(output, index, maxLength);
+ }
+
+ public byte getByte() {
+ return intHash.getByte();
+ }
+
+ public short getShort() {
+ return intHash.getShort();
+ }
+
+ public int getInt() {
+ return intHash.getInt();
+ }
+
+ public long getLong() {
+ return intHash.getLong();
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/IntStatelessLongHash.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/IntStatelessLongHash.java
new file mode 100644
index 0000000..4111842
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/IntStatelessLongHash.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import java.nio.ByteBuffer;
+
+import com.scurrilous.circe.StatefulLongHash;
+import com.scurrilous.circe.StatelessIntHash;
+import com.scurrilous.circe.StatelessLongHash;
+
+/**
+ * Promotes a {@link StatelessIntHash} to a {@link StatelessLongHash}.
+ */
+public final class IntStatelessLongHash implements StatelessLongHash {
+
+ private final StatelessIntHash intHash;
+
+ /**
+ * Constructs a new {@link IntStatelessLongHash} that delegates to the given
+ * {@link StatelessIntHash}.
+ *
+ * @param intHash the underlying int-width hash
+ */
+ public IntStatelessLongHash(StatelessIntHash intHash) {
+ this.intHash = intHash;
+ }
+
+ @Override
+ public String algorithm() {
+ return intHash.algorithm();
+ }
+
+ @Override
+ public int length() {
+ return intHash.length();
+ }
+
+ @Override
+ public boolean supportsUnsafe() {
+ return intHash.supportsUnsafe();
+ }
+
+ @Override
+ public StatefulLongHash createStateful() {
+ return new IntStatefulLongHash(intHash.createStateful());
+ }
+
+ @Override
+ public long calculate(byte[] input) {
+ return intHash.calculate(input);
+ }
+
+ @Override
+ public long calculate(byte[] input, int index, int length) {
+ return intHash.calculate(input, index, length);
+ }
+
+ @Override
+ public long calculate(ByteBuffer input) {
+ return intHash.calculate(input);
+ }
+
+ @Override
+ public long calculate(long address, long length) {
+ return intHash.calculate(address, length);
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/impl/package-info.java b/circe-checksum/src/main/java/com/scurrilous/circe/impl/package-info.java
new file mode 100644
index 0000000..3c40dda
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/impl/package-info.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+/**
+ * Provides support for implementing new {@linkplain
+ * com.scurrilous.circe.HashProvider hash providers} in the form of abstract
+ * base classes and utility classes.
+ */
+package com.scurrilous.circe.impl;
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/package-info.java b/circe-checksum/src/main/java/com/scurrilous/circe/package-info.java
new file mode 100644
index 0000000..fd710c5
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/package-info.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+/**
+ * Provides interfaces and minimal support classes for providing and consuming
+ * various forms of hash functions. The actual hash algorithms are implemented
+ * by {@linkplain com.scurrilous.circe.HashProvider hash providers}.
+ */
+package com.scurrilous.circe;
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/params/CrcParameters.java b/circe-checksum/src/main/java/com/scurrilous/circe/params/CrcParameters.java
new file mode 100644
index 0000000..10e9cc3
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/params/CrcParameters.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.params;
+
+import com.scurrilous.circe.HashParameters;
+
+/**
+ * Hash parameters used to define a <a
+ * href="http://en.wikipedia.org/wiki/Cyclic_redundancy_check">cyclic redundancy
+ * check</a> (CRC). Includes some commonly used sets of parameters.
+ */
+public class CrcParameters implements HashParameters {
+
+ private final String name;
+ private final int bitWidth;
+ private final long polynomial;
+ private final long initial;
+ private final long xorOut;
+ private final boolean reflected;
+
+ /**
+ * Constructs a {@link CrcParameters} with the given parameters.
+ *
+ * @param name the canonical name of the CRC function
+ * @param bitWidth the width of the CRC function
+ * @param polynomial the polynomial in binary form (non-reflected)
+ * @param initial the initial value of the CRC register
+ * @param xorOut a value XOR'ed with the CRC when it is read
+ * @param reflected indicates whether the CRC is reflected (LSB-first)
+ * @throws IllegalArgumentException if the width is less than 1 or greater
+ * than 64
+ */
+ public CrcParameters(String name, int bitWidth, long polynomial, long initial, long xorOut,
+ boolean reflected) {
+ if (bitWidth < 1 || bitWidth > 64)
+ throw new IllegalArgumentException();
+ this.name = name;
+ this.bitWidth = bitWidth;
+ final long mask = bitWidth < 64 ? (1L << bitWidth) - 1 : ~0L;
+ this.polynomial = polynomial & mask;
+ this.initial = initial & mask;
+ this.xorOut = xorOut & mask;
+ this.reflected = reflected;
+ }
+
+ @Override
+ public String algorithm() {
+ return name;
+ }
+
+ /**
+ * Returns the width in bits of the CRC function. The width is also the
+ * position of the implicit set bit at the top of the polynomial.
+ *
+ * @return the CRC width in bits
+ */
+ public int bitWidth() {
+ return bitWidth;
+ }
+
+ /**
+ * Returns the binary form of polynomial that defines the CRC function (with
+ * the implicit top bit omitted). For instance, the CRC-16 polynomial
+ * x<sup>16</sup> + x<sup>15</sup> + x<sup>2</sup> + 1 is represented as
+ * {@code 1000 0000 0000 0101} ({@code 0x8005}).
+ *
+ * @return the CRC polynomial
+ */
+ public long polynomial() {
+ return polynomial;
+ }
+
+ /**
+ * Returns the initial value of the CRC register.
+ *
+ * @return the CRC initial value
+ */
+ public long initial() {
+ return initial;
+ }
+
+ /**
+ * Returns the value XOR'ed with the CRC register when it is read to
+ * determine the output value.
+ *
+ * @return the final XOR value
+ */
+ public long xorOut() {
+ return xorOut;
+ }
+
+ /**
+ * Returns whether the CRC function is "reflected". Reflected CRCs process
+ * data LSB-first, whereas "normal" CRCs are MSB-first.
+ *
+ * @return whether the CRC function is reflected
+ */
+ public boolean reflected() {
+ return reflected;
+ }
+
+ /**
+ * Returns whether this object matches the given CRC parameters.
+ *
+ * @param bitWidth the width of the CRC function
+ * @param polynomial the polynomial in binary form (non-reflected)
+ * @param initial the initial value of the CRC register
+ * @param xorOut a value XOR'ed with the CRC when it is read
+ * @param reflected indicates whether the CRC is reflected (LSB-first)
+ * @return true if all parameters match exactly, false otherwise
+ */
+ public boolean match(int bitWidth, long polynomial, long initial, long xorOut, boolean reflected) {
+ return bitWidth == this.bitWidth && polynomial == this.polynomial &&
+ initial == this.initial && xorOut == this.xorOut && reflected == this.reflected;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ final CrcParameters other = (CrcParameters) obj;
+ return bitWidth == other.bitWidth && polynomial == other.polynomial &&
+ initial == other.initial && xorOut == other.xorOut && reflected == other.reflected;
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) (polynomial ^ (polynomial >>> 32) ^ initial ^ (initial >>> 32) ^ xorOut ^ (xorOut >>> 32)) ^
+ (reflected ? ~0 : 0);
+ }
+
+ /**
+ * Parameters for CRC-16, used in the ARC and LHA compression utilities.
+ */
+ public static final CrcParameters CRC16 = new CrcParameters("CRC-16", 16, 0x8005, 0, 0, true);
+
+ /**
+ * Parameters for CRC-16/CCITT, used in the Kermit protocol.
+ */
+ public static final CrcParameters CRC16_CCITT = new CrcParameters("CRC-16/CCITT", 16, 0x1021,
+ 0, 0, true);
+
+ /**
+ * Parameters for CRC-16/XMODEM, used in the XMODEM protocol.
+ */
+ public static final CrcParameters CRC16_XMODEM = new CrcParameters("CRC-16/XMODEM", 16, 0x1021,
+ 0, 0, false);
+
+ /**
+ * Parameters for CRC-32, used in Ethernet, SATA, PKZIP, ZMODEM, etc.
+ */
+ public static final CrcParameters CRC32 = new CrcParameters("CRC-32", 32, 0x04c11db7, ~0, ~0,
+ true);
+
+ /**
+ * Parameters for CRC-32/BZIP2, used in BZIP2.
+ */
+ public static final CrcParameters CRC32_BZIP2 = new CrcParameters("CRC-32/BZIP2", 32,
+ 0x04c11db7, ~0, ~0, false);
+
+ /**
+ * Parameters for CRC-32C, used in iSCSI and SCTP.
+ */
+ public static final CrcParameters CRC32C = new CrcParameters("CRC-32C", 32, 0x1edc6f41, ~0, ~0,
+ true);
+
+ /**
+ * Parameters for CRC-32/MPEG-2, used in MPEG-2.
+ */
+ public static final CrcParameters CRC32_MPEG2 = new CrcParameters("CRC-32/MPEG-2", 32,
+ 0x04c11db7, ~0, 0, false);
+
+ /**
+ * Parameters for CRC-32/POSIX, used in the {@code cksum} utility.
+ */
+ public static final CrcParameters CRC32_POSIX = new CrcParameters("CRC-32/POSIX", 32,
+ 0x04c11db7, 0, ~0, false);
+
+ /**
+ * Parameters for CRC-64, used in the ECMA-182 standard for DLT-1 tapes.
+ */
+ public static final CrcParameters CRC64 = new CrcParameters("CRC-64", 64, 0x42f0e1eba9ea3693L,
+ 0L, 0L, false);
+
+ /**
+ * Parameters for CRC-64/XZ, used in the {@code .xz} file format.
+ */
+ public static final CrcParameters CRC64_XZ = new CrcParameters("CRC-64/XZ", 64,
+ 0x42f0e1eba9ea3693L, ~0L, ~0L, true);
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/params/MurmurHash3Parameters.java b/circe-checksum/src/main/java/com/scurrilous/circe/params/MurmurHash3Parameters.java
new file mode 100644
index 0000000..5eda097
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/params/MurmurHash3Parameters.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.params;
+
+import com.scurrilous.circe.HashParameters;
+
+/**
+ * Hash parameters for <a
+ * href="https://code.google.com/p/smhasher/wiki/MurmurHash3">MurmurHash3</a>.
+ */
+public final class MurmurHash3Parameters implements HashParameters {
+
+ private final MurmurHash3Variant variant;
+ private final int seed;
+
+ /**
+ * Constructs a {@link MurmurHash3Parameters} with the given variant and a
+ * seed value of zero.
+ *
+ * @param variant the variant of the algorithm
+ */
+ public MurmurHash3Parameters(MurmurHash3Variant variant) {
+ this(variant, 0);
+ }
+
+ /**
+ * Constructs a {@link MurmurHash3Parameters} with the given variant and
+ * seed value.
+ *
+ * @param variant the variant of the algorithm
+ * @param seed the seed value
+ */
+ public MurmurHash3Parameters(MurmurHash3Variant variant, int seed) {
+ this.variant = variant;
+ this.seed = seed;
+ }
+
+ /**
+ * Returns the variant of the hash algorithm.
+ *
+ * @return the algorithm variant
+ */
+ public MurmurHash3Variant variant() {
+ return variant;
+ }
+
+ /**
+ * Returns the seed value for the hash function.
+ *
+ * @return the seed value
+ */
+ public int seed() {
+ return seed;
+ }
+
+ @Override
+ public String algorithm() {
+ return variant.algorithm();
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/params/MurmurHash3Variant.java b/circe-checksum/src/main/java/com/scurrilous/circe/params/MurmurHash3Variant.java
new file mode 100644
index 0000000..1233444
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/params/MurmurHash3Variant.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.params;
+
+/**
+ * Enumeration of MurmurHash3 variants.
+ */
+public enum MurmurHash3Variant {
+
+ /**
+ * 32-bit variant (optimized for x86).
+ */
+ X86_32("MurmurHash3_x86_32"),
+
+ /**
+ * 128-bit variant optimized for x86.
+ */
+ X86_128("MurmurHash3_x86_128"),
+
+ /**
+ * 128-bit variant optimized for x64.
+ */
+ X64_128("MurmurHash3_x64_128");
+
+ private final String algorithm;
+
+ private MurmurHash3Variant(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ /**
+ * Returns the algorithm name corresponding to this variant.
+ *
+ * @return this variant's algorithm name
+ */
+ public String algorithm() {
+ return algorithm;
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/params/SimpleHashParameters.java b/circe-checksum/src/main/java/com/scurrilous/circe/params/SimpleHashParameters.java
new file mode 100644
index 0000000..d69c020
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/params/SimpleHashParameters.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.params;
+
+import com.scurrilous.circe.HashParameters;
+
+/**
+ * Hash parameters consisting only of an algorithm name. Includes instances
+ * describing some commonly used algorithms.
+ */
+public class SimpleHashParameters implements HashParameters {
+
+ private final String algorithm;
+
+ /**
+ * Constructs a {@link SimpleHashParameters} with the given algorithm name.
+ *
+ * @param algorithm the name of the hash algorithm
+ */
+ public SimpleHashParameters(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ @Override
+ public String algorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public int hashCode() {
+ return algorithm.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+ if (obj == null || obj.getClass() != SimpleHashParameters.class)
+ return false;
+ return algorithm.equals(((SimpleHashParameters) obj).algorithm);
+ }
+
+ @Override
+ public String toString() {
+ return algorithm;
+ }
+
+ /**
+ * Represents the MD5 (128-bit) hash algorithm.
+ */
+ public static final SimpleHashParameters MD5 = new SimpleHashParameters("MD5");
+
+ /**
+ * Represents the SHA-1 (160-bit) hash algorithm.
+ */
+ public static final SimpleHashParameters SHA1 = new SimpleHashParameters("SHA-1");
+
+ /**
+ * Represents the SHA-256 (256-bit) hash algorithm.
+ */
+ public static final SimpleHashParameters SHA256 = new SimpleHashParameters("SHA-256");
+
+ /**
+ * Represents the SHA-384 (384-bit) hash algorithm.
+ */
+ public static final SimpleHashParameters SHA384 = new SimpleHashParameters("SHA-384");
+
+ /**
+ * Represents the SHA-512 (512-bit) hash algorithm.
+ */
+ public static final SimpleHashParameters SHA512 = new SimpleHashParameters("SHA-512");
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/params/SipHash24Parameters.java b/circe-checksum/src/main/java/com/scurrilous/circe/params/SipHash24Parameters.java
new file mode 100644
index 0000000..068f96d
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/params/SipHash24Parameters.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.params;
+
+import com.scurrilous.circe.HashParameters;
+
+/**
+ * Hash parameters for <a href="https://131002.net/siphash/">SipHash-2-4</a>.
+ */
+public final class SipHash24Parameters implements HashParameters {
+
+ private final long seedLow;
+ private final long seedHigh;
+
+ /**
+ * Constructs a {@link SipHash24Parameters} with the default seed,
+ * {@code 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F}.
+ */
+ public SipHash24Parameters() {
+ this(0x0706050403020100L, 0x0f0e0d0c0b0a0908L);
+ }
+
+ /**
+ * Constructs a {@link SipHash24Parameters} with the given seed.
+ *
+ * @param seedLow the low-order 64 bits of the seed
+ * @param seedHigh the high-order 64 bits of the seed
+ */
+ public SipHash24Parameters(long seedLow, long seedHigh) {
+ this.seedLow = seedLow;
+ this.seedHigh = seedHigh;
+ }
+
+ /**
+ * Returns the low-order 64 bits of the seed.
+ *
+ * @return low-order bits of seed
+ */
+ public long seedLow() {
+ return seedLow;
+ }
+
+ /**
+ * Returns the high-order 64 bits of the seed.
+ *
+ * @return high-order bits of seed
+ */
+ public long seedHigh() {
+ return seedHigh;
+ }
+
+ @Override
+ public String algorithm() {
+ return "SipHash-2-4";
+ }
+}
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/params/package-info.java b/circe-checksum/src/main/java/com/scurrilous/circe/params/package-info.java
new file mode 100644
index 0000000..87d9390
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/params/package-info.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+/**
+ * Defines {@linkplain com.scurrilous.circe.HashParameters hash parameters}
+ * classes that describe various commonly-used hash functions.
+ */
+package com.scurrilous.circe.params;
\ No newline at end of file
diff --git a/circe-checksum/src/main/java/com/scurrilous/circe/utils/NativeUtils.java b/circe-checksum/src/main/java/com/scurrilous/circe/utils/NativeUtils.java
new file mode 100644
index 0000000..8776092
--- /dev/null
+++ b/circe-checksum/src/main/java/com/scurrilous/circe/utils/NativeUtils.java
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.scurrilous.circe.utils;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Locale;
+
+/**
+ * Utils for loading native checksum library.
+ */
+public class NativeUtils {
+
+ public static final String OS_NAME = System.getProperty("os.name").toLowerCase(Locale.US);
+
+ /**
+ * loads given library from the this jar. ie: this jar contains: /lib/pulsar-checksum.jnilib
+ *
+ * @param path
+ * : absolute path of the library in the jar <br/>
+ * if this jar contains: /lib/pulsar-checksum.jnilib then provide the same absolute path as input
+ * @throws Exception
+ */
+ public static void loadLibraryFromJar(String path) throws Exception {
+
+ checkArgument(path.startsWith("/"), "absolute path must start with /");
+
+ String[] parts = path.split("/");
+ String filename = (parts.length > 0) ? parts[parts.length - 1] : null;
+
+ File dir = File.createTempFile("native", "");
+ dir.delete();
+ if (!(dir.mkdir())) {
+ throw new IOException("Failed to create temp directory " + dir.getAbsolutePath());
+ }
+ dir.deleteOnExit();
+ File temp = new File(dir, filename);
+ temp.deleteOnExit();
+
+ byte[] buffer = new byte[1024];
+ int read;
+
+ InputStream input = NativeUtils.class.getResourceAsStream(path);
+ if (input == null) {
+ throw new FileNotFoundException("Couldn't find file into jar " + path);
+ }
+
+ OutputStream out = new FileOutputStream(temp);
+ try {
+ while ((read = input.read(buffer)) != -1) {
+ out.write(buffer, 0, read);
+ }
+ } finally {
+ out.close();
+ input.close();
+ }
+
+ if (!temp.exists()) {
+ throw new FileNotFoundException("Failed to copy file from jar at " + temp.getAbsolutePath());
+ }
+
+ System.load(temp.getAbsolutePath());
+ }
+
+ /**
+ * Returns jni library extension based on OS specification. Maven-nar generates jni library based on different OS :
+ * http://mark.donszelmann.org/maven-nar-plugin/aol.html (jni.extension)
+ *
+ * @return
+ */
+ public static String libType() {
+
+ if (OS_NAME.indexOf("mac") >= 0) {
+ return "jnilib";
+ } else if (OS_NAME.indexOf("nix") >= 0 || OS_NAME.indexOf("nux") >= 0 || OS_NAME.indexOf("aix") > 0) {
+ return "so";
+ } else if (OS_NAME.indexOf("win") >= 0) {
+ return "dll";
+ }
+ throw new TypeNotPresentException(OS_NAME + " not supported", null);
+ }
+}
diff --git a/circe-checksum/src/main/resources/META-INF/services/com.scurrilous.circe.HashProvider b/circe-checksum/src/main/resources/META-INF/services/com.scurrilous.circe.HashProvider
new file mode 100644
index 0000000..7822e75
--- /dev/null
+++ b/circe-checksum/src/main/resources/META-INF/services/com.scurrilous.circe.HashProvider
@@ -0,0 +1 @@
+com.scurrilous.circe.crc.StandardCrcProvider
\ No newline at end of file
diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/CommonHashesTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/CommonHashesTest.java
new file mode 100644
index 0000000..a42de85
--- /dev/null
+++ b/circe-checksum/src/test/java/com/scurrilous/circe/CommonHashesTest.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe;
+
+import static org.testng.Assert.assertEquals;
+
+import java.nio.charset.Charset;
+
+import org.testng.annotations.Test;
+
+@SuppressWarnings("javadoc")
+public class CommonHashesTest {
+
+ private static final Charset ASCII = Charset.forName("ASCII");
+ private static final byte[] DIGITS = "123456789".getBytes(ASCII);
+
+
+ @Test
+ public void testCrc32() {
+ assertEquals(0xcbf43926, CommonHashes.crc32().calculate(DIGITS));
+ }
+
+ @Test
+ public void testCrc32c() {
+ assertEquals(0xe3069283, CommonHashes.crc32c().calculate(DIGITS));
+ }
+
+ @Test
+ public void testCrc64() {
+ assertEquals(0x6c40df5f0b497347L, CommonHashes.crc64().calculate(DIGITS));
+ }
+}
diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCProvidersTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCProvidersTest.java
new file mode 100644
index 0000000..b3ac059
--- /dev/null
+++ b/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCProvidersTest.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+import static com.scurrilous.circe.HashSupport.HARDWARE;
+import static com.scurrilous.circe.HashSupport.INCREMENTAL;
+import static com.scurrilous.circe.HashSupport.INT_SIZED;
+import static com.scurrilous.circe.HashSupport.LONG_SIZED;
+import static com.scurrilous.circe.HashSupport.NATIVE;
+import static com.scurrilous.circe.HashSupport.STATEFUL;
+import static com.scurrilous.circe.HashSupport.STATELESS_INCREMENTAL;
+import static com.scurrilous.circe.params.CrcParameters.CRC32;
+import static com.scurrilous.circe.params.CrcParameters.CRC64;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.SortedMap;
+
+import org.testng.annotations.Test;
+
+import com.scurrilous.circe.HashProvider;
+import com.scurrilous.circe.HashProviders;
+import com.scurrilous.circe.HashSupport;
+import com.scurrilous.circe.IncrementalLongHash;
+
+@SuppressWarnings("javadoc")
+public class CRCProvidersTest {
+
+ @Test
+ public void testAll() {
+ final Iterator<HashProvider> i = HashProviders.iterator();
+ assertTrue(i.hasNext());
+ assertTrue(i.next() instanceof StandardCrcProvider);
+ assertFalse(i.hasNext());
+ }
+
+ @Test
+ public void testNonUnique() {
+ final HashProvider provider = HashProviders.best(CRC32);
+ final IncrementalLongHash i1 = provider.getIncrementalLong(CRC32);
+ final IncrementalLongHash i2 = provider.getIncrementalLong(CRC32);
+ assertTrue(i1 != i2);
+ }
+
+ @Test
+ public void testSearchCRCParametersCRC32() {
+ final SortedMap<EnumSet<HashSupport>, HashProvider> map = HashProviders.search(CRC32);
+ assertEquals(1, map.size());
+ final Entry<EnumSet<HashSupport>, HashProvider> entry = map.entrySet().iterator().next();
+ assertEquals(EnumSet.of(NATIVE, STATELESS_INCREMENTAL, INCREMENTAL, INT_SIZED, LONG_SIZED,
+ STATEFUL), entry.getKey());
+ assertTrue(entry.getValue() instanceof StandardCrcProvider);
+ }
+
+ @Test
+ public void testSearchCRCParametersCRC64() {
+ final SortedMap<EnumSet<HashSupport>, HashProvider> map = HashProviders.search(CRC64);
+ assertEquals(1, map.size());
+ final Entry<EnumSet<HashSupport>, HashProvider> entry = map.entrySet().iterator().next();
+ assertEquals(EnumSet.of(STATELESS_INCREMENTAL, INCREMENTAL, LONG_SIZED, STATEFUL),
+ entry.getKey());
+ assertTrue(entry.getValue() instanceof StandardCrcProvider);
+ }
+
+ @Test
+ public void testSearchCRCParametersEnumSet() {
+ assertEquals(1, HashProviders.search(CRC32, EnumSet.of(NATIVE)).size());
+ assertTrue(HashProviders.search(CRC64, EnumSet.of(NATIVE)).isEmpty());
+ assertTrue(HashProviders.search(CRC32, EnumSet.of(HARDWARE)).isEmpty());
+ }
+}
diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCTest.java
new file mode 100644
index 0000000..c2803c9
--- /dev/null
+++ b/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCTest.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.crc;
+
+import static com.scurrilous.circe.params.CrcParameters.CRC16;
+import static com.scurrilous.circe.params.CrcParameters.CRC16_CCITT;
+import static com.scurrilous.circe.params.CrcParameters.CRC16_XMODEM;
+import static com.scurrilous.circe.params.CrcParameters.CRC32;
+import static com.scurrilous.circe.params.CrcParameters.CRC32C;
+import static com.scurrilous.circe.params.CrcParameters.CRC32_BZIP2;
+import static com.scurrilous.circe.params.CrcParameters.CRC32_POSIX;
+import static com.scurrilous.circe.params.CrcParameters.CRC64;
+import static com.scurrilous.circe.params.CrcParameters.CRC64_XZ;
+import static org.testng.Assert.assertEquals;
+
+import java.nio.charset.Charset;
+
+import org.testng.annotations.Test;
+
+import com.scurrilous.circe.HashProvider;
+import com.scurrilous.circe.IncrementalIntHash;
+import com.scurrilous.circe.params.CrcParameters;
+
+/**
+ * Tests the {@link StandardCrcProvider} with various CRC algorithms. See the <a
+ * href="http://reveng.sourceforge.net/crc-catalogue/">Catalogue of parametrised
+ * CRC algorithms</a> for more information on these algorithms and others.
+ */
+@SuppressWarnings("javadoc")
+public class CRCTest {
+
+ private static final HashProvider PROVIDER = new StandardCrcProvider();
+ private static final Charset ASCII = Charset.forName("ASCII");
+ private static final byte[] DIGITS = "123456789".getBytes(ASCII);
+
+ @Test
+ public void testCRC3_ROHC() {
+ final CrcParameters CRC3_ROHC = new CrcParameters("CRC-3/ROHC", 3, 0x3, 0x7, 0, true);
+ assertEquals(0x6, PROVIDER.getIncrementalInt(CRC3_ROHC).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC5_EPC() {
+ final CrcParameters CRC5_EPC = new CrcParameters("CRC-5/EPC", 5, 0x09, 0x09, 0, false);
+ assertEquals(0x00, PROVIDER.getIncrementalInt(CRC5_EPC).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC5_USB() {
+ final CrcParameters CRC5_USB = new CrcParameters("CRC-5/USB", 5, 0x05, 0x1f, 0x1f, true);
+ assertEquals(0x19, PROVIDER.getIncrementalInt(CRC5_USB).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC7() {
+ final CrcParameters CRC7 = new CrcParameters("CRC-7", 7, 0x09, 0, 0, false);
+ assertEquals(0x75, PROVIDER.getIncrementalInt(CRC7).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC7ROHC() {
+ final CrcParameters CRC7_ROHC = new CrcParameters("CRC-7/ROHC", 7, 0x4f, 0x7f, 0, true);
+ assertEquals(0x53, PROVIDER.getIncrementalInt(CRC7_ROHC).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC8() {
+ final CrcParameters CRC8 = new CrcParameters("CRC-8", 8, 0x07, 0, 0, false);
+ assertEquals(0xf4, PROVIDER.getIncrementalInt(CRC8).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC10() {
+ final CrcParameters CRC10 = new CrcParameters("CRC-10", 10, 0x233, 0, 0, false);
+ assertEquals(0x199, PROVIDER.getIncrementalInt(CRC10).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC15() {
+ final CrcParameters CRC15 = new CrcParameters("CRC-15", 15, 0x4599, 0, 0, false);
+ assertEquals(0x059e, PROVIDER.getIncrementalInt(CRC15).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC16() {
+ assertEquals(0xbb3d, PROVIDER.getIncrementalInt(CRC16).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC16_CCITT() {
+ assertEquals(0x2189, PROVIDER.getIncrementalInt(CRC16_CCITT).calculate(DIGITS));
+ }
+
+ @Test
+ public void testXMODEM() {
+ assertEquals(0x31c3, PROVIDER.getIncrementalInt(CRC16_XMODEM).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC24() {
+ final CrcParameters CRC24 = new CrcParameters("CRC-24", 24, 0x864cfb, 0xb704ce, 0, false);
+ assertEquals(0x21cf02, PROVIDER.getIncrementalInt(CRC24).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC32() {
+ assertEquals(0xcbf43926, PROVIDER.getIncrementalInt(CRC32).calculate(DIGITS));
+ }
+
+ @Test
+ public void testJavaCRC32() {
+ assertEquals(0xcbf43926, PROVIDER.getStatelessInt(CRC32).calculate(DIGITS));
+ }
+
+ @Test
+ public void testBZIP2() {
+ assertEquals(0xfc891918, PROVIDER.getIncrementalInt(CRC32_BZIP2).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC32C() {
+ assertEquals(0xe3069283, PROVIDER.getIncrementalInt(CRC32C).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC32D() {
+ final CrcParameters CRC32D = new CrcParameters("CRC-32D", 32, 0xa833982b, ~0, ~0, true);
+ assertEquals(0x87315576, PROVIDER.getIncrementalInt(CRC32D).calculate(DIGITS));
+ }
+
+ @Test
+ public void testPOSIX() {
+ assertEquals(0x765e7680, PROVIDER.getIncrementalInt(CRC32_POSIX).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC32Q() {
+ final CrcParameters CRC32Q = new CrcParameters("CRC-32Q", 32, 0x814141ab, 0, 0, false);
+ assertEquals(0x3010bf7f, PROVIDER.getIncrementalInt(CRC32Q).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC64() {
+ assertEquals(0x6c40df5f0b497347L, PROVIDER.getIncrementalLong(CRC64).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC64_XZ() {
+ assertEquals(0x995dc9bbdf1939faL, PROVIDER.getIncrementalLong(CRC64_XZ).calculate(DIGITS));
+ }
+
+ @Test
+ public void testCRC32CIncremental() {
+ // reflected
+ testIncremental(PROVIDER.getIncrementalInt(CRC32C));
+ }
+
+ private void testIncremental(IncrementalIntHash hash) {
+ final String data = "data";
+ final String combined = data + data;
+
+ final int dataChecksum = hash.calculate(data.getBytes(ASCII));
+ final int combinedChecksum = hash.calculate(combined.getBytes(ASCII));
+ final int incrementalChecksum = hash.resume(dataChecksum, data.getBytes(ASCII));
+ assertEquals(combinedChecksum, incrementalChecksum);
+ }
+}
\ No newline at end of file
diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalIntHashTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalIntHashTest.java
new file mode 100644
index 0000000..0f947c9
--- /dev/null
+++ b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalIntHashTest.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import static org.testng.Assert.*;
+
+import com.scurrilous.circe.StatefulHash;
+import java.nio.ByteBuffer;
+import mockit.Expectations;
+import mockit.Mocked;
+import org.testng.annotations.Test;
+
+@SuppressWarnings("javadoc")
+public class AbstractIncrementalIntHashTest {
+
+ @Mocked
+ private AbstractIncrementalIntHash hash;
+
+ @Test
+ public void testAsStateful() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.algorithm();
+ hash.length();
+ hash.initial();
+ result = 42;
+ hash.resumeUnchecked(42, input, 2, 4);
+ result = 99;
+ }
+ };
+ StatefulHash stateful = hash.createStateful();
+ stateful.algorithm();
+ stateful.length();
+ assertNotEquals(stateful, stateful.createNew());
+ stateful.reset();
+ stateful.update(input, 2, 4);
+ assertEquals(99, stateful.getInt());
+ }
+
+ @Test
+ public void testCalculateByteArray() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.initial();
+ result = 42;
+ hash.resume(42, input);
+ }
+ };
+ hash.calculate(input);
+ }
+
+ @Test
+ public void testCalculateByteArrayIntInt() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.initial();
+ result = 42;
+ hash.resume(42, input, 2, 4);
+ }
+ };
+ hash.calculate(input, 2, 4);
+ }
+
+ @Test
+ public void testCalculateByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(10);
+ new Expectations(hash) {
+ {
+ hash.initial();
+ result = 42;
+ hash.resume(42, input);
+ }
+ };
+ hash.calculate(input);
+ }
+
+ @Test
+ public void testResumeIntByteArray() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.resumeUnchecked(42, input, 0, input.length);
+ }
+ };
+ hash.resume(42, input);
+ }
+
+ @Test
+ public void testResumeIntByteArrayIntInt() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.resumeUnchecked(42, input, 2, 4);
+ }
+ };
+ hash.resume(42, input, 2, 4);
+ }
+
+ @Test
+ public void testResumeIntByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(20);
+ input.position(5);
+ input.limit(15);
+ new Expectations(hash) {
+ {
+ hash.resumeUnchecked(42, input.array(), input.arrayOffset() + 5, 10);
+ }
+ };
+ hash.resume(42, input);
+ assertEquals(input.limit(), input.position());
+ }
+
+ @Test
+ public void testResumeIntReadOnlyByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(20).asReadOnlyBuffer();
+ input.position(5);
+ input.limit(15);
+ new Expectations(hash) {
+ {
+ hash.resumeUnchecked(42, withInstanceOf(byte[].class), 0, 10);
+ }
+ };
+ hash.resume(42, input);
+ assertEquals(input.limit(), input.position());
+ }
+}
diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalLongHashTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalLongHashTest.java
new file mode 100644
index 0000000..0468da8
--- /dev/null
+++ b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalLongHashTest.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import static org.testng.Assert.*;
+
+import java.nio.ByteBuffer;
+
+import mockit.Expectations;
+import mockit.Mocked;
+
+import org.testng.annotations.Test;
+
+import com.scurrilous.circe.StatefulHash;
+import com.scurrilous.circe.impl.AbstractIncrementalLongHash;
+
+@SuppressWarnings("javadoc")
+public class AbstractIncrementalLongHashTest {
+
+ @Mocked
+ private AbstractIncrementalLongHash hash;
+
+ @Test
+ public void testAsStateful() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.algorithm();
+ hash.length();
+ hash.initial();
+ result = 0x4200000000L;
+ hash.resumeUnchecked(0x4200000000L, input, 2, 4);
+ result = 0x990000000000L;
+ }
+ };
+ StatefulHash stateful = hash.createStateful();
+ stateful.algorithm();
+ stateful.length();
+ assertNotSame(stateful, stateful.createNew());
+ stateful.reset();
+ stateful.update(input, 2, 4);
+ assertEquals(0, stateful.getInt());
+ assertEquals(0x990000000000L, stateful.getLong());
+ }
+
+ @Test
+ public void testCalculateByteArray() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.initial();
+ result = 0x4200000000L;
+ hash.resume(0x4200000000L, input);
+ }
+ };
+ hash.calculate(input);
+ }
+
+ @Test
+ public void testCalculateByteArrayIntInt() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.initial();
+ result = 0x4200000000L;
+ hash.resume(0x4200000000L, input, 2, 4);
+ }
+ };
+ hash.calculate(input, 2, 4);
+ }
+
+ @Test
+ public void testCalculateByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(10);
+ new Expectations(hash) {
+ {
+ hash.initial();
+ result = 0x4200000000L;
+ hash.resume(0x4200000000L, input);
+ }
+ };
+ hash.calculate(input);
+ }
+
+ @Test
+ public void testResumeLongByteArray() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.resumeUnchecked(0x4200000000L, input, 0, input.length);
+ }
+ };
+ hash.resume(0x4200000000L, input);
+ }
+
+ @Test
+ public void testResumeLongByteArrayIntInt() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.resumeUnchecked(0x4200000000L, input, 2, 4);
+ }
+ };
+ hash.resume(0x4200000000L, input, 2, 4);
+ }
+
+ @Test
+ public void testResumeLongByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(20);
+ input.position(5);
+ input.limit(15);
+ new Expectations(hash) {
+ {
+ hash.resumeUnchecked(0x4200000000L, input.array(), input.arrayOffset() + 5, 10);
+ }
+ };
+ hash.resume(0x4200000000L, input);
+ assertEquals(input.limit(), input.position());
+ }
+
+ @Test
+ public void testResumeLongReadOnlyByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(20).asReadOnlyBuffer();
+ input.position(5);
+ input.limit(15);
+ new Expectations(hash) {
+ {
+ hash.resumeUnchecked(0x4200000000L, withInstanceOf(byte[].class), 0, 10);
+ }
+ };
+ hash.resume(0x4200000000L, input);
+ assertEquals(input.limit(), input.position());
+ }
+}
diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatefulHashTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatefulHashTest.java
new file mode 100644
index 0000000..8cad8b1
--- /dev/null
+++ b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatefulHashTest.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import static org.testng.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import mockit.Expectations;
+import mockit.Mocked;
+import mockit.NonStrictExpectations;
+
+import org.testng.annotations.Test;
+
+@SuppressWarnings("javadoc")
+public class AbstractStatefulHashTest {
+
+ @Mocked
+ private AbstractStatefulHash hash;
+
+ @Test
+ public void testUpdateByteArray() {
+ final byte[] input = new byte[42];
+ new Expectations(hash) {
+ {
+ hash.updateUnchecked(input, 0, input.length);
+ }
+ };
+ hash.update(input);
+ }
+
+ @Test
+ public void testUpdateByteArrayIntInt() {
+ final byte[] input = new byte[42];
+ new Expectations(hash) {
+ {
+ hash.updateUnchecked(input, 5, 10);
+ }
+ };
+ hash.update(input, 5, 10);
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testUpdateByteArrayIntNegInt() {
+ final byte[] input = new byte[42];
+ new Expectations(hash) {
+ };
+ hash.update(input, 1, -1);
+ }
+
+ @Test(expectedExceptions = IndexOutOfBoundsException.class)
+ public void testUpdateByteArrayNegIntInt() {
+ final byte[] input = new byte[42];
+ new Expectations(hash) {
+ };
+ hash.update(input, -1, 10);
+ }
+
+ @Test(expectedExceptions = IndexOutOfBoundsException.class)
+ public void testUpdateByteArrayIntIntOverflow() {
+ final byte[] input = new byte[42];
+ new Expectations(hash) {
+ };
+ hash.update(input, 40, 3);
+ }
+
+ @Test
+ public void testUpdateByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(20);
+ input.position(5);
+ input.limit(15);
+ new Expectations(hash) {
+ {
+ hash.updateUnchecked(input.array(), input.arrayOffset() + 5, 10);
+ }
+ };
+ hash.update(input);
+ assertEquals(input.limit(), input.position());
+ }
+
+ @Test
+ public void testUpdateReadOnlyByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(20).asReadOnlyBuffer();
+ input.position(5);
+ input.limit(15);
+ new Expectations(hash) {
+ {
+ hash.updateUnchecked(withInstanceOf(byte[].class), 0, 10);
+ }
+ };
+ hash.update(input);
+ assertEquals(input.limit(), input.position());
+ }
+
+ @Test
+ public void testGetBytes() {
+ final List<byte[]> captures = new ArrayList<>();
+ new Expectations(hash) {
+ {
+ hash.length();
+ result = 5;
+ hash.writeBytes(withCapture(captures), 0, 5);
+ }
+ };
+ hash.getBytes();
+ assertEquals(5, captures.get(0).length);
+ }
+
+ @Test
+ public void testGetBytesByteArrayInt() {
+ final byte[] output = new byte[5];
+ new Expectations(hash) {
+ {
+ hash.length();
+ result = output.length;
+ hash.getLong();
+ result = 0x1234567890L;
+ }
+ };
+ hash.getBytes(output, 0, output.length);
+ assertEquals(new byte[] { (byte) 0x90, 0x78, 0x56, 0x34, 0x12 }, output);
+ }
+
+ @Test(expectedExceptions = IndexOutOfBoundsException.class)
+ public void testGetBytesByteArrayNegInt() {
+ final byte[] output = new byte[5];
+ new NonStrictExpectations(hash) {
+ {
+ hash.length();
+ result = output.length;
+ }
+ };
+ hash.getBytes(output, -1, output.length);
+ }
+
+ @Test(expectedExceptions = IndexOutOfBoundsException.class)
+ public void testGetBytesByteArrayIntOverflow() {
+ final byte[] output = new byte[5];
+ new Expectations(hash) {
+ };
+ hash.getBytes(output, 0, output.length + 1);
+ }
+
+ @Test
+ public void testGetBytesByteArrayIntPartial() {
+ final byte[] output = new byte[5];
+ new Expectations(hash) {
+ {
+ hash.length();
+ result = output.length + 1;
+ hash.writeBytes(output, 0, output.length);
+ }
+ };
+ hash.getBytes(output, 0, output.length);
+ }
+
+ @Test
+ public void testGetByte() {
+ new Expectations(hash) {
+ {
+ hash.getInt();
+ result = 0x12345678;
+ }
+ };
+ assertEquals(0x78, hash.getByte());
+ }
+
+ @Test
+ public void testGetShort() {
+ new Expectations(hash) {
+ {
+ hash.getInt();
+ result = 0x12345678;
+ }
+ };
+ assertEquals(0x5678, hash.getShort());
+ }
+}
diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessIntHashTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessIntHashTest.java
new file mode 100644
index 0000000..184b546
--- /dev/null
+++ b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessIntHashTest.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import static org.testng.Assert.*;
+
+import java.nio.ByteBuffer;
+
+import mockit.Expectations;
+import mockit.Mocked;
+
+import org.testng.annotations.Test;
+
+import com.scurrilous.circe.impl.AbstractStatelessIntHash;
+
+@SuppressWarnings("javadoc")
+public class AbstractStatelessIntHashTest {
+
+ @Mocked
+ private AbstractStatelessIntHash hash;
+
+ @Test
+ public void testCalculateByteArray() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.calculateUnchecked(input, 0, input.length);
+ }
+ };
+ hash.calculate(input);
+ }
+
+ @Test
+ public void testCalculateByteArrayIntInt() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.calculateUnchecked(input, 2, 4);
+ }
+ };
+ hash.calculate(input, 2, 4);
+ }
+
+ @Test
+ public void testCalculateByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(20);
+ input.position(5);
+ input.limit(15);
+ new Expectations(hash) {
+ {
+ hash.calculateUnchecked(input.array(), input.arrayOffset() + 5, 10);
+ }
+ };
+ hash.calculate(input);
+ assertEquals(input.limit(), input.position());
+ }
+
+ @Test
+ public void testCalculateReadOnlyByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(20).asReadOnlyBuffer();
+ input.position(5);
+ input.limit(15);
+ new Expectations(hash) {
+ {
+ hash.calculateUnchecked(withInstanceOf(byte[].class), 0, 10);
+ }
+ };
+ hash.calculate(input);
+ assertEquals(input.limit(), input.position());
+ }
+}
diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessLongHashTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessLongHashTest.java
new file mode 100644
index 0000000..a4a607f
--- /dev/null
+++ b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessLongHashTest.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright 2014 Trevor Robinson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.scurrilous.circe.impl;
+
+import static org.testng.Assert.*;
+
+import java.nio.ByteBuffer;
+
+import mockit.Expectations;
+import mockit.Mocked;
+
+import org.testng.annotations.Test;
+
+import com.scurrilous.circe.impl.AbstractStatelessLongHash;
+
+@SuppressWarnings("javadoc")
+public class AbstractStatelessLongHashTest {
+
+ @Mocked
+ private AbstractStatelessLongHash hash;
+
+ @Test
+ public void testCalculateByteArray() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.calculateUnchecked(input, 0, input.length);
+ }
+ };
+ hash.calculate(input);
+ }
+
+ @Test
+ public void testCalculateByteArrayIntInt() {
+ final byte[] input = new byte[10];
+ new Expectations(hash) {
+ {
+ hash.calculateUnchecked(input, 2, 4);
+ }
+ };
+ hash.calculate(input, 2, 4);
+ }
+
+ @Test
+ public void testCalculateByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(20);
+ input.position(5);
+ input.limit(15);
+ new Expectations(hash) {
+ {
+ hash.calculateUnchecked(input.array(), input.arrayOffset() + 5, 10);
+ }
+ };
+ hash.calculate(input);
+ assertEquals(input.limit(), input.position());
+ }
+
+ @Test
+ public void testCalculateReadOnlyByteBuffer() {
+ final ByteBuffer input = ByteBuffer.allocate(20).asReadOnlyBuffer();
+ input.position(5);
+ input.limit(15);
+ new Expectations(hash) {
+ {
+ hash.calculateUnchecked(withInstanceOf(byte[].class), 0, 10);
+ }
+ };
+ hash.calculate(input);
+ assertEquals(input.limit(), input.position());
+ }
+}
diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/utils/NativeUtilsTests.java b/circe-checksum/src/test/java/com/scurrilous/circe/utils/NativeUtilsTests.java
new file mode 100644
index 0000000..f1d4928
--- /dev/null
+++ b/circe-checksum/src/test/java/com/scurrilous/circe/utils/NativeUtilsTests.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.scurrilous.circe.utils;
+
+import java.io.FileNotFoundException;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Unit test of {@link NativeUtils}.
+ */
+public class NativeUtilsTests {
+
+ @Test
+ public void testLoadLibrary() throws Exception {
+
+ final String fileName = "test" + NativeUtils.libType();
+ try {
+ NativeUtils.loadLibraryFromJar(fileName);
+ Assert.fail("Should fail because of not having absolute path");
+ } catch (IllegalArgumentException e) {
+ // OK
+ }
+
+ try {
+ NativeUtils.loadLibraryFromJar("/" + fileName);
+ Assert.fail("Should fail because no file present into the jar");
+ } catch (FileNotFoundException e) {
+ // OK
+ }
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index b3f6b75..d284723 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,9 +52,10 @@
</ciManagement>
<modules>
<module>buildtools</module>
- <module>bookkeeper-proto</module>
+ <module>circe-checksum</module>
<module>bookkeeper-common</module>
<module>bookkeeper-stats</module>
+ <module>bookkeeper-proto</module>
<module>bookkeeper-server</module>
<module>bookkeeper-benchmark</module>
<module>bookkeeper-stats-providers</module>
--
To stop receiving notification emails like this one, please contact
['"commits@bookkeeper.apache.org" <co...@bookkeeper.apache.org>'].